1#[cfg(feature = "json")]
2use crate::error::QqlError;
3use alloc::string::String;
4use alloc::vec::Vec;
5
6#[derive(Clone, PartialEq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub enum Value {
10 Str(String),
12 Int(i64),
14 UInt(u64),
17 Float(f64),
19 Bool(bool),
21 Null,
23 Dict(Vec<(String, Value)>),
25 List(Vec<Value>),
27 F32Array(Vec<f32>),
29 Param(
31 String,
32 #[cfg_attr(
33 feature = "serde",
34 serde(default, skip_serializing_if = "Option::is_none")
35 )]
36 Option<alloc::boxed::Box<crate::error::Span>>,
37 ),
38 PositionalParam(
40 usize,
41 #[cfg_attr(
42 feature = "serde",
43 serde(default, skip_serializing_if = "Option::is_none")
44 )]
45 Option<alloc::boxed::Box<crate::error::Span>>,
46 ),
47}
48
49impl core::fmt::Debug for Value {
50 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51 match self {
52 Self::Str(value) => f.debug_tuple("Str").field(value).finish(),
53 Self::Int(value) => f.debug_tuple("Int").field(value).finish(),
54 Self::UInt(value) => f.debug_tuple("UInt").field(value).finish(),
55 Self::Float(value) => f.debug_tuple("Float").field(value).finish(),
56 Self::Bool(value) => f.debug_tuple("Bool").field(value).finish(),
57 Self::Null => f.write_str("Null"),
58 Self::Dict(value) => f.debug_tuple("Dict").field(value).finish(),
59 Self::List(value) => f.debug_tuple("List").field(value).finish(),
60 Self::F32Array(value) => f.debug_tuple("F32Array").field(value).finish(),
61 Self::Param(value, span) => f.debug_tuple("Param").field(value).field(span).finish(),
62 Self::PositionalParam(idx, span) => f
63 .debug_tuple("PositionalParam")
64 .field(idx)
65 .field(span)
66 .finish(),
67 }
68 }
69}
70
71impl Value {
72 pub fn dict_get(&self, key: &str) -> Option<&Value> {
74 match self {
75 Self::Dict(items) => items
76 .iter()
77 .find(|(candidate, _)| candidate.eq_ignore_ascii_case(key))
78 .map(|(_, value)| value),
79 _ => None,
80 }
81 }
82
83 pub fn dict_set(&mut self, key: String, value: Value) -> bool {
88 let Self::Dict(items) = self else {
89 return false;
90 };
91 if let Some((_, current)) = items
92 .iter_mut()
93 .find(|(candidate, _)| candidate.eq_ignore_ascii_case(&key))
94 {
95 *current = value;
96 } else {
97 items.push((key, value));
98 }
99 true
100 }
101
102 pub fn as_str(&self) -> Option<&str> {
104 match self {
105 Self::Str(value) => Some(value),
106 _ => None,
107 }
108 }
109
110 #[cfg(feature = "json")]
115 pub fn from_json(value: serde_json::Value) -> Result<Self, QqlError> {
116 match value {
117 serde_json::Value::String(value) => Ok(Self::Str(value)),
118 serde_json::Value::Number(value) => match value.as_i64() {
119 Some(int) => Ok(Self::Int(int)),
120 None => match value.as_u64() {
121 Some(uint) => Ok(Self::UInt(uint)),
122 None => value.as_f64().map(Self::Float).ok_or_else(|| {
123 QqlError::validation(
124 "QQL-JSON-NUMBER",
125 "JSON number cannot be represented by QQL",
126 None,
127 )
128 }),
129 },
130 },
131 serde_json::Value::Bool(value) => Ok(Self::Bool(value)),
132 serde_json::Value::Null => Ok(Self::Null),
133 serde_json::Value::Array(items) => items
134 .into_iter()
135 .map(Self::from_json)
136 .collect::<Result<Vec<_>, _>>()
137 .map(Self::List),
138 serde_json::Value::Object(items) => items
139 .into_iter()
140 .map(|(key, value)| Self::from_json(value).map(|value| (key, value)))
141 .collect::<Result<Vec<_>, _>>()
142 .map(Self::Dict),
143 }
144 }
145
146 #[cfg(feature = "json")]
154 pub fn to_json(&self) -> Result<serde_json::Value, QqlError> {
155 match self {
156 Self::Str(value) => Ok(serde_json::Value::String(value.clone())),
157 Self::Int(value) => Ok(serde_json::Value::Number((*value).into())),
158 Self::UInt(value) => Ok(serde_json::Value::Number((*value).into())),
159 Self::Float(value) => serde_json::Number::from_f64(*value)
160 .map(serde_json::Value::Number)
161 .ok_or_else(|| {
162 QqlError::validation(
163 "QQL-JSON-NONFINITE",
164 "non-finite floats cannot be converted to JSON",
165 None,
166 )
167 }),
168 Self::Bool(value) => Ok(serde_json::Value::Bool(*value)),
169 Self::Null => Ok(serde_json::Value::Null),
170 Self::Dict(items) => {
171 let mut object = serde_json::Map::new();
172 for (key, value) in items {
173 object.insert(key.clone(), value.to_json()?);
174 }
175 Ok(serde_json::Value::Object(object))
176 }
177 Self::List(items) => items
178 .iter()
179 .map(Self::to_json)
180 .collect::<Result<Vec<_>, _>>()
181 .map(serde_json::Value::Array),
182 Self::F32Array(values) => {
183 let items = values
184 .iter()
185 .map(|&f| {
186 serde_json::Number::from_f64(f as f64)
187 .map(serde_json::Value::Number)
188 .ok_or_else(|| {
189 QqlError::validation(
190 "QQL-JSON-NONFINITE",
191 "non-finite floats cannot be converted to JSON",
192 None,
193 )
194 })
195 })
196 .collect::<Result<Vec<_>, _>>()?;
197 Ok(serde_json::Value::Array(items))
198 }
199 Self::Param(name, span) => {
200 if let Some(sp) = span {
201 Ok(serde_json::json!({ "$param": name, "$span": [sp.start, sp.end] }))
202 } else {
203 Ok(serde_json::json!({ "$param": name }))
204 }
205 }
206 Self::PositionalParam(idx, span) => {
207 if let Some(sp) = span {
208 Ok(serde_json::json!({ "$param_idx": idx, "$span": [sp.start, sp.end] }))
209 } else {
210 Ok(serde_json::json!({ "$param_idx": idx }))
211 }
212 }
213 }
214 }
215
216 pub fn param(name: impl Into<String>) -> Self {
218 Self::Param(name.into(), None)
219 }
220
221 pub fn param_with_span(name: impl Into<String>, span: crate::error::Span) -> Self {
223 Self::Param(name.into(), Some(alloc::boxed::Box::new(span)))
224 }
225
226 pub fn positional_param(idx: usize) -> Self {
228 Self::PositionalParam(idx, None)
229 }
230
231 pub fn positional_param_with_span(idx: usize, span: crate::error::Span) -> Self {
233 Self::PositionalParam(idx, Some(alloc::boxed::Box::new(span)))
234 }
235
236 pub fn param_name(&self) -> Option<&str> {
238 match self {
239 Self::Param(name, _) => Some(name.as_str()),
240 _ => None,
241 }
242 }
243
244 pub fn param_span(&self) -> Option<crate::error::Span> {
246 match self {
247 Self::Param(_, span) | Self::PositionalParam(_, span) => span.as_deref().copied(),
248 _ => None,
249 }
250 }
251}
252
253impl From<Vec<f32>> for Value {
254 fn from(values: Vec<f32>) -> Self {
255 Self::F32Array(values)
256 }
257}