Skip to main content

qubit_value/value/
value.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # Single Value Container
10//!
11//! Provides type-safe storage and access functionality for single values.
12//!
13//! # Author
14//!
15//! Haixing Hu
16
17use bigdecimal::BigDecimal;
18use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc};
19use num_bigint::BigInt;
20use serde::{Deserialize, Serialize};
21use std::collections::HashMap;
22use std::time::Duration;
23use url::Url;
24
25use qubit_common::lang::DataType;
26
27use crate::error::ValueResult;
28
29/// Single value container
30///
31/// Uses an enum to represent different types of values, providing
32/// type-safe value storage and access.
33///
34/// # Features
35///
36/// - Zero-cost abstraction with compile-time type checking
37/// - Supports multiple basic data types
38/// - Provides two sets of APIs for type checking and type conversion
39/// - Automatic memory management
40///
41/// # Example
42///
43/// ```rust
44/// use qubit_value::Value;
45///
46/// // Create an integer value
47/// let value = Value::Int32(42);
48/// assert_eq!(value.get_int32().unwrap(), 42);
49///
50/// // Type conversion
51/// let converted = value.to::<i64>().unwrap();
52/// assert_eq!(converted, 42i64);
53///
54/// // String value
55/// let text = Value::String("hello".to_string());
56/// assert_eq!(text.get_string().unwrap(), "hello");
57/// ```
58///
59/// # Author
60///
61/// Haixing Hu
62///
63#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
64pub enum Value {
65    /// Empty value (has type but no value)
66    Empty(DataType),
67    /// Boolean value
68    Bool(bool),
69    /// Character value
70    Char(char),
71    /// 8-bit signed integer
72    Int8(i8),
73    /// 16-bit signed integer
74    Int16(i16),
75    /// 32-bit signed integer
76    Int32(i32),
77    /// 64-bit signed integer
78    Int64(i64),
79    /// 128-bit signed integer
80    Int128(i128),
81    /// 8-bit unsigned integer
82    UInt8(u8),
83    /// 16-bit unsigned integer
84    UInt16(u16),
85    /// 32-bit unsigned integer
86    UInt32(u32),
87    /// 64-bit unsigned integer
88    UInt64(u64),
89    /// 128-bit unsigned integer
90    UInt128(u128),
91    /// Platform-dependent signed integer (isize)
92    IntSize(isize),
93    /// Platform-dependent unsigned integer (usize)
94    UIntSize(usize),
95    /// 32-bit floating point number
96    Float32(f32),
97    /// 64-bit floating point number
98    Float64(f64),
99    /// Big integer type
100    BigInteger(BigInt),
101    /// Big decimal type
102    BigDecimal(BigDecimal),
103    /// String
104    String(String),
105    /// Date
106    Date(NaiveDate),
107    /// Time
108    Time(NaiveTime),
109    /// Date and time
110    DateTime(NaiveDateTime),
111    /// UTC instant
112    Instant(DateTime<Utc>),
113    /// Duration type (std::time::Duration)
114    Duration(Duration),
115    /// URL type (url::Url)
116    Url(Url),
117    /// String map type (HashMap<String, String>)
118    StringMap(HashMap<String, String>),
119    /// JSON value type (serde_json::Value)
120    Json(serde_json::Value),
121}
122
123#[doc(hidden)]
124pub use super::value_converters::{ValueConstructor, ValueConverter, ValueGetter, ValueSetter};
125
126// ============================================================================
127// Getter method generation macro
128// ============================================================================
129
130/// Unified getter generation macro
131///
132/// Supports two modes:
133/// 1. `copy:` - For types implementing the Copy trait, directly returns the value
134/// 2. `ref:` - For non-Copy types, returns a reference
135///
136/// # Documentation Comment Support
137///
138/// The macro automatically extracts preceding documentation comments, so
139/// you can add `///` comments before macro invocations.
140///
141/// # Author
142///
143/// Haixing Hu
144///
145impl Value {
146    /// Generic constructor method
147    ///
148    /// Creates a `Value` from any supported type, avoiding direct use of
149    /// enum variants.
150    ///
151    /// # Supported Generic Types
152    ///
153    /// `Value::new<T>(value)` currently supports the following `T`:
154    ///
155    /// - `bool`
156    /// - `char`
157    /// - `i8`, `i16`, `i32`, `i64`, `i128`
158    /// - `u8`, `u16`, `u32`, `u64`, `u128`
159    /// - `f32`, `f64`
160    /// - `String`, `&str`
161    /// - `NaiveDate`, `NaiveTime`, `NaiveDateTime`, `DateTime<Utc>`
162    /// - `BigInt`, `BigDecimal`
163    /// - `isize`, `usize`
164    /// - `Duration`
165    /// - `Url`
166    /// - `HashMap<String, String>`
167    /// - `serde_json::Value`
168    ///
169    /// # Type Parameters
170    ///
171    /// * `T` - The type of the value to wrap
172    ///
173    /// # Returns
174    ///
175    /// Returns a `Value` wrapping the given value
176    ///
177    /// # Example
178    ///
179    /// ```rust
180    /// use qubit_value::Value;
181    ///
182    /// // Basic types
183    /// let v = Value::new(42i32);
184    /// assert_eq!(v.get_int32().unwrap(), 42);
185    ///
186    /// let v = Value::new(true);
187    /// assert_eq!(v.get_bool().unwrap(), true);
188    ///
189    /// // String
190    /// let v = Value::new("hello".to_string());
191    /// assert_eq!(v.get_string().unwrap(), "hello");
192    /// ```
193    #[inline]
194    pub fn new<T>(value: T) -> Self
195    where
196        Self: ValueConstructor<T>,
197    {
198        <Self as ValueConstructor<T>>::from_type(value)
199    }
200
201    /// Generic getter method
202    ///
203    /// Automatically selects the correct getter method based on the target
204    /// type, performing strict type checking.
205    ///
206    /// `get<T>()` performs strict type matching. It does not do cross-type
207    /// conversion.
208    ///
209    /// For example, `Value::Int32(42).get::<i64>()` fails, while
210    /// `Value::Int32(42).to::<i64>()` succeeds.
211    ///
212    /// # Supported Generic Types
213    ///
214    /// `Value::get<T>()` currently supports the following `T`:
215    ///
216    /// - `bool`
217    /// - `char`
218    /// - `i8`, `i16`, `i32`, `i64`, `i128`
219    /// - `u8`, `u16`, `u32`, `u64`, `u128`
220    /// - `f32`, `f64`
221    /// - `String`
222    /// - `NaiveDate`, `NaiveTime`, `NaiveDateTime`, `DateTime<Utc>`
223    /// - `BigInt`, `BigDecimal`
224    /// - `isize`, `usize`
225    /// - `Duration`
226    /// - `Url`
227    /// - `HashMap<String, String>`
228    /// - `serde_json::Value`
229    ///
230    /// # Type Parameters
231    ///
232    /// * `T` - The target type to retrieve
233    ///
234    /// # Returns
235    ///
236    /// If types match, returns the value of the corresponding type;
237    /// otherwise returns an error
238    ///
239    /// # Example
240    ///
241    /// ```rust
242    /// use qubit_value::Value;
243    ///
244    /// let value = Value::Int32(42);
245    ///
246    /// // Through type inference
247    /// let num: i32 = value.get().unwrap();
248    /// assert_eq!(num, 42);
249    ///
250    /// // Explicitly specify type parameter
251    /// let num = value.get::<i32>().unwrap();
252    /// assert_eq!(num, 42);
253    ///
254    /// // Different type
255    /// let text = Value::String("hello".to_string());
256    /// let s: String = text.get().unwrap();
257    /// assert_eq!(s, "hello");
258    ///
259    /// // Boolean value
260    /// let flag = Value::Bool(true);
261    /// let b: bool = flag.get().unwrap();
262    /// assert_eq!(b, true);
263    /// ```
264    #[inline]
265    pub fn get<T>(&self) -> ValueResult<T>
266    where
267        Self: ValueGetter<T>,
268    {
269        <Self as ValueGetter<T>>::get_value(self)
270    }
271
272    /// Generic conversion method
273    ///
274    /// Converts the current value to the target type according to the conversion
275    /// rules defined by [`ValueConverter<T>`].
276    ///
277    /// # Supported Target Types And Source Variants
278    ///
279    /// `Value::to<T>()` currently supports the following target types:
280    ///
281    /// - `bool`
282    ///   - `Value::Bool`
283    ///   - `Value::Int8`, `Value::Int16`, `Value::Int32`, `Value::Int64`,
284    ///     `Value::Int128`
285    ///   - `Value::UInt8`, `Value::UInt16`, `Value::UInt32`,
286    ///     `Value::UInt64`, `Value::UInt128`
287    ///   - `Value::String`, parsed as `bool`
288    /// - `char`
289    ///   - `Value::Char`
290    /// - `i8`
291    ///   - `Value::Int8`
292    ///   - `Value::Bool`
293    ///   - `Value::Char`
294    ///   - all integer variants
295    ///   - `Value::Float32`, `Value::Float64`
296    ///   - `Value::String`, parsed as `i8`
297    ///   - `Value::BigInteger`, `Value::BigDecimal`
298    /// - `i16`
299    ///   - `Value::Int16`
300    ///   - `Value::Bool`
301    ///   - `Value::Char`
302    ///   - all integer variants
303    ///   - `Value::Float32`, `Value::Float64`
304    ///   - `Value::String`, parsed as `i16`
305    ///   - `Value::BigInteger`, `Value::BigDecimal`
306    /// - `i32`
307    ///   - `Value::Int32`
308    ///   - `Value::Bool`
309    ///   - `Value::Char`
310    ///   - `Value::Int8`, `Value::Int16`, `Value::Int64`, `Value::Int128`
311    ///   - `Value::UInt8`, `Value::UInt16`, `Value::UInt32`,
312    ///     `Value::UInt64`, `Value::UInt128`
313    ///   - `Value::Float32`, `Value::Float64`
314    ///   - `Value::String`, parsed as `i32`
315    ///   - `Value::BigInteger`, `Value::BigDecimal`
316    /// - `i64`
317    ///   - `Value::Int64`
318    ///   - `Value::Bool`
319    ///   - `Value::Char`
320    ///   - `Value::Int8`, `Value::Int16`, `Value::Int32`, `Value::Int128`
321    ///   - `Value::UInt8`, `Value::UInt16`, `Value::UInt32`,
322    ///     `Value::UInt64`, `Value::UInt128`
323    ///   - `Value::Float32`, `Value::Float64`
324    ///   - `Value::String`, parsed as `i64`
325    ///   - `Value::BigInteger`, `Value::BigDecimal`
326    /// - `i128`
327    ///   - `Value::Int128`
328    ///   - `Value::Bool`
329    ///   - `Value::Char`
330    ///   - all integer variants
331    ///   - `Value::Float32`, `Value::Float64`
332    ///   - `Value::String`, parsed as `i128`
333    ///   - `Value::BigInteger`, `Value::BigDecimal`
334    /// - `u8`
335    ///   - `Value::UInt8`
336    ///   - `Value::Bool`
337    ///   - `Value::Char`
338    ///   - `Value::Int8`, `Value::Int16`, `Value::Int32`, `Value::Int64`,
339    ///     `Value::Int128`
340    ///   - `Value::UInt16`, `Value::UInt32`, `Value::UInt64`,
341    ///     `Value::UInt128`
342    ///   - `Value::String`, parsed as `u8`
343    /// - `u16`
344    ///   - `Value::UInt8`, `Value::UInt16`, `Value::UInt32`,
345    ///     `Value::UInt64`, `Value::UInt128`
346    ///   - `Value::Bool`
347    ///   - `Value::Char`
348    ///   - `Value::Int8`, `Value::Int16`, `Value::Int32`, `Value::Int64`,
349    ///     `Value::Int128`
350    ///   - `Value::String`, parsed as `u16`
351    /// - `u32`
352    ///   - `Value::UInt8`, `Value::UInt16`, `Value::UInt32`,
353    ///     `Value::UInt64`, `Value::UInt128`
354    ///   - `Value::Bool`
355    ///   - `Value::Char`
356    ///   - `Value::Int8`, `Value::Int16`, `Value::Int32`, `Value::Int64`,
357    ///     `Value::Int128`
358    ///   - `Value::String`, parsed as `u32`
359    /// - `u64`
360    ///   - `Value::UInt8`, `Value::UInt16`, `Value::UInt32`,
361    ///     `Value::UInt64`, `Value::UInt128`
362    ///   - `Value::Bool`
363    ///   - `Value::Char`
364    ///   - `Value::Int8`, `Value::Int16`, `Value::Int32`, `Value::Int64`,
365    ///     `Value::Int128`
366    ///   - `Value::String`, parsed as `u64`
367    /// - `u128`
368    ///   - `Value::UInt8`, `Value::UInt16`, `Value::UInt32`,
369    ///     `Value::UInt64`, `Value::UInt128`
370    ///   - `Value::Bool`
371    ///   - `Value::Char`
372    ///   - `Value::Int8`, `Value::Int16`, `Value::Int32`, `Value::Int64`,
373    ///     `Value::Int128`
374    ///   - `Value::String`, parsed as `u128`
375    /// - `f32`
376    ///   - `Value::Float32`, `Value::Float64`
377    ///   - `Value::Bool`
378    ///   - `Value::Char`
379    ///   - `Value::Int8`, `Value::Int16`, `Value::Int32`, `Value::Int64`,
380    ///     `Value::Int128`
381    ///   - `Value::UInt8`, `Value::UInt16`, `Value::UInt32`,
382    ///     `Value::UInt64`, `Value::UInt128`
383    ///   - `Value::String`, parsed as `f32`
384    ///   - `Value::BigInteger`, `Value::BigDecimal`
385    /// - `f64`
386    ///   - `Value::Float64`
387    ///   - `Value::Bool`
388    ///   - `Value::Char`
389    ///   - `Value::Int8`, `Value::Int16`, `Value::Int32`, `Value::Int64`,
390    ///     `Value::Int128`
391    ///   - `Value::UInt8`, `Value::UInt16`, `Value::UInt32`,
392    ///     `Value::UInt64`, `Value::UInt128`
393    ///   - `Value::Float32`
394    ///   - `Value::String`, parsed as `f64`
395    ///   - `Value::BigInteger`, `Value::BigDecimal`
396    /// - `String`
397    ///   - `Value::String`
398    ///   - `Value::Bool`, `Value::Char`
399    ///   - all integer and floating-point variants
400    ///   - `Value::Date`, `Value::Time`, `Value::DateTime`, `Value::Instant`
401    ///   - `Value::BigInteger`, `Value::BigDecimal`
402    ///   - `Value::IntSize`, `Value::UIntSize`
403    ///   - `Value::Duration`, formatted as `<nanoseconds>ns`
404    ///   - `Value::Url`
405    ///   - `Value::StringMap`, serialized as JSON text
406    ///   - `Value::Json`, serialized as JSON text
407    /// - `NaiveDate`
408    ///   - `Value::Date`
409    /// - `NaiveTime`
410    ///   - `Value::Time`
411    /// - `NaiveDateTime`
412    ///   - `Value::DateTime`
413    /// - `DateTime<Utc>`
414    ///   - `Value::Instant`
415    /// - `BigInt`
416    ///   - `Value::BigInteger`
417    /// - `BigDecimal`
418    ///   - `Value::BigDecimal`
419    /// - `isize`
420    ///   - `Value::IntSize`
421    ///   - `Value::Bool`
422    ///   - `Value::Char`
423    ///   - all integer variants
424    ///   - `Value::Float32`, `Value::Float64`
425    ///   - `Value::String`, parsed as `isize`
426    ///   - `Value::BigInteger`, `Value::BigDecimal`
427    /// - `usize`
428    ///   - `Value::UIntSize`
429    ///   - `Value::Bool`
430    ///   - `Value::Char`
431    ///   - all integer variants
432    ///   - `Value::String`, parsed as `usize`
433    /// - `Duration`
434    ///   - `Value::Duration`
435    ///   - `Value::String`, parsed from `<nanoseconds>ns`
436    /// - `Url`
437    ///   - `Value::Url`
438    ///   - `Value::String`, parsed as URL text
439    /// - `HashMap<String, String>`
440    ///   - `Value::StringMap`
441    /// - `serde_json::Value`
442    ///   - `Value::Json`
443    ///   - `Value::String`, parsed as JSON text
444    ///   - `Value::StringMap`, converted to a JSON object
445    ///
446    /// Any target type not listed above is not supported by `Value::to<T>()`.
447    ///
448    /// # Type Parameters
449    ///
450    /// * `T` - The target type to convert to
451    ///
452    /// # Returns
453    ///
454    /// Returns the converted value on success, or an error if conversion is not
455    /// supported or fails.
456    ///
457    /// # Example
458    ///
459    /// ```rust
460    /// use qubit_value::Value;
461    ///
462    /// let value = Value::Int32(42);
463    ///
464    /// let num: i64 = value.to().unwrap();
465    /// assert_eq!(num, 42);
466    ///
467    /// let text: String = value.to().unwrap();
468    /// assert_eq!(text, "42");
469    /// ```
470    #[inline]
471    pub fn to<T>(&self) -> ValueResult<T>
472    where
473        Self: ValueConverter<T>,
474    {
475        <Self as ValueConverter<T>>::convert(self)
476    }
477
478    /// Generic setter method
479    ///
480    /// Automatically selects the correct setter method based on the target
481    /// type and replaces the current value.
482    ///
483    /// This operation updates the stored type to `T` when needed. It does not
484    /// perform runtime type-mismatch validation against the previous variant.
485    ///
486    /// # Supported Generic Types
487    ///
488    /// `Value::set<T>(value)` currently supports the following `T`:
489    ///
490    /// - `bool`
491    /// - `char`
492    /// - `i8`, `i16`, `i32`, `i64`, `i128`
493    /// - `u8`, `u16`, `u32`, `u64`, `u128`
494    /// - `f32`, `f64`
495    /// - `String`, `&str`
496    /// - `NaiveDate`, `NaiveTime`, `NaiveDateTime`, `DateTime<Utc>`
497    /// - `BigInt`, `BigDecimal`
498    /// - `isize`, `usize`
499    /// - `Duration`
500    /// - `Url`
501    /// - `HashMap<String, String>`
502    /// - `serde_json::Value`
503    ///
504    /// # Type Parameters
505    ///
506    /// * `T` - The target type to set
507    ///
508    /// # Parameters
509    ///
510    /// * `value` - The value to set
511    ///
512    /// # Returns
513    ///
514    /// If setting succeeds, returns `Ok(())`; otherwise returns an error
515    ///
516    /// # Example
517    ///
518    /// ```rust
519    /// use qubit_common::lang::DataType;
520    /// use qubit_value::Value;
521    ///
522    /// let mut value = Value::Empty(DataType::Int32);
523    ///
524    /// // Through type inference
525    /// value.set(42i32).unwrap();
526    /// assert_eq!(value.get_int32().unwrap(), 42);
527    ///
528    /// // Explicitly specify type parameter
529    /// value.set::<i32>(100).unwrap();
530    /// assert_eq!(value.get_int32().unwrap(), 100);
531    ///
532    /// // String type
533    /// let mut text = Value::Empty(DataType::String);
534    /// text.set("hello".to_string()).unwrap();
535    /// assert_eq!(text.get_string().unwrap(), "hello");
536    /// ```
537    #[inline]
538    pub fn set<T>(&mut self, value: T) -> ValueResult<()>
539    where
540        Self: ValueSetter<T>,
541    {
542        <Self as ValueSetter<T>>::set_value(self, value)
543    }
544
545    /// Get the data type of the value
546    ///
547    /// # Returns
548    ///
549    /// Returns the data type corresponding to this value
550    ///
551    /// # Example
552    ///
553    /// ```rust
554    /// use qubit_common::lang::DataType;
555    /// use qubit_value::Value;
556    ///
557    /// let value = Value::Int32(42);
558    /// assert_eq!(value.data_type(), DataType::Int32);
559    ///
560    /// let empty = Value::Empty(DataType::String);
561    /// assert_eq!(empty.data_type(), DataType::String);
562    /// ```
563    #[inline]
564    pub fn data_type(&self) -> DataType {
565        match self {
566            Value::Empty(dt) => *dt,
567            Value::Bool(_) => DataType::Bool,
568            Value::Char(_) => DataType::Char,
569            Value::Int8(_) => DataType::Int8,
570            Value::Int16(_) => DataType::Int16,
571            Value::Int32(_) => DataType::Int32,
572            Value::Int64(_) => DataType::Int64,
573            Value::Int128(_) => DataType::Int128,
574            Value::UInt8(_) => DataType::UInt8,
575            Value::UInt16(_) => DataType::UInt16,
576            Value::UInt32(_) => DataType::UInt32,
577            Value::UInt64(_) => DataType::UInt64,
578            Value::UInt128(_) => DataType::UInt128,
579            Value::Float32(_) => DataType::Float32,
580            Value::Float64(_) => DataType::Float64,
581            Value::String(_) => DataType::String,
582            Value::Date(_) => DataType::Date,
583            Value::Time(_) => DataType::Time,
584            Value::DateTime(_) => DataType::DateTime,
585            Value::Instant(_) => DataType::Instant,
586            Value::BigInteger(_) => DataType::BigInteger,
587            Value::BigDecimal(_) => DataType::BigDecimal,
588            Value::IntSize(_) => DataType::IntSize,
589            Value::UIntSize(_) => DataType::UIntSize,
590            Value::Duration(_) => DataType::Duration,
591            Value::Url(_) => DataType::Url,
592            Value::StringMap(_) => DataType::StringMap,
593            Value::Json(_) => DataType::Json,
594        }
595    }
596
597    /// Check if the value is empty
598    ///
599    /// # Returns
600    ///
601    /// Returns `true` if the value is empty
602    ///
603    /// # Example
604    ///
605    /// ```rust
606    /// use qubit_common::lang::DataType;
607    /// use qubit_value::Value;
608    ///
609    /// let value = Value::Int32(42);
610    /// assert!(!value.is_empty());
611    ///
612    /// let empty = Value::Empty(DataType::String);
613    /// assert!(empty.is_empty());
614    /// ```
615    #[inline]
616    pub fn is_empty(&self) -> bool {
617        matches!(self, Value::Empty(_))
618    }
619
620    /// Clear the value while preserving the type
621    ///
622    /// Sets the current value to empty but retains its data type.
623    ///
624    /// # Example
625    ///
626    /// ```rust
627    /// use qubit_common::lang::DataType;
628    /// use qubit_value::Value;
629    ///
630    /// let mut value = Value::Int32(42);
631    /// value.clear();
632    /// assert!(value.is_empty());
633    /// assert_eq!(value.data_type(), DataType::Int32);
634    /// ```
635    #[inline]
636    pub fn clear(&mut self) {
637        let dt = self.data_type();
638        *self = Value::Empty(dt);
639    }
640
641    /// Set the data type
642    ///
643    /// If the new type differs from the current type, clears the value
644    /// and sets the new type.
645    ///
646    /// # Parameters
647    ///
648    /// * `data_type` - The data type to set
649    ///
650    /// # Example
651    ///
652    /// ```rust
653    /// use qubit_common::lang::DataType;
654    /// use qubit_value::Value;
655    ///
656    /// let mut value = Value::Int32(42);
657    /// value.set_type(DataType::String);
658    /// assert!(value.is_empty());
659    /// assert_eq!(value.data_type(), DataType::String);
660    /// ```
661    #[inline]
662    pub fn set_type(&mut self, data_type: DataType) {
663        if self.data_type() != data_type {
664            *self = Value::Empty(data_type);
665        }
666    }
667}
668
669impl Default for Value {
670    #[inline]
671    fn default() -> Self {
672        Value::Empty(DataType::String)
673    }
674}