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}