1use std::fmt::Debug;
17use super::{BaseValue, InvalidValue};
18
19pub trait Value: Debug + Sync + Send + stepflow_base::as_any::AsAny {
20 fn get_baseval(&self) -> BaseValue;
21 fn clone_box(&self) -> Box<dyn Value>;
22 fn eq_box(&self, other: &Box<dyn Value>) -> bool;
23}
24
25impl dyn Value {
27 pub fn downcast<T>(&self) -> Option<&T>
28 where T: Value + std::any::Any
29 {
30 self.as_any().downcast_ref::<T>()
31 }
32 pub fn is<T>(&self) -> bool
33 where T: Value + std::any::Any
34 {
35 self.as_any().is::<T>()
36 }
37}
38
39impl Clone for Box<dyn Value> {
40 fn clone(&self) -> Box<dyn Value> {
41 self.clone_box()
42 }
43}
44
45impl PartialEq for Box<dyn Value> {
46 fn eq(&self, other: &Box<dyn Value>) -> bool {
47 self.eq_box(other)
48 }
49}
50
51#[cfg(feature = "serde-support")]
52impl serde::Serialize for Box<dyn Value> {
53 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
54 where S: serde::Serializer
55 {
56 match self.get_baseval() {
57 BaseValue::String(s) => s.serialize(serializer),
58 BaseValue::Boolean(b) => b.serialize(serializer),
59 BaseValue::Float(float) => float.serialize(serializer),
60 }
61 }
62}
63
64#[macro_use]
65macro_rules! define_value_impl {
66 ($name:ident) => {
67 impl Value for $name {
68 fn get_baseval(&self) -> BaseValue {
69 self.val.clone().into()
70 }
71 fn clone_box(&self) -> Box<dyn Value> {
72 Box::new(self.clone())
73 }
74 fn eq_box(&self, other: &Box<dyn Value>) -> bool {
75 if !other.is::<Self>() {
77 return false;
78 }
79
80 self.get_baseval() == other.get_baseval()
82 }
83 }
84 }
85}
86
87#[macro_use]
88macro_rules! define_base_value {
89 ($name:ident, $basetype:ident) => {
90 #[derive(Debug, PartialEq, Clone)]
91 pub struct $name {
92 val: $basetype,
93 }
94
95 impl $name {
96 pub fn val(&self) -> &$basetype {
97 &self.val
98 }
99 pub fn boxed(self) -> Box<dyn Value> {
100 Box::new(self)
101 }
102 }
103
104 define_value_impl!($name);
105 };
106}
107
108#[macro_use]
109macro_rules! define_value {
110 ($name:ident, $basetype:ident) => {
111 define_base_value!($name, $basetype);
112 impl $name {
113 pub fn new(val: $basetype) -> Self {
114 $name { val }
115 }
116 }
117 };
118
119 ($name:ident, $basetype:ident, $validate_fn:ident) => {
120 define_base_value!($name, $basetype);
121 impl $name {
122 pub fn try_new(val: $basetype) -> Result<Self, InvalidValue> {
123 Self::$validate_fn(&val)?;
124 Ok(Self { val })
125 }
126 }
127 };
128}
129
130mod valid_value;
131pub use valid_value::ValidVal;
132
133mod string_value;
134pub use string_value::StringValue;
135
136mod email_value;
137pub use email_value::EmailValue;
138
139mod bool_value;
140pub use bool_value::BoolValue;
141
142mod true_value;
143pub use true_value::TrueValue;
144
145
146#[cfg(test)]
147mod tests {
148 use super::{EmailValue, Value, StringValue, TrueValue};
149
150 #[test]
151 fn val_downcast() {
152 let strval = StringValue::try_new("hi").unwrap();
154 let r: &(dyn Value + 'static) = &strval;
155 assert!(r.as_any().is::<StringValue>());
156
157 let val: Box<dyn Value> = Box::new(strval.clone());
159 assert!(val.as_any().is::<StringValue>());
160 assert!(val.as_ref().as_any().is::<StringValue>());
161 let stringval: Option<&StringValue> = val.downcast::<StringValue>();
162 assert!(matches!(stringval, Some(_)));
163
164 assert_eq!(val.downcast::<StringValue>().unwrap().val(), "hi");
166 assert_eq!(val.is::<StringValue>(), true);
167 assert_eq!(val.downcast::<EmailValue>(), None);
168 assert_eq!(val.is::<EmailValue>(), false);
169 }
170
171 #[test]
172 fn partial_eq() {
173 const EMAIL: &str = "a@b.com";
174 let true_val: Box<dyn Value> = TrueValue::new().boxed();
175 let email_val: Box<dyn Value> = EmailValue::try_new(EMAIL).unwrap().boxed();
176 let string_val: Box<dyn Value> = StringValue::try_new(EMAIL).unwrap().boxed();
177 assert!(email_val.clone() == email_val.clone()); assert!(true_val != email_val.clone()); assert!(email_val.clone() != string_val); }
181}