Skip to main content

serde_toon2/
value.rs

1//! Generic TOON value type for dynamic content.
2//!
3//! The [`Value`] enum represents any valid TOON value, similar to `serde_json::Value`.
4
5use indexmap::IndexMap;
6use serde::{Deserialize, Serialize};
7use std::fmt;
8
9/// An order-preserving map type used for TOON objects.
10///
11/// Uses [`IndexMap`] to preserve the insertion order of keys, which is important
12/// for maintaining consistent serialization output.
13pub type Map<K, V> = IndexMap<K, V>;
14
15/// Represents any valid TOON value.
16///
17/// This type is useful when you need to work with TOON data dynamically without
18/// knowing the schema ahead of time.
19///
20/// # Examples
21///
22/// ```
23/// use serde_toon2::{Value, Map, Number};
24///
25/// // Create a simple value
26/// let name = Value::String("Ada".to_string());
27///
28/// // Create an object
29/// let mut map = Map::new();
30/// map.insert("name".to_string(), Value::String("Ada".to_string()));
31/// map.insert("age".to_string(), Value::Number(Number::U64(42)));
32/// let obj = Value::Object(map);
33/// ```
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
35#[serde(untagged)]
36pub enum Value {
37    /// Represents a null value.
38    Null,
39    /// Represents a boolean value.
40    Bool(bool),
41    /// Represents a numeric value.
42    Number(Number),
43    /// Represents a string value.
44    String(String),
45    /// Represents an array of values.
46    Array(Vec<Value>),
47    /// Represents an object (map of string keys to values).
48    Object(Map<String, Value>),
49}
50
51/// Represents a TOON number.
52///
53/// TOON supports signed integers, unsigned integers, and floating point numbers.
54///
55/// # Examples
56///
57/// ```
58/// use serde_toon2::{Number, Value};
59///
60/// let int = Number::I64(-42);
61/// let uint = Number::U64(42);
62/// let float = Number::F64(3.14);
63///
64/// assert_eq!(int.as_i64(), Some(-42));
65/// assert_eq!(uint.as_u64(), Some(42));
66/// assert_eq!(float.as_f64(), 3.14);
67/// ```
68#[derive(Debug, Clone, PartialEq)]
69pub enum Number {
70    /// A signed 64-bit integer.
71    I64(i64),
72    /// An unsigned 64-bit integer.
73    U64(u64),
74    /// A 64-bit floating point number.
75    F64(f64),
76}
77
78impl Number {
79    /// Tries to convert this number to an `i64`.
80    ///
81    /// Returns `None` if the conversion would lose precision or overflow.
82    ///
83    /// # Examples
84    ///
85    /// ```
86    /// use serde_toon2::Number;
87    ///
88    /// assert_eq!(Number::I64(42).as_i64(), Some(42));
89    /// assert_eq!(Number::U64(42).as_i64(), Some(42));
90    /// assert_eq!(Number::F64(42.0).as_i64(), Some(42));
91    /// assert_eq!(Number::F64(42.5).as_i64(), None);
92    /// ```
93    pub fn as_i64(&self) -> Option<i64> {
94        match self {
95            Number::I64(n) => Some(*n),
96            Number::U64(n) => i64::try_from(*n).ok(),
97            Number::F64(n) => {
98                if n.fract() == 0.0 && *n >= i64::MIN as f64 && *n <= i64::MAX as f64 {
99                    Some(*n as i64)
100                } else {
101                    None
102                }
103            }
104        }
105    }
106
107    /// Tries to convert this number to a `u64`.
108    ///
109    /// Returns `None` if the conversion would lose precision or overflow.
110    ///
111    /// # Examples
112    ///
113    /// ```
114    /// use serde_toon2::Number;
115    ///
116    /// assert_eq!(Number::U64(42).as_u64(), Some(42));
117    /// assert_eq!(Number::I64(42).as_u64(), Some(42));
118    /// assert_eq!(Number::I64(-42).as_u64(), None);
119    /// assert_eq!(Number::F64(42.0).as_u64(), Some(42));
120    /// assert_eq!(Number::F64(42.5).as_u64(), None);
121    /// ```
122    pub fn as_u64(&self) -> Option<u64> {
123        match self {
124            Number::I64(n) => u64::try_from(*n).ok(),
125            Number::U64(n) => Some(*n),
126            Number::F64(n) => {
127                if n.fract() == 0.0 && *n >= 0.0 && *n <= u64::MAX as f64 {
128                    Some(*n as u64)
129                } else {
130                    None
131                }
132            }
133        }
134    }
135
136    /// Converts this number to an `f64`.
137    ///
138    /// This conversion is always possible, though very large integers may lose precision.
139    ///
140    /// # Examples
141    ///
142    /// ```
143    /// use serde_toon2::Number;
144    ///
145    /// assert_eq!(Number::I64(42).as_f64(), 42.0);
146    /// assert_eq!(Number::U64(42).as_f64(), 42.0);
147    /// assert_eq!(Number::F64(3.14).as_f64(), 3.14);
148    /// ```
149    pub fn as_f64(&self) -> f64 {
150        match self {
151            Number::I64(n) => *n as f64,
152            Number::U64(n) => *n as f64,
153            Number::F64(n) => *n,
154        }
155    }
156
157    /// Returns `true` if this number is stored as an `i64`.
158    ///
159    /// # Examples
160    ///
161    /// ```
162    /// use serde_toon2::Number;
163    ///
164    /// assert!(Number::I64(42).is_i64());
165    /// assert!(!Number::U64(42).is_i64());
166    /// assert!(!Number::F64(42.0).is_i64());
167    /// ```
168    pub fn is_i64(&self) -> bool {
169        matches!(self, Number::I64(_))
170    }
171
172    /// Returns `true` if this number is stored as a `u64`.
173    ///
174    /// # Examples
175    ///
176    /// ```
177    /// use serde_toon2::Number;
178    ///
179    /// assert!(Number::U64(42).is_u64());
180    /// assert!(!Number::I64(42).is_u64());
181    /// assert!(!Number::F64(42.0).is_u64());
182    /// ```
183    pub fn is_u64(&self) -> bool {
184        matches!(self, Number::U64(_))
185    }
186
187    /// Returns `true` if this number is stored as an `f64`.
188    ///
189    /// # Examples
190    ///
191    /// ```
192    /// use serde_toon2::Number;
193    ///
194    /// assert!(Number::F64(3.14).is_f64());
195    /// assert!(!Number::I64(42).is_f64());
196    /// assert!(!Number::U64(42).is_f64());
197    /// ```
198    pub fn is_f64(&self) -> bool {
199        matches!(self, Number::F64(_))
200    }
201}
202
203impl Serialize for Number {
204    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
205    where
206        S: serde::Serializer,
207    {
208        match self {
209            Number::I64(n) => serializer.serialize_i64(*n),
210            Number::U64(n) => serializer.serialize_u64(*n),
211            Number::F64(n) => serializer.serialize_f64(*n),
212        }
213    }
214}
215
216impl<'de> Deserialize<'de> for Number {
217    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
218    where
219        D: serde::Deserializer<'de>,
220    {
221        struct NumberVisitor;
222
223        impl<'de> serde::de::Visitor<'de> for NumberVisitor {
224            type Value = Number;
225
226            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
227                formatter.write_str("a number")
228            }
229
230            fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
231                Ok(Number::I64(value))
232            }
233
234            fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
235                Ok(Number::U64(value))
236            }
237
238            fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> {
239                Ok(Number::F64(value))
240            }
241        }
242
243        deserializer.deserialize_any(NumberVisitor)
244    }
245}
246
247impl Value {
248    /// Returns `true` if this value is null.
249    ///
250    /// # Examples
251    ///
252    /// ```
253    /// use serde_toon2::Value;
254    ///
255    /// assert!(Value::Null.is_null());
256    /// assert!(!Value::Bool(false).is_null());
257    /// ```
258    pub fn is_null(&self) -> bool {
259        matches!(self, Value::Null)
260    }
261
262    /// If this value is a boolean, returns it. Otherwise returns `None`.
263    ///
264    /// # Examples
265    ///
266    /// ```
267    /// use serde_toon2::Value;
268    ///
269    /// assert_eq!(Value::Bool(true).as_bool(), Some(true));
270    /// assert_eq!(Value::Null.as_bool(), None);
271    /// ```
272    pub fn as_bool(&self) -> Option<bool> {
273        match self {
274            Value::Bool(b) => Some(*b),
275            _ => None,
276        }
277    }
278
279    /// If this value is a number, tries to convert it to `i64`. Otherwise returns `None`.
280    ///
281    /// # Examples
282    ///
283    /// ```
284    /// use serde_toon2::Value;
285    ///
286    /// let v: Value = 42i64.into();
287    /// assert_eq!(v.as_i64(), Some(42));
288    ///
289    /// let v = Value::String("42".to_string());
290    /// assert_eq!(v.as_i64(), None);
291    /// ```
292    pub fn as_i64(&self) -> Option<i64> {
293        match self {
294            Value::Number(n) => n.as_i64(),
295            _ => None,
296        }
297    }
298
299    /// If this value is a number, tries to convert it to `u64`. Otherwise returns `None`.
300    ///
301    /// # Examples
302    ///
303    /// ```
304    /// use serde_toon2::Value;
305    ///
306    /// let v: Value = 42u64.into();
307    /// assert_eq!(v.as_u64(), Some(42));
308    ///
309    /// let v: Value = (-42i64).into();
310    /// assert_eq!(v.as_u64(), None);
311    /// ```
312    pub fn as_u64(&self) -> Option<u64> {
313        match self {
314            Value::Number(n) => n.as_u64(),
315            _ => None,
316        }
317    }
318
319    /// If this value is a number, converts it to `f64`. Otherwise returns `None`.
320    ///
321    /// # Examples
322    ///
323    /// ```
324    /// use serde_toon2::Value;
325    ///
326    /// let v: Value = 3.14.into();
327    /// assert_eq!(v.as_f64(), Some(3.14));
328    ///
329    /// let v = Value::String("3.14".to_string());
330    /// assert_eq!(v.as_f64(), None);
331    /// ```
332    pub fn as_f64(&self) -> Option<f64> {
333        match self {
334            Value::Number(n) => Some(n.as_f64()),
335            _ => None,
336        }
337    }
338
339    /// If this value is a string, returns a reference to it. Otherwise returns `None`.
340    ///
341    /// # Examples
342    ///
343    /// ```
344    /// use serde_toon2::Value;
345    ///
346    /// let v = Value::String("hello".to_string());
347    /// assert_eq!(v.as_str(), Some("hello"));
348    ///
349    /// let v = Value::Null;
350    /// assert_eq!(v.as_str(), None);
351    /// ```
352    pub fn as_str(&self) -> Option<&str> {
353        match self {
354            Value::String(s) => Some(s),
355            _ => None,
356        }
357    }
358
359    /// If this value is an array, returns a reference to it. Otherwise returns `None`.
360    ///
361    /// # Examples
362    ///
363    /// ```
364    /// use serde_toon2::Value;
365    ///
366    /// let v = Value::Array(vec![Value::String("a".to_string())]);
367    /// assert!(v.as_array().is_some());
368    ///
369    /// let v = Value::Null;
370    /// assert!(v.as_array().is_none());
371    /// ```
372    pub fn as_array(&self) -> Option<&Vec<Value>> {
373        match self {
374            Value::Array(arr) => Some(arr),
375            _ => None,
376        }
377    }
378
379    /// If this value is an object, returns a reference to it. Otherwise returns `None`.
380    ///
381    /// # Examples
382    ///
383    /// ```
384    /// use serde_toon2::{Value, Map};
385    ///
386    /// let mut map = Map::new();
387    /// map.insert("key".to_string(), Value::String("value".to_string()));
388    /// let v = Value::Object(map);
389    /// assert!(v.as_object().is_some());
390    ///
391    /// let v = Value::Null;
392    /// assert!(v.as_object().is_none());
393    /// ```
394    pub fn as_object(&self) -> Option<&Map<String, Value>> {
395        match self {
396            Value::Object(obj) => Some(obj),
397            _ => None,
398        }
399    }
400}
401
402impl From<bool> for Value {
403    fn from(b: bool) -> Self {
404        Value::Bool(b)
405    }
406}
407
408impl From<i64> for Value {
409    fn from(n: i64) -> Self {
410        Value::Number(Number::I64(n))
411    }
412}
413
414impl From<u64> for Value {
415    fn from(n: u64) -> Self {
416        Value::Number(Number::U64(n))
417    }
418}
419
420impl From<f64> for Value {
421    fn from(n: f64) -> Self {
422        Value::Number(Number::F64(n))
423    }
424}
425
426impl From<String> for Value {
427    fn from(s: String) -> Self {
428        Value::String(s)
429    }
430}
431
432impl From<&str> for Value {
433    fn from(s: &str) -> Self {
434        Value::String(s.to_string())
435    }
436}
437
438impl<T: Into<Value>> From<Vec<T>> for Value {
439    fn from(v: Vec<T>) -> Self {
440        Value::Array(v.into_iter().map(Into::into).collect())
441    }
442}
443
444impl From<Map<String, Value>> for Value {
445    fn from(m: Map<String, Value>) -> Self {
446        Value::Object(m)
447    }
448}