Skip to main content

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