qubit_value/multi_values/multi_values.rs
1// =============================================================================
2// Copyright (c) 2025 - 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! # Multiple Values Container
9//!
10//! Provides type-safe storage and access functionality for multiple values.
11// Tests are intentionally distributed across behavior-specific files under
12// tests/multi_values/ rather than collected in multi_values_tests.rs.
13use std::collections::HashMap;
14use std::fmt;
15#[cfg(feature = "json")]
16use std::hash::Hash;
17#[cfg(feature = "json")]
18use std::hash::Hasher;
19#[cfg(feature = "json")]
20use std::mem::discriminant;
21use std::mem::replace;
22use std::time::Duration;
23
24#[cfg(feature = "big-decimal")]
25use bigdecimal::BigDecimal;
26#[cfg(feature = "chrono")]
27use chrono::DateTime;
28#[cfg(feature = "chrono")]
29use chrono::NaiveDate;
30#[cfg(feature = "chrono")]
31use chrono::NaiveDateTime;
32#[cfg(feature = "chrono")]
33use chrono::NaiveTime;
34#[cfg(feature = "chrono")]
35use chrono::Utc;
36#[cfg(feature = "big-integer")]
37use num_bigint::BigInt;
38#[cfg(feature = "json")]
39use qubit_budget::MeasuredBudgetError;
40#[cfg(feature = "json")]
41use qubit_budget::ResourceQuantity;
42#[cfg(feature = "json")]
43use qubit_budget::json::JsonValueBudget;
44#[cfg(feature = "converter")]
45use qubit_datatype::ConversionLimits;
46#[cfg(feature = "converter")]
47use qubit_datatype::ConversionPolicy;
48#[cfg(feature = "converter")]
49use qubit_datatype::ConversionSession;
50#[cfg(feature = "converter")]
51use qubit_datatype::DataConversionError;
52#[cfg(feature = "converter")]
53use qubit_datatype::DataConversionTarget;
54#[cfg(feature = "converter")]
55use qubit_datatype::DataConverter;
56#[cfg(feature = "converter")]
57use qubit_datatype::DataConverters;
58use qubit_datatype::DataType;
59#[cfg(feature = "json")]
60use serde_json::Value as JsonValue;
61#[cfg(feature = "url")]
62use url::Url;
63
64use super::internal::MultiValuesRepr;
65#[cfg(feature = "json")]
66use super::multi_values_identity::hash_non_json_multi_values_payload;
67use super::multi_values_ref::MultiValuesRef;
68use crate::IntoValueDefault;
69use crate::StrictValueRead;
70use crate::Value;
71use crate::ValueError;
72use crate::ValueResult;
73#[cfg(feature = "json")]
74use crate::identity::hash_json;
75#[cfg(feature = "json")]
76use crate::identity::preflight_json;
77use crate::value::ValueRepr;
78
79/// Multiple typed runtime values with private storage representation.
80///
81/// # Equality and hashing
82///
83/// Equality includes the collection variant and preserves element count and
84/// order. An unset collection's declared element type also participates in its
85/// identity. Floating-point elements use the same-width NaN and signed-zero
86/// normalization as [`Value`]. String maps and JSON objects compare and hash
87/// independently of entry order, while JSON arrays preserve element order.
88/// BigDecimal elements use numeric equality with a consistent normalized hash.
89/// Use [`Value::numeric_cmp`] to compare numeric values across runtime types;
90/// `Eq` does not provide cross-type numeric comparison. Hash output is intended
91/// for in-process collections and is not a persistent fingerprint.
92///
93/// # JSON nesting and lifecycle
94///
95/// With the `json` feature, JSON equality and hashing use iterative traversal.
96/// This does not provide the same guarantee for the entire value lifecycle:
97/// cloning, ordinary `Debug` formatting, and dropping JSON payloads still
98/// follow recursive paths in the underlying `serde_json::Value`.
99/// Very deeply nested trees may exhaust the thread stack during those
100/// operations. This applies to JSON elements, not to the outer collection
101/// length.
102///
103/// Keep untrusted JSON nesting bounded, and consider these lifecycle operations
104/// before raising decoder depth limits. Directly constructed in-memory JSON
105/// does not pass through those decoder limits. Borrowed reads avoid unnecessary
106/// clones but do not remove recursive destruction of the source value.
107/// There is no universal safe depth across platforms and thread configurations.
108///
109/// # Examples
110///
111/// ```
112/// use qubit_value::MultiValues;
113///
114/// let values = MultiValues::from(vec![1_i32, 2, 3]);
115/// assert_eq!(values.get_int32s().unwrap(), &[1, 2, 3]);
116/// ```
117///
118/// Equality preserves element order and normalizes NaNs within one float width:
119///
120/// ```
121/// use qubit_value::MultiValues;
122///
123/// assert_ne!(MultiValues::Float64(vec![1.0, 2.0]), MultiValues::Float64(vec![2.0, 1.0]));
124/// assert_eq!(
125/// MultiValues::Float64(vec![f64::NAN]),
126/// MultiValues::Float64(vec![f64::NAN]),
127/// );
128/// ```
129#[must_use]
130#[derive(Clone)]
131pub struct MultiValues {
132 /// Private homogeneous storage backing the stable public accessor API.
133 pub(crate) repr: MultiValuesRepr,
134}
135
136impl fmt::Debug for MultiValues {
137 /// Formats the borrowed semantic view without cloning stored elements.
138 ///
139 /// # Parameters
140 ///
141 /// * `formatter` - Destination and formatting options.
142 ///
143 /// # Returns
144 ///
145 /// `Ok(())` after the view is written.
146 ///
147 /// # Errors
148 ///
149 /// Propagates an error from the formatting destination.
150 #[inline]
151 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
152 self.view().fmt(formatter)
153 }
154}
155
156/// Implements named collection constructors from the shared value table.
157macro_rules! impl_multi_values_constructors {
158 (
159 ;
160 $(
161 (
162 [$($cfg:meta),*],
163 $variant:ident,
164 $type:ty,
165 $data_type:expr,
166 $materialization:ident,
167 $json_class:ident,
168 $number_projection:ident,
169 $value_doc:literal,
170 $multi_doc:literal
171 $(, $_wire:tt)*
172 )
173 ),+ $(,)?
174 ) => {
175 impl MultiValues {
176 /// Creates an unset collection with an explicit element type.
177 ///
178 /// # Parameters
179 ///
180 /// * `data_type` - Element type retained while the collection is unset.
181 ///
182 /// # Returns
183 ///
184 /// An unset collection retaining `data_type`.
185 #[allow(non_snake_case)]
186 #[inline(always)]
187 pub const fn Unset(data_type: DataType) -> Self {
188 Self::new_unset(data_type)
189 }
190
191 /// Creates an unset collection with an explicit element type.
192 ///
193 /// # Parameters
194 ///
195 /// * `data_type` - Element type retained while the collection is unset.
196 ///
197 /// # Returns
198 ///
199 /// An unset collection retaining `data_type`.
200 #[inline(always)]
201 pub const fn new_unset(data_type: DataType) -> Self {
202 Self { repr: MultiValuesRepr::Unset(data_type) }
203 }
204
205 $(
206 #[doc = concat!("Creates a collection of ", $multi_doc, ".")]
207 ///
208 /// # Parameters
209 ///
210 /// * `values` - Homogeneous elements stored by the collection.
211 ///
212 /// # Returns
213 ///
214 /// A typed collection containing `values` in their original order.
215 $(#[$cfg])*
216 $(#[cfg_attr(docsrs, doc($cfg))])*
217 #[allow(non_snake_case)]
218 #[inline(always)]
219 pub fn $variant(values: Vec<$type>) -> Self {
220 Self { repr: MultiValuesRepr::$variant(values) }
221 }
222 )+
223 }
224 };
225}
226
227/// Borrows owned storage through the shared type table.
228macro_rules! owned_view_match {
229 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
230 match &$value.repr {
231 MultiValuesRepr::Unset(data_type) => MultiValuesRef::Unset(*data_type),
232 $($(#[$cfg])* MultiValuesRepr::$variant(value) => MultiValuesRef::$variant(
233 value.as_slice()
234 ),)+
235 }
236 };
237}
238
239for_each_value_type!(impl_multi_values_constructors);
240
241impl MultiValues {
242 /// Strictly borrows the first stored item without allocating.
243 ///
244 /// The returned reference is tied to this collection's lifetime. The
245 /// requested type must match the stored element type.
246 ///
247 /// # Type Parameters
248 ///
249 /// * `T` - Stored element type to borrow.
250 ///
251 /// # Returns
252 ///
253 /// A reference to the first item.
254 ///
255 /// # Errors
256 ///
257 /// Returns [`ValueError::Missing`] when no first item is available, or a
258 /// type conversion error when the stored element type does not match `T`.
259 ///
260 /// # Examples
261 ///
262 /// ```
263 /// use qubit_value::{MultiValues, ValueError};
264 ///
265 /// let values = MultiValues::new(vec![String::from("a"), String::from("b")]);
266 /// let first: &String = values.get_first_ref().unwrap();
267 /// assert_eq!(first, "a");
268 /// let empty = MultiValues::new(Vec::<String>::new());
269 /// assert!(matches!(empty.get_first_ref::<String>(), Err(ValueError::Missing(_))));
270 /// ```
271 ///
272 /// A first-item borrow does not accept a complete slice target:
273 ///
274 /// ```compile_fail
275 /// use qubit_value::MultiValues;
276 ///
277 /// let values = MultiValues::Int32(vec![1, 2]);
278 /// let _: &[i32] = values.get_first_ref::<[i32]>().unwrap();
279 /// ```
280 #[inline(always)]
281 pub fn get_first_ref<'a, T: ?Sized>(&'a self) -> ValueResult<&'a T>
282 where
283 &'a T: TryFrom<&'a Value, Error = ValueError> + TryFrom<&'a Self, Error = ValueError>,
284 {
285 <&'a T>::try_from(self)
286 }
287
288 /// Strictly borrows the complete collection without allocating.
289 ///
290 /// The returned slice is tied to this collection's lifetime. The
291 /// requested element type must match the stored type.
292 ///
293 /// # Type Parameters
294 ///
295 /// * `T` - Stored element type of the borrowed slice.
296 ///
297 /// # Returns
298 ///
299 /// A slice of all stored items, including an empty slice for an empty
300 /// collection.
301 ///
302 /// # Errors
303 ///
304 /// Returns [`ValueError::TypeMismatch`] when the stored element type does
305 /// not match `T`. Returns [`ValueError::Missing`] when the collection is
306 /// unset with the requested stored type, with reason
307 /// [`crate::ValueMissingReason::UnsetCollection`]. A concrete empty
308 /// collection succeeds with an empty slice.
309 ///
310 /// # Examples
311 ///
312 /// ```
313 /// use qubit_value::MultiValues;
314 ///
315 /// let values = MultiValues::new(vec![String::from("a"), String::from("b")]);
316 /// let all: &[String] = values.get_slice().unwrap();
317 /// assert_eq!(all.len(), 2);
318 /// let empty = MultiValues::new(Vec::<String>::new());
319 /// assert!(empty.get_slice::<String>().unwrap().is_empty());
320 /// let unset = MultiValues::Unset(qubit_datatype::DataType::String);
321 /// let error = unset.get_slice::<String>().unwrap_err();
322 /// assert!(matches!(error, qubit_value::ValueError::Missing(_)));
323 /// assert_eq!(
324 /// error.missing().unwrap().reason(),
325 /// qubit_value::ValueMissingReason::UnsetCollection,
326 /// );
327 /// let error = unset.get_slice::<i32>().unwrap_err();
328 /// assert!(matches!(error, qubit_value::ValueError::TypeMismatch { .. }));
329 /// ```
330 #[inline(always)]
331 pub fn get_slice<'a, T>(&'a self) -> ValueResult<&'a [T]>
332 where
333 &'a [T]: TryFrom<&'a Self, Error = ValueError>,
334 {
335 <&'a [T]>::try_from(self)
336 }
337
338 /// Hashes this collection while applying `budget` to JSON elements.
339 ///
340 /// # Type Parameters
341 ///
342 /// * `H` - Hasher receiving the semantic collection identity.
343 /// * `R` - Resource identifier used by the JSON budget.
344 /// * `Q` - Quantity type used by the JSON budget.
345 ///
346 /// # Parameters
347 ///
348 /// * `state` - Hasher that receives the same identity representation as
349 /// [`Hash::hash`].
350 /// * `budget` - Mutable JSON traversal budget, used only for JSON elements.
351 ///
352 /// # Returns
353 ///
354 /// `Ok(())` after the complete semantic identity is hashed.
355 ///
356 /// # Errors
357 ///
358 /// Returns [`qubit_budget::MeasuredBudgetError`] when a JSON element
359 /// exceeds a configured limit.
360 /// On error, neither `state` nor the committed portion of `budget` is
361 /// modified. A hasher panic also drops the staged budget transaction.
362 ///
363 /// # Examples
364 ///
365 /// ```
366 /// use std::collections::hash_map::DefaultHasher;
367 ///
368 /// use qubit_budget::{ResourceLimit, StructureLimits};
369 /// use qubit_budget::json::{JsonResource, JsonValueBudget, JsonValueLimits};
370 /// use qubit_value::MultiValues;
371 ///
372 /// let values = MultiValues::Json(vec![serde_json::json!([null])]);
373 /// let structure = StructureLimits::<JsonResource, usize>::builder().nodes_limit(
374 /// ResourceLimit::new(JsonResource::Nodes, 1_usize),
375 /// ).build();
376 /// let mut budget = JsonValueBudget::new(
377 /// JsonValueLimits::builder().structure_limits(structure).build(),
378 /// );
379 /// let mut hasher = DefaultHasher::new();
380 ///
381 /// assert!(values.hash_with_json_budget(&mut hasher, &mut budget).is_err());
382 /// drop(hasher);
383 /// // The rejected values did not consume committed budget state.
384 /// ```
385 #[cfg(feature = "json")]
386 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
387 pub fn hash_with_json_budget<H, R, Q>(
388 &self,
389 state: &mut H,
390 budget: &mut JsonValueBudget<R, Q>,
391 ) -> Result<(), MeasuredBudgetError<R, Q>>
392 where
393 H: Hasher,
394 R: Clone,
395 Q: ResourceQuantity,
396 {
397 match &self.repr {
398 MultiValuesRepr::Json(values) => {
399 let mut transaction = budget.transaction();
400 for value in values {
401 preflight_json(value, &mut transaction)?;
402 }
403 discriminant(&self.repr).hash(state);
404 values.len().hash(state);
405 for value in values {
406 hash_json(value, state);
407 }
408 transaction.commit()
409 }
410 _ => {
411 discriminant(&self.repr).hash(state);
412 hash_non_json_multi_values_payload(&self.repr, state);
413 Ok(())
414 }
415 }
416 }
417
418 /// Borrows the stable semantic view of this collection.
419 ///
420 /// # Returns
421 ///
422 /// A non-owning homogeneous view that hides private storage details.
423 #[inline(always)]
424 pub fn view(&self) -> MultiValuesRef<'_> {
425 for_each_value_type!(owned_view_match, self)
426 }
427}
428
429// ============================================================================
430// Getter method generation macros
431// ============================================================================
432
433/// Unified multiple values getter generation macro
434///
435/// Generates `get_[xxx]s` methods for `MultiValues`, returning a reference to
436/// value slices.
437///
438/// # Documentation Comment Support
439///
440/// The macro automatically extracts preceding documentation comments, so you
441/// can add `///` comments before macro invocations.
442macro_rules! impl_get_multi_values {
443 // Every generated getter returns a borrowed slice.
444 ($(#[$attr:meta])* slice: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
445 $(#[$attr])*
446 #[doc = ""]
447 #[doc = "# Errors"]
448 #[doc = ""]
449 #[doc = "Returns [`ValueError::Missing`] when the container is unset"]
450 #[doc = "with the requested type, or [`ValueError::TypeMismatch`] when"]
451 #[doc = "the stored data type differs. A concrete empty vector returns"]
452 #[doc = "an empty slice."]
453 #[inline(always)]
454 pub fn $method(&self) -> ValueResult<&[$type]> {
455 match &self.repr {
456 MultiValuesRepr::$variant(v) => Ok(v.as_slice()),
457 MultiValuesRepr::Unset(dt) if *dt == $data_type => {
458 Err(ValueError::Missing($crate::ValueMissing::unset_collection(*dt, *dt)))
459 }
460 _ => Err(ValueError::TypeMismatch {
461 expected: $data_type,
462 actual: self.data_type(),
463 }),
464 }
465 }
466 };
467
468 // Compatibility label for existing internal invocations; use the shared slice implementation.
469 ($(#[$attr:meta])* vec: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
470 impl_get_multi_values! {
471 $(#[$attr])*
472 slice: $method, $variant, $type, $data_type
473 }
474 };
475}
476
477/// Unified multiple values get_first method generation macro
478///
479/// Generates `get_first_[xxx]` methods for `MultiValues`, used to get the first
480/// value.
481///
482/// # Documentation Comment Support
483///
484/// The macro automatically extracts preceding documentation comments, so you
485/// can add `///` comments before macro invocations.
486macro_rules! impl_get_first_value {
487 // Copy type: directly return value
488 ($(#[$attr:meta])* copy: $method:ident, $variant:ident, $type:ty, $data_type:expr) => {
489 $(#[$attr])*
490 #[doc = ""]
491 #[doc = "# Errors"]
492 #[doc = ""]
493 #[doc = "Returns [`ValueError::Missing`] when the requested type matches"]
494 #[doc = "but no value is stored, or [`ValueError::TypeMismatch`] when"]
495 #[doc = "the stored data type differs."]
496 #[inline(always)]
497 pub fn $method(&self) -> ValueResult<$type> {
498 match &self.repr {
499 MultiValuesRepr::$variant(v) if !v.is_empty() => Ok(v[0]),
500 MultiValuesRepr::$variant(_) => {
501 Err(ValueError::Missing($crate::ValueMissing::empty_collection($data_type, $data_type)))
502 }
503 MultiValuesRepr::Unset(dt) if *dt == $data_type => {
504 Err(ValueError::Missing($crate::ValueMissing::unset_collection(*dt, *dt)))
505 }
506 _ => Err(ValueError::TypeMismatch {
507 expected: $data_type,
508 actual: self.data_type(),
509 }),
510 }
511 }
512 };
513
514 // Reference type: return reference
515 ($(#[$attr:meta])* ref: $method:ident, $variant:ident, $ret_type:ty, $data_type:expr, $conversion:expr) => {
516 $(#[$attr])*
517 #[doc = ""]
518 #[doc = "# Errors"]
519 #[doc = ""]
520 #[doc = "Returns [`ValueError::Missing`] when the requested type matches"]
521 #[doc = "but no value is stored, or [`ValueError::TypeMismatch`] when"]
522 #[doc = "the stored data type differs."]
523 #[inline(always)]
524 pub fn $method(&self) -> ValueResult<$ret_type> {
525 match &self.repr {
526 MultiValuesRepr::$variant(v) if !v.is_empty() => {
527 let conv_fn: fn(&_) -> $ret_type = $conversion;
528 Ok(conv_fn(&v[0]))
529 },
530 MultiValuesRepr::$variant(_) => {
531 Err(ValueError::Missing($crate::ValueMissing::empty_collection($data_type, $data_type)))
532 }
533 MultiValuesRepr::Unset(dt) if *dt == $data_type => {
534 Err(ValueError::Missing($crate::ValueMissing::unset_collection(*dt, *dt)))
535 }
536 _ => Err(ValueError::TypeMismatch {
537 expected: $data_type,
538 actual: self.data_type(),
539 }),
540 }
541 }
542 };
543}
544
545#[cfg(all(feature = "converter", feature = "json"))]
546#[cfg_attr(docsrs, doc(cfg(all(feature = "converter", feature = "json"))))]
547impl MultiValues {
548 /// Projects this collection to its natural JSON representation.
549 ///
550 /// Unset is `null`; every concrete collection is an array, including empty
551 /// and one-item collections.
552 ///
553 /// # Returns
554 ///
555 /// The natural JSON representation of this collection.
556 ///
557 /// For natural JSON projection, `max_text_bytes` bounds each string value
558 /// and each formatted number or rich-value text by its UTF-8 byte length,
559 /// including strings inside materialized JSON. Object keys are excluded
560 /// from this per-item bound but still consume applicable key and
561 /// cumulative input, output, and payload budgets. This is neither a
562 /// cumulative text limit nor a limit on escaped JSON encoding size.
563 ///
564 /// # Errors
565 ///
566 /// Returns a list conversion error containing the zero-based source index
567 /// when an item cannot be represented as JSON.
568 #[inline]
569 pub fn to_json_value(&self) -> ValueResult<JsonValue> {
570 self.to_json_value_with(ConversionPolicy::default_ref(), ConversionLimits::default_ref())
571 }
572
573 /// Projects this collection using explicit conversion policy and limits.
574 ///
575 /// # Parameters
576 ///
577 /// * `policy` - Controls duration units and precision-loss behavior.
578 /// * `limits` - Bounds conversion resource consumption.
579 ///
580 /// # Returns
581 ///
582 /// The natural JSON representation of this collection.
583 ///
584 /// # Errors
585 ///
586 /// Returns [`ValueError::JsonProjectionLimit`] when a projection resource
587 /// limit is exceeded; its collection index is absent for container-wide
588 /// limits and identifies an item for item-specific limits. Returns an
589 /// indexed [`ValueError::ListConversion`] when an item cannot be
590 /// represented under the requested policy, or another structured
591 /// conversion error for unsupported values.
592 #[inline(always)]
593 pub fn to_json_value_with(&self, policy: &ConversionPolicy, limits: &ConversionLimits) -> ValueResult<JsonValue> {
594 crate::json::multi_values_to_json_value_with(self, policy, limits)
595 }
596}
597
598/// Maps private collection storage variants to their runtime data types.
599macro_rules! multi_values_data_type_match {
600 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
601 match &$value.repr {
602 MultiValuesRepr::Unset(dt) => *dt,
603 $($(#[$cfg])* MultiValuesRepr::$variant(_) => $data_type,)+
604 }
605 };
606}
607
608/// Returns the concrete element count for each collection storage variant.
609macro_rules! multi_values_count_match {
610 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
611 match &$value.repr {
612 MultiValuesRepr::Unset(_) => 0,
613 $($(#[$cfg])* MultiValuesRepr::$variant(values) => values.len(),)+
614 }
615 };
616}
617
618/// Clears the concrete elements of each collection storage variant.
619macro_rules! multi_values_clear_match {
620 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
621 match &mut $value.repr {
622 MultiValuesRepr::Unset(_) => {}
623 $($(#[$cfg])* MultiValuesRepr::$variant(values) => values.clear(),)+
624 }
625 };
626}
627
628/// Appends same-typed elements to an existing collection storage variant.
629macro_rules! multi_values_append_match {
630 ($left:expr, $right:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
631 match (&mut $left.repr, &mut $right.repr) {
632 $(
633 $(#[$cfg])*
634 (MultiValuesRepr::$variant(values), MultiValuesRepr::$variant(other_values)) => {
635 values.append(other_values);
636 }
637 )+
638 (slot @ MultiValuesRepr::Unset(_), other_values) => {
639 *slot = replace(other_values, MultiValuesRepr::Unset(DataType::String));
640 }
641 _ => unreachable!(),
642 }
643 };
644}
645
646/// Clones the first collection element into a scalar value.
647macro_rules! multi_values_first_value_match {
648 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
649 match &$value.repr {
650 MultiValuesRepr::Unset(data_type) => Value::new_unset(*data_type),
651 $(
652 $(#[$cfg])*
653 MultiValuesRepr::$variant(values) => values
654 .first()
655 .map(|value| materialize_stored!($materialization, value))
656 .map(Value::$variant)
657 .unwrap_or(Value::new_unset($data_type)),
658 )+
659 }
660 };
661}
662
663/// Moves the first collection element into a scalar value.
664macro_rules! multi_values_into_first_value_match {
665 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
666 match $value.repr {
667 MultiValuesRepr::Unset(data_type) => Value::new_unset(data_type),
668 $(
669 $(#[$cfg])*
670 MultiValuesRepr::$variant(values) => values
671 .into_iter()
672 .next()
673 .map(Value::$variant)
674 .unwrap_or(Value::new_unset($data_type)),
675 )+
676 }
677 };
678}
679
680/// Merges same-typed collection storage while preserving element order.
681macro_rules! multi_values_merge_match {
682 ($left:expr, $right:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
683 match (&mut $left.repr, &$right.repr) {
684 $(
685 $(#[$cfg])*
686 (MultiValuesRepr::$variant(values), MultiValuesRepr::$variant(other_values)) => {
687 values.extend_from_slice(other_values)
688 }
689 )+
690 (slot @ MultiValuesRepr::Unset(_), other_values) => *slot = other_values.clone(),
691 _ => unreachable!(),
692 }
693 };
694}
695
696/// Converts one private scalar storage variant into collection storage.
697macro_rules! value_into_multi_values_match {
698 ($value:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
699 match $value.repr {
700 ValueRepr::Unset(data_type) => MultiValues::new_unset(data_type),
701 $($(#[$cfg])* ValueRepr::$variant(value) => {
702 MultiValues::$variant(vec![value_storage_into_multi!($variant, value)])
703 },)+
704 }
705 };
706}
707
708impl MultiValues {
709 /// Generic constructor method
710 ///
711 /// Creates `MultiValues` from any supported input form, avoiding direct
712 /// use of type-specific named constructors at call sites.
713 ///
714 /// Supported input forms include single values, vectors, slices, arrays,
715 /// borrowed vectors, and borrowed string collections for supported element
716 /// types.
717 ///
718 /// # Type Parameters
719 ///
720 /// * `S` - Input type convertible into [`MultiValues`].
721 ///
722 /// # Parameters
723 ///
724 /// * `values` - Values to convert into a collection.
725 ///
726 /// # Returns
727 ///
728 /// Returns `MultiValues` wrapping the converted input values.
729 ///
730 /// # Examples
731 ///
732 /// ```rust
733 /// use qubit_value::MultiValues;
734 ///
735 /// // Basic types
736 /// let mv = MultiValues::new(vec![1, 2, 3]);
737 /// assert_eq!(mv.len(), 3);
738 ///
739 /// // Strings
740 /// let mv = MultiValues::new(vec!["a".to_string(), "b".to_string()]);
741 /// assert_eq!(mv.len(), 2);
742 /// ```
743 #[inline(always)]
744 pub fn new<S>(values: S) -> Self
745 where
746 S: Into<Self>,
747 {
748 values.into()
749 }
750
751 /// Generic getter method for multiple values.
752 ///
753 /// Performs a strict typed read of all stored values as `Vec<T>`.
754 ///
755 /// # Type Parameters
756 ///
757 /// * `T` - The target element type to retrieve.
758 ///
759 /// # Returns
760 ///
761 /// Returns the list of values when the stored type matches `T`.
762 ///
763 /// # Errors
764 ///
765 /// Returns [`ValueError::Missing`] when the container is unset with the
766 /// requested type, or [`ValueError::TypeMismatch`] when the stored type
767 /// differs from `T`.
768 ///
769 /// # Examples
770 ///
771 /// ```rust
772 /// use qubit_value::MultiValues;
773 ///
774 /// let multi = MultiValues::Int32(vec![1, 2, 3]);
775 ///
776 /// // Through type inference
777 /// let nums: Vec<i32> = multi.get().unwrap();
778 /// assert_eq!(nums, vec![1, 2, 3]);
779 ///
780 /// // Explicitly specify type parameter
781 /// let nums = multi.get::<i32>().unwrap();
782 /// assert_eq!(nums, vec![1, 2, 3]);
783 /// ```
784 #[inline(always)]
785 pub fn get<T>(&self) -> ValueResult<Vec<T>>
786 where
787 for<'a> Vec<T>: TryFrom<&'a Self, Error = ValueError>,
788 {
789 Vec::<T>::try_from(self)
790 }
791
792 /// Generic getter method with a default value list.
793 ///
794 /// Returns the supplied default only when this container is unset. A
795 /// concrete empty vector remains an empty result.
796 ///
797 /// # Type Parameters
798 ///
799 /// * `T` - Target element type for the strict read.
800 ///
801 /// # Parameters
802 ///
803 /// * `default` - Lazily materialized list used only for unset storage.
804 ///
805 /// # Returns
806 ///
807 /// The concrete stored list, or `default` for unset storage.
808 ///
809 /// # Errors
810 ///
811 /// Returns [`ValueError::TypeMismatch`] when the stored type differs from
812 /// `T`.
813 #[inline(always)]
814 pub fn get_or<T>(&self, default: impl IntoValueDefault<Vec<T>>) -> ValueResult<Vec<T>>
815 where
816 for<'a> Vec<T>: TryFrom<&'a Self, Error = ValueError>,
817 {
818 match self.get() {
819 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_strict_read() => {
820 Ok(default.into_value_default())
821 }
822 result => result,
823 }
824 }
825
826 /// Strictly reads all values or calls `default` only when storage is unset.
827 ///
828 /// A concrete empty collection is returned unchanged and type mismatches
829 /// are preserved without invoking the callback.
830 ///
831 /// # Type Parameters
832 ///
833 /// * `T` - Target element type.
834 /// * `F` - Deferred fallback producing the complete list.
835 ///
836 /// # Parameters
837 ///
838 /// * `default` - Callback invoked only for unset storage.
839 ///
840 /// # Returns
841 ///
842 /// The stored list or the callback result.
843 ///
844 /// # Errors
845 ///
846 /// Returns [`ValueError::TypeMismatch`] for an incompatible concrete
847 /// collection without invoking the callback.
848 #[inline(always)]
849 pub fn get_or_else<T, F>(&self, default: F) -> ValueResult<Vec<T>>
850 where
851 for<'a> Vec<T>: TryFrom<&'a Self, Error = ValueError>,
852 F: FnOnce() -> Vec<T>,
853 {
854 match self.get() {
855 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_strict_read() => Ok(default()),
856 result => result,
857 }
858 }
859
860 /// Generic getter method for the first value
861 ///
862 /// Reads the first stored value as `T`, performing strict type checking.
863 ///
864 /// `get_first<T>()` does not do cross-type conversion.
865 ///
866 /// # Type Parameters
867 ///
868 /// * `T` - The target element type to retrieve.
869 ///
870 /// # Returns
871 ///
872 /// Returns the first value when the stored type matches `T` and at least
873 /// one value exists.
874 ///
875 /// # Errors
876 ///
877 /// Returns [`ValueError::Missing`] when the requested type matches but no
878 /// value is stored, or [`ValueError::TypeMismatch`] when the stored type
879 /// differs from `T`.
880 ///
881 /// # Examples
882 ///
883 /// ```rust
884 /// use qubit_value::MultiValues;
885 ///
886 /// let multi = MultiValues::Int32(vec![42, 100, 200]);
887 ///
888 /// // Through type inference
889 /// let first: i32 = multi.get_first().unwrap();
890 /// assert_eq!(first, 42);
891 ///
892 /// // Explicitly specify type parameter
893 /// let first = multi.get_first::<i32>().unwrap();
894 /// assert_eq!(first, 42);
895 ///
896 /// // String type
897 /// let multi = MultiValues::String(vec!["hello".to_string(), "world".to_string()]);
898 /// let first: String = multi.get_first().unwrap();
899 /// assert_eq!(first, "hello");
900 /// ```
901 ///
902 /// A first-item read does not accept a complete collection target:
903 ///
904 /// ```compile_fail
905 /// use qubit_value::MultiValues;
906 ///
907 /// let values = MultiValues::Int32(vec![1, 2]);
908 /// let _: Vec<i32> = values.get_first::<Vec<i32>>().unwrap();
909 /// ```
910 #[cfg_attr(
911 feature = "converter",
912 doc = "When the `converter` feature is enabled, use [`Self::to_first`] for compatible cross-type conversion."
913 )]
914 #[cfg_attr(
915 not(feature = "converter"),
916 doc = "With the `converter` feature enabled, `to_first` provides compatible cross-type conversion."
917 )]
918 #[inline(always)]
919 pub fn get_first<T>(&self) -> ValueResult<T>
920 where
921 T: StrictValueRead,
922 {
923 T::read_collection_first(self)
924 }
925
926 /// Generic first-value getter with a default value.
927 ///
928 /// Returns the supplied default only when the container is unset. A
929 /// concrete empty vector returns [`ValueError::Missing`]; type mismatches
930 /// are also preserved.
931 ///
932 /// # Type Parameters
933 ///
934 /// * `T` - Target type for the strict first-item read.
935 ///
936 /// # Parameters
937 ///
938 /// * `default` - Lazily materialized value used only for unset storage.
939 ///
940 /// # Returns
941 ///
942 /// The first concrete item, or `default` for unset storage.
943 ///
944 /// # Errors
945 ///
946 /// Returns [`ValueError::Missing`] for a concrete empty collection or
947 /// [`ValueError::TypeMismatch`] when the stored type differs from `T`.
948 ///
949 /// ```compile_fail
950 /// use qubit_value::MultiValues;
951 ///
952 /// let values = MultiValues::Int32(vec![1, 2]);
953 /// let _: Vec<i32> = values.get_first_or::<Vec<i32>>(Vec::new()).unwrap();
954 /// ```
955 #[inline(always)]
956 pub fn get_first_or<T>(&self, default: impl IntoValueDefault<T>) -> ValueResult<T>
957 where
958 T: StrictValueRead,
959 {
960 match self.get_first() {
961 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_strict_read() => {
962 Ok(default.into_value_default())
963 }
964 result => result,
965 }
966 }
967
968 /// Strictly reads the first value or calls `default` only when unset.
969 ///
970 /// # Type Parameters
971 ///
972 /// * `T` - Target element type.
973 /// * `F` - Deferred fallback producing one element.
974 ///
975 /// # Parameters
976 ///
977 /// * `default` - Callback invoked only for unset storage.
978 ///
979 /// # Returns
980 ///
981 /// The first stored item or the callback result.
982 ///
983 /// # Errors
984 ///
985 /// Preserves empty-collection and type-mismatch errors without invoking
986 /// the callback.
987 ///
988 /// ```compile_fail
989 /// use qubit_value::MultiValues;
990 ///
991 /// let values = MultiValues::Int32(vec![1, 2]);
992 /// let _: Vec<i32> = values.get_first_or_else::<Vec<i32>, _>(Vec::new).unwrap();
993 /// ```
994 #[inline(always)]
995 pub fn get_first_or_else<T, F>(&self, default: F) -> ValueResult<T>
996 where
997 T: StrictValueRead,
998 F: FnOnce() -> T,
999 {
1000 match self.get_first() {
1001 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_strict_read() => Ok(default()),
1002 result => result,
1003 }
1004 }
1005
1006 /// Get the data type of the values
1007 ///
1008 /// # Returns
1009 ///
1010 /// Returns the data type corresponding to these multiple values
1011 ///
1012 /// # Examples
1013 ///
1014 /// ```rust
1015 /// use qubit_datatype::DataType;
1016 /// use qubit_value::MultiValues;
1017 ///
1018 /// let values = MultiValues::Int32(vec![1, 2, 3]);
1019 /// assert_eq!(values.data_type(), DataType::Int32);
1020 /// ```
1021 #[must_use = "the collection element type should be used"]
1022 #[inline(always)]
1023 pub fn data_type(&self) -> DataType {
1024 for_each_value_type!(multi_values_data_type_match, self)
1025 }
1026
1027 /// Returns the number of values.
1028 ///
1029 /// # Returns
1030 ///
1031 /// The number of values contained in these multiple values. An unset
1032 /// collection has length zero.
1033 ///
1034 /// # Examples
1035 ///
1036 /// ```rust
1037 /// use qubit_datatype::DataType;
1038 /// use qubit_value::MultiValues;
1039 ///
1040 /// let values = MultiValues::Int32(vec![1, 2, 3]);
1041 /// assert_eq!(values.len(), 3);
1042 ///
1043 /// let empty = MultiValues::Unset(DataType::String);
1044 /// assert_eq!(empty.len(), 0);
1045 /// ```
1046 #[inline(always)]
1047 #[must_use]
1048 pub fn len(&self) -> usize {
1049 for_each_value_type!(multi_values_count_match, self)
1050 }
1051
1052 /// Tests whether this collection contains no values.
1053 ///
1054 /// An unset collection and a concrete empty vector both have length zero.
1055 /// Use [`MultiValues::is_unset`] when the distinction between no collection
1056 /// and a concrete empty collection matters.
1057 ///
1058 /// # Returns
1059 ///
1060 /// `true` when [`Self::len`] is zero; otherwise, `false`.
1061 #[inline(always)]
1062 #[must_use]
1063 pub fn is_empty(&self) -> bool {
1064 self.len() == 0
1065 }
1066
1067 /// Tests whether this container has no concrete vector.
1068 ///
1069 /// # Returns
1070 ///
1071 /// Returns `true` only for [`MultiValues::Unset`]. A concrete empty vector
1072 /// returns `false`.
1073 ///
1074 /// # Examples
1075 ///
1076 /// ```rust
1077 /// use qubit_datatype::DataType;
1078 /// use qubit_value::MultiValues;
1079 ///
1080 /// let values = MultiValues::Int32(vec![]);
1081 /// assert!(!values.is_unset());
1082 ///
1083 /// let empty = MultiValues::Unset(DataType::String);
1084 /// assert!(empty.is_unset());
1085 /// ```
1086 #[inline(always)]
1087 #[must_use]
1088 pub fn is_unset(&self) -> bool {
1089 matches!(self.repr, MultiValuesRepr::Unset(_))
1090 }
1091
1092 /// Tests whether a concrete collection belongs to the numeric type family.
1093 ///
1094 /// A concrete empty numeric vector returns `true`; an unset collection
1095 /// returns `false`, even when its declared type is numeric.
1096 ///
1097 /// # Returns
1098 ///
1099 /// `true` for concrete collections with a numeric element type.
1100 #[inline]
1101 #[must_use]
1102 pub fn is_numeric(&self) -> bool {
1103 !self.is_unset() && self.data_type().is_numeric()
1104 }
1105
1106 /// Converts the first element to a single [`Value`].
1107 ///
1108 /// Returns `Value::Unset` with the same declared type when no element is
1109 /// stored.
1110 ///
1111 /// # Returns
1112 ///
1113 /// A cloned first item, or a typed unset value when no item exists.
1114 #[inline(always)]
1115 pub fn first_value(&self) -> Value {
1116 for_each_value_type!(multi_values_first_value_match, self)
1117 }
1118
1119 /// Consumes this collection and returns its first item as a [`Value`].
1120 ///
1121 /// Empty and unset collections become [`Value::Unset`] with the same data
1122 /// type. Owned element storage is moved instead of cloned.
1123 ///
1124 /// # Returns
1125 ///
1126 /// The owned first item, or a typed unset value when no item exists.
1127 pub fn into_first_value(self) -> Value {
1128 for_each_value_type!(multi_values_into_first_value_match, self)
1129 }
1130
1131 /// Generic setter method
1132 ///
1133 /// Replaces the entire list with the converted input values.
1134 ///
1135 /// This operation updates the stored type to the input element type and
1136 /// does not validate runtime compatibility with the previous variant.
1137 ///
1138 /// Supports any input that can be converted into [`MultiValues`], including
1139 /// single values, vectors, slices, arrays, and borrowed vectors for
1140 /// supported element types.
1141 ///
1142 /// Existing values are replaced, and the stored type becomes the converted
1143 /// input type.
1144 ///
1145 /// # Type Parameters
1146 ///
1147 /// * `S` - Input type convertible into [`MultiValues`].
1148 ///
1149 /// # Parameters
1150 ///
1151 /// * `values` - The values to set.
1152 ///
1153 /// # Compile-time restriction
1154 ///
1155 /// Unsupported input types fail to compile because they do not implement
1156 /// `Into<MultiValues>`.
1157 ///
1158 /// # Examples
1159 ///
1160 /// ```rust
1161 /// use qubit_datatype::DataType;
1162 /// use qubit_value::MultiValues;
1163 ///
1164 /// // 1) Vec<T>
1165 /// let mut mv = MultiValues::Unset(DataType::Int32);
1166 /// mv.set(vec![42, 100, 200]);
1167 /// assert_eq!(mv.get_int32s().unwrap(), &[42, 100, 200]);
1168 ///
1169 /// // 2) &[T]
1170 /// let mut mv = MultiValues::Unset(DataType::Int32);
1171 /// let slice = &[7, 8, 9][..];
1172 /// mv.set(slice);
1173 /// assert_eq!(mv.get_int32s().unwrap(), &[7, 8, 9]);
1174 ///
1175 /// // 3) Single T
1176 /// let mut mv = MultiValues::Unset(DataType::Int32);
1177 /// mv.set(42);
1178 /// assert_eq!(mv.get_int32s().unwrap(), &[42]);
1179 ///
1180 /// // String example
1181 /// let mut mv = MultiValues::Unset(DataType::String);
1182 /// mv.set(vec!["hello".to_string(), "world".to_string()]);
1183 /// assert_eq!(mv.get_strings().unwrap(), &["hello", "world"]);
1184 /// ```
1185 #[inline(always)]
1186 pub fn set<S>(&mut self, values: S)
1187 where
1188 S: Into<Self>,
1189 {
1190 *self = values.into();
1191 }
1192
1193 /// Generic add method
1194 ///
1195 /// Appends converted input values to the existing list with strict type
1196 /// checking.
1197 ///
1198 /// Supports any input that can be converted into [`MultiValues`], including
1199 /// single values, vectors, slices, arrays, and borrowed vectors for
1200 /// supported element types.
1201 ///
1202 /// The converted input must have the same data type as the current
1203 /// container. An empty container keeps its declared type until
1204 /// non-empty values of the same type are appended.
1205 ///
1206 /// # Type Parameters
1207 ///
1208 /// * `S` - Input type convertible into [`MultiValues`].
1209 ///
1210 /// # Parameters
1211 ///
1212 /// * `values` - Values to append.
1213 ///
1214 /// # Returns
1215 ///
1216 /// `Ok(())` after appending, including when the input is empty.
1217 ///
1218 /// # Errors
1219 ///
1220 /// Returns [`ValueError::TypeMismatch`] when the converted input data type
1221 /// differs from the current container data type.
1222 ///
1223 /// # Examples
1224 ///
1225 /// ```rust
1226 /// use qubit_datatype::DataType;
1227 /// use qubit_value::MultiValues;
1228 ///
1229 /// // 1) Single T
1230 /// let mut mv = MultiValues::Int32(vec![42]);
1231 /// mv.add(100).unwrap();
1232 /// assert_eq!(mv.get_int32s().unwrap(), &[42, 100]);
1233 ///
1234 /// // 2) Vec<T>
1235 /// mv.add(vec![200, 300]).unwrap();
1236 /// assert_eq!(mv.get_int32s().unwrap(), &[42, 100, 200, 300]);
1237 ///
1238 /// // 3) &[T]
1239 /// let slice = &[400, 500][..];
1240 /// mv.add(slice).unwrap();
1241 /// assert_eq!(mv.get_int32s().unwrap(), &[42, 100, 200, 300, 400, 500]);
1242 /// ```
1243 pub fn add<S>(&mut self, values: S) -> ValueResult<()>
1244 where
1245 S: Into<Self>,
1246 {
1247 let mut other = values.into();
1248 if self.data_type() != other.data_type() {
1249 return Err(ValueError::TypeMismatch {
1250 expected: self.data_type(),
1251 actual: other.data_type(),
1252 });
1253 }
1254 if other.is_empty() {
1255 return Ok(());
1256 }
1257
1258 for_each_value_type!(multi_values_append_match, self, other);
1259
1260 Ok(())
1261 }
1262
1263 /// Set the data type
1264 ///
1265 /// If the new type differs from the current type, clears all values and
1266 /// sets the new type.
1267 ///
1268 /// # Parameters
1269 ///
1270 /// * `data_type` - The data type to set
1271 ///
1272 /// # Examples
1273 ///
1274 /// ```rust
1275 /// use qubit_datatype::DataType;
1276 /// use qubit_value::MultiValues;
1277 ///
1278 /// let mut values = MultiValues::Int32(vec![1, 2, 3]);
1279 /// values.set_type(DataType::String);
1280 /// assert!(values.is_unset());
1281 /// assert_eq!(values.data_type(), DataType::String);
1282 /// ```
1283 #[inline]
1284 pub fn set_type(&mut self, data_type: DataType) {
1285 if self.data_type() != data_type {
1286 *self = MultiValues::new_unset(data_type);
1287 }
1288 }
1289
1290 /// Appends all values from another container with the same data type.
1291 ///
1292 /// # Parameters
1293 ///
1294 /// * `other` - Collection whose values are cloned and appended.
1295 ///
1296 /// # Returns
1297 ///
1298 /// `Ok(())` after appending, including when `other` is empty.
1299 ///
1300 /// # Errors
1301 ///
1302 /// Returns [`ValueError::TypeMismatch`] when `other` has a different data
1303 /// type.
1304 pub fn merge(&mut self, other: &MultiValues) -> ValueResult<()> {
1305 if self.data_type() != other.data_type() {
1306 return Err(ValueError::TypeMismatch {
1307 expected: self.data_type(),
1308 actual: other.data_type(),
1309 });
1310 }
1311 if other.is_empty() {
1312 return Ok(());
1313 }
1314 for_each_value_type!(multi_values_merge_match, self, other);
1315 Ok(())
1316 }
1317
1318 /// Removes the concrete vector while preserving its declared data type.
1319 #[inline]
1320 pub fn unset(&mut self) {
1321 *self = MultiValues::new_unset(self.data_type());
1322 }
1323
1324 /// Clears all values while preserving a concrete collection and its type.
1325 /// An unset collection remains unset because it has no concrete vector to
1326 /// clear.
1327 ///
1328 /// # Examples
1329 ///
1330 /// ```rust
1331 /// use qubit_datatype::DataType;
1332 /// use qubit_value::MultiValues;
1333 ///
1334 /// let mut values = MultiValues::Int32(vec![1, 2, 3]);
1335 /// values.clear();
1336 /// assert_eq!(values.len(), 0);
1337 /// assert_eq!(values.data_type(), DataType::Int32);
1338 /// ```
1339 #[inline]
1340 pub fn clear(&mut self) {
1341 for_each_value_type!(multi_values_clear_match, self)
1342 }
1343}
1344
1345impl From<Value> for MultiValues {
1346 /// Moves a scalar payload into a one-item collection, preserving its type.
1347 ///
1348 /// An unset scalar becomes an unset collection with the same declared type.
1349 ///
1350 /// # Parameters
1351 ///
1352 /// * `value` - Scalar whose owned storage is transferred to the collection.
1353 ///
1354 /// # Returns
1355 ///
1356 /// A one-item collection, or a typed unset collection for an unset scalar.
1357 fn from(value: Value) -> Self {
1358 for_each_value_type!(value_into_multi_values_match, value)
1359 }
1360}
1361
1362/// Converts the first collection element with a standalone policy and limits.
1363#[cfg(feature = "converter")]
1364macro_rules! multi_values_convert_first_match {
1365 ($value:expr, $policy:expr, $limits:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
1366 match &$value.repr {
1367 MultiValuesRepr::Unset(from) => {
1368 Err(DataConversionError::missing(*from, T::DATA_TYPE).into())
1369 }
1370 $(
1371 $(#[$cfg])*
1372 MultiValuesRepr::$variant(values) => {
1373 convert_first_with(DataConverters::from(values), $policy, $limits)
1374 }
1375 )+
1376 }
1377 };
1378}
1379
1380/// Converts every collection element with a standalone policy and limits.
1381#[cfg(feature = "converter")]
1382macro_rules! multi_values_convert_list_match {
1383 ($value:expr, $policy:expr, $limits:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
1384 match &$value.repr {
1385 MultiValuesRepr::Unset(from) => {
1386 Err(DataConversionError::missing(*from, T::DATA_TYPE).into())
1387 }
1388 $(
1389 $(#[$cfg])*
1390 MultiValuesRepr::$variant(values) => {
1391 convert_values_with(DataConverters::from(values), $policy, $limits)
1392 }
1393 )+
1394 }
1395 };
1396}
1397
1398/// Converts the first collection element through a caller-owned session.
1399#[cfg(feature = "converter")]
1400macro_rules! multi_values_convert_first_in_match {
1401 ($value:expr, $session:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
1402 match &$value.repr {
1403 MultiValuesRepr::Unset(from) => {
1404 Err(DataConversionError::missing(*from, T::DATA_TYPE).into())
1405 }
1406 $(
1407 $(#[$cfg])*
1408 MultiValuesRepr::$variant(values) => {
1409 DataConverters::from(values)
1410 .to_first_in($session)
1411 .map_err(ValueError::from)
1412 }
1413 )+
1414 }
1415 };
1416}
1417
1418/// Converts every collection element through a caller-owned session.
1419#[cfg(feature = "converter")]
1420macro_rules! multi_values_convert_list_in_match {
1421 ($value:expr, $session:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal $(, $_wire:tt)*)),+ $(,)?) => {
1422 match &$value.repr {
1423 MultiValuesRepr::Unset(from) => {
1424 Err(DataConversionError::missing(*from, T::DATA_TYPE).into())
1425 }
1426 $(
1427 $(#[$cfg])*
1428 MultiValuesRepr::$variant(values) => {
1429 DataConverters::from(values)
1430 .to_vec_in($session)
1431 .map_err(ValueError::from)
1432 }
1433 )+
1434 }
1435 };
1436}
1437
1438// ============================================================================
1439// Inherent conversion APIs
1440// ============================================================================
1441
1442/// Converts the first item from a batch converter using conversion policy and
1443/// limits.
1444///
1445/// # Type Parameters
1446///
1447/// * `T` - Target type.
1448/// * `I` - Iterator type wrapped by `DataConverters`.
1449///
1450/// # Parameters
1451///
1452/// * `values` - Batch converter containing source values.
1453/// * `policy` - Conversion policy forwarded to `qubit_datatype`.
1454/// * `limits` - Conversion limits forwarded to `qubit_datatype`.
1455///
1456/// # Returns
1457///
1458/// Returns the converted first value.
1459///
1460/// # Errors
1461///
1462/// Returns the mapped single-value conversion error for an empty source or an
1463/// invalid first source value.
1464#[inline(always)]
1465#[cfg(feature = "converter")]
1466fn convert_first_with<'a, T, I>(
1467 values: DataConverters<I>,
1468 policy: &ConversionPolicy,
1469 limits: &ConversionLimits,
1470) -> ValueResult<T>
1471where
1472 T: DataConversionTarget,
1473 I: Iterator,
1474 I::Item: Into<DataConverter<'a>>,
1475{
1476 values.to_first_with(policy, limits).map_err(ValueError::from)
1477}
1478
1479/// Converts every item from a batch converter using conversion policy and
1480/// limits.
1481///
1482/// # Type Parameters
1483///
1484/// * `T` - Target element type.
1485/// * `I` - Iterator type wrapped by `DataConverters`.
1486///
1487/// # Parameters
1488///
1489/// * `values` - Batch converter containing source values.
1490/// * `policy` - Conversion policy forwarded to `qubit_datatype`.
1491/// * `limits` - Conversion limits forwarded to `qubit_datatype`.
1492///
1493/// # Returns
1494///
1495/// Returns converted values in the original order.
1496///
1497/// # Errors
1498///
1499/// Returns a mapped batch conversion error containing the failing source index.
1500#[inline(always)]
1501#[cfg(feature = "converter")]
1502fn convert_values_with<'a, T, I>(
1503 values: DataConverters<I>,
1504 policy: &ConversionPolicy,
1505 limits: &ConversionLimits,
1506) -> ValueResult<Vec<T>>
1507where
1508 T: DataConversionTarget,
1509 I: Iterator,
1510 I::Item: Into<DataConverter<'a>>,
1511{
1512 values.to_vec_with(policy, limits).map_err(ValueError::from)
1513}
1514
1515#[cfg(feature = "converter")]
1516impl MultiValues {
1517 /// Converts the first stored value to `T`.
1518 ///
1519 /// Unlike [`Self::get_first`], this method uses shared `DataConverter`
1520 /// conversion rules instead of strict type matching. For example, a stored
1521 /// `String("1")` can be converted to `bool`.
1522 ///
1523 /// # Type Parameters
1524 ///
1525 /// * `T` - Target type.
1526 ///
1527 /// # Returns
1528 ///
1529 /// The converted first value.
1530 ///
1531 /// # Errors
1532 ///
1533 /// Returns a structured missing-value conversion error when the container
1534 /// is unset, an empty-collection error for a concrete empty vector, or a
1535 /// conversion error when the first value cannot be converted to `T`.
1536 #[inline(always)]
1537 pub fn to_first<T>(&self) -> ValueResult<T>
1538 where
1539 T: DataConversionTarget,
1540 {
1541 self.to_first_with(ConversionPolicy::default_ref(), ConversionLimits::default_ref())
1542 }
1543
1544 /// Converts the first stored value to `T`, or returns `default` when the
1545 /// collection is unset.
1546 ///
1547 /// An unset collection can use the default. A concrete empty collection
1548 /// and a policy-missing collection item (including the first item) remain
1549 /// errors and do not use the default; ordinary conversion errors are also
1550 /// preserved.
1551 ///
1552 /// # Type Parameters
1553 ///
1554 /// * `T` - Target type.
1555 ///
1556 /// # Parameters
1557 ///
1558 /// * `default` - Value returned for unset storage. Errors from concrete
1559 /// collection items are returned.
1560 ///
1561 /// # Returns
1562 ///
1563 /// The converted first value, or `default` for an unset collection.
1564 ///
1565 /// # Errors
1566 ///
1567 /// Returns an empty-collection error for a concrete empty vector, a
1568 /// policy-missing first-item error, or another conversion error when the
1569 /// first value cannot be converted to `T`.
1570 #[inline]
1571 pub fn to_first_or<T>(&self, default: impl IntoValueDefault<T>) -> ValueResult<T>
1572 where
1573 T: DataConversionTarget,
1574 {
1575 match self.to_first() {
1576 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => {
1577 Ok(default.into_value_default())
1578 }
1579 result => result,
1580 }
1581 }
1582
1583 /// Converts the first value or calls `default` when the collection is
1584 /// unset.
1585 ///
1586 /// # Type Parameters
1587 ///
1588 /// * `T` - Target conversion type.
1589 /// * `F` - Deferred fallback producing `T`.
1590 ///
1591 /// # Parameters
1592 ///
1593 /// * `default` - Callback invoked only for unset storage.
1594 ///
1595 /// # Returns
1596 ///
1597 /// The converted first item or the callback result for an unset
1598 /// collection.
1599 ///
1600 /// # Errors
1601 ///
1602 /// Returns an empty-collection error or a conversion error for a concrete
1603 /// value that cannot be converted to `T`. A policy-missing item, including
1604 /// item zero, remains an error and does not invoke the callback.
1605 #[inline]
1606 pub fn to_first_or_else<T, F>(&self, default: F) -> ValueResult<T>
1607 where
1608 T: DataConversionTarget,
1609 F: FnOnce() -> T,
1610 {
1611 match self.to_first() {
1612 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => Ok(default()),
1613 result => result,
1614 }
1615 }
1616
1617 /// Converts the first stored value to `T` using conversion policy and
1618 /// limits.
1619 ///
1620 /// Stored strings are collection items and are never split again by scalar
1621 /// string collection policy.
1622 ///
1623 /// # Type Parameters
1624 ///
1625 /// * `T` - Target type.
1626 ///
1627 /// # Parameters
1628 ///
1629 /// * `policy` - Conversion policy forwarded to `qubit_datatype`.
1630 /// * `limits` - Conversion limits forwarded to `qubit_datatype`.
1631 ///
1632 /// # Returns
1633 ///
1634 /// The converted first value.
1635 ///
1636 /// # Errors
1637 ///
1638 /// Returns a structured missing-value conversion error when the container
1639 /// is unset, an empty-collection error for a concrete empty vector, or a
1640 /// conversion error when the first value cannot be converted to `T`.
1641 pub fn to_first_with<T>(&self, policy: &ConversionPolicy, limits: &ConversionLimits) -> ValueResult<T>
1642 where
1643 T: DataConversionTarget,
1644 {
1645 for_each_value_type!(multi_values_convert_first_match, self, policy, limits)
1646 .map_err(|error| self.contextual_conversion_error(error, true))
1647 }
1648
1649 /// Converts the first stored value using an existing conversion session.
1650 ///
1651 /// # Type Parameters
1652 ///
1653 /// * `T` - Target element type supported by the shared conversion layer.
1654 ///
1655 /// # Parameters
1656 ///
1657 /// * `session` - Caller-owned session providing policy, limits, and budget.
1658 ///
1659 /// # Returns
1660 ///
1661 /// The converted first element.
1662 ///
1663 /// # Errors
1664 ///
1665 /// Returns a structured missing, conversion, or budget error when the
1666 /// first element cannot be produced as `T`.
1667 pub fn to_first_in<T>(&self, session: &mut ConversionSession<'_>) -> ValueResult<T>
1668 where
1669 T: DataConversionTarget,
1670 {
1671 for_each_value_type!(multi_values_convert_first_in_match, self, session)
1672 .map_err(|error| self.contextual_conversion_error(error, true))
1673 }
1674
1675 /// Converts the first stored value to `T` using conversion policy and
1676 /// limits, or returns `default` when the collection is unset.
1677 ///
1678 /// # Type Parameters
1679 ///
1680 /// * `T` - Target conversion type.
1681 ///
1682 /// # Parameters
1683 ///
1684 /// * `default` - Value used only when storage is unset.
1685 /// * `policy` - Conversion policy forwarded to `qubit_datatype`.
1686 /// * `limits` - Conversion limits forwarded to `qubit_datatype`.
1687 ///
1688 /// # Returns
1689 ///
1690 /// The converted first item, or `default` for an unset collection.
1691 ///
1692 /// # Errors
1693 ///
1694 /// Returns an empty-collection error, a policy-missing error at item zero,
1695 /// or an ordinary conversion error for concrete values that cannot be
1696 /// converted under the provided policy and limits. These errors do not
1697 /// invoke the fallback.
1698 ///
1699 /// # Examples
1700 ///
1701 /// ```rust
1702 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1703 /// use qubit_datatype::{ConversionLimits, ConversionPolicy, DataType};
1704 /// use qubit_value::MultiValues;
1705 ///
1706 /// let policy = ConversionPolicy::env_friendly();
1707 /// let limits = ConversionLimits::default();
1708 /// let unset = MultiValues::new_unset(DataType::String);
1709 /// assert_eq!(unset.to_first_or_with::<u16>(8080, &policy, &limits)?, 8080);
1710 ///
1711 /// let concrete = MultiValues::new([""]);
1712 /// assert!(concrete.to_first_or_with::<u16>(8080, &policy, &limits).is_err());
1713 /// # Ok(())
1714 /// # }
1715 /// ```
1716 #[inline]
1717 pub fn to_first_or_with<T>(
1718 &self,
1719 default: impl IntoValueDefault<T>,
1720 policy: &ConversionPolicy,
1721 limits: &ConversionLimits,
1722 ) -> ValueResult<T>
1723 where
1724 T: DataConversionTarget,
1725 {
1726 match self.to_first_with(policy, limits) {
1727 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => {
1728 Ok(default.into_value_default())
1729 }
1730 result => result,
1731 }
1732 }
1733
1734 /// Converts the first value with the provided policy and limits, or calls
1735 /// `default` when the collection is unset.
1736 ///
1737 /// # Type Parameters
1738 ///
1739 /// * `T` - Target conversion type.
1740 /// * `F` - Deferred fallback producing `T`.
1741 ///
1742 /// # Parameters
1743 ///
1744 /// * `default` - Callback invoked only for unset storage.
1745 /// * `policy` - Conversion policy forwarded to the shared converter.
1746 /// * `limits` - Conversion limits forwarded to the shared converter.
1747 ///
1748 /// # Returns
1749 ///
1750 /// The converted first item or the callback result for an unset
1751 /// collection.
1752 ///
1753 /// # Errors
1754 ///
1755 /// Returns an empty-collection error or a conversion error for concrete
1756 /// values. A policy-missing collection item, including item zero, remains
1757 /// an error and does not invoke the callback.
1758 #[inline]
1759 pub fn to_first_or_else_with<T, F>(
1760 &self,
1761 default: F,
1762 policy: &ConversionPolicy,
1763 limits: &ConversionLimits,
1764 ) -> ValueResult<T>
1765 where
1766 T: DataConversionTarget,
1767 F: FnOnce() -> T,
1768 {
1769 match self.to_first_with(policy, limits) {
1770 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => Ok(default()),
1771 result => result,
1772 }
1773 }
1774
1775 /// Converts all stored values to `T`.
1776 ///
1777 /// Unlike [`Self::get`], this method uses shared `DataConverter` conversion
1778 /// rules for every element instead of strict type matching. A concrete
1779 /// empty vector returns an empty vector; an unset container reports a
1780 /// missing-value conversion error.
1781 ///
1782 /// # Type Parameters
1783 ///
1784 /// * `T` - Target element type.
1785 ///
1786 /// # Returns
1787 ///
1788 /// A vector containing all converted values in the original order.
1789 ///
1790 /// # Errors
1791 ///
1792 /// Returns the first conversion error encountered while converting an
1793 /// element.
1794 #[inline]
1795 pub fn to_list<T>(&self) -> ValueResult<Vec<T>>
1796 where
1797 T: DataConversionTarget,
1798 {
1799 self.to_list_with(ConversionPolicy::default_ref(), ConversionLimits::default_ref())
1800 }
1801
1802 /// Converts all stored values to `T`, or returns `default` when the
1803 /// collection is unset.
1804 ///
1805 /// # Type Parameters
1806 ///
1807 /// * `T` - Target element type.
1808 ///
1809 /// # Parameters
1810 ///
1811 /// * `default` - List used only when storage is unset.
1812 ///
1813 /// # Returns
1814 ///
1815 /// All converted items, or `default` for an unset collection. A concrete
1816 /// empty collection produces an empty vector; a policy-missing item or an
1817 /// ordinary conversion error never uses the default.
1818 ///
1819 /// # Errors
1820 ///
1821 /// Returns the first indexed item-conversion error for concrete storage.
1822 /// A policy-missing collection item is preserved and does not use the
1823 /// fallback.
1824 #[inline]
1825 pub fn to_list_or<T>(&self, default: impl IntoValueDefault<Vec<T>>) -> ValueResult<Vec<T>>
1826 where
1827 T: DataConversionTarget,
1828 {
1829 match self.to_list() {
1830 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => {
1831 Ok(default.into_value_default())
1832 }
1833 result => result,
1834 }
1835 }
1836
1837 /// Converts all values or calls `default` when the collection is unset.
1838 ///
1839 /// # Type Parameters
1840 ///
1841 /// * `T` - Target element conversion type.
1842 /// * `F` - Deferred fallback producing the complete list.
1843 ///
1844 /// # Parameters
1845 ///
1846 /// * `default` - Callback invoked only for unset storage.
1847 ///
1848 /// # Returns
1849 ///
1850 /// The converted list or the callback result for an unset collection.
1851 ///
1852 /// # Errors
1853 ///
1854 /// Returns the first indexed item-conversion error for concrete storage
1855 /// without invoking the callback.
1856 #[inline]
1857 pub fn to_list_or_else<T, F>(&self, default: F) -> ValueResult<Vec<T>>
1858 where
1859 T: DataConversionTarget,
1860 F: FnOnce() -> Vec<T>,
1861 {
1862 match self.to_list() {
1863 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => Ok(default()),
1864 result => result,
1865 }
1866 }
1867
1868 /// Converts all stored values to `T` using conversion policy and limits.
1869 ///
1870 /// Stored strings are collection items and are never split again by scalar
1871 /// string collection policy.
1872 ///
1873 /// # Type Parameters
1874 ///
1875 /// * `T` - Target element type.
1876 ///
1877 /// # Parameters
1878 ///
1879 /// * `policy` - Conversion policy forwarded to `qubit_datatype`.
1880 /// * `limits` - Conversion limits forwarded to `qubit_datatype`.
1881 ///
1882 /// # Returns
1883 ///
1884 /// A vector containing all converted values in the original order.
1885 ///
1886 /// # Errors
1887 ///
1888 /// Returns the first conversion or budget error encountered while
1889 /// converting an element. A policy-missing item returns
1890 /// [`ValueError::Missing`]; its source index is retained by
1891 /// [`crate::ValueMissing::source_index`]. Other element conversion failures
1892 /// can return [`ValueError::ListConversion`].
1893 pub fn to_list_with<T>(&self, policy: &ConversionPolicy, limits: &ConversionLimits) -> ValueResult<Vec<T>>
1894 where
1895 T: DataConversionTarget,
1896 {
1897 for_each_value_type!(multi_values_convert_list_match, self, policy, limits)
1898 .map_err(|error| self.contextual_conversion_error(error, false))
1899 }
1900
1901 /// Converts every stored value using an existing conversion session.
1902 ///
1903 /// # Type Parameters
1904 ///
1905 /// * `T` - Target element type supported by the shared conversion layer.
1906 ///
1907 /// # Parameters
1908 ///
1909 /// * `session` - Caller-owned session providing policy, limits, and budget.
1910 ///
1911 /// # Returns
1912 ///
1913 /// Converted elements in their original order.
1914 ///
1915 /// # Errors
1916 ///
1917 /// Returns the first structured missing, conversion, or budget error.
1918 pub fn to_list_in<T>(&self, session: &mut ConversionSession<'_>) -> ValueResult<Vec<T>>
1919 where
1920 T: DataConversionTarget,
1921 {
1922 for_each_value_type!(multi_values_convert_list_in_match, self, session)
1923 .map_err(|error| self.contextual_conversion_error(error, false))
1924 }
1925
1926 /// Converts all stored values to `T` using conversion policy and limits,
1927 /// or returns `default` when the collection is unset.
1928 ///
1929 /// # Type Parameters
1930 ///
1931 /// * `T` - Target element type.
1932 ///
1933 /// # Parameters
1934 ///
1935 /// * `default` - List used only when storage is unset.
1936 /// * `policy` - Conversion policy forwarded to `qubit_datatype`.
1937 /// * `limits` - Conversion limits forwarded to `qubit_datatype`.
1938 ///
1939 /// # Returns
1940 ///
1941 /// All converted items, or `default` for an unset collection. A concrete
1942 /// empty collection produces an empty vector; a missing collection item
1943 /// or ordinary conversion error never uses the default.
1944 ///
1945 /// # Errors
1946 ///
1947 /// Returns the first indexed item-conversion error for concrete storage.
1948 /// Missing collection items and ordinary conversion errors are preserved.
1949 #[inline]
1950 pub fn to_list_or_with<T>(
1951 &self,
1952 default: impl IntoValueDefault<Vec<T>>,
1953 policy: &ConversionPolicy,
1954 limits: &ConversionLimits,
1955 ) -> ValueResult<Vec<T>>
1956 where
1957 T: DataConversionTarget,
1958 {
1959 match self.to_list_with(policy, limits) {
1960 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => {
1961 Ok(default.into_value_default())
1962 }
1963 result => result,
1964 }
1965 }
1966
1967 /// Converts all values with the provided policy and limits, or calls
1968 /// `default` when the collection is unset.
1969 ///
1970 /// # Type Parameters
1971 ///
1972 /// * `T` - Target element conversion type.
1973 /// * `F` - Deferred fallback producing the complete list.
1974 ///
1975 /// # Parameters
1976 ///
1977 /// * `default` - Callback invoked only for unset storage.
1978 /// * `policy` - Conversion policy forwarded to the shared converter.
1979 /// * `limits` - Conversion limits forwarded to the shared converter.
1980 ///
1981 /// # Returns
1982 ///
1983 /// The converted list or the callback result for an unset collection.
1984 ///
1985 /// # Errors
1986 ///
1987 /// Returns the first indexed policy-missing item or ordinary conversion
1988 /// error for concrete storage without invoking the callback.
1989 #[inline]
1990 pub fn to_list_or_else_with<T, F>(
1991 &self,
1992 default: F,
1993 policy: &ConversionPolicy,
1994 limits: &ConversionLimits,
1995 ) -> ValueResult<Vec<T>>
1996 where
1997 T: DataConversionTarget,
1998 F: FnOnce() -> Vec<T>,
1999 {
2000 match self.to_list_with(policy, limits) {
2001 Err(ValueError::Missing(missing)) if missing.is_defaultable_for_conversion() => Ok(default()),
2002 result => result,
2003 }
2004 }
2005
2006 /// Enriches only missing failures after conversion, retaining
2007 /// resource-error priority.
2008 ///
2009 /// # Parameters
2010 ///
2011 /// * `error` - Conversion failure to enrich only when it denotes a missing
2012 /// value.
2013 /// * `first` - Whether to attach the first-item index to missing-value
2014 /// context.
2015 ///
2016 /// # Returns
2017 ///
2018 /// The missing failure with storage context, or the original non-missing
2019 /// failure.
2020 fn contextual_conversion_error(&self, error: ValueError, first: bool) -> ValueError {
2021 let ValueError::Missing(missing) = error else {
2022 return error;
2023 };
2024 let reason = if self.is_unset() {
2025 crate::ValueMissingReason::UnsetCollection
2026 } else if self.is_empty() {
2027 crate::ValueMissingReason::EmptyCollection
2028 } else {
2029 crate::ValueMissingReason::Conversion
2030 };
2031 let missing = missing.with_storage(self.data_type(), reason);
2032 ValueError::Missing(if first { missing.with_first_index() } else { missing })
2033 }
2034}
2035
2036impl MultiValues {
2037 // ========================================================================
2038 // Get first value (as single value access)
2039 // ========================================================================
2040
2041 impl_get_first_value! {
2042 /// Get the first boolean value.
2043 ///
2044 /// # Returns
2045 ///
2046 /// If types match and a value exists, returns the first boolean value; see `# Errors`.
2047 ///
2048 /// # Examples
2049 ///
2050 /// ```rust
2051 /// use qubit_value::MultiValues;
2052 ///
2053 /// let values = MultiValues::Bool(vec![true, false]);
2054 /// assert_eq!(values.get_first_bool().unwrap(), true);
2055 /// ```
2056 copy: get_first_bool, Bool, bool, DataType::Bool
2057 }
2058
2059 impl_get_first_value! {
2060 /// Get the first character value
2061 ///
2062 /// # Returns
2063 ///
2064 /// If types match and a value exists, returns the first character value; see `# Errors`.
2065 copy: get_first_char, Char, char, DataType::Char
2066 }
2067
2068 impl_get_first_value! {
2069 /// Get the first int8 value
2070 ///
2071 /// # Returns
2072 ///
2073 /// If types match and a value exists, returns the first int8 value; see `# Errors`.
2074 copy: get_first_int8, Int8, i8, DataType::Int8
2075 }
2076
2077 impl_get_first_value! {
2078 /// Get the first int16 value
2079 ///
2080 /// # Returns
2081 ///
2082 /// If types match and a value exists, returns the first int16 value; see `# Errors`.
2083 copy: get_first_int16, Int16, i16, DataType::Int16
2084 }
2085
2086 impl_get_first_value! {
2087 /// Get the first int32 value
2088 ///
2089 /// # Returns
2090 ///
2091 /// If types match and a value exists, returns the first int32 value; see `# Errors`.
2092 copy: get_first_int32, Int32, i32, DataType::Int32
2093 }
2094
2095 impl_get_first_value! {
2096 /// Get the first int64 value
2097 ///
2098 /// # Returns
2099 ///
2100 /// If types match and a value exists, returns the first int64 value; see `# Errors`.
2101 copy: get_first_int64, Int64, i64, DataType::Int64
2102 }
2103
2104 impl_get_first_value! {
2105 /// Get the first int128 value
2106 ///
2107 /// # Returns
2108 ///
2109 /// If types match and a value exists, returns the first int128 value; see `# Errors`.
2110 copy: get_first_int128, Int128, i128, DataType::Int128
2111 }
2112
2113 impl_get_first_value! {
2114 /// Get the first uint8 value
2115 ///
2116 /// # Returns
2117 ///
2118 /// If types match and a value exists, returns the first uint8 value; see `# Errors`.
2119 copy: get_first_uint8, UInt8, u8, DataType::UInt8
2120 }
2121
2122 impl_get_first_value! {
2123 /// Get the first uint16 value
2124 ///
2125 /// # Returns
2126 ///
2127 /// If types match and a value exists, returns the first uint16 value; see `# Errors`.
2128 copy: get_first_uint16, UInt16, u16, DataType::UInt16
2129 }
2130
2131 impl_get_first_value! {
2132 /// Get the first uint32 value
2133 ///
2134 /// # Returns
2135 ///
2136 /// If types match and a value exists, returns the first uint32 value; see `# Errors`.
2137 copy: get_first_uint32, UInt32, u32, DataType::UInt32
2138 }
2139
2140 impl_get_first_value! {
2141 /// Get the first uint64 value
2142 ///
2143 /// # Returns
2144 ///
2145 /// If types match and a value exists, returns the first uint64 value; see `# Errors`.
2146 copy: get_first_uint64, UInt64, u64, DataType::UInt64
2147 }
2148
2149 impl_get_first_value! {
2150 /// Get the first uint128 value
2151 ///
2152 /// # Returns
2153 ///
2154 /// If types match and a value exists, returns the first uint128 value; see `# Errors`.
2155 copy: get_first_uint128, UInt128, u128, DataType::UInt128
2156 }
2157
2158 impl_get_first_value! {
2159 /// Get the first float32 value
2160 ///
2161 /// # Returns
2162 ///
2163 /// If types match and a value exists, returns the first float32 value; see `# Errors`.
2164 copy: get_first_float32, Float32, f32, DataType::Float32
2165 }
2166
2167 impl_get_first_value! {
2168 /// Get the first float64 value
2169 ///
2170 /// # Returns
2171 ///
2172 /// If types match and a value exists, returns the first float64 value; see `# Errors`.
2173 copy: get_first_float64, Float64, f64, DataType::Float64
2174 }
2175
2176 impl_get_first_value! {
2177 /// Get the first string reference
2178 ///
2179 /// # Returns
2180 ///
2181 /// If types match and a value exists, returns a reference to the first
2182 /// string; see `# Errors`.
2183 ref: get_first_string, String, &str, DataType::String, |s: &String| s.as_str()
2184 }
2185
2186 #[cfg(feature = "chrono")]
2187 impl_get_first_value! {
2188 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2189 /// Get the first date value
2190 ///
2191 /// # Returns
2192 ///
2193 /// If types match and a value exists, returns the first date value; see `# Errors`.
2194 copy: get_first_date, Date, NaiveDate, DataType::Date
2195 }
2196
2197 #[cfg(feature = "chrono")]
2198 impl_get_first_value! {
2199 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2200 /// Get the first time value
2201 ///
2202 /// # Returns
2203 ///
2204 /// If types match and a value exists, returns the first time value; see `# Errors`.
2205 copy: get_first_time, Time, NaiveTime, DataType::Time
2206 }
2207
2208 #[cfg(feature = "chrono")]
2209 impl_get_first_value! {
2210 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2211 /// Get the first datetime value
2212 ///
2213 /// # Returns
2214 ///
2215 /// If types match and a value exists, returns the first datetime value; see `# Errors`.
2216 copy: get_first_datetime, DateTime, NaiveDateTime, DataType::DateTime
2217 }
2218
2219 #[cfg(feature = "chrono")]
2220 impl_get_first_value! {
2221 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2222 /// Get the first UTC instant value
2223 ///
2224 /// # Returns
2225 ///
2226 /// If types match and a value exists, returns the first UTC instant
2227 /// value; see `# Errors`.
2228 copy: get_first_instant, Instant, DateTime<Utc>, DataType::Instant
2229 }
2230
2231 #[cfg(feature = "big-integer")]
2232 impl_get_first_value! {
2233 #[cfg_attr(docsrs, doc(cfg(feature = "big-integer")))]
2234 /// Get the first big integer value
2235 ///
2236 /// # Returns
2237 ///
2238 /// If types match and a value exists, returns the first big integer
2239 /// value; see `# Errors`.
2240 ref: get_first_biginteger, BigInteger, BigInt, DataType::BigInteger, |v: &BigInt| v.clone()
2241 }
2242
2243 #[cfg(feature = "big-decimal")]
2244 impl_get_first_value! {
2245 #[cfg_attr(docsrs, doc(cfg(feature = "big-decimal")))]
2246 /// Get the first big decimal value
2247 ///
2248 /// # Returns
2249 ///
2250 /// If types match and a value exists, returns the first big decimal
2251 /// value; see `# Errors`.
2252 ref: get_first_bigdecimal, BigDecimal, BigDecimal, DataType::BigDecimal, |v: &BigDecimal| v.clone()
2253 }
2254
2255 impl_get_first_value! {
2256 /// Get the first Duration value
2257 ///
2258 /// # Returns
2259 ///
2260 /// The first duration when the stored type matches.
2261 copy: get_first_duration, Duration, Duration, DataType::Duration
2262 }
2263
2264 #[cfg(feature = "url")]
2265 impl_get_first_value! {
2266 #[cfg_attr(docsrs, doc(cfg(feature = "url")))]
2267 /// Get the first Url value
2268 ///
2269 /// # Returns
2270 ///
2271 /// A clone of the first URL when the stored type matches.
2272 ref: get_first_url, Url, Url, DataType::Url, |v: &Url| v.clone()
2273 }
2274
2275 impl_get_first_value! {
2276 /// Get the first StringMap value
2277 ///
2278 /// # Returns
2279 ///
2280 /// A clone of the first string map when the stored type matches.
2281 ref: get_first_string_map, StringMap, HashMap<String, String>, DataType::StringMap, |v: &HashMap<String, String>| v.clone()
2282 }
2283
2284 #[cfg(feature = "json")]
2285 impl_get_first_value! {
2286 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
2287 /// Get the first Json value
2288 ///
2289 /// # Returns
2290 ///
2291 /// A clone of the first JSON value when the stored type matches.
2292 ref: get_first_json, Json, JsonValue, DataType::Json, |v: &JsonValue| v.clone()
2293 }
2294
2295 // ========================================================================
2296 // Get all values (type checking)
2297 // ========================================================================
2298
2299 impl_get_multi_values! {
2300 /// Get reference to all boolean values
2301 ///
2302 /// # Returns
2303 ///
2304 /// If types match, returns a reference to the boolean value array; see `# Errors`.
2305 ///
2306 /// # Examples
2307 ///
2308 /// ```rust
2309 /// use qubit_value::MultiValues;
2310 ///
2311 /// let values = MultiValues::Bool(vec![true, false, true]);
2312 /// assert_eq!(values.get_bools().unwrap(), &[true, false, true]);
2313 /// ```
2314 slice: get_bools, Bool, bool, DataType::Bool
2315 }
2316
2317 impl_get_multi_values! {
2318 /// Get reference to all character values
2319 ///
2320 /// # Returns
2321 ///
2322 /// If types match, returns a reference to the character value array; see `# Errors`.
2323 slice: get_chars, Char, char, DataType::Char
2324 }
2325
2326 impl_get_multi_values! {
2327 /// Get reference to all int8 values
2328 ///
2329 /// # Returns
2330 ///
2331 /// If types match, returns a reference to the int8 value array; see `# Errors`.
2332 slice: get_int8s, Int8, i8, DataType::Int8
2333 }
2334
2335 impl_get_multi_values! {
2336 /// Get reference to all int16 values
2337 ///
2338 /// # Returns
2339 ///
2340 /// If types match, returns a reference to the int16 value array; see `# Errors`.
2341 slice: get_int16s, Int16, i16, DataType::Int16
2342 }
2343
2344 impl_get_multi_values! {
2345 /// Get reference to all int32 values
2346 ///
2347 /// # Returns
2348 ///
2349 /// If types match, returns a reference to the int32 value array; see `# Errors`.
2350 slice: get_int32s, Int32, i32, DataType::Int32
2351 }
2352
2353 impl_get_multi_values! {
2354 /// Get reference to all int64 values
2355 ///
2356 /// # Returns
2357 ///
2358 /// If types match, returns a reference to the int64 value array; see `# Errors`.
2359 slice: get_int64s, Int64, i64, DataType::Int64
2360 }
2361
2362 impl_get_multi_values! {
2363 /// Get reference to all int128 values
2364 ///
2365 /// # Returns
2366 ///
2367 /// If types match, returns a reference to the int128 value array; see `# Errors`.
2368 slice: get_int128s, Int128, i128, DataType::Int128
2369 }
2370
2371 impl_get_multi_values! {
2372 /// Get reference to all uint8 values
2373 ///
2374 /// # Returns
2375 ///
2376 /// If types match, returns a reference to the uint8 value array; see `# Errors`.
2377 slice: get_uint8s, UInt8, u8, DataType::UInt8
2378 }
2379
2380 impl_get_multi_values! {
2381 /// Get reference to all uint16 values
2382 ///
2383 /// # Returns
2384 ///
2385 /// If types match, returns a reference to the uint16 value array; see `# Errors`.
2386 slice: get_uint16s, UInt16, u16, DataType::UInt16
2387 }
2388
2389 impl_get_multi_values! {
2390 /// Get reference to all uint32 values
2391 ///
2392 /// # Returns
2393 ///
2394 /// If types match, returns a reference to the uint32 value array; see `# Errors`.
2395 slice: get_uint32s, UInt32, u32, DataType::UInt32
2396 }
2397
2398 impl_get_multi_values! {
2399 /// Get reference to all uint64 values
2400 ///
2401 /// # Returns
2402 ///
2403 /// If types match, returns a reference to the uint64 value array; see `# Errors`.
2404 slice: get_uint64s, UInt64, u64, DataType::UInt64
2405 }
2406
2407 impl_get_multi_values! {
2408 /// Get reference to all uint128 values
2409 ///
2410 /// # Returns
2411 ///
2412 /// If types match, returns a reference to the uint128 value array; see `# Errors`.
2413 slice: get_uint128s, UInt128, u128, DataType::UInt128
2414 }
2415
2416 impl_get_multi_values! {
2417 /// Get reference to all float32 values
2418 ///
2419 /// # Returns
2420 ///
2421 /// If types match, returns a reference to the float32 value array; see `# Errors`.
2422 slice: get_float32s, Float32, f32, DataType::Float32
2423 }
2424
2425 impl_get_multi_values! {
2426 /// Get reference to all float64 values
2427 ///
2428 /// # Returns
2429 ///
2430 /// If types match, returns a reference to the float64 value array; see `# Errors`.
2431 slice: get_float64s, Float64, f64, DataType::Float64
2432 }
2433
2434 impl_get_multi_values! {
2435 /// Get reference to all strings
2436 ///
2437 /// # Returns
2438 ///
2439 /// If types match, returns a reference to the string array; otherwise
2440 /// returns an error
2441 vec: get_strings, String, String, DataType::String
2442 }
2443
2444 #[cfg(feature = "chrono")]
2445 impl_get_multi_values! {
2446 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2447 /// Get reference to all date values
2448 ///
2449 /// # Returns
2450 ///
2451 /// If types match, returns a reference to the date value array; see `# Errors`.
2452 slice: get_dates, Date, NaiveDate, DataType::Date
2453 }
2454
2455 #[cfg(feature = "chrono")]
2456 impl_get_multi_values! {
2457 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2458 /// Get reference to all time values
2459 ///
2460 /// # Returns
2461 ///
2462 /// If types match, returns a reference to the time value array; see `# Errors`.
2463 slice: get_times, Time, NaiveTime, DataType::Time
2464 }
2465
2466 #[cfg(feature = "chrono")]
2467 impl_get_multi_values! {
2468 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2469 /// Get reference to all datetime values
2470 ///
2471 /// # Returns
2472 ///
2473 /// If types match, returns a reference to the datetime value array; see `# Errors`.
2474 slice: get_datetimes, DateTime, NaiveDateTime, DataType::DateTime
2475 }
2476
2477 #[cfg(feature = "chrono")]
2478 impl_get_multi_values! {
2479 #[cfg_attr(docsrs, doc(cfg(feature = "chrono")))]
2480 /// Get reference to all UTC instant values
2481 ///
2482 /// # Returns
2483 ///
2484 /// If types match, returns a reference to the UTC instant value array; see `# Errors`.
2485 slice: get_instants, Instant, DateTime<Utc>, DataType::Instant
2486 }
2487
2488 #[cfg(feature = "big-integer")]
2489 impl_get_multi_values! {
2490 #[cfg_attr(docsrs, doc(cfg(feature = "big-integer")))]
2491 /// Get reference to all big integers
2492 ///
2493 /// # Returns
2494 ///
2495 /// If types match, returns a reference to the big integer array; see `# Errors`.
2496 vec: get_bigintegers, BigInteger, BigInt, DataType::BigInteger
2497 }
2498
2499 #[cfg(feature = "big-decimal")]
2500 impl_get_multi_values! {
2501 #[cfg_attr(docsrs, doc(cfg(feature = "big-decimal")))]
2502 /// Get reference to all big decimals
2503 ///
2504 /// # Returns
2505 ///
2506 /// If types match, returns a reference to the big decimal array; see `# Errors`.
2507 vec: get_bigdecimals, BigDecimal, BigDecimal, DataType::BigDecimal
2508 }
2509
2510 impl_get_multi_values! {
2511 /// Get reference to all Duration values
2512 ///
2513 /// # Returns
2514 ///
2515 /// A slice containing all stored durations.
2516 slice: get_durations, Duration, Duration, DataType::Duration
2517 }
2518
2519 #[cfg(feature = "url")]
2520 impl_get_multi_values! {
2521 #[cfg_attr(docsrs, doc(cfg(feature = "url")))]
2522 /// Get reference to all Url values
2523 ///
2524 /// # Returns
2525 ///
2526 /// A borrowed slice containing all stored URLs. The slice borrows from this
2527 /// collection; no elements are cloned.
2528 vec: get_urls, Url, Url, DataType::Url
2529 }
2530
2531 impl_get_multi_values! {
2532 /// Get reference to all StringMap values
2533 ///
2534 /// # Returns
2535 ///
2536 /// A borrowed slice containing all stored string maps. The slice borrows from
2537 /// this collection; no maps or entries are cloned.
2538 vec: get_string_maps, StringMap, HashMap<String, String>, DataType::StringMap
2539 }
2540
2541 #[cfg(feature = "json")]
2542 impl_get_multi_values! {
2543 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
2544 /// Get reference to all Json values
2545 ///
2546 /// # Returns
2547 ///
2548 /// A borrowed slice containing all stored JSON values. The slice borrows from
2549 /// this collection; no JSON trees are cloned.
2550 vec: get_jsons, Json, JsonValue, DataType::Json
2551 }
2552}