1use crate::error::{Error, Result};
7use std::collections::BTreeMap;
8use std::fmt;
9
10#[derive(Debug, Clone, PartialEq)]
12pub enum Value {
13 Null,
15 Bool(bool),
17 Integer(i64),
19 Float(f64),
21 String(String),
23 Array(Vec<Value>),
25 Table(BTreeMap<String, Value>),
27 #[cfg(feature = "chrono")]
29 DateTime(chrono::DateTime<chrono::Utc>),
30}
31
32impl Value {
33 pub fn null() -> Self {
35 Value::Null
36 }
37
38 pub fn bool(value: bool) -> Self {
40 Value::Bool(value)
41 }
42
43 pub fn integer(value: i64) -> Self {
45 Value::Integer(value)
46 }
47
48 pub fn float(value: f64) -> Self {
50 Value::Float(value)
51 }
52
53 pub fn string<S: Into<String>>(value: S) -> Self {
55 Value::String(value.into())
56 }
57
58 pub fn array(values: Vec<Value>) -> Self {
60 Value::Array(values)
61 }
62
63 pub fn table(table: BTreeMap<String, Value>) -> Self {
65 Value::Table(table)
66 }
67
68 #[cfg(feature = "chrono")]
70 pub fn datetime(dt: chrono::DateTime<chrono::Utc>) -> Self {
71 Value::DateTime(dt)
72 }
73
74 pub fn type_name(&self) -> &'static str {
76 match self {
77 Value::Null => "null",
78 Value::Bool(_) => "bool",
79 Value::Integer(_) => "integer",
80 Value::Float(_) => "float",
81 Value::String(_) => "string",
82 Value::Array(_) => "array",
83 Value::Table(_) => "table",
84 #[cfg(feature = "chrono")]
85 Value::DateTime(_) => "datetime",
86 }
87 }
88
89 pub fn is_null(&self) -> bool {
91 matches!(self, Value::Null)
92 }
93
94 pub fn is_bool(&self) -> bool {
96 matches!(self, Value::Bool(_))
97 }
98
99 pub fn is_integer(&self) -> bool {
101 matches!(self, Value::Integer(_))
102 }
103
104 pub fn is_float(&self) -> bool {
106 matches!(self, Value::Float(_))
107 }
108
109 pub fn is_string(&self) -> bool {
111 matches!(self, Value::String(_))
112 }
113
114 pub fn is_array(&self) -> bool {
116 matches!(self, Value::Array(_))
117 }
118
119 pub fn is_table(&self) -> bool {
121 matches!(self, Value::Table(_))
122 }
123
124 pub fn as_bool(&self) -> Result<bool> {
126 match self {
127 Value::Bool(b) => Ok(*b),
128 Value::String(s) => match s.to_lowercase().as_str() {
129 "true" | "yes" | "1" | "on" => Ok(true),
130 "false" | "no" | "0" | "off" => Ok(false),
131 _ => Err(Error::type_error(
132 "Cannot convert to boolean",
133 "bool",
134 self.type_name(),
135 )),
136 },
137 _ => Err(Error::type_error(
138 "Cannot convert to boolean",
139 "bool",
140 self.type_name(),
141 )),
142 }
143 }
144
145 pub fn as_integer(&self) -> Result<i64> {
147 match self {
148 Value::Integer(i) => Ok(*i),
149 Value::Float(f) => Ok(*f as i64),
150 Value::String(s) => s.parse::<i64>().map_err(|_| {
151 Error::type_error("Cannot convert to integer", "integer", self.type_name())
152 }),
153 _ => Err(Error::type_error(
154 "Cannot convert to integer",
155 "integer",
156 self.type_name(),
157 )),
158 }
159 }
160
161 pub fn as_float(&self) -> Result<f64> {
163 match self {
164 Value::Float(f) => Ok(*f),
165 Value::Integer(i) => Ok(*i as f64),
166 Value::String(s) => s.parse::<f64>().map_err(|_| {
167 Error::type_error("Cannot convert to float", "float", self.type_name())
168 }),
169 _ => Err(Error::type_error(
170 "Cannot convert to float",
171 "float",
172 self.type_name(),
173 )),
174 }
175 }
176
177 pub fn as_string(&self) -> Result<&str> {
179 match self {
180 Value::String(s) => Ok(s.as_str()),
181 _ => Err(Error::type_error(
182 "Cannot convert to string",
183 "string",
184 self.type_name(),
185 )),
186 }
187 }
188
189 pub fn to_string_representation(&self) -> Result<String> {
191 match self {
192 Value::String(s) => Ok(s.clone()),
193 Value::Integer(i) => Ok(i.to_string()),
194 Value::Float(f) => Ok(f.to_string()),
195 Value::Bool(b) => Ok(b.to_string()),
196 _ => Err(Error::type_error(
197 "Cannot convert to string representation",
198 "string",
199 self.type_name(),
200 )),
201 }
202 }
203
204 pub fn as_array(&self) -> Result<&Vec<Value>> {
206 match self {
207 Value::Array(arr) => Ok(arr),
208 _ => Err(Error::type_error(
209 "Cannot convert to array",
210 "array",
211 self.type_name(),
212 )),
213 }
214 }
215
216 pub fn as_array_mut(&mut self) -> Result<&mut Vec<Value>> {
218 match self {
219 Value::Array(arr) => Ok(arr),
220 _ => Err(Error::type_error(
221 "Cannot convert to array",
222 "array",
223 self.type_name(),
224 )),
225 }
226 }
227
228 pub fn as_table(&self) -> Result<&BTreeMap<String, Value>> {
230 match self {
231 Value::Table(table) => Ok(table),
232 _ => Err(Error::type_error(
233 "Cannot convert to table",
234 "table",
235 self.type_name(),
236 )),
237 }
238 }
239
240 pub fn as_table_mut(&mut self) -> Result<&mut BTreeMap<String, Value>> {
242 match self {
243 Value::Table(table) => Ok(table),
244 _ => Err(Error::type_error(
245 "Cannot convert to table",
246 "table",
247 self.type_name(),
248 )),
249 }
250 }
251
252 pub fn get(&self, path: &str) -> Option<&Value> {
254 if path.is_empty() {
255 return Some(self);
256 }
257
258 let parts: Vec<&str> = path.split('.').collect();
260 let mut current = self;
261 let mut found_nested = true;
262
263 for part in parts {
264 match current {
265 Value::Table(table) => {
266 if let Some(next) = table.get(part) {
267 current = next;
268 } else {
269 found_nested = false;
270 break;
271 }
272 }
273 _ => {
274 found_nested = false;
275 break;
276 }
277 }
278 }
279
280 if found_nested {
282 return Some(current);
283 }
284
285 if let Value::Table(table) = self {
287 table.get(path)
288 } else {
289 None
290 }
291 }
292
293 pub fn get_mut_nested(&mut self, path: &str) -> Result<&mut Value> {
295 if path.is_empty() {
296 return Ok(self);
297 }
298
299 let parts: Vec<&str> = path.split('.').collect();
300 if parts.is_empty() {
301 return Err(Error::key_not_found(path));
302 }
303
304 let (last_key, parent_path) = parts
305 .split_last()
306 .ok_or_else(|| Error::key_not_found(path))?;
307
308 let mut current = self;
310 for part in parent_path {
311 match current {
312 Value::Table(table) => {
313 current = table
314 .get_mut(*part)
315 .ok_or_else(|| Error::key_not_found(*part))?;
316 }
317 _ => {
318 return Err(Error::type_error(
319 format!(
320 "Cannot navigate into {} when looking for key '{}'",
321 current.type_name(),
322 part
323 ),
324 "table",
325 current.type_name(),
326 ))
327 }
328 }
329 }
330
331 match current {
333 Value::Table(table) => table
334 .get_mut(*last_key)
335 .ok_or_else(|| Error::key_not_found(*last_key)),
336 _ => Err(Error::type_error(
337 format!("Cannot get key '{}' from {}", last_key, current.type_name()),
338 "table",
339 current.type_name(),
340 )),
341 }
342 }
343
344 pub fn set_nested(&mut self, path: &str, value: Value) -> Result<()> {
346 if path.is_empty() {
347 return Err(Error::key_not_found(""));
348 }
349
350 let parts: Vec<&str> = path.split('.').collect();
351 if parts.is_empty() {
352 return Err(Error::key_not_found(path));
353 }
354
355 let (last_key, parent_path) = parts
356 .split_last()
357 .ok_or_else(|| Error::key_not_found(path))?;
358
359 let mut current = self;
361 for part in parent_path {
362 if let Value::Table(table) = current {
363 let entry = table
365 .entry((*part).to_string())
366 .or_insert_with(|| Value::table(BTreeMap::new()));
367 current = entry;
368 } else {
369 return Err(Error::type_error(
370 format!("Cannot navigate into {}", current.type_name()),
371 "table",
372 current.type_name(),
373 ));
374 }
375 }
376
377 if let Value::Table(table) = current {
379 table.insert((*last_key).to_string(), value);
380 Ok(())
381 } else {
382 Err(Error::type_error(
383 format!("Cannot set key in {}", current.type_name()),
384 "table",
385 current.type_name(),
386 ))
387 }
388 }
389
390 pub fn remove(&mut self, path: &str) -> Result<Option<Value>> {
392 if path.is_empty() {
393 let old = std::mem::replace(self, Value::Null);
394 return Ok(Some(old));
395 }
396
397 let parts: Vec<&str> = path.split('.').collect();
398 if parts.is_empty() {
399 return Err(Error::key_not_found(path));
400 }
401
402 let (last_key, parent_path) = parts
403 .split_last()
404 .ok_or_else(|| Error::key_not_found(path))?;
405
406 let mut current = self;
408 for part in parent_path {
409 match current {
410 Value::Table(table) => {
411 current = table
412 .get_mut(*part)
413 .ok_or_else(|| Error::key_not_found(*part))?;
414 }
415 _ => {
416 return Err(Error::type_error(
417 format!(
418 "Cannot navigate into {} when removing key '{}'",
419 current.type_name(),
420 part
421 ),
422 "table",
423 current.type_name(),
424 ))
425 }
426 }
427 }
428
429 if let Value::Table(table) = current {
431 Ok(table.remove(*last_key))
432 } else {
433 Err(Error::type_error(
434 format!(
435 "Cannot remove key '{}' from {}",
436 last_key,
437 current.type_name()
438 ),
439 "table",
440 current.type_name(),
441 ))
442 }
443 }
444
445 pub fn keys(&self) -> Result<Vec<&str>> {
447 match self {
448 Value::Table(table) => Ok(table.keys().map(|k| k.as_str()).collect()),
449 _ => Err(Error::type_error(
450 "Cannot get keys from non-table value",
451 "table",
452 self.type_name(),
453 )),
454 }
455 }
456
457 pub fn contains_key(&self, path: &str) -> bool {
459 self.get(path).is_some()
460 }
461
462 pub fn set(&mut self, path: &str, value: Value) -> Result<()> {
464 self.set_nested(path, value)
465 }
466
467 pub fn len(&self) -> usize {
469 match self {
470 Value::Array(arr) => arr.len(),
471 Value::Table(table) => table.len(),
472 Value::String(s) => s.len(),
473 _ => 0,
474 }
475 }
476
477 pub fn is_empty(&self) -> bool {
479 self.len() == 0
480 }
481}
482
483impl fmt::Display for Value {
484 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
485 match self {
486 Value::Null => write!(f, "null"),
487 Value::Bool(b) => write!(f, "{b}"),
488 Value::Integer(i) => write!(f, "{i}"),
489 Value::Float(fl) => write!(f, "{fl}"),
490 Value::String(s) => write!(f, "{s}"),
491 Value::Array(arr) => {
492 write!(f, "[")?;
493 for (i, item) in arr.iter().enumerate() {
494 if i > 0 {
495 write!(f, ", ")?;
496 }
497 write!(f, "{item}")?;
498 }
499 write!(f, "]")
500 }
501 Value::Table(table) => {
502 write!(f, "{{")?;
503 for (i, (key, value)) in table.iter().enumerate() {
504 if i > 0 {
505 write!(f, ", ")?;
506 }
507 write!(f, "{key}: {value}")?;
508 }
509 write!(f, "}}")
510 }
511 #[cfg(feature = "chrono")]
512 Value::DateTime(dt) => write!(f, "{}", dt.to_rfc3339()),
513 }
514 }
515}
516
517impl From<bool> for Value {
519 fn from(value: bool) -> Self {
520 Value::Bool(value)
521 }
522}
523
524impl From<i32> for Value {
525 fn from(value: i32) -> Self {
526 Value::Integer(i64::from(value))
527 }
528}
529
530impl From<i64> for Value {
531 fn from(value: i64) -> Self {
532 Value::Integer(value)
533 }
534}
535
536impl From<f32> for Value {
537 fn from(value: f32) -> Self {
538 Value::Float(f64::from(value))
539 }
540}
541
542impl From<f64> for Value {
543 fn from(value: f64) -> Self {
544 Value::Float(value)
545 }
546}
547
548impl From<String> for Value {
549 fn from(value: String) -> Self {
550 Value::String(value)
551 }
552}
553
554impl From<&str> for Value {
555 fn from(value: &str) -> Self {
556 Value::String(value.to_string())
557 }
558}
559
560impl From<Vec<Value>> for Value {
561 fn from(value: Vec<Value>) -> Self {
562 Value::Array(value)
563 }
564}
565
566impl From<BTreeMap<String, Value>> for Value {
567 fn from(value: BTreeMap<String, Value>) -> Self {
568 Value::Table(value)
569 }
570}
571
572impl Value {
574 pub fn string_from_slice(value: &str) -> Self {
576 Value::String(value.to_string())
577 }
578
579 pub fn as_str(&self) -> Result<&str> {
581 match self {
582 Value::String(s) => Ok(s.as_str()),
583 _ => Err(Error::type_error(
584 "Value is not a string",
585 "string",
586 self.type_name(),
587 )),
588 }
589 }
590}
591
592#[cfg(test)]
593mod tests {
594 use super::*;
595
596 #[test]
597 fn test_value_creation() {
598 assert_eq!(Value::null(), Value::Null);
599 assert_eq!(Value::bool(true), Value::Bool(true));
600 assert_eq!(Value::integer(42), Value::Integer(42));
601 assert_eq!(Value::float(1.234), Value::Float(1.234));
602 assert_eq!(Value::string("test"), Value::String("test".to_string()));
603 }
604
605 #[test]
606 fn test_type_checking() {
607 let null = Value::null();
608 let bool_val = Value::bool(true);
609 let int_val = Value::integer(42);
610 let float_val = Value::float(5.678);
611 let string_val = Value::string("test");
612 let array_val = Value::array(vec![Value::integer(1), Value::integer(2)]);
613 let table_val = Value::table(BTreeMap::new());
614
615 assert!(null.is_null());
616 assert!(bool_val.is_bool());
617 assert!(int_val.is_integer());
618 assert!(float_val.is_float());
619 assert!(string_val.is_string());
620 assert!(array_val.is_array());
621 assert!(table_val.is_table());
622 }
623
624 #[test]
625 fn test_value_conversion() {
626 let bool_val = Value::bool(true);
627 let int_val = Value::integer(42);
628 let float_val = Value::float(1.234);
629 let string_val = Value::string("test");
630
631 assert!(bool_val.as_bool().unwrap());
632 assert_eq!(int_val.as_integer().unwrap(), 42);
633 assert_eq!(float_val.as_float().unwrap(), 1.234);
634 assert_eq!(string_val.as_string().unwrap(), "test");
635 }
636
637 #[test]
638 fn test_nested_access() {
639 let mut table = BTreeMap::new();
640 let mut inner_table = BTreeMap::new();
641 inner_table.insert("inner_key".to_string(), Value::string("inner_value"));
642 table.insert("outer_key".to_string(), Value::table(inner_table));
643
644 let value = Value::table(table);
645
646 assert_eq!(
647 value
648 .get("outer_key.inner_key")
649 .unwrap()
650 .as_string()
651 .unwrap(),
652 "inner_value"
653 );
654 }
655
656 #[test]
657 fn test_enterprise_error_handling() {
658 let mut value = Value::table(BTreeMap::new());
659
660 assert!(value.get_mut_nested("nonexistent.key").is_err());
662 assert!(value.remove("nonexistent.key").is_err());
663
664 assert!(value.set_nested("test.key", Value::string("value")).is_ok());
666 assert!(value.get("test.key").is_some());
667 }
668}