1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
use std::fmt::Debug; use std::any::Any; use super::*; pub trait ValueConstraint: 'static + PartialEq + Eq + Debug + Clone { } impl<T: 'static + ?Sized + PartialEq + Eq + Debug + Clone> ValueConstraint for T { } pub trait Value: Any + AnyExtension + AsAny + Debug { fn equals(&self, other: &dyn Any) -> bool { self.reference_equals(other) } as_trait!(Value); as_boxed!(Value); } impl<T: ?Sized + ValueConstraint> Value for T { fn equals(&self, other: &dyn Any) -> bool { match other.downcast_ref::<T>() { Some(r) => *self == *r, None => false } } as_trait!(impl Value); as_boxed!(impl Value); } #[macro_export] macro_rules! boxed_value_trait { ($type: tt) => { impl PartialEq for Box<dyn $type> { fn eq(&self, other: &Self) -> bool { self.as_ref().equals(other.as_ref().as_any_ref()) } } impl Eq for Box<dyn $type> { } impl Clone for Box<dyn $type> { fn clone(&self) -> Self { $type::clone_boxed(self.as_ref()) } } }; } boxed_value_trait!(Value); #[cfg(test)] mod tests { use super::*; #[derive(PartialEq, Eq, Debug, Clone)] struct S1 { a: i32, b: u32 } #[test] fn eq() { let s = S1 { a: 1, b: 2 }; let t: Box<dyn Value> = Box::new(s.clone()); let t2: Box<dyn Value> = Box::new(s.clone()); assert!(t == t2); } #[test] fn debug() { let s = S1 { a: 1, b: 2 }; let t: Box<dyn Value> = Box::new(s); println!("{:?}", t); } #[test] fn clone() { let s = S1 { a: 1, b: 2 }; let b = s.clone_boxed(); assert_eq!(type_name::<S1>(), b.as_ref().type_name()); assert_eq!(type_name::<Box<dyn Value>>(), b.type_name()); assert!(s.equals(b.as_ref().as_any_ref())); } #[test] fn as_trait_as_boxed() { let s = S1 { a: 1, b: 2 }; s.as_trait_ref(); println!("{:p}", s.as_trait_ref() as &dyn Value); let mut s = s; s.as_trait_mut(); assert_eq!(&s.clone_boxed(), &s.to_boxed()); } }