1use std::any::Any;
2use std::hash::{Hash, Hasher};
3
4use crate::db_handle::DbHandle;
5
6pub trait Run: Sized {
7 fn run(self, db: &mut DbHandle<Self>) -> Value;
8}
9
10pub struct Value(Box<dyn ValueTrait>);
11
12impl Value {
13 pub fn new(obj: impl ValueTrait) -> Value {
14 Value(Box::new(obj))
15 }
16
17 pub fn downcast_obj_ref<T: 'static>(&self) -> Option<&T> {
18 let obj = self.0.as_ref() as &dyn Any;
19 obj.downcast_ref()
20 }
21}
22
23impl std::fmt::Debug for Value {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 write!(f, "(Value)")
26 }
27}
28
29impl HashEqObj for Value {
30 fn hash_value(&self, hasher: &mut std::hash::DefaultHasher) {
31 self.0.hash_value(hasher);
32 }
33
34 fn eq_value(&self, other: &dyn ValueTrait) -> bool {
35 self.0.eq_value(other)
36 }
37}
38
39impl Eq for Value {}
40
41impl PartialEq for Value {
42 fn eq(&self, other: &Self) -> bool {
43 self.0.as_ref().eq_value(other.0.as_ref())
44 }
45}
46
47impl<T: ValueTrait> From<T> for Value {
48 fn from(value: T) -> Self {
49 Self::new(value)
50 }
51}
52
53pub trait ValueTrait: Any + HashEqObj {}
54
55pub trait HashEqObj {
56 fn hash_value(&self, hasher: &mut std::hash::DefaultHasher);
58
59 fn eq_value(&self, other: &dyn ValueTrait) -> bool;
61
62 fn get_hash(&self) -> u64 {
63 let mut hasher = std::hash::DefaultHasher::default();
64 self.hash_value(&mut hasher);
65 hasher.finish()
66 }
67}
68
69impl<T> ValueTrait for T where T: Any + Hash + Eq {}
70
71impl<T> HashEqObj for T where T: Any + Hash + Eq {
72 fn hash_value(&self, hasher: &mut std::hash::DefaultHasher) {
73 self.hash(hasher);
74 }
75
76 fn eq_value(&self, other: &dyn ValueTrait) -> bool {
77 let Some(other) = (other as &dyn Any).downcast_ref() else {
78 return false;
79 };
80 self == other
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::Value;
87
88 #[test]
89 fn dyn_eq() {
90 let i32_0 = Value::new(0i32);
91 let i32_1 = Value::new(1i32);
92 let u32_0 = Value::new(0u32);
93
94 assert_eq!(i32_0, i32_0, "i32_0 == i32_0");
95 assert_ne!(i32_0, i32_1, "i32_0 == i32_1");
96 assert_ne!(i32_0, u32_0, "i32_0 == u32_0");
97 assert_eq!(i32_0, Value::new(0i32), "i32_0 == fresh i32_0");
98 }
99}