1#[cfg(feature = "json")]
2use crate::error::QqlError;
3use alloc::string::String;
4use alloc::vec::Vec;
5
6#[derive(Clone, PartialEq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub enum Value {
9 Str(String),
10 Int(i64),
11 Float(f64),
12 Bool(bool),
13 Null,
14 Dict(Vec<(String, Value)>),
15 List(Vec<Value>),
16}
17
18impl core::fmt::Debug for Value {
19 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
20 match self {
21 Self::Str(value) => f.debug_tuple("Str").field(value).finish(),
22 Self::Int(value) => f.debug_tuple("Int").field(value).finish(),
23 Self::Float(value) => f.debug_tuple("Float").field(value).finish(),
24 Self::Bool(value) => f.debug_tuple("Bool").field(value).finish(),
25 Self::Null => f.write_str("Null"),
26 Self::Dict(value) => f.debug_tuple("Dict").field(value).finish(),
27 Self::List(value) => f.debug_tuple("List").field(value).finish(),
28 }
29 }
30}
31
32impl Value {
33 pub fn dict_get(&self, key: &str) -> Option<&Value> {
34 match self {
35 Self::Dict(items) => items
36 .iter()
37 .find(|(candidate, _)| candidate.eq_ignore_ascii_case(key))
38 .map(|(_, value)| value),
39 _ => None,
40 }
41 }
42
43 pub fn dict_set(&mut self, key: String, value: Value) {
44 if let Self::Dict(items) = self {
45 if let Some((_, current)) = items
46 .iter_mut()
47 .find(|(candidate, _)| candidate.eq_ignore_ascii_case(&key))
48 {
49 *current = value;
50 } else {
51 items.push((key, value));
52 }
53 }
54 }
55
56 pub fn as_str(&self) -> Option<&str> {
57 match self {
58 Self::Str(value) => Some(value),
59 _ => None,
60 }
61 }
62
63 #[cfg(feature = "json")]
64 pub fn from_json(value: serde_json::Value) -> Result<Self, QqlError> {
65 match value {
66 serde_json::Value::String(value) => Ok(Self::Str(value)),
67 serde_json::Value::Number(value) => value
68 .as_i64()
69 .map(Self::Int)
70 .or_else(|| value.as_f64().map(Self::Float))
71 .ok_or_else(|| {
72 QqlError::validation(
73 "QQL-JSON-NUMBER",
74 "JSON number cannot be represented by QQL",
75 None,
76 )
77 }),
78 serde_json::Value::Bool(value) => Ok(Self::Bool(value)),
79 serde_json::Value::Null => Ok(Self::Null),
80 serde_json::Value::Array(items) => items
81 .into_iter()
82 .map(Self::from_json)
83 .collect::<Result<Vec<_>, _>>()
84 .map(Self::List),
85 serde_json::Value::Object(items) => items
86 .into_iter()
87 .map(|(key, value)| Self::from_json(value).map(|value| (key, value)))
88 .collect::<Result<Vec<_>, _>>()
89 .map(Self::Dict),
90 }
91 }
92
93 #[cfg(feature = "json")]
94 pub fn to_json(&self) -> Result<serde_json::Value, QqlError> {
95 match self {
96 Self::Str(value) => Ok(serde_json::Value::String(value.clone())),
97 Self::Int(value) => Ok(serde_json::Value::Number((*value).into())),
98 Self::Float(value) => serde_json::Number::from_f64(*value)
99 .map(serde_json::Value::Number)
100 .ok_or_else(|| {
101 QqlError::validation(
102 "QQL-JSON-NONFINITE",
103 "non-finite floats cannot be converted to JSON",
104 None,
105 )
106 }),
107 Self::Bool(value) => Ok(serde_json::Value::Bool(*value)),
108 Self::Null => Ok(serde_json::Value::Null),
109 Self::Dict(items) => {
110 let mut object = serde_json::Map::new();
111 for (key, value) in items {
112 object.insert(key.clone(), value.to_json()?);
113 }
114 Ok(serde_json::Value::Object(object))
115 }
116 Self::List(items) => items
117 .iter()
118 .map(Self::to_json)
119 .collect::<Result<Vec<_>, _>>()
120 .map(serde_json::Value::Array),
121 }
122 }
123}