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}