query_interface/
lib.rs

1//! query-interface - dynamically query a type-erased object for any trait implementation
2//!
3//! ```rust
4//! #[macro_use]
5//! extern crate query_interface;
6//! use query_interface::{Object, ObjectClone};
7//! use std::fmt::Debug;
8//!
9//! #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
10//! struct Foo;
11//!
12//! interfaces!(Foo: ObjectClone, Debug, Bar);
13//!
14//! trait Bar {
15//!     fn do_something(&self);
16//! }
17//! impl Bar for Foo {
18//!     fn do_something(&self) {
19//!         println!("I'm a Foo!");
20//!     }
21//! }
22//!
23//! fn main() {
24//!     let obj = Box::new(Foo) as Box<Object>;
25//!     let obj2 = obj.clone();
26//!     println!("{:?}", obj2);
27//!
28//!     obj2.query_ref::<Bar>().unwrap().do_something();  // Prints: "I'm a Foo!"
29//! }
30//! ```
31#[cfg(feature = "dynamic")]
32#[macro_use]
33extern crate lazy_static;
34
35use std::any::{TypeId, Any};
36use std::ptr;
37use std::cmp::Ordering;
38use std::hash::{Hash, Hasher};
39use std::collections::hash_map::DefaultHasher;
40use std::fmt::{Debug, Display};
41use std::path::PathBuf;
42
43#[cfg(feature = "dynamic")]
44#[macro_use]
45pub mod dynamic;
46
47/// Represents a trait object's vtable pointer. You shouldn't need to use this as a
48/// consumer of the crate but it is required for macro expansion.
49#[doc(hidden)]
50#[repr(C)]
51#[derive(Copy, Clone, Debug)]
52pub struct VTable(*const ());
53
54impl VTable {
55    pub fn none() -> VTable {
56        VTable(ptr::null())
57    }
58}
59
60unsafe impl Send for VTable {}
61unsafe impl Sync for VTable {}
62
63/// Represents a trait object's layout. You shouldn't need to use this as a
64/// consumer of the crate but it is required for macro expansion.
65#[doc(hidden)]
66#[repr(C)]
67#[derive(Copy, Clone, Debug)]
68pub struct TraitObject {
69    pub data: *const (),
70    pub vtable: VTable
71}
72
73/// Obtain the vtable for a type/trait pair. You shouldn't need to use this as a
74/// consumer of the crate but it is required for macro expansion.
75#[doc(hidden)]
76#[macro_export]
77macro_rules! vtable_for {
78    ($x:ty as $y:ty) => ({
79        let x = ::std::ptr::null::<$x>() as *const $y;
80        #[allow(unused_unsafe)]
81        unsafe { ::std::mem::transmute::<_, $crate::TraitObject>(x).vtable }
82    })
83}
84
85/// Define a custom Object-like trait. The `query`, `query_ref` and `query_mut`
86/// methods will be automatically implemented on this trait object.
87/// 
88/// You may add additional static bounds to your custom trait via the
89/// `HasInterface<I>` trait. This example will statically ensure that all
90/// types convertible to `MyObject` can be cloned. Your trait must extend
91/// `Object`.
92/// 
93/// ```rust
94/// # #[macro_use]
95/// # extern crate query_interface;
96/// # use query_interface::*;
97/// trait MyObject: Object + ObjectClone + HasInterface<ObjectClone> { }
98/// mopo!(MyObject);
99/// # fn main() {}
100/// ```
101#[macro_export]
102macro_rules! mopo {
103    ($name:ty) => (
104        impl $name {
105            pub fn query_ref<U: ::std::any::Any + ?Sized>(&self) -> Option<&U> {
106                if let Some(vtable) = self.query_vtable(::std::any::TypeId::of::<U>()) {
107                    unsafe {
108                        let data = self as *const Self;
109                        let u = $crate::TraitObject { data: data as *const (), vtable: vtable };
110                        Some(*::std::mem::transmute::<_, &&U>(&u))
111                    }
112                } else {
113                    None
114                }
115            }
116            pub fn query_mut<U: ::std::any::Any + ?Sized>(&mut self) -> Option<&mut U> {
117                if let Some(vtable) = self.query_vtable(::std::any::TypeId::of::<U>()) {
118                    unsafe {
119                        let data = self as *mut Self;
120                        let mut u = $crate::TraitObject { data: data as *const (), vtable: vtable };
121                        Some(*::std::mem::transmute::<_, &mut &mut U>(&mut u))
122                    }
123                } else {
124                    None
125                }
126            }
127            pub fn query<U: ::std::any::Any + ?Sized>(self: Box<Self>) -> ::std::result::Result<Box<U>, Box<Self>> {
128                if let Some(vtable) = self.query_vtable(::std::any::TypeId::of::<U>()) {
129                    unsafe {
130                        let data = Box::into_raw(self);
131                        let mut u = $crate::TraitObject { data: data as *const (), vtable: vtable };
132                        Ok(Box::from_raw(*::std::mem::transmute::<_, &mut *mut U>(&mut u)))
133                    }
134                } else {
135                    Err(self)
136                }
137            }
138            pub fn query_arc<U: ::std::any::Any + ?Sized>(self_: ::std::sync::Arc<Self>) -> ::std::result::Result<::std::sync::Arc<U>, ::std::sync::Arc<Self>> {
139                if let Some(vtable) = self_.query_vtable(::std::any::TypeId::of::<U>()) {
140                    unsafe {
141                        let data = ::std::sync::Arc::into_raw(self_);
142                        let mut u = $crate::TraitObject { data: data as *const (), vtable: vtable };
143                        Ok(::std::sync::Arc::from_raw(*::std::mem::transmute::<_, &mut *mut U>(&mut u)))
144                    }
145                } else {
146                    Err(self_)
147                }
148            }
149            pub fn query_rc<U: ::std::any::Any + ?Sized>(self_: ::std::rc::Rc<Self>) -> ::std::result::Result<::std::rc::Rc<U>, ::std::rc::Rc<Self>> {
150                if let Some(vtable) = self_.query_vtable(::std::any::TypeId::of::<U>()) {
151                    unsafe {
152                        let data = ::std::rc::Rc::into_raw(self_);
153                        let mut u = $crate::TraitObject { data: data as *const (), vtable: vtable };
154                        Ok(::std::rc::Rc::from_raw(*::std::mem::transmute::<_, &mut *mut U>(&mut u)))
155                    }
156                } else {
157                    Err(self_)
158                }
159            }
160            pub fn obj_partial_eq(&self, other: &Self) -> bool {
161                if let Some(x) = self.query_ref::<$crate::ObjectPartialEq>() {
162                    x.obj_eq(other.query_ref().unwrap())
163                } else {
164                    (self as *const Self) == (other as *const Self)
165                }
166            }
167            pub fn obj_partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
168                if let Some(x) = self.query_ref::<$crate::ObjectPartialOrd>() {
169                    x.obj_partial_cmp(other.query_ref().unwrap())
170                } else {
171                    None
172                }
173            }
174        }
175        impl ::std::clone::Clone for Box<$name> {
176            fn clone(&self) -> Self {
177                (**self).to_owned()
178            }
179        }
180        impl ::std::borrow::ToOwned for $name {
181            type Owned = Box<$name>;
182            fn to_owned(&self) -> Box<$name> {
183                self.query_ref::<$crate::ObjectClone>().expect("Object not clonable!").obj_clone().query::<$name>().unwrap()
184            }
185        }
186        impl ::std::fmt::Debug for $name {
187            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
188                if let Some(o) = self.query_ref::<::std::fmt::Debug>() {
189                    o.fmt(f)
190                } else {
191                    writeln!(f, "Object {{ <no `Debug` implementation> }}")
192                }
193            }
194        }
195        impl ::std::cmp::PartialEq for $name {
196            fn eq(&self, other: &Self) -> bool {
197                // Require `Eq` rather than `PartialEq` as this allows `Object`s to be used as
198                // key in hash maps
199                if let Some(x) = self.query_ref::<$crate::ObjectEq>() {
200                    x.obj_eq(other.query_ref().unwrap())
201                } else {
202                    // This trivially meets the requirements of `Eq`
203                    (self as *const Self) == (other as *const Self)
204                }
205            }
206        }
207        impl ::std::cmp::Eq for $name {}
208        impl ::std::cmp::PartialOrd for $name {
209            fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
210                Some(self.cmp(other))
211            }
212        }
213        impl ::std::cmp::Ord for $name {
214            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
215                if let Some(x) = self.query_ref::<$crate::ObjectOrd>() {
216                    if let Some(o) = x.obj_cmp(other.query_ref().unwrap()) {
217                        return o
218                    }
219                }
220                Ord::cmp(&(self as *const Self), &(other as *const Self))
221            }
222        }
223        impl ::std::hash::Hash for $name {
224            fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
225                if let Some(x) = self.query_ref::<$crate::ObjectHash>() {
226                    x.obj_hash(state)
227                } else {
228                    state.write_usize(self as *const Self as *const () as usize)
229                }
230            }
231        }
232    )
233}
234
235/// This trait is the primary function of the library. `Object` trait objects
236/// can be freely queried for any other trait, allowing conversion between
237/// trait objects.
238pub unsafe trait Object: Any {
239    /// This is implemented by the `interfaces!` macro, and should never be
240    /// manually implemented.
241    #[doc(hidden)]
242    fn query_vtable(&self, id: TypeId) -> Option<VTable>;
243}
244
245/// You can use this trait to ensure that a type implements a trait as an
246/// interface. This means the type declared the trait in its `interfaces!(...)`
247/// list, and guarantees that querying an `Object` of that type for the trait
248/// will always succeed.
249/// 
250/// When using `HasInterface<SomeTrait>` in a generic bound, you should also
251/// specify `SomeTrait` as a bound. While `HasInterface<SomeTrait>` is a more
252/// stringent requirement than, and in practice implies `SomeTrait`, the
253/// compiler cannot deduce that because it is enforced through macros rather
254/// than the type system.
255pub unsafe trait HasInterface<I: ?Sized> {}
256
257mopo!(Object);
258
259
260/// This is an object-safe version of `Clone`, which is automatically
261/// implemented for all `Clone + Object` types. This is a support trait used to
262/// allow `Object` trait objects to be clonable.
263pub trait ObjectClone {
264    fn obj_clone(&self) -> Box<Object>;
265}
266impl<T: Clone + Object> ObjectClone for T {
267    fn obj_clone(&self) -> Box<Object> {
268        Box::new(self.clone())
269    }
270}
271
272/// This is an object-safe version of `PartialEq`, which is automatically
273/// implemented for all `PartialEq + Object` types. This is a support trait used to
274/// allow `Object` trait objects to be comparable in this way.
275pub trait ObjectPartialEq {
276    fn obj_eq(&self, other: &Object) -> bool;
277}
278impl<T: PartialEq + Object> ObjectPartialEq for T {
279    fn obj_eq(&self, other: &Object) -> bool {
280        if let Some(o) = other.query_ref::<Self>() {
281            self == o
282        } else {
283            false
284        }
285    }
286}
287
288/// This is an object-safe version of `Eq`, which is automatically
289/// implemented for all `Eq + Object` types. This is a support trait used to
290/// allow `Object` trait objects to be comparable in this way.
291pub trait ObjectEq: ObjectPartialEq {}
292impl<T: Eq + Object> ObjectEq for T {}
293
294/// This is an object-safe version of `PartialOrd`, which is automatically
295/// implemented for all `PartialOrd + Object` types. This is a support trait used to
296/// allow `Object` trait objects to be comparable in this way.
297pub trait ObjectPartialOrd {
298    fn obj_partial_cmp(&self, other: &Object) -> Option<Ordering>;
299}
300impl<T: PartialOrd + Object> ObjectPartialOrd for T {
301    fn obj_partial_cmp(&self, other: &Object) -> Option<Ordering> {
302        if let Some(o) = other.query_ref::<Self>() {
303            self.partial_cmp(o)
304        } else {
305            None
306        }
307    }
308}
309
310/// This is an object-safe version of `Ord`, which is automatically
311/// implemented for all `Ord + Object` types. This is a support trait used to
312/// allow `Object` trait objects to be comparable in this way.
313pub trait ObjectOrd {
314    fn obj_cmp(&self, other: &Object) -> Option<Ordering>;
315}
316impl<T: Ord + Object> ObjectOrd for T {
317    fn obj_cmp(&self, other: &Object) -> Option<Ordering> {
318        if let Some(o) = other.query_ref::<Self>() {
319            Some(self.cmp(o))
320        } else {
321            None
322        }
323    }
324}
325
326/// This is an object-safe version of `Hash`, which is automatically
327/// implemented for all `Hash + Object` types. This is a support trait used to
328/// allow `Object` trait objects to be comparable in this way.
329///
330/// Note: `Object`s are not guaranteed to hash to the same value as their
331/// underlying type.
332pub trait ObjectHash {
333    fn obj_hash(&self, state: &mut Hasher);
334}
335impl<T: Hash + Object> ObjectHash for T {
336    fn obj_hash(&self, state: &mut Hasher) {
337        let mut h = DefaultHasher::new();
338        self.hash(&mut h);
339        state.write_u64(h.finish());
340    }
341}
342
343/// Allow a set of traits to be dynamically queried from a type when it is
344/// stored as an `Object` trait object.
345/// 
346/// Example use:
347/// 
348/// ```rust
349/// # #[macro_use]
350/// # extern crate query_interface;
351/// # use query_interface::*;
352/// #[derive(Clone)]
353/// struct Foo;
354/// interfaces!(Foo: ObjectClone);
355/// # fn main() {}
356/// ```
357#[macro_export]
358macro_rules! interfaces {
359    (@unbracket $(($($v:tt)*))*) => ($($($v)*)*);
360    (@inner $imp:tt $cond:tt $name:ty: $($iface:ty),+ {}) => (
361        interfaces!(@unbracket $imp ($crate::HasInterface<$name> for $name) $cond ({}));
362        interfaces!(@unbracket $imp ($crate::HasInterface<$crate::Object> for $name) $cond ({}));
363        $(interfaces!(@unbracket $imp ($crate::HasInterface<$iface> for $name) $cond ({}));)*
364        interfaces!(@unbracket $imp ($crate::Object for $name) $cond ({
365            fn query_vtable(&self, id: ::std::any::TypeId) -> Option<$crate::VTable> {
366                if id == ::std::any::TypeId::of::<$name>() {
367                    Some($crate::VTable::none())
368                } else if id == ::std::any::TypeId::of::<$crate::Object>() {
369                    Some(vtable_for!($name as $crate::Object))
370                } else $(if id == ::std::any::TypeId::of::<$iface>() {
371                    Some(vtable_for!($name as $iface))
372                } else)* {
373                    // If "dynamic" feature is enabled, fall back to
374                    // looking in the registry
375                    #[cfg(feature = "dynamic")]
376                    { $crate::dynamic::find_in_registry::<$name>(id) }
377                    // No dynamic lookup
378                    #[cfg(not(feature = "dynamic"))]
379                    { None }
380                }
381            }
382        }));
383    );
384    (@imp ($($result:tt)*) $name:ty: $($iface:ty),+ $(where $($cond:tt)*)*) => (
385        interfaces!(@inner (unsafe impl<$($result)*>) ($(where $($cond)*)*) $name: $($iface),+ {});
386    );
387    (@parse < $($rest:tt)*) => (
388        interfaces!(@parseArg () $($rest)*);
389    );
390    (@parse $($rest:tt)*) => (
391        interfaces!(@imp () $($rest)*);
392    );
393    (@parseArg ($($result:tt)*) $name:ident , $($rest:tt)*) => (
394        interfaces!(@parseArg ($($result)* $name ,) $($rest)*);
395    );
396    (@parseArg ($($result:tt)*) $name:ident : $($rest:tt)*) => (
397        interfaces!(@parseBound ($($result)* $name : ) $($rest)*);
398    );
399    (@parseArg ($($result:tt)*) $name:ident > $($rest:tt)*) => (
400        interfaces!(@imp ($($result)* $name) $($rest)*);
401    );
402    (@parseBound ($($result:tt)*) $bound:tt + $($rest:tt)*) => (
403        interfaces!(@parseBound ($($result)* $bound +) $($rest)*);
404    );
405    (@parseBound ($($result:tt)*) $bound:tt , $($rest:tt)*) => (
406        interfaces!(@parseArg ($($result)* $bound ,) $($rest)*);
407    );
408    (@parseBound ($($result:tt)*) $bound:tt > $($rest:tt)*) => (
409        interfaces!(@imp ($($result)* $bound) $($rest)*);
410    );
411    (< $($rest:tt)*) => (
412        interfaces!(@parse < $($rest)*);
413    );
414    ($x:ty: $($rest:tt)*) => (
415        interfaces!(@parse $x: $($rest)*);
416    );
417    (@expand2 ($name:ty) ($($rest:tt)*)) => (
418        interfaces!($name $($rest)*);
419    );
420    (@expand {$($name:ty),*} $rest:tt) => (
421        $( interfaces!(@expand2 ($name) $rest); )*
422    );
423    ({$($name:ty),*} $($rest:tt)*) => (
424        interfaces!(@expand {$($name),*} ($($rest)*));
425    );
426}
427
428// Integral types
429interfaces!({
430    bool, i8, u8, i16, u16, i32, u32, i64, u64, char
431}: ObjectClone, Debug, Display, ObjectPartialEq, ObjectPartialOrd, ObjectEq, ObjectOrd, ObjectHash, ToString);
432
433// Floating point types
434interfaces!({
435    f32, f64
436}: ObjectClone, Debug, Display, ObjectPartialEq, ObjectPartialOrd, ToString);
437
438// Strings
439interfaces!(String: ObjectClone, Debug, Display, ObjectPartialEq, ObjectPartialOrd, ObjectEq, ObjectOrd, ObjectHash, ToString);
440
441// Paths
442interfaces!(PathBuf: ObjectClone, Debug, ObjectPartialEq, ObjectPartialOrd, ObjectEq, ObjectOrd, ObjectHash);
443
444// Vecs
445interfaces!({
446    Vec<bool>, Vec<i8>, Vec<u8>, Vec<i16>, Vec<u16>, Vec<i32>, Vec<u32>, Vec<i64>, Vec<u64>, Vec<char>
447}: ObjectClone, Debug, ObjectPartialEq, ObjectPartialOrd, ObjectEq, ObjectOrd, ObjectHash);
448interfaces!({
449    Vec<f32>, Vec<f64>
450}: ObjectClone, Debug, ObjectPartialEq, ObjectPartialOrd);
451interfaces!({
452    Vec<String>, Vec<PathBuf>
453}: ObjectClone, Debug, ObjectPartialEq, ObjectPartialOrd, ObjectEq, ObjectOrd, ObjectHash);
454
455
456#[cfg(test)]
457mod tests {
458    use std::fmt::Debug;
459    use std::sync::Arc;
460    use std::rc::Rc;
461
462    #[derive(Debug, Clone)]
463    struct Bar;
464    interfaces!(Bar: Foo, super::ObjectClone, Debug, Custom);
465
466    trait Foo: Debug {
467        fn test(&self) -> bool { false }
468    }
469    trait Foo2: Debug {}
470    impl Foo for Bar {
471        fn test(&self) -> bool { true }
472    }
473    impl Foo2 for Bar {}
474
475    #[derive(Debug, Clone)]
476    struct GenericBar<T>(T);
477    interfaces!(<T: Debug + 'static> GenericBar<T>: super::ObjectClone, Debug where T: Clone);
478
479    #[test]
480    fn test_ref() {
481        let x = Box::new(Bar) as Box<super::Object>;
482        let foo: Option<&Foo> = x.query_ref();
483        assert!(foo.is_some());
484        assert!(foo.unwrap().test());
485        let foo2: Option<&Foo2> = x.query_ref();
486        assert!(foo2.is_none());
487        let bar: Option<&Bar> = x.query_ref();
488        assert!(bar.is_some());
489    }
490
491    #[test]
492    fn test_mut() {
493        let mut x = Box::new(Bar) as Box<super::Object>;
494        {
495            let foo = x.query_mut::<Foo>();
496            assert!(foo.is_some());
497            assert!(foo.unwrap().test());
498        }
499        {
500            let foo2 = x.query_mut::<Foo2>();
501            assert!(foo2.is_none());
502        }
503        {
504            let bar = x.query_mut::<Bar>();
505            assert!(bar.is_some());
506        }
507    }
508
509    #[test]
510    fn test_owned() {
511        let x = Box::new(Bar) as Box<super::Object>;
512        let foo: Result<Box<Foo>, _> = x.clone().query();
513        assert!(foo.is_ok());
514        assert!(foo.unwrap().test());
515        let foo2: Result<Box<Foo2>, _> = x.clone().query();
516        assert!(foo2.is_err());
517        let bar: Result<Box<Bar>, _> = x.clone().query();
518        assert!(bar.is_ok());
519    }
520
521    #[test]
522    fn test_rc() {
523        let x = Rc::new(Bar) as Rc<super::Object>;
524        let foo: Result<Rc<Foo>, _> = super::Object::query_rc(x.clone());
525        assert!(foo.is_ok());
526        assert!(foo.unwrap().test());
527        let foo2: Result<Rc<Foo2>, _> = super::Object::query_rc(x.clone());
528        assert!(foo2.is_err());
529        let bar: Result<Rc<Bar>, _> = super::Object::query_rc(x.clone());
530        assert!(bar.is_ok());
531    }
532
533    #[test]
534    fn test_arc() {
535        let x = Arc::new(Bar) as Arc<super::Object>;
536        let foo: Result<Arc<Foo>, _> = super::Object::query_arc(x.clone());
537        assert!(foo.is_ok());
538        assert!(foo.unwrap().test());
539        let foo2: Result<Arc<Foo2>, _> = super::Object::query_arc(x.clone());
540        assert!(foo2.is_err());
541        let bar: Result<Arc<Bar>, _> = super::Object::query_arc(x.clone());
542        assert!(bar.is_ok());
543    }
544
545    trait Custom : super::Object {}
546    impl Custom for Bar {}
547    mopo!(Custom);
548
549    #[test]
550    fn test_derived() {
551        let x = Box::new(Bar) as Box<Custom>;
552        let foo: Result<Box<Foo>, _> = x.clone().query();
553        assert!(foo.is_ok());
554        assert!(foo.unwrap().test());
555        let foo2: Result<Box<Foo2>, _> = x.clone().query();
556        assert!(foo2.is_err());
557        let bar: Result<Box<Bar>, _> = x.clone().query();
558        assert!(bar.is_ok());
559    }
560
561    trait Dynamic {
562        fn test(&self) -> u32;
563    }
564    impl Dynamic for Bar {
565        fn test(&self) -> u32 { 42 }
566    }
567
568    #[test]
569    fn test_dynamic() {
570        let x = Box::new(Bar) as Box<super::Object>;
571        let dyn1: Option<&Dynamic> = x.query_ref();
572        assert!(dyn1.is_none());
573
574        dynamic_interfaces! {
575            Bar: Dynamic;
576        }
577
578        let dyn2: Option<&Dynamic> = x.query_ref();
579        assert!(dyn2.unwrap().test() == 42);
580    }
581
582    #[test]
583    fn test_primitives() {
584        Box::new(1) as Box<super::Object>;
585        Box::new(1f32) as Box<super::Object>;
586        Box::new("test".to_string()) as Box<super::Object>;
587        Box::new(vec![1,2,3]) as Box<super::Object>;
588    }
589}