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}