blueprint_engine_core/value/
mod.rs

1mod functions;
2mod generator;
3mod io;
4mod methods;
5mod structs;
6
7pub use functions::{
8    LambdaFunction, NativeFn, NativeFunction, NativeFuture, Parameter, ParameterKind, UserFunction,
9};
10pub use generator::{Generator, GeneratorMessage, StreamIterator};
11pub use io::{HttpResponse, ProcessResult};
12pub use structs::{StructField, StructInstance, StructType, TypeAnnotation};
13
14use std::fmt;
15use std::hash::{Hash, Hasher};
16use std::sync::Arc;
17
18use indexmap::{IndexMap, IndexSet};
19use tokio::sync::RwLock;
20
21use crate::error::{BlueprintError, Result};
22
23#[derive(Clone)]
24pub enum Value {
25    None,
26    Bool(bool),
27    Int(i64),
28    Float(f64),
29    String(Arc<String>),
30    List(Arc<RwLock<Vec<Value>>>),
31    Dict(Arc<RwLock<IndexMap<String, Value>>>),
32    Set(Arc<RwLock<IndexSet<Value>>>),
33    Tuple(Arc<Vec<Value>>),
34    Function(Arc<UserFunction>),
35    Lambda(Arc<LambdaFunction>),
36    NativeFunction(Arc<NativeFunction>),
37    Response(Arc<HttpResponse>),
38    ProcessResult(Arc<ProcessResult>),
39    Iterator(Arc<StreamIterator>),
40    Generator(Arc<Generator>),
41    StructType(Arc<StructType>),
42    StructInstance(Arc<StructInstance>),
43}
44
45impl fmt::Debug for Value {
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        match self {
48            Value::None => write!(f, "None"),
49            Value::Bool(b) => write!(f, "Bool({b})"),
50            Value::Int(i) => write!(f, "Int({i})"),
51            Value::Float(fl) => write!(f, "Float({fl})"),
52            Value::String(s) => write!(f, "String({s:?})"),
53            Value::List(_) => write!(f, "List([...])"),
54            Value::Dict(_) => write!(f, "Dict({{...}})"),
55            Value::Set(_) => write!(f, "Set({{...}})"),
56            Value::Tuple(t) => write!(f, "Tuple({:?})", t.as_ref()),
57            Value::Function(func) => write!(f, "Function({})", func.name),
58            Value::Lambda(_) => write!(f, "Lambda"),
59            Value::NativeFunction(func) => write!(f, "NativeFunction({})", func.name),
60            Value::Response(r) => write!(f, "Response(status={})", r.status),
61            Value::ProcessResult(r) => write!(f, "ProcessResult(code={})", r.code),
62            Value::Iterator(_) => write!(f, "Iterator"),
63            Value::Generator(_) => write!(f, "Generator"),
64            Value::StructType(s) => write!(f, "StructType({})", s.name),
65            Value::StructInstance(s) => write!(f, "StructInstance({})", s.struct_type.name),
66        }
67    }
68}
69
70impl Value {
71    pub fn type_name(&self) -> &'static str {
72        match self {
73            Value::None => "NoneType",
74            Value::Bool(_) => "bool",
75            Value::Int(_) => "int",
76            Value::Float(_) => "float",
77            Value::String(_) => "string",
78            Value::List(_) => "list",
79            Value::Dict(_) => "dict",
80            Value::Set(_) => "set",
81            Value::Tuple(_) => "tuple",
82            Value::Function(_) => "function",
83            Value::Lambda(_) => "function",
84            Value::NativeFunction(_) => "builtin_function",
85            Value::Response(_) => "Response",
86            Value::ProcessResult(_) => "Result",
87            Value::Iterator(_) => "iterator",
88            Value::Generator(_) => "generator",
89            Value::StructType(_) => "type",
90            Value::StructInstance(_) => "struct",
91        }
92    }
93
94    pub fn is_truthy(&self) -> bool {
95        match self {
96            Value::None => false,
97            Value::Bool(b) => *b,
98            Value::Int(i) => *i != 0,
99            Value::Float(f) => *f != 0.0,
100            Value::String(s) => !s.is_empty(),
101            Value::List(l) => {
102                if let Ok(guard) = l.try_read() {
103                    !guard.is_empty()
104                } else {
105                    true
106                }
107            }
108            Value::Dict(d) => {
109                if let Ok(guard) = d.try_read() {
110                    !guard.is_empty()
111                } else {
112                    true
113                }
114            }
115            Value::Set(s) => {
116                if let Ok(guard) = s.try_read() {
117                    !guard.is_empty()
118                } else {
119                    true
120                }
121            }
122            Value::Tuple(t) => !t.is_empty(),
123            _ => true,
124        }
125    }
126
127    pub async fn is_truthy_async(&self) -> bool {
128        match self {
129            Value::None => false,
130            Value::Bool(b) => *b,
131            Value::Int(i) => *i != 0,
132            Value::Float(f) => *f != 0.0,
133            Value::String(s) => !s.is_empty(),
134            Value::List(l) => {
135                let guard = l.read().await;
136                !guard.is_empty()
137            }
138            Value::Dict(d) => {
139                let guard = d.read().await;
140                !guard.is_empty()
141            }
142            Value::Set(s) => {
143                let guard = s.read().await;
144                !guard.is_empty()
145            }
146            Value::Tuple(t) => !t.is_empty(),
147            _ => true,
148        }
149    }
150
151    pub fn is_none(&self) -> bool {
152        matches!(self, Value::None)
153    }
154
155    pub async fn deep_copy(&self) -> Value {
156        match self {
157            Value::List(l) => {
158                let items = l.read().await;
159                let mut copied = Vec::with_capacity(items.len());
160                for item in items.iter() {
161                    copied.push(Box::pin(item.deep_copy()).await);
162                }
163                Value::List(Arc::new(RwLock::new(copied)))
164            }
165            Value::Dict(d) => {
166                let map = d.read().await;
167                let mut copied = IndexMap::with_capacity(map.len());
168                for (k, v) in map.iter() {
169                    copied.insert(k.clone(), Box::pin(v.deep_copy()).await);
170                }
171                Value::Dict(Arc::new(RwLock::new(copied)))
172            }
173            Value::Tuple(t) => {
174                let mut copied = Vec::with_capacity(t.len());
175                for item in t.iter() {
176                    copied.push(Box::pin(item.deep_copy()).await);
177                }
178                Value::Tuple(Arc::new(copied))
179            }
180            other => other.clone(),
181        }
182    }
183
184    pub fn as_bool(&self) -> Result<bool> {
185        match self {
186            Value::Bool(b) => Ok(*b),
187            _ => Err(BlueprintError::TypeError {
188                expected: "bool".into(),
189                actual: self.type_name().into(),
190            }),
191        }
192    }
193
194    pub fn as_int(&self) -> Result<i64> {
195        match self {
196            Value::Int(i) => Ok(*i),
197            _ => Err(BlueprintError::TypeError {
198                expected: "int".into(),
199                actual: self.type_name().into(),
200            }),
201        }
202    }
203
204    pub fn as_float(&self) -> Result<f64> {
205        match self {
206            Value::Float(f) => Ok(*f),
207            Value::Int(i) => Ok(*i as f64),
208            _ => Err(BlueprintError::TypeError {
209                expected: "float".into(),
210                actual: self.type_name().into(),
211            }),
212        }
213    }
214
215    pub fn as_string(&self) -> Result<String> {
216        match self {
217            Value::String(s) => Ok(s.as_ref().clone()),
218            _ => Err(BlueprintError::TypeError {
219                expected: "string".into(),
220                actual: self.type_name().into(),
221            }),
222        }
223    }
224
225    pub fn as_str(&self) -> Result<&str> {
226        match self {
227            Value::String(s) => Ok(s.as_ref()),
228            _ => Err(BlueprintError::TypeError {
229                expected: "string".into(),
230                actual: self.type_name().into(),
231            }),
232        }
233    }
234
235    pub fn to_display_string(&self) -> String {
236        match self {
237            Value::None => "None".into(),
238            Value::Bool(b) => if *b { "True" } else { "False" }.into(),
239            Value::Int(i) => i.to_string(),
240            Value::Float(f) => {
241                if f.fract() == 0.0 {
242                    format!("{f:.1}")
243                } else {
244                    f.to_string()
245                }
246            }
247            Value::String(s) => s.as_ref().clone(),
248            Value::List(l) => match l.try_read() {
249                Ok(guard) => {
250                    let items: Vec<String> = guard.iter().map(|v| v.repr()).collect();
251                    format!("[{}]", items.join(", "))
252                }
253                Err(_) => "[<locked>]".into(),
254            },
255            Value::Dict(d) => match d.try_read() {
256                Ok(guard) => {
257                    let items: Vec<String> = guard
258                        .iter()
259                        .map(|(k, v)| format!("{:?}: {}", k, v.repr()))
260                        .collect();
261                    format!("{{{}}}", items.join(", "))
262                }
263                Err(_) => "{<locked>}".into(),
264            },
265            Value::Set(s) => match s.try_read() {
266                Ok(guard) => {
267                    let items: Vec<String> = guard.iter().map(|v| v.repr()).collect();
268                    format!("{{{}}}", items.join(", "))
269                }
270                Err(_) => "{<locked>}".into(),
271            },
272            Value::Tuple(t) => {
273                let items: Vec<String> = t.iter().map(|v| v.repr()).collect();
274                if t.len() == 1 {
275                    format!("({},)", items[0])
276                } else {
277                    format!("({})", items.join(", "))
278                }
279            }
280            Value::Function(f) => format!("<function {}>", f.name),
281            Value::Lambda(_) => "<lambda>".into(),
282            Value::NativeFunction(f) => format!("<builtin_function {}>", f.name),
283            Value::Response(r) => format!("<Response status={}>", r.status),
284            Value::ProcessResult(r) => format!("<Result code={}>", r.code),
285            Value::Iterator(_) => "<iterator>".into(),
286            Value::Generator(_) => "<generator>".into(),
287            Value::StructType(s) => format!("<type {}>", s.name),
288            Value::StructInstance(s) => s.to_display_string(),
289        }
290    }
291
292    pub fn repr(&self) -> String {
293        match self {
294            Value::String(s) => format!("{:?}", s.as_ref()),
295            _ => self.to_display_string(),
296        }
297    }
298
299    pub fn get_attr(&self, name: &str) -> Option<Value> {
300        match self {
301            Value::Response(r) => r.get_attr(name),
302            Value::ProcessResult(r) => r.get_attr(name),
303            Value::String(s) => methods::get_string_method(s.clone(), name),
304            Value::List(l) => methods::get_list_method(l.clone(), name),
305            Value::Dict(d) => methods::get_dict_method(d.clone(), name),
306            Value::Set(s) => methods::get_set_method(s.clone(), name),
307            Value::Iterator(it) => it.get_attr(name),
308            Value::StructInstance(s) => s.get_field(name),
309            _ => None,
310        }
311    }
312
313    pub fn has_attr(&self, name: &str) -> bool {
314        self.get_attr(name).is_some()
315    }
316}
317
318impl PartialEq for Value {
319    fn eq(&self, other: &Self) -> bool {
320        match (self, other) {
321            (Value::None, Value::None) => true,
322            (Value::Bool(a), Value::Bool(b)) => a == b,
323            (Value::Int(a), Value::Int(b)) => a == b,
324            (Value::Float(a), Value::Float(b)) => a == b,
325            (Value::Int(a), Value::Float(b)) => (*a as f64) == *b,
326            (Value::Float(a), Value::Int(b)) => *a == (*b as f64),
327            (Value::String(a), Value::String(b)) => a == b,
328            (Value::Tuple(a), Value::Tuple(b)) => a == b,
329            _ => false,
330        }
331    }
332}
333
334impl Eq for Value {}
335
336impl Hash for Value {
337    fn hash<H: Hasher>(&self, state: &mut H) {
338        std::mem::discriminant(self).hash(state);
339        match self {
340            Value::None => {}
341            Value::Bool(b) => b.hash(state),
342            Value::Int(i) => i.hash(state),
343            Value::Float(f) => f.to_bits().hash(state),
344            Value::String(s) => s.hash(state),
345            Value::Tuple(t) => t.hash(state),
346            _ => {}
347        }
348    }
349}