Skip to main content

qubit_value/
value_container.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
9//! Explicit scalar-or-collection value storage.
10
11use std::mem::replace;
12use std::slice::from_ref;
13
14#[cfg(feature = "converter")]
15use qubit_datatype::ConversionLimits;
16#[cfg(feature = "converter")]
17use qubit_datatype::ConversionPolicy;
18#[cfg(feature = "converter")]
19use qubit_datatype::ConversionSession;
20#[cfg(feature = "converter")]
21use qubit_datatype::DataConversionTarget;
22use qubit_datatype::DataType;
23#[cfg(feature = "converter")]
24use qubit_datatype::ScalarStringDataConverters;
25#[cfg(all(feature = "converter", feature = "json"))]
26use serde_json::Value as JsonValue;
27
28use crate::MultiValues;
29use crate::StrictValueRead;
30use crate::Value;
31use crate::ValueError;
32use crate::ValueResult;
33use crate::multi_values::MultiValuesRepr;
34#[cfg(feature = "converter")]
35use crate::value::ValueRef;
36use crate::value::ValueRepr;
37
38/// A typed value whose scalar or collection shape is explicit.
39///
40/// The shape is never inferred from collection length. In particular,
41/// `Scalar(Value::Int32(42))` and
42/// `Collection(MultiValues::Int32(vec![42]))` remain distinguishable through
43/// conversion and serialization boundaries.
44///
45/// # Examples
46///
47/// ```
48/// use qubit_value::ValueContainer;
49///
50/// let scalar = ValueContainer::from(42_i32);
51/// let collection = ValueContainer::from(vec![42_i32]);
52/// assert!(scalar.is_scalar());
53/// assert!(collection.is_collection());
54/// ```
55#[must_use]
56#[derive(Debug, Clone, PartialEq, Eq, Hash)]
57pub enum ValueContainer {
58    /// One typed value.
59    Scalar(
60        /// Stored scalar value.
61        Value,
62    ),
63    /// A homogeneous typed collection.
64    Collection(
65        /// Stored homogeneous collection.
66        MultiValues,
67    ),
68}
69
70/// Implements scalar and collection conversions from the shared value table.
71macro_rules! impl_value_container_from_table {
72    (
73        ;
74        $(
75            (
76                [$($cfg:meta),*],
77                $variant:ident,
78                $type:ty,
79                $data_type:expr,
80                $materialization:ident,
81                $json_class:ident,
82                $number_projection:ident,
83                $value_doc:literal,
84                $multi_doc:literal
85                $(, $_wire:tt)*
86            )
87        ),+ $(,)?
88    ) => {
89        $(
90            $(#[$cfg])*
91            $(#[cfg_attr(docsrs, doc($cfg))])*
92            impl From<$type> for ValueContainer {
93                /// Creates a scalar container by taking ownership of `value`.
94                ///
95                /// # Parameters
96                ///
97                /// * `value` - Input converted with the ownership behavior described above.
98                ///
99                /// # Returns
100                ///
101                /// A container preserving the input data type and scalar or collection shape.
102                #[inline(always)]
103                fn from(value: $type) -> Self {
104                    Self::Scalar(Value::$variant(value))
105                }
106            }
107
108            $(#[$cfg])*
109            $(#[cfg_attr(docsrs, doc($cfg))])*
110            impl From<Vec<$type>> for ValueContainer {
111                /// Takes ownership of the vector and its element storage without cloning elements.
112                /// An empty vector creates a concrete empty collection.
113                ///
114                /// # Parameters
115                ///
116                /// * `values` - Input converted with the ownership behavior described above.
117                ///
118                /// # Returns
119                ///
120                /// A container preserving the input data type and scalar or collection shape.
121                #[inline(always)]
122                fn from(values: Vec<$type>) -> Self {
123                    Self::Collection(MultiValues::$variant(values))
124                }
125            }
126
127            $(#[$cfg])*
128            $(#[cfg_attr(docsrs, doc($cfg))])*
129            impl From<&[$type]> for ValueContainer {
130                /// Clones the elements into an owned collection, preserving order.
131                /// An empty slice creates a concrete empty collection.
132                ///
133                /// # Parameters
134                ///
135                /// * `values` - Input converted with the ownership behavior described above.
136                ///
137                /// # Returns
138                ///
139                /// A container preserving the input data type and scalar or collection shape.
140                #[inline]
141                fn from(values: &[$type]) -> Self {
142                    Self::Collection(MultiValues::$variant(values.to_vec()))
143                }
144            }
145
146            $(#[$cfg])*
147            $(#[cfg_attr(docsrs, doc($cfg))])*
148            impl From<&Vec<$type>> for ValueContainer {
149                /// Clones the elements into an owned collection, preserving order.
150                /// An empty vector creates a concrete empty collection.
151                ///
152                /// # Parameters
153                ///
154                /// * `values` - Input converted with the ownership behavior described above.
155                ///
156                /// # Returns
157                ///
158                /// A container preserving the input data type and scalar or collection shape.
159                #[inline]
160                fn from(values: &Vec<$type>) -> Self {
161                    Self::Collection(MultiValues::$variant(values.clone()))
162                }
163            }
164
165            $(#[$cfg])*
166            $(#[cfg_attr(docsrs, doc($cfg))])*
167            impl<const N: usize> From<[$type; N]> for ValueContainer {
168                /// Moves the array elements into a newly allocated vector, preserving order.
169                /// An empty array creates a concrete empty collection.
170                ///
171                /// # Type Parameters
172                ///
173                /// * `N` - Number of input array elements.
174                ///
175                /// # Parameters
176                ///
177                /// * `values` - Input converted with the ownership behavior described above.
178                ///
179                /// # Returns
180                ///
181                /// A container preserving the input data type and scalar or collection shape.
182                #[inline]
183                fn from(values: [$type; N]) -> Self {
184                    Self::Collection(MultiValues::$variant(Vec::from(values)))
185                }
186            }
187
188            $(#[$cfg])*
189            $(#[cfg_attr(docsrs, doc($cfg))])*
190            impl<const N: usize> From<&[$type; N]> for ValueContainer {
191                /// Clones the elements into an owned collection, preserving order.
192                /// An empty array creates a concrete empty collection.
193                ///
194                /// # Type Parameters
195                ///
196                /// * `N` - Number of input array elements.
197                ///
198                /// # Parameters
199                ///
200                /// * `values` - Input converted with the ownership behavior described above.
201                ///
202                /// # Returns
203                ///
204                /// A container preserving the input data type and scalar or collection shape.
205                #[inline]
206                fn from(values: &[$type; N]) -> Self {
207                    Self::Collection(MultiValues::$variant(values.to_vec()))
208                }
209            }
210        )+
211    };
212}
213
214for_each_value_type!(impl_value_container_from_table);
215
216/// Builds a typed collection from one or two same-typed scalar values.
217macro_rules! value_container_pair_match {
218    ($first:expr, $second: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)*)),+ $(,)?) => {
219        match ($first.repr, $second.repr) {
220            $(
221                $(#[$cfg])*
222                (ValueRepr::$variant(first), ValueRepr::$variant(second)) => {
223                    MultiValues::$variant(vec![
224                        value_storage_into_multi!($variant, first),
225                        value_storage_into_multi!($variant, second),
226                    ])
227                }
228            )+
229            $(
230                $(#[$cfg])*
231                (ValueRepr::Unset(_), ValueRepr::$variant(second)) => {
232                    MultiValues::$variant(vec![value_storage_into_multi!($variant, second)])
233                }
234            )+
235            _ => unreachable!(),
236        }
237    };
238}
239
240/// Pushes a same-typed scalar directly into collection storage.
241macro_rules! value_container_push_match {
242    ($collection:expr, $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)*)),+ $(,)?) => {
243        match (&mut $collection.repr, $value.repr) {
244            $(
245                $(#[$cfg])*
246                (MultiValuesRepr::$variant(values), ValueRepr::$variant(value)) => {
247                    values.push(value_storage_into_multi!($variant, value))
248                },
249            )+
250            $(
251                $(#[$cfg])*
252                (slot @ MultiValuesRepr::Unset(_), ValueRepr::$variant(value)) => {
253                    *slot = MultiValuesRepr::$variant(vec![value_storage_into_multi!($variant, value)]);
254                }
255            )+
256            _ => unreachable!(),
257        }
258    };
259}
260
261impl From<&str> for ValueContainer {
262    /// Copies the text into an owned scalar string.
263    ///
264    /// # Parameters
265    ///
266    /// * `value` - Input converted with the ownership behavior described above.
267    ///
268    /// # Returns
269    ///
270    /// A container preserving the input data type and scalar or collection
271    /// shape.
272    #[inline]
273    fn from(value: &str) -> Self {
274        Self::Scalar(Value::String(value.to_string()))
275    }
276}
277
278impl<'a> From<Vec<&'a str>> for ValueContainer {
279    /// Copies each string into an owned collection, preserving order.
280    /// An empty vector creates a concrete empty collection.
281    ///
282    /// # Parameters
283    ///
284    /// * `values` - Input converted with the ownership behavior described
285    ///   above.
286    ///
287    /// # Returns
288    ///
289    /// A container preserving the input data type and scalar or collection
290    /// shape.
291    #[inline]
292    fn from(values: Vec<&'a str>) -> Self {
293        Self::Collection(MultiValues::from(values))
294    }
295}
296
297impl<'a, 'b> From<&'a [&'b str]> for ValueContainer {
298    /// Copies each string into an owned collection, preserving order.
299    /// An empty slice creates a concrete empty collection.
300    ///
301    /// # Parameters
302    ///
303    /// * `values` - Input converted with the ownership behavior described
304    ///   above.
305    ///
306    /// # Returns
307    ///
308    /// A container preserving the input data type and scalar or collection
309    /// shape.
310    #[inline]
311    fn from(values: &'a [&'b str]) -> Self {
312        Self::Collection(MultiValues::from(values))
313    }
314}
315
316impl<'a, 'b> From<&'a Vec<&'b str>> for ValueContainer {
317    /// Copies each string into an owned collection, preserving order.
318    /// An empty vector creates a concrete empty collection.
319    ///
320    /// # Parameters
321    ///
322    /// * `values` - Input converted with the ownership behavior described
323    ///   above.
324    ///
325    /// # Returns
326    ///
327    /// A container preserving the input data type and scalar or collection
328    /// shape.
329    #[inline]
330    fn from(values: &'a Vec<&'b str>) -> Self {
331        Self::Collection(MultiValues::from(values))
332    }
333}
334
335impl<'a, const N: usize> From<[&'a str; N]> for ValueContainer {
336    /// Copies each string into an owned collection, preserving order.
337    /// An empty array creates a concrete empty collection.
338    ///
339    /// # Type Parameters
340    ///
341    /// * `N` - Number of input array elements.
342    ///
343    /// # Parameters
344    ///
345    /// * `values` - Input converted with the ownership behavior described
346    ///   above.
347    ///
348    /// # Returns
349    ///
350    /// A container preserving the input data type and scalar or collection
351    /// shape.
352    #[inline]
353    fn from(values: [&'a str; N]) -> Self {
354        Self::Collection(MultiValues::from(values))
355    }
356}
357
358impl<'a, 'b, const N: usize> From<&'a [&'b str; N]> for ValueContainer {
359    /// Copies each string into an owned collection, preserving order.
360    /// An empty array creates a concrete empty collection.
361    ///
362    /// # Type Parameters
363    ///
364    /// * `N` - Number of input array elements.
365    ///
366    /// # Parameters
367    ///
368    /// * `values` - Input converted with the ownership behavior described
369    ///   above.
370    ///
371    /// # Returns
372    ///
373    /// A container preserving the input data type and scalar or collection
374    /// shape.
375    #[inline]
376    fn from(values: &'a [&'b str; N]) -> Self {
377        Self::Collection(MultiValues::from(values))
378    }
379}
380
381impl From<Value> for ValueContainer {
382    /// Wraps the value as a scalar without cloning it.
383    ///
384    /// # Parameters
385    ///
386    /// * `value` - Input converted with the ownership behavior described above.
387    ///
388    /// # Returns
389    ///
390    /// A container preserving the input data type and scalar or collection
391    /// shape.
392    #[inline]
393    fn from(value: Value) -> Self {
394        Self::Scalar(value)
395    }
396}
397
398impl From<MultiValues> for ValueContainer {
399    /// Wraps the collection without cloning its elements.
400    ///
401    /// # Parameters
402    ///
403    /// * `values` - Input converted with the ownership behavior described
404    ///   above.
405    ///
406    /// # Returns
407    ///
408    /// A container preserving the input data type and scalar or collection
409    /// shape.
410    #[inline]
411    fn from(values: MultiValues) -> Self {
412        Self::Collection(values)
413    }
414}
415
416impl ValueContainer {
417    /// Creates an unset scalar container for a declared data type.
418    ///
419    /// # Parameters
420    ///
421    /// * `data_type` - Declared scalar type while no value is set.
422    ///
423    /// # Returns
424    ///
425    /// A scalar `ValueContainer` with explicit unset storage.
426    #[inline]
427    pub const fn new_unset_scalar(data_type: DataType) -> Self {
428        Self::Scalar(Value::new_unset(data_type))
429    }
430
431    /// Creates an unset collection container for a declared element type.
432    ///
433    /// # Parameters
434    ///
435    /// * `data_type` - Declared element type while no values are set.
436    ///
437    /// # Returns
438    ///
439    /// A collection `ValueContainer` with explicit unset storage.
440    #[inline]
441    pub const fn new_unset_collection(data_type: DataType) -> Self {
442        Self::Collection(MultiValues::new_unset(data_type))
443    }
444
445    /// Strictly borrows the scalar or first collection item without allocating.
446    ///
447    /// The returned reference is tied to this container's lifetime. The
448    /// requested type must match the scalar or collection element type.
449    ///
450    /// # Type Parameters
451    ///
452    /// * `T` - Stored scalar or element type to borrow.
453    ///
454    /// # Returns
455    ///
456    /// A reference to the scalar or the first collection item.
457    ///
458    /// # Errors
459    ///
460    /// Returns [`ValueError::Missing`] when no item is available, or a type
461    /// conversion error when the stored type does not match `T`.
462    ///
463    /// # Examples
464    ///
465    /// ```
466    /// use qubit_value::ValueContainer;
467    /// use qubit_value::ValueError;
468    ///
469    /// let values = ValueContainer::from(vec![String::from("a"), String::from("b")]);
470    /// let first: &String = values.get_first_ref().unwrap();
471    /// assert_eq!(first, "a");
472    /// let empty = ValueContainer::from(Vec::<String>::new());
473    /// assert!(matches!(empty.get_first_ref::<String>(), Err(ValueError::Missing(_))));
474    /// ```
475    #[inline(always)]
476    pub fn get_first_ref<'a, T: ?Sized>(&'a self) -> ValueResult<&'a T>
477    where
478        &'a T: TryFrom<&'a Value, Error = ValueError> + TryFrom<&'a MultiValues, Error = ValueError>,
479    {
480        match self {
481            Self::Scalar(value) => <&'a T>::try_from(value),
482            Self::Collection(values) => <&'a T>::try_from(values),
483        }
484    }
485
486    /// Strictly borrows a scalar as a one-item slice or a complete collection.
487    ///
488    /// The returned slice is tied to this container's lifetime. The requested
489    /// element type must match the stored type.
490    ///
491    /// # Type Parameters
492    ///
493    /// * `T` - Stored element type of the borrowed slice.
494    ///
495    /// # Returns
496    ///
497    /// A one-item slice for a scalar, or all collection items. An empty
498    /// collection returns an empty slice.
499    ///
500    /// # Errors
501    ///
502    /// Returns [`ValueError::Missing`] when an unset scalar or collection has
503    /// the requested type, or [`ValueError::TypeMismatch`] when the stored type
504    /// does not match `T`. A concrete empty collection returns an empty slice.
505    ///
506    /// # Examples
507    ///
508    /// ```
509    /// use qubit_datatype::DataType;
510    ///
511    /// use qubit_value::ValueContainer;
512    /// use qubit_value::ValueError;
513    ///
514    /// let values = ValueContainer::from(vec![String::from("a"), String::from("b")]);
515    /// let all: &[String] = values.get_slice().unwrap();
516    /// assert_eq!(all.len(), 2);
517    /// let empty = ValueContainer::from(Vec::<String>::new());
518    /// assert!(empty.get_slice::<String>().unwrap().is_empty());
519    /// let unset_scalar = ValueContainer::new_unset_scalar(DataType::String);
520    /// let unset_collection = ValueContainer::new_unset_collection(DataType::String);
521    /// assert!(matches!(unset_scalar.get_slice::<String>(), Err(ValueError::Missing(_))));
522    /// assert!(matches!(unset_collection.get_slice::<String>(), Err(ValueError::Missing(_))));
523    /// ```
524    #[inline(always)]
525    pub fn get_slice<'a, T>(&'a self) -> ValueResult<&'a [T]>
526    where
527        &'a T: TryFrom<&'a Value, Error = ValueError>,
528        &'a [T]: TryFrom<&'a MultiValues, Error = ValueError>,
529    {
530        match self {
531            Self::Scalar(value) => value.get_ref().map(from_ref),
532            Self::Collection(values) => values.get_slice(),
533        }
534    }
535
536    /// Returns the stored or declared data type.
537    ///
538    /// # Returns
539    ///
540    /// The scalar or collection element type, including the declared type of
541    /// unset storage.
542    #[inline]
543    pub fn data_type(&self) -> DataType {
544        match self {
545            Self::Scalar(value) => value.data_type(),
546            Self::Collection(values) => values.data_type(),
547        }
548    }
549
550    /// Returns whether this container has scalar shape.
551    ///
552    /// # Returns
553    ///
554    /// `true` for [`ValueContainer::Scalar`].
555    #[inline]
556    #[must_use]
557    pub const fn is_scalar(&self) -> bool {
558        matches!(self, Self::Scalar(_))
559    }
560
561    /// Returns the contained scalar without consuming this container.
562    ///
563    /// # Returns
564    ///
565    /// `Some` for scalar storage, or `None` for collection storage.
566    #[must_use]
567    #[inline]
568    pub const fn as_scalar(&self) -> Option<&Value> {
569        match self {
570            Self::Scalar(value) => Some(value),
571            Self::Collection(_) => None,
572        }
573    }
574
575    /// Returns whether this container has collection shape.
576    ///
577    /// # Returns
578    ///
579    /// `true` for [`ValueContainer::Collection`].
580    #[inline]
581    #[must_use]
582    pub const fn is_collection(&self) -> bool {
583        matches!(self, Self::Collection(_))
584    }
585
586    /// Returns the contained collection without consuming this container.
587    ///
588    /// # Returns
589    ///
590    /// `Some` for collection storage, or `None` for scalar storage.
591    #[must_use]
592    #[inline]
593    pub const fn as_collection(&self) -> Option<&MultiValues> {
594        match self {
595            Self::Scalar(_) => None,
596            Self::Collection(values) => Some(values),
597        }
598    }
599
600    /// Returns whether the shape contains no concrete value or collection.
601    ///
602    /// # Returns
603    ///
604    /// `true` when the contained scalar or collection is unset.
605    #[inline(always)]
606    #[must_use]
607    pub fn is_unset(&self) -> bool {
608        match self {
609            Self::Scalar(value) => value.is_unset(),
610            Self::Collection(values) => values.is_unset(),
611        }
612    }
613
614    /// Returns zero for unset storage, one for a concrete scalar, or the
615    /// concrete collection length.
616    ///
617    /// # Returns
618    ///
619    /// The number of concrete values represented by this container.
620    #[inline]
621    #[must_use]
622    #[allow(clippy::len_without_is_empty)]
623    pub fn len(&self) -> usize {
624        match self {
625            Self::Scalar(value) => usize::from(!value.is_unset()),
626            Self::Collection(values) => values.len(),
627        }
628    }
629
630    /// Tests whether this container represents no concrete values.
631    ///
632    /// # Returns
633    ///
634    /// `true` for unset storage or a concrete empty collection.
635    #[inline]
636    #[must_use]
637    pub fn is_empty(&self) -> bool {
638        self.len() == 0
639    }
640
641    /// Strictly reads a scalar or the first collection item as `T`.
642    ///
643    /// # Type Parameters
644    ///
645    /// * `T` - Strict target type.
646    ///
647    /// # Returns
648    ///
649    /// The scalar value or first collection item.
650    ///
651    /// # Errors
652    ///
653    /// Returns [`ValueError::Missing`] for unset or empty matching storage and
654    /// [`ValueError::TypeMismatch`] when the stored data type differs.
655    #[inline(always)]
656    pub fn get_first<T>(&self) -> ValueResult<T>
657    where
658        T: StrictValueRead,
659    {
660        match self {
661            Self::Scalar(value) => T::read_scalar(value),
662            Self::Collection(values) => T::read_collection_first(values),
663        }
664    }
665
666    /// Strictly reads a scalar as a one-item list or all collection items.
667    ///
668    /// # Type Parameters
669    ///
670    /// * `T` - Strict target element type.
671    ///
672    /// # Returns
673    ///
674    /// A one-item scalar list or all collection items.
675    ///
676    /// # Errors
677    ///
678    /// Returns [`ValueError::Missing`] for unset matching storage and
679    /// [`ValueError::TypeMismatch`] when the stored data type differs.
680    #[inline(always)]
681    pub fn get_list<T>(&self) -> ValueResult<Vec<T>>
682    where
683        T: StrictValueRead,
684    {
685        match self {
686            Self::Scalar(value) => T::read_scalar(value).map(|item| vec![item]),
687            Self::Collection(values) => T::read_collection_list(values),
688        }
689    }
690
691    /// Converts a scalar or the first collection item to `T`.
692    ///
693    /// # Type Parameters
694    ///
695    /// * `T` - Target conversion type.
696    ///
697    /// # Returns
698    ///
699    /// The converted scalar or first collection item.
700    ///
701    /// # Errors
702    ///
703    /// Returns the mapped `qubit-datatype` conversion error.
704    #[cfg(feature = "converter")]
705    #[inline(always)]
706    #[cfg_attr(docsrs, doc(cfg(feature = "converter")))]
707    pub fn to_first<T>(&self) -> ValueResult<T>
708    where
709        T: DataConversionTarget,
710    {
711        self.to_first_with(ConversionPolicy::default_ref(), ConversionLimits::default_ref())
712    }
713
714    /// Converts a scalar or the first collection item using explicit policy and
715    /// limits.
716    ///
717    /// # Type Parameters
718    ///
719    /// * `T` - Target conversion type.
720    ///
721    /// # Parameters
722    ///
723    /// * `policy` - Conversion policy forwarded to the contained value.
724    /// * `limits` - Conversion limits forwarded to the contained value.
725    ///
726    /// # Returns
727    ///
728    /// The converted scalar or first collection item.
729    ///
730    /// # Errors
731    ///
732    /// Returns the mapped `qubit-datatype` conversion error.
733    #[cfg(feature = "converter")]
734    #[inline(always)]
735    #[cfg_attr(docsrs, doc(cfg(feature = "converter")))]
736    pub fn to_first_with<T>(&self, policy: &ConversionPolicy, limits: &ConversionLimits) -> ValueResult<T>
737    where
738        T: DataConversionTarget,
739    {
740        match self {
741            Self::Scalar(value) => value.to_with(policy, limits),
742            Self::Collection(values) => values.to_first_with(policy, limits),
743        }
744    }
745
746    /// Converts the scalar or first collection item using an existing
747    /// conversion session.
748    ///
749    /// # Type Parameters
750    ///
751    /// * `T` - Target conversion type.
752    ///
753    /// # Parameters
754    ///
755    /// * `session` - Caller-owned session providing policy, limits, and budget.
756    ///
757    /// # Returns
758    ///
759    /// The converted scalar or first collection item.
760    ///
761    /// # Errors
762    ///
763    /// Returns the mapped missing, conversion, or budget error.
764    #[cfg(feature = "converter")]
765    #[inline(always)]
766    #[cfg_attr(docsrs, doc(cfg(feature = "converter")))]
767    pub fn to_first_in<T>(&self, session: &mut ConversionSession<'_>) -> ValueResult<T>
768    where
769        T: DataConversionTarget,
770    {
771        match self {
772            Self::Scalar(value) => value.to_in(session),
773            Self::Collection(values) => values.to_first_in(session),
774        }
775    }
776
777    /// Converts a scalar to a list or converts every collection item.
778    ///
779    /// Scalar strings may be split according to collection conversion policy;
780    /// strings already stored in a collection are never split again.
781    ///
782    /// # Type Parameters
783    ///
784    /// * `T` - Target list element type.
785    ///
786    /// # Returns
787    ///
788    /// A converted scalar list or all converted collection items.
789    ///
790    /// # Errors
791    ///
792    /// Returns the mapped single-value or indexed list conversion error.
793    #[cfg(feature = "converter")]
794    #[inline(always)]
795    #[cfg_attr(docsrs, doc(cfg(feature = "converter")))]
796    pub fn to_list<T>(&self) -> ValueResult<Vec<T>>
797    where
798        T: DataConversionTarget,
799    {
800        self.to_list_with(ConversionPolicy::default_ref(), ConversionLimits::default_ref())
801    }
802
803    /// Converts to a list using explicit conversion policy and limits.
804    ///
805    /// # Type Parameters
806    ///
807    /// * `T` - Target list element type.
808    ///
809    /// # Parameters
810    ///
811    /// * `policy` - Conversion policy forwarded to the contained value.
812    /// * `limits` - Conversion limits forwarded to the contained value.
813    ///
814    /// # Returns
815    ///
816    /// A converted scalar list or all converted collection items.
817    ///
818    /// # Errors
819    ///
820    /// Returns the mapped single-value or indexed list conversion error.
821    #[cfg(feature = "converter")]
822    #[cfg_attr(docsrs, doc(cfg(feature = "converter")))]
823    pub fn to_list_with<T>(&self, policy: &ConversionPolicy, limits: &ConversionLimits) -> ValueResult<Vec<T>>
824    where
825        T: DataConversionTarget,
826    {
827        match self {
828            Self::Scalar(value) => match value.view() {
829                ValueRef::String(value) => ScalarStringDataConverters::from(value)
830                    .to_vec_with(policy, limits)
831                    .map_err(ValueError::from),
832                _ => value.to_with(policy, limits).map(|value| vec![value]),
833            },
834            Self::Collection(values) => values.to_list_with(policy, limits),
835        }
836    }
837
838    /// Converts this container to a list using an existing conversion session.
839    ///
840    /// # Type Parameters
841    ///
842    /// * `T` - Target list element type.
843    ///
844    /// # Parameters
845    ///
846    /// * `session` - Caller-owned session providing policy, limits, and budget.
847    ///
848    /// # Returns
849    ///
850    /// A converted scalar list or all converted collection items.
851    ///
852    /// # Errors
853    ///
854    /// Returns the mapped missing, conversion, indexed-list, or budget error.
855    #[cfg(feature = "converter")]
856    #[cfg_attr(docsrs, doc(cfg(feature = "converter")))]
857    pub fn to_list_in<T>(&self, session: &mut ConversionSession<'_>) -> ValueResult<Vec<T>>
858    where
859        T: DataConversionTarget,
860    {
861        match self {
862            Self::Scalar(value) => match value.view() {
863                ValueRef::String(value) => ScalarStringDataConverters::from(value)
864                    .to_vec_in(session)
865                    .map_err(ValueError::from),
866                _ => value.to_in(session).map(|value| vec![value]),
867            },
868            Self::Collection(values) => values.to_list_in(session),
869        }
870    }
871
872    /// Consumes this container and returns its scalar value.
873    ///
874    /// # Returns
875    ///
876    /// The contained scalar value when this container has scalar shape.
877    ///
878    /// # Errors
879    ///
880    /// Returns the original container unchanged when it has collection shape.
881    #[inline(always)]
882    pub fn into_scalar(self) -> Result<Value, Self> {
883        match self {
884            Self::Scalar(value) => Ok(value),
885            Self::Collection(_) => Err(self),
886        }
887    }
888
889    /// Consumes this container and returns its collection values.
890    ///
891    /// # Returns
892    ///
893    /// The contained values when this container has collection shape.
894    ///
895    /// # Errors
896    ///
897    /// Returns the original container unchanged when it has scalar shape.
898    #[inline(always)]
899    pub fn into_collection(self) -> Result<MultiValues, Self> {
900        match self {
901            Self::Scalar(_) => Err(self),
902            Self::Collection(values) => Ok(values),
903        }
904    }
905
906    /// Replaces this container, including its shape, from a supported input.
907    ///
908    /// # Type Parameters
909    ///
910    /// * `S` - Input type convertible into [`ValueContainer`].
911    ///
912    /// # Parameters
913    ///
914    /// * `value` - New scalar or collection value.
915    #[inline(always)]
916    pub fn set<S>(&mut self, value: S)
917    where
918        S: Into<Self>,
919    {
920        *self = value.into();
921    }
922
923    /// Appends values, promoting scalar storage to collection storage when the
924    /// input contains at least one concrete value. Same-typed empty and unset
925    /// input is a no-op.
926    ///
927    /// # Type Parameters
928    ///
929    /// * `S` - Input type convertible into [`ValueContainer`].
930    ///
931    /// # Parameters
932    ///
933    /// * `values` - Scalar or collection values to append.
934    ///
935    /// # Returns
936    ///
937    /// `Ok(())` after appending or accepting an empty same-typed input.
938    ///
939    /// # Errors
940    ///
941    /// Returns [`ValueError::TypeMismatch`] when the appended values have a
942    /// different data type.
943    pub fn add<S>(&mut self, values: S) -> ValueResult<()>
944    where
945        S: Into<Self>,
946    {
947        let other = values.into();
948        let expected = self.data_type();
949        let actual = other.data_type();
950        if expected != actual {
951            return Err(ValueError::TypeMismatch { expected, actual });
952        }
953        if other.is_empty() {
954            return Ok(());
955        }
956
957        match other {
958            Self::Scalar(value) => {
959                self.add_scalar(value, expected);
960                Ok(())
961            }
962            Self::Collection(other) => match self {
963                Self::Scalar(value) => {
964                    let value = replace(value, Value::new_unset(expected));
965                    let mut collection = MultiValues::from(value);
966                    collection.add(other)?;
967                    *self = Self::Collection(collection);
968                    Ok(())
969                }
970                Self::Collection(collection) => collection.add(other),
971            },
972        }
973    }
974
975    /// Removes concrete storage while preserving its shape and data type.
976    #[inline(always)]
977    pub fn unset(&mut self) {
978        match self {
979            Self::Scalar(value) => value.unset(),
980            Self::Collection(values) => values.unset(),
981        }
982    }
983
984    /// Appends a concrete scalar, promoting scalar storage to a collection.
985    ///
986    /// # Parameters
987    ///
988    /// * `value` - Concrete scalar to append.
989    /// * `data_type` - Shared runtime type of `self` and `value`.
990    ///
991    /// # Constraints
992    ///
993    /// Callers must ensure `value` is concrete and has `data_type`; the public
994    /// mutation entry points validate those invariants before calling this
995    /// helper.
996    #[inline]
997    fn add_scalar(&mut self, value: Value, data_type: DataType) {
998        match self {
999            Self::Scalar(current) => {
1000                let current = replace(current, Value::new_unset(data_type));
1001                let collection = for_each_value_type!(value_container_pair_match, current, value);
1002                *self = Self::Collection(collection);
1003            }
1004            Self::Collection(collection) => {
1005                for_each_value_type!(value_container_push_match, collection, value);
1006            }
1007        }
1008    }
1009}
1010
1011#[cfg(all(feature = "converter", feature = "json"))]
1012#[cfg_attr(docsrs, doc(cfg(all(feature = "converter", feature = "json"))))]
1013impl ValueContainer {
1014    /// Projects this container while preserving concrete collection shape.
1015    ///
1016    /// Scalar storage uses the natural scalar projection; concrete collection
1017    /// storage always uses a JSON array.
1018    ///
1019    /// # Returns
1020    ///
1021    /// The natural JSON representation, except scalar and collection unset
1022    /// values both project to `null`.
1023    ///
1024    /// For natural JSON projection, `max_text_bytes` bounds each string value
1025    /// and each formatted number or rich-value text by its UTF-8 byte length,
1026    /// including strings inside materialized JSON. Object keys are excluded
1027    /// from this per-item bound but still consume applicable key and
1028    /// cumulative input, output, and payload budgets. This is neither a
1029    /// cumulative text limit nor a limit on escaped JSON encoding size.
1030    ///
1031    /// # Errors
1032    ///
1033    /// Returns the same structured projection error as the contained value.
1034    #[inline(always)]
1035    pub fn to_json_value(&self) -> ValueResult<JsonValue> {
1036        self.to_json_value_with(ConversionPolicy::default_ref(), ConversionLimits::default_ref())
1037    }
1038
1039    /// Projects this container using explicit conversion policy and limits.
1040    ///
1041    /// # Parameters
1042    ///
1043    /// * `policy` - Controls duration units and precision-loss behavior.
1044    /// * `limits` - Bounds conversion resource consumption.
1045    ///
1046    /// # Returns
1047    ///
1048    /// The natural JSON representation, except scalar and collection unset
1049    /// values both project to `null`.
1050    ///
1051    /// # Errors
1052    ///
1053    /// Returns the same structured projection error as the contained value.
1054    #[inline]
1055    pub fn to_json_value_with(&self, policy: &ConversionPolicy, limits: &ConversionLimits) -> ValueResult<JsonValue> {
1056        crate::json::value_container_to_json_value_with(self, policy, limits)
1057    }
1058}