Skip to main content

qubit_value/multi_values/
multi_values.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! # Multiple Values Container
11//!
12//! Provides type-safe storage and access functionality for multiple values.
13//!
14
15use bigdecimal::BigDecimal;
16use chrono::{
17    DateTime,
18    NaiveDate,
19    NaiveDateTime,
20    NaiveTime,
21    Utc,
22};
23use num_bigint::BigInt;
24use serde::{
25    Deserialize,
26    Serialize,
27};
28use std::collections::HashMap;
29use std::time::Duration;
30use url::Url;
31
32use qubit_datatype::DataType;
33
34/// Multiple values container
35///
36/// Uses an enum to represent multiple values of different types, providing
37/// type-safe storage and access for multiple values.
38///
39/// # Features
40///
41/// - Supports collections of multiple basic data types.
42/// - Provides two sets of APIs for type checking and type conversion.
43/// - Supports unified access to single and multiple values.
44/// - Automatic memory management.
45///
46/// # Example
47///
48/// ```rust
49/// use qubit_value::MultiValues;
50///
51/// // Create integer multiple values
52/// let mut values = MultiValues::Int32(vec![1, 2, 3]);
53/// assert_eq!(values.count(), 3);
54/// assert_eq!(values.get_first_int32().unwrap(), 1);
55///
56/// // Get all values
57/// let all = values.get_int32s().unwrap();
58/// assert_eq!(all, &[1, 2, 3]);
59///
60/// // Use generic method to add value
61/// values.add(4).unwrap();
62/// assert_eq!(values.count(), 4);
63/// ```
64///
65///
66#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
67pub enum MultiValues {
68    /// Empty value (has type but no values)
69    Empty(DataType),
70    /// Boolean value list
71    Bool(Vec<bool>),
72    /// Character value list
73    Char(Vec<char>),
74    /// i8 list
75    Int8(Vec<i8>),
76    /// i16 list
77    Int16(Vec<i16>),
78    /// i32 list
79    Int32(Vec<i32>),
80    /// i64 list
81    Int64(Vec<i64>),
82    /// i128 list
83    Int128(Vec<i128>),
84    /// u8 list
85    UInt8(Vec<u8>),
86    /// u16 list
87    UInt16(Vec<u16>),
88    /// u32 list
89    UInt32(Vec<u32>),
90    /// u64 list
91    UInt64(Vec<u64>),
92    /// u128 list
93    UInt128(Vec<u128>),
94    /// isize list
95    IntSize(Vec<isize>),
96    /// usize list
97    UIntSize(Vec<usize>),
98    /// f32 list
99    Float32(Vec<f32>),
100    /// f64 list
101    Float64(Vec<f64>),
102    /// Big integer list
103    BigInteger(Vec<BigInt>),
104    /// Big decimal list
105    BigDecimal(Vec<BigDecimal>),
106    /// String list
107    String(Vec<String>),
108    /// Date list
109    Date(Vec<NaiveDate>),
110    /// Time list
111    Time(Vec<NaiveTime>),
112    /// DateTime list
113    DateTime(Vec<NaiveDateTime>),
114    /// UTC instant list
115    Instant(Vec<DateTime<Utc>>),
116    /// Duration list
117    Duration(Vec<Duration>),
118    /// Url list
119    Url(Vec<Url>),
120    /// StringMap list
121    StringMap(Vec<HashMap<String, String>>),
122    /// Json list
123    Json(Vec<serde_json::Value>),
124}
125
126// ============================================================================
127// Getter method generation macros
128// ============================================================================
129
130/// Unified multiple values getter generation macro
131///
132/// Generates `get_[xxx]s` methods for `MultiValues`, returning a reference to
133/// value slices.
134///
135/// # Documentation Comment Support
136///
137/// The macro automatically extracts preceding documentation comments, so you
138/// can add `///` comments before macro invocations.
139///
140///
141macro_rules! impl_get_multi_values {
142    // Simple type: return slice reference
143    ($(#[$attr:meta])* slice: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
144        $(#[$attr])*
145        #[doc = ""]
146        #[doc = "# Errors"]
147        #[doc = ""]
148        #[doc = "Returns [`ValueError::TypeMismatch`] when the stored data type"]
149        #[doc = "differs. Empty values of the requested type return an empty slice."]
150        #[inline]
151        pub fn $method(&self) -> ValueResult<&[$type]> {
152            match self {
153                MultiValues::$variant(v) => Ok(v),
154                MultiValues::Empty(dt) if *dt == $data_type => Ok(&[]),
155                _ => Err(ValueError::TypeMismatch {
156                    expected: $data_type,
157                    actual: self.data_type(),
158                }),
159            }
160        }
161    };
162
163    // Complex type: return Vec reference (e.g., Vec<String>, Vec<Vec<u8>>)
164    ($(#[$attr:meta])* vec: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
165        $(#[$attr])*
166        #[doc = ""]
167        #[doc = "# Errors"]
168        #[doc = ""]
169        #[doc = "Returns [`ValueError::TypeMismatch`] when the stored data type"]
170        #[doc = "differs. Empty values of the requested type return an empty slice."]
171        #[inline]
172        pub fn $method(&self) -> ValueResult<&[$type]> {
173            match self {
174                MultiValues::$variant(v) => Ok(v.as_slice()),
175                MultiValues::Empty(dt) if *dt == $data_type => Ok(&[]),
176                _ => Err(ValueError::TypeMismatch {
177                    expected: $data_type,
178                    actual: self.data_type(),
179                }),
180            }
181        }
182    };
183}
184
185/// Unified multiple values get_first method generation macro
186///
187/// Generates `get_first_[xxx]` methods for `MultiValues`, used to get the first
188/// value.
189///
190/// # Documentation Comment Support
191///
192/// The macro automatically extracts preceding documentation comments, so you
193/// can add `///` comments before macro invocations.
194///
195///
196macro_rules! impl_get_first_value {
197    // Copy type: directly return value
198    ($(#[$attr:meta])* copy: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
199        $(#[$attr])*
200        #[doc = ""]
201        #[doc = "# Errors"]
202        #[doc = ""]
203        #[doc = "Returns [`ValueError::NoValue`] when the requested type matches"]
204        #[doc = "but no value is stored, or [`ValueError::TypeMismatch`] when"]
205        #[doc = "the stored data type differs."]
206        #[inline]
207        pub fn $method(&self) -> ValueResult<$type> {
208            match self {
209                MultiValues::$variant(v) if !v.is_empty() => Ok(v[0]),
210                MultiValues::$variant(_) => Err(ValueError::NoValue),
211                MultiValues::Empty(dt) if *dt == $data_type => Err(ValueError::NoValue),
212                _ => Err(ValueError::TypeMismatch {
213                    expected: $data_type,
214                    actual: self.data_type(),
215                }),
216            }
217        }
218    };
219
220    // Reference type: return reference
221    ($(#[$attr:meta])* ref: $method:ident, $variant:ident, $ret_type:ty, $data_type:expr, $conversion:expr) => {
222        $(#[$attr])*
223        #[doc = ""]
224        #[doc = "# Errors"]
225        #[doc = ""]
226        #[doc = "Returns [`ValueError::NoValue`] when the requested type matches"]
227        #[doc = "but no value is stored, or [`ValueError::TypeMismatch`] when"]
228        #[doc = "the stored data type differs."]
229        #[inline]
230        pub fn $method(&self) -> ValueResult<$ret_type> {
231            match self {
232                MultiValues::$variant(v) if !v.is_empty() => {
233                    let conv_fn: fn(&_) -> $ret_type = $conversion;
234                    Ok(conv_fn(&v[0]))
235                },
236                MultiValues::$variant(_) => Err(ValueError::NoValue),
237                MultiValues::Empty(dt) if *dt == $data_type => Err(ValueError::NoValue),
238                _ => Err(ValueError::TypeMismatch {
239                    expected: $data_type,
240                    actual: self.data_type(),
241                }),
242            }
243        }
244    };
245}
246
247/// Unified multiple values add method generation macro
248///
249/// Generates `add_[xxx]` methods for `MultiValues`, used to add a single value.
250///
251/// # Documentation Comment Support
252///
253/// The macro automatically extracts preceding documentation comments, so you
254/// can add `///` comments before macro invocations.
255///
256///
257macro_rules! impl_add_single_value {
258    ($(#[$attr:meta])* $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
259        $(#[$attr])*
260        #[doc = ""]
261        #[doc = "# Errors"]
262        #[doc = ""]
263        #[doc = "Returns [`ValueError::TypeMismatch`] when the current stored"]
264        #[doc = "data type differs from the value being appended."]
265        #[inline]
266        pub fn $method(&mut self, value: $type) -> ValueResult<()> {
267            match self {
268                MultiValues::$variant(v) => {
269                    v.push(value);
270                    Ok(())
271                }
272                MultiValues::Empty(dt) if *dt == $data_type => {
273                    *self = MultiValues::$variant(vec![value]);
274                    Ok(())
275                }
276                _ => Err(ValueError::TypeMismatch {
277                    expected: $data_type,
278                    actual: self.data_type(),
279                }),
280            }
281        }
282    };
283}
284
285/// Unified multiple values add multiple method generation macro
286///
287/// Generates `add_[xxx]s` methods for `MultiValues`, used to add multiple values.
288///
289/// # Documentation Comment Support
290///
291/// The macro automatically extracts preceding documentation comments, so you
292/// can add `///` comments before macro invocations.
293///
294///
295macro_rules! impl_add_multi_values {
296    ($(#[$attr:meta])* $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
297        $(#[$attr])*
298        #[doc = ""]
299        #[doc = "# Errors"]
300        #[doc = ""]
301        #[doc = "Returns [`ValueError::TypeMismatch`] when the current stored"]
302        #[doc = "data type differs from the values being appended."]
303        #[inline]
304        pub fn $method(&mut self, values: Vec<$type>) -> ValueResult<()> {
305            match self {
306                MultiValues::$variant(v) => {
307                    v.extend(values);
308                    Ok(())
309                }
310                MultiValues::Empty(dt) if *dt == $data_type => {
311                    *self = MultiValues::$variant(values);
312                    Ok(())
313                }
314                _ => Err(ValueError::TypeMismatch {
315                    expected: $data_type,
316                    actual: self.data_type(),
317                }),
318            }
319        }
320    };
321}
322
323/// Unified multiple values add from slice method generation macro
324///
325/// Generates `add_[xxx]s_slice` methods for `MultiValues`, used to append
326/// multiple values at once from a slice.
327///
328///
329macro_rules! impl_add_multi_values_slice {
330    ($(#[$attr:meta])* $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
331        $(#[$attr])*
332        #[doc = ""]
333        #[doc = "# Errors"]
334        #[doc = ""]
335        #[doc = "Returns [`ValueError::TypeMismatch`] when the current stored"]
336        #[doc = "data type differs from the slice values being appended."]
337        #[inline]
338        pub fn $method(&mut self, values: &[$type]) -> ValueResult<()> {
339            match self {
340                MultiValues::$variant(v) => {
341                    v.extend_from_slice(values);
342                    Ok(())
343                }
344                MultiValues::Empty(dt) if *dt == $data_type => {
345                    *self = MultiValues::$variant(values.to_vec());
346                    Ok(())
347                }
348                _ => Err(ValueError::TypeMismatch {
349                    expected: $data_type,
350                    actual: self.data_type(),
351                }),
352            }
353        }
354    };
355}
356
357/// Unified multiple values single value set method generation macro
358///
359/// Generates `set_[xxx]` methods for `MultiValues`, used to set a single value
360/// (replacing the entire list).
361///
362/// # Documentation Comment Support
363///
364/// The macro automatically extracts preceding documentation comments, so you
365/// can add `///` comments before macro invocations.
366///
367///
368macro_rules! impl_set_single_value {
369    ($(#[$attr:meta])* $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
370        $(#[$attr])*
371        pub fn $method(&mut self, value: $type) -> ValueResult<()> {
372            *self = MultiValues::$variant(vec![value]);
373            Ok(())
374        }
375    };
376}
377
378/// Unified multiple values set method generation macro
379///
380/// Generates `set_[xxx]s` methods for `MultiValues`, used to set the entire
381/// value list.
382///
383/// # Documentation Comment Support
384///
385/// The macro automatically extracts preceding documentation comments, so you
386/// can add `///` comments before macro invocations.
387///
388///
389macro_rules! impl_set_multi_values {
390    ($(#[$attr:meta])* $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
391        $(#[$attr])*
392        pub fn $method(&mut self, values: Vec<$type>) -> ValueResult<()> {
393            *self = MultiValues::$variant(values);
394            Ok(())
395        }
396    };
397}
398
399/// Unified multiple values set (slice) method generation macro
400///
401/// Generates `set_[xxx]s_slice` methods for `MultiValues`, used to set the
402/// entire value list from a slice.
403///
404/// This method directly replaces the internally stored list without type
405/// matching checks, behaving consistently with `set_[xxx]s`.
406///
407/// # Documentation Comment Support
408///
409/// The macro automatically extracts preceding documentation comments, so you
410/// can add `///` comments before macro invocations.
411///
412///
413macro_rules! impl_set_multi_values_slice {
414    ($(#[$attr:meta])* $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
415        $(#[$attr])*
416        pub fn $method(&mut self, values: &[$type]) -> ValueResult<()> {
417            *self = MultiValues::$variant(values.to_vec());
418            Ok(())
419        }
420    };
421}