Skip to main content

qubit_value/multi_values/
multi_values.rs

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