Skip to main content

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}