1use std::collections::BTreeMap;
4
5use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
6
7use super::error::DocumentError;
8
9#[derive(Debug, Clone, PartialEq)]
12pub enum Value {
13 Null,
14 Bool(bool),
15 Integer(i64),
16 Unsigned(u64),
17 Float(f64),
18 Number(String),
33 String(String),
34 Array(Vec<Value>),
35 Object(BTreeMap<String, Value>),
37}
38
39impl Value {
40 #[must_use]
45 pub const fn kind_name(&self) -> &'static str {
46 match self {
47 Self::Null => "null",
48 Self::Bool(_) => "boolean",
49 Self::Integer(_) | Self::Unsigned(_) => "integer",
50 Self::Float(_) => "float",
51 Self::Number(_) => "number",
52 Self::String(_) => "string",
53 Self::Array(_) => "array",
54 Self::Object(_) => "object",
55 }
56 }
57
58 pub fn is_null(&self) -> bool {
59 matches!(self, Value::Null)
60 }
61
62 pub fn is_bool(&self) -> bool {
63 matches!(self, Value::Bool(_))
64 }
65
66 pub fn as_bool(&self) -> Option<bool> {
67 match self {
68 Value::Bool(b) => Some(*b),
69 _ => None,
70 }
71 }
72
73 pub fn is_integer(&self) -> bool {
78 match self {
79 Value::Integer(_) | Value::Unsigned(_) => true,
80 Value::Number(text) => is_integer_literal(text),
81 _ => false,
82 }
83 }
84
85 pub fn as_integer(&self) -> Option<i64> {
90 match self {
91 Value::Integer(i) => Some(*i),
92 _ => None,
93 }
94 }
95
96 pub fn as_unsigned(&self) -> Option<u64> {
97 match self {
98 Value::Unsigned(value) => Some(*value),
99 _ => None,
100 }
101 }
102
103 pub fn is_float(&self) -> bool {
106 match self {
107 Value::Float(_) => true,
108 Value::Number(text) => !is_integer_literal(text),
109 _ => false,
110 }
111 }
112
113 pub fn as_float(&self) -> Option<f64> {
120 match self {
121 Value::Float(f) => Some(*f),
122 Value::Number(text) => text.parse::<f64>().ok(),
123 _ => None,
124 }
125 }
126
127 pub fn is_number_literal(&self) -> bool {
130 matches!(self, Value::Number(_))
131 }
132
133 pub fn as_number_literal(&self) -> Option<&str> {
139 match self {
140 Value::Number(text) => Some(text),
141 _ => None,
142 }
143 }
144
145 pub fn is_string(&self) -> bool {
146 matches!(self, Value::String(_))
147 }
148
149 pub fn as_str(&self) -> Option<&str> {
150 match self {
151 Value::String(s) => Some(s),
152 _ => None,
153 }
154 }
155
156 pub fn is_array(&self) -> bool {
157 matches!(self, Value::Array(_))
158 }
159
160 pub fn as_array(&self) -> Option<&Vec<Value>> {
161 match self {
162 Value::Array(a) => Some(a),
163 _ => None,
164 }
165 }
166
167 pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
168 match self {
169 Value::Array(a) => Some(a),
170 _ => None,
171 }
172 }
173
174 pub fn is_object(&self) -> bool {
175 matches!(self, Value::Object(_))
176 }
177
178 pub fn as_object(&self) -> Option<&BTreeMap<String, Value>> {
179 match self {
180 Value::Object(o) => Some(o),
181 _ => None,
182 }
183 }
184
185 pub fn as_object_mut(&mut self) -> Option<&mut BTreeMap<String, Value>> {
186 match self {
187 Value::Object(o) => Some(o),
188 _ => None,
189 }
190 }
191
192 pub fn get(&self, key: &str) -> Option<&Value> {
193 self.as_object().and_then(|o| o.get(key))
194 }
195
196 pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
197 self.as_object_mut().and_then(|o| o.get_mut(key))
198 }
199}
200
201fn is_integer_literal(text: &str) -> bool {
204 !text.contains(['.', 'e', 'E'])
205}
206
207impl std::fmt::Display for Value {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 match self {
210 Value::Null => write!(f, "null"),
211 Value::Bool(b) => write!(f, "{}", b),
212 Value::Integer(i) => write!(f, "{}", i),
213 Value::Unsigned(i) => write!(f, "{}", i),
214 Value::Float(fl) => write!(f, "{}", fl),
215 Value::Number(text) => write!(f, "{text}"),
216 Value::String(s) => write!(f, "\"{}\"", s.escape_default()),
217 Value::Array(_) => write!(f, "[...]"),
218 Value::Object(_) => write!(f, "{{...}}"),
219 }
220 }
221}
222
223impl Serialize for Value {
224 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
225 match self {
226 Value::Null => serializer.serialize_none(),
227 Value::Bool(value) => serializer.serialize_bool(*value),
228 Value::Integer(value) => serializer.serialize_i64(*value),
229 Value::Unsigned(value) => serializer.serialize_u64(*value),
230 Value::Float(value) if value.is_finite() => serializer.serialize_f64(*value),
231 Value::Float(_) => Err(serde::ser::Error::custom(
232 "non-finite float is not representable as structured data",
233 )),
234 Value::Number(text) => {
235 let number = serde_json::from_str::<serde_json::Value>(text)
236 .ok()
237 .filter(serde_json::Value::is_number)
238 .ok_or_else(|| {
239 serde::ser::Error::custom(format!(
240 "invalid preserved number literal `{text}`"
241 ))
242 })?;
243 number.serialize(serializer)
244 }
245 Value::String(value) => serializer.serialize_str(value),
246 Value::Array(values) => values.serialize(serializer),
247 Value::Object(values) => values.serialize(serializer),
248 }
249 }
250}
251
252impl<'de> Deserialize<'de> for Value {
253 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
254 struct ValueVisitor;
255
256 impl<'de> de::Visitor<'de> for ValueVisitor {
257 type Value = Value;
258
259 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
260 formatter.write_str("a document value")
261 }
262
263 fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
264 Ok(Value::Null)
265 }
266
267 fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
268 Ok(Value::Null)
269 }
270
271 fn visit_bool<E: de::Error>(self, value: bool) -> Result<Self::Value, E> {
272 Ok(Value::Bool(value))
273 }
274
275 fn visit_i64<E: de::Error>(self, value: i64) -> Result<Self::Value, E> {
276 Ok(Value::Integer(value))
277 }
278
279 fn visit_u64<E: de::Error>(self, value: u64) -> Result<Self::Value, E> {
280 Ok(Value::Unsigned(value))
281 }
282
283 fn visit_f64<E: de::Error>(self, value: f64) -> Result<Self::Value, E> {
284 Ok(Value::Float(value))
285 }
286
287 fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
288 Ok(Value::String(value.to_string()))
289 }
290
291 fn visit_string<E: de::Error>(self, value: String) -> Result<Self::Value, E> {
292 Ok(Value::String(value))
293 }
294
295 fn visit_seq<A: de::SeqAccess<'de>>(
296 self,
297 mut access: A,
298 ) -> Result<Self::Value, A::Error> {
299 let mut values = Vec::new();
300 while let Some(value) = access.next_element()? {
301 values.push(value);
302 }
303 Ok(Value::Array(values))
304 }
305
306 fn visit_map<A: de::MapAccess<'de>>(
307 self,
308 mut access: A,
309 ) -> Result<Self::Value, A::Error> {
310 let mut values = BTreeMap::new();
311 while let Some((key, value)) = access.next_entry()? {
312 values.insert(key, value);
313 }
314 Ok(Value::Object(values))
315 }
316 }
317
318 deserializer.deserialize_any(ValueVisitor)
319 }
320}
321
322mod json_convert {
323 use super::*;
324
325 impl From<serde_json::Value> for Value {
326 fn from(v: serde_json::Value) -> Self {
327 match v {
328 serde_json::Value::Null => Value::Null,
329 serde_json::Value::Bool(b) => Value::Bool(b),
330 serde_json::Value::Number(n) => {
331 if let Some(i) = n.as_i64() {
341 Value::Integer(i)
342 } else if let Some(u) = n.as_u64() {
343 Value::Unsigned(u)
344 } else {
345 Value::Number(n.as_str().to_string())
346 }
347 }
348 serde_json::Value::String(s) => Value::String(s),
349 serde_json::Value::Array(a) => {
350 Value::Array(a.into_iter().map(Value::from).collect())
351 }
352 serde_json::Value::Object(o) => {
353 let map = o.into_iter().map(|(k, v)| (k, Value::from(v))).collect();
354 Value::Object(map)
355 }
356 }
357 }
358 }
359
360 impl TryFrom<&Value> for serde_json::Value {
361 type Error = DocumentError;
362
363 fn try_from(value: &Value) -> Result<Self, Self::Error> {
364 let unsupported = |detail: String| DocumentError::UnsupportedOperation {
365 format: "JSON".to_string(),
366 operation: "serialize".to_string(),
367 detail,
368 };
369 match value {
370 Value::Null => Ok(Self::Null),
371 Value::Bool(value) => Ok(Self::Bool(*value)),
372 Value::Integer(value) => Ok(Self::Number((*value).into())),
373 Value::Unsigned(value) => Ok(Self::Number((*value).into())),
374 Value::Float(value) => serde_json::Number::from_f64(*value)
375 .map(Self::Number)
376 .ok_or_else(|| {
377 unsupported("non-finite float is not representable in JSON".to_string())
378 }),
379 Value::Number(text) => serde_json::from_str::<Self>(text)
380 .ok()
381 .filter(Self::is_number)
382 .ok_or_else(|| unsupported(format!("invalid number literal `{text}`"))),
383 Value::String(value) => Ok(Self::String(value.clone())),
384 Value::Array(values) => values
385 .iter()
386 .map(Self::try_from)
387 .collect::<Result<Vec<_>, _>>()
388 .map(Self::Array),
389 Value::Object(values) => {
390 let mut object = serde_json::Map::new();
391 for (key, value) in values {
392 object.insert(key.clone(), Self::try_from(value)?);
393 }
394 Ok(Self::Object(object))
395 }
396 }
397 }
398 }
399
400 impl TryFrom<Value> for serde_json::Value {
401 type Error = DocumentError;
402
403 fn try_from(value: Value) -> Result<Self, Self::Error> {
404 Self::try_from(&value)
405 }
406 }
407}
408
409#[cfg(test)]
410mod tests {
411 use super::Value;
412 use std::collections::BTreeMap;
413
414 #[test]
415 fn value_kind_names_are_stable() {
416 let cases = [
417 (Value::Null, "null"),
418 (Value::Bool(true), "boolean"),
419 (Value::Integer(-1), "integer"),
420 (Value::Unsigned(1), "integer"),
421 (Value::Float(1.5), "float"),
422 (Value::Number("1e1000".to_string()), "number"),
423 (Value::String("value".to_string()), "string"),
424 (Value::Array(Vec::new()), "array"),
425 (Value::Object(BTreeMap::new()), "object"),
426 ];
427
428 for (value, expected) in cases {
429 assert_eq!(value.kind_name(), expected);
430 }
431 }
432
433 #[test]
434 fn json_conversion_rejects_non_finite_float() {
435 for value in [f64::NAN, f64::INFINITY, f64::NEG_INFINITY] {
436 let error = serde_json::Value::try_from(Value::Float(value))
437 .expect_err("non-finite float must fail");
438 assert_eq!(error.code(), "document_unsupported_operation");
439 assert!(error.to_string().contains("non-finite"));
440 }
441 }
442
443 #[test]
444 fn serde_rejects_non_finite_float_instead_of_emitting_null() {
445 let error =
446 serde_json::to_string(&Value::Float(f64::NAN)).expect_err("non-finite float must fail");
447 assert!(error.to_string().contains("non-finite"));
448 }
449}