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}