1#![deny(missing_docs, warnings)]
2
3extern crate unsafe_any as uany;
6pub mod typemap;
7
8use std::any::Any;
9use typemap::{Key, TypeMap};
10use typemap::Implements;
11
12pub trait Plugin<E: ?Sized>: Key {
17 type Error;
19
20 fn eval(ext_type: &mut E) -> Result<Self::Value, Self::Error>;
27}
28
29pub trait Extensible<A: uany::UnsafeAnyExt + ?Sized = uany::UnsafeAny> {
33 fn extensions(&self) -> &TypeMap<A>;
35
36 fn extensions_mut(&mut self) -> &mut TypeMap<A>;
38}
39
40pub trait Pluggable<A: uany::UnsafeAnyExt + ?Sized = uany::UnsafeAny> {
42 fn get<'a, P: Plugin<Self>>(&'a mut self) -> Result<P::Value, P::Error>
49 where P::Value: Clone + Any + Implements<A>, Self: Extensible<A>, A: 'a {
50 self.get_ref::<P>().map(|v| v.clone())
51 }
52
53 fn get_ref<'a, P: Plugin<Self>>(&'a mut self) -> Result<&P::Value, P::Error>
60 where P::Value: Any + Implements<A>, Self: Extensible<A>, A: 'a {
61 self.get_mut::<P>().map(|mutref| &*mutref)
62 }
63
64 fn get_mut<'a, P: Plugin<Self>>(&'a mut self) -> Result<&mut P::Value, P::Error>
71 where P::Value: Any + Implements<A>, Self: Extensible<A>, A: 'a {
72 use typemap::Entry::{Occupied, Vacant};
73
74 if self.extensions().contains::<P>() {
75 return Ok(self.extensions_mut().get_mut::<P>().unwrap());
76 }
77
78 P::eval(self).map(move |data| {
79 match self.extensions_mut().entry::<P>() {
80 Vacant(entry) => entry.insert(data),
81 Occupied(..) => panic!("Unreachable.")
82 }
83 })
84 }
85
86 fn compute<P: Plugin<Self>>(&mut self) -> Result<P::Value, P::Error> {
88 <P as Plugin<Self>>::eval(self)
89 }
90}
91
92#[cfg(test)]
93mod test {
94 extern crate void;
95
96 use test::void::{Void, ResultVoidExt};
97
98 use typemap::{SendMap, Key};
99 use super::{Extensible, Plugin, Pluggable};
100
101 struct Extended {
102 map: SendMap
103 }
104
105 impl Extended {
106 fn new() -> Extended {
107 Extended { map: SendMap::custom() }
108 }
109 }
110
111 impl Extensible<::uany::UnsafeAny + Send> for Extended {
112 fn extensions(&self) -> &SendMap { &self.map }
113 fn extensions_mut(&mut self) -> &mut SendMap { &mut self.map }
114 }
115
116 impl Pluggable<::uany::UnsafeAny + Send> for Extended {}
117
118 macro_rules! generate_simple_plugin (
119 ($t:ty, $v:ident, $v2:expr) => {
120 #[derive(PartialEq, Debug, Clone)]
121 struct $v(i32);
122
123 impl Key for $t { type Value = $t; }
124
125 impl Plugin<Extended> for $t {
126 type Error = Void;
127
128 fn eval(_: &mut Extended) -> Result<$t, Void> {
129 Ok($v($v2))
130 }
131 }
132 }
133 );
134
135 generate_simple_plugin!(One, One, 1);
136 generate_simple_plugin!(Two, Two, 2);
137 generate_simple_plugin!(Three, Three, 3);
138 generate_simple_plugin!(Four, Four, 4);
139 generate_simple_plugin!(Five, Five, 5);
140 generate_simple_plugin!(Six, Six, 6);
141 generate_simple_plugin!(Seven, Seven, 7);
142 generate_simple_plugin!(Eight, Eight, 8);
143 generate_simple_plugin!(Nine, Nine, 9);
144 generate_simple_plugin!(Ten, Ten, 10);
145
146 #[test] fn test_simple() {
147 let mut extended = Extended::new();
148 assert_eq!(extended.get::<One>(), Ok(One(1)));
149 assert_eq!(extended.get::<Two>(), Ok(Two(2)));
150 assert_eq!(extended.get::<Three>(), Ok(Three(3)));
151 }
152
153 #[test] fn test_resize() {
154 let mut extended = Extended::new();
155 extended.get::<One>().void_unwrap();
156 extended.get::<Two>().void_unwrap();
157 extended.get::<Three>().void_unwrap();
158 extended.get::<Four>().void_unwrap();
159 extended.get::<Five>().void_unwrap();
160 extended.get::<Six>().void_unwrap();
161 extended.get::<Seven>().void_unwrap();
162 extended.get::<Eight>().void_unwrap();
163 extended.get::<Nine>().void_unwrap();
164 extended.get::<Ten>().void_unwrap();
165 assert_eq!(extended.get_ref::<One>(), Ok(&One(1)))
166 }
167
168 #[test] fn test_custom_return_type() {
169 let mut extended = Extended::new();
170
171 struct IntPlugin;
173
174 impl Key for IntPlugin { type Value = i32; }
176
177 impl Plugin<Extended> for IntPlugin {
179 type Error = Void;
180
181 fn eval(_: &mut Extended) -> Result<i32, Void> {
182 Ok(0i32)
183 }
184 }
185 assert_eq!(extended.get::<IntPlugin>().void_unwrap(), 0i32);
186 }
187}
188