helix/dna/atp/
value.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use crate::atp::types::Duration;
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
5pub enum ValueType {
6    String,
7    Number,
8    Boolean,
9    Array,
10    Object,
11    Null,
12}
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub enum Value {
15    String(String),
16    Number(f64),
17    Bool(bool),
18    Array(Vec<Value>),
19    Object(HashMap<String, Value>),
20    Null,
21    Duration(Duration),
22    Reference(String),
23    Identifier(String),
24}
25
26// Add Default implementation for Value
27impl Default for Value {
28    fn default() -> Self {
29        Value::Null
30    }
31}
32
33impl Value {
34    pub fn value_type(&self) -> ValueType {
35        match self {
36            Value::String(_) => ValueType::String,
37            Value::Number(_) => ValueType::Number,
38            Value::Bool(_) => ValueType::Boolean,
39            Value::Array(_) => ValueType::Array,
40            Value::Object(_) => ValueType::Object,
41            Value::Null => ValueType::Null,
42            Value::Duration(_) => ValueType::String, // Treat as string for now
43            Value::Reference(_) => ValueType::String,
44            Value::Identifier(_) => ValueType::String,
45        }
46    }
47    pub fn is_string(&self) -> bool {
48        matches!(self, Value::String(_))
49    }
50    pub fn is_number(&self) -> bool {
51        matches!(self, Value::Number(_))
52    }
53    pub fn is_boolean(&self) -> bool {
54        matches!(self, Value::Bool(_))
55    }
56    pub fn is_array(&self) -> bool {
57        matches!(self, Value::Array(_))
58    }
59    pub fn is_object(&self) -> bool {
60        matches!(self, Value::Object(_))
61    }
62    pub fn is_null(&self) -> bool {
63        matches!(self, Value::Null)
64    }
65    pub fn as_string(&self) -> Option<&str> {
66        match self {
67            Value::String(s) => Some(s),
68            _ => None,
69        }
70    }
71    pub fn as_number(&self) -> Option<f64> {
72        match self {
73            Value::Number(n) => Some(*n),
74            _ => None,
75        }
76    }
77    pub fn as_f64(&self) -> Option<f64> {
78        self.as_number()
79    }
80    pub fn as_str(&self) -> Option<&str> {
81        self.as_string()
82    }
83    pub fn as_boolean(&self) -> Option<bool> {
84        match self {
85            Value::Bool(b) => Some(*b),
86            _ => None,
87        }
88    }
89    pub fn as_array(&self) -> Option<&[Value]> {
90        match self {
91            Value::Array(arr) => Some(arr),
92            _ => None,
93        }
94    }
95    pub fn as_object(&self) -> Option<&HashMap<String, Value>> {
96        match self {
97            Value::Object(obj) => Some(obj),
98            _ => None,
99        }
100    }
101    pub fn get(&self, key: &str) -> Option<&Value> {
102        match self {
103            Value::Object(obj) => obj.get(key),
104            _ => None,
105        }
106    }
107    pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
108        match self {
109            Value::Object(obj) => obj.get_mut(key),
110            _ => None,
111        }
112    }
113    pub fn get_string(&self, key: &str) -> Option<&str> {
114        self.get(key)?.as_string()
115    }
116    pub fn get_number(&self, key: &str) -> Option<f64> {
117        self.get(key)?.as_number()
118    }
119    pub fn get_boolean(&self, key: &str) -> Option<bool> {
120        self.get(key)?.as_boolean()
121    }
122    pub fn get_array(&self, key: &str) -> Option<&[Value]> {
123        self.get(key)?.as_array()
124    }
125    pub fn get_object(&self, key: &str) -> Option<&HashMap<String, Value>> {
126        self.get(key)?.as_object()
127    }
128    pub fn to_string(&self) -> String {
129        match self {
130            Value::String(s) => s.clone(),
131            Value::Number(n) => n.to_string(),
132            Value::Bool(b) => b.to_string(),
133            Value::Array(arr) => {
134                let items: Vec<String> = arr.iter().map(|v| v.to_string()).collect();
135                format!("[{}]", items.join(", "))
136            }
137            Value::Object(obj) => {
138                let items: Vec<String> = obj
139                    .iter()
140                    .map(|(k, v)| format!("{}: {}", k, v.to_string()))
141                    .collect();
142                format!("{{{}}}", items.join(", "))
143            }
144            Value::Null => "null".to_string(),
145            Value::Duration(d) => format!("{} {:?}", d.value, d.unit),
146            Value::Reference(r) => format!("@{}", r),
147            Value::Identifier(i) => i.clone(),
148        }
149    }
150    pub fn to_json(&self) -> Result<String, serde_json::Error> {
151        serde_json::to_string_pretty(self)
152    }
153    pub fn to_yaml(&self) -> Result<String, serde_yaml::Error> {
154        serde_yaml::to_string(self)
155    }
156    pub fn from_json(json_value: serde_json::Value) -> Self {
157        match json_value {
158            serde_json::Value::String(s) => Value::String(s),
159            serde_json::Value::Number(n) => Value::Number(n.as_f64().unwrap_or(0.0)),
160            serde_json::Value::Bool(b) => Value::Bool(b),
161            serde_json::Value::Array(arr) => {
162                Value::Array(arr.iter().map(|v| Value::from_json(v.clone())).collect())
163            }
164            serde_json::Value::Object(obj) => {
165                Value::Object(
166                    obj
167                        .iter()
168                        .map(|(k, v)| (k.clone(), Value::from_json(v.clone())))
169                        .collect(),
170                )
171            }
172            serde_json::Value::Null => Value::Null,
173        }
174    }
175}
176impl From<String> for Value {
177    fn from(s: String) -> Self {
178        Value::String(s.to_string())
179    }
180}
181impl From<&str> for Value {
182    fn from(s: &str) -> Self {
183        Value::String(s.to_string())
184    }
185}
186impl From<i32> for Value {
187    fn from(n: i32) -> Self {
188        Value::Number(n as f64)
189    }
190}
191impl From<i64> for Value {
192    fn from(n: i64) -> Self {
193        Value::Number(n as f64)
194    }
195}
196impl From<f64> for Value {
197    fn from(n: f64) -> Self {
198        Value::Number(n)
199    }
200}
201impl From<bool> for Value {
202    fn from(b: bool) -> Self {
203        Value::Bool(b)
204    }
205}
206impl From<Vec<Value>> for Value {
207    fn from(arr: Vec<Value>) -> Self {
208        Value::Array(arr)
209    }
210}
211impl From<HashMap<String, Value>> for Value {
212    fn from(obj: HashMap<String, Value>) -> Self {
213        Value::Object(obj)
214    }
215}
216impl std::fmt::Display for Value {
217    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218        write!(f, "{}", self.to_string())
219    }
220}
221#[cfg(test)]
222mod tests {
223    use super::*;
224    #[test]
225    fn test_value_type() {
226        assert_eq!(Value::String("test".to_string()).value_type(), ValueType::String);
227        assert_eq!(Value::Number(42.0).value_type(), ValueType::Number);
228        assert_eq!(Value::Bool(true).value_type(), ValueType::Boolean);
229        assert_eq!(Value::Array(vec![]).value_type(), ValueType::Array);
230        assert_eq!(Value::Object(HashMap::new()).value_type(), ValueType::Object);
231        assert_eq!(Value::Null.value_type(), ValueType::Null);
232    }
233    #[test]
234    fn test_type_checks() {
235        let string_val = Value::String("test".to_string());
236        assert!(string_val.is_string());
237        assert!(! string_val.is_number());
238        let number_val = Value::Number(42.0);
239        assert!(number_val.is_number());
240        assert!(! number_val.is_string());
241    }
242    #[test]
243    fn test_conversions() {
244        let string_val = Value::from("test");
245        assert_eq!(string_val, Value::String("test".to_string()));
246        let number_val = Value::from(42);
247        assert_eq!(number_val, Value::Number(42.0));
248        let bool_val = Value::from(true);
249        assert_eq!(bool_val, Value::Bool(true));
250    }
251    #[test]
252    fn test_object_access() {
253        let mut obj = HashMap::new();
254        obj.insert("name".to_string(), Value::String("test".to_string()));
255        obj.insert("count".to_string(), Value::Number(42.0));
256        let value = Value::Object(obj);
257        assert_eq!(value.get_string("name"), Some("test"));
258        assert_eq!(value.get_number("count"), Some(42.0));
259        assert_eq!(value.get_string("missing"), None);
260    }
261    #[test]
262    fn test_to_string() {
263        assert_eq!(Value::String("test".to_string()).to_string(), "test");
264        assert_eq!(Value::Number(42.0).to_string(), "42");
265        assert_eq!(Value::Bool(true).to_string(), "true");
266        assert_eq!(Value::Null.to_string(), "null");
267    }
268}