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:
479            TryFrom<&'a Value, Error = ValueError> + TryFrom<&'a MultiValues, Error = ValueError>,
480    {
481        match self {
482            Self::Scalar(value) => <&'a T>::try_from(value),
483            Self::Collection(values) => <&'a T>::try_from(values),
484        }
485    }
486
487    /// Strictly borrows a scalar as a one-item slice or a complete collection.
488    ///
489    /// The returned slice is tied to this container's lifetime. The requested
490    /// element type must match the stored type.
491    ///
492    /// # Type Parameters
493    ///
494    /// * `T` - Stored element type of the borrowed slice.
495    ///
496    /// # Returns
497    ///
498    /// A one-item slice for a scalar, or all collection items. An empty
499    /// collection returns an empty slice.
500    ///
501    /// # Errors
502    ///
503    /// Returns [`ValueError::Missing`] when an unset scalar or collection has
504    /// the requested type, or [`ValueError::TypeMismatch`] when the stored type
505    /// does not match `T`. A concrete empty collection returns an empty slice.
506    ///
507    /// # Examples
508    ///
509    /// ```
510    /// use qubit_datatype::DataType;
511    ///
512    /// use qubit_value::ValueContainer;
513    /// use qubit_value::ValueError;
514    ///
515    /// let values = ValueContainer::from(vec![String::from("a"), String::from("b")]);
516    /// let all: &[String] = values.get_slice().unwrap();
517    /// assert_eq!(all.len(), 2);
518    /// let empty = ValueContainer::from(Vec::<String>::new());
519    /// assert!(empty.get_slice::<String>().unwrap().is_empty());
520    /// let unset_scalar = ValueContainer::new_unset_scalar(DataType::String);
521    /// let unset_collection = ValueContainer::new_unset_collection(DataType::String);
522    /// assert!(matches!(unset_scalar.get_slice::<String>(), Err(ValueError::Missing(_))));
523    /// assert!(matches!(unset_collection.get_slice::<String>(), Err(ValueError::Missing(_))));
524    /// ```
525    #[inline(always)]
526    pub fn get_slice<'a, T>(&'a self) -> ValueResult<&'a [T]>
527    where
528        &'a T: TryFrom<&'a Value, Error = ValueError>,
529        &'a [T]: TryFrom<&'a MultiValues, Error = ValueError>,
530    {
531        match self {
532            Self::Scalar(value) => value.get_ref().map(from_ref),
533            Self::Collection(values) => values.get_slice(),
534        }
535    }
536
537    /// Returns the stored or declared data type.
538    ///
539    /// # Returns
540    ///
541    /// The scalar or collection element type, including the declared type of
542    /// unset storage.
543    #[inline]
544    pub fn data_type(&self) -> DataType {
545        match self {
546            Self::Scalar(value) => value.data_type(),
547            Self::Collection(values) => values.data_type(),
548        }
549    }
550
551    /// Returns whether this container has scalar shape.
552    ///
553    /// # Returns
554    ///
555    /// `true` for [`ValueContainer::Scalar`].
556    #[inline]
557    #[must_use]
558    pub const fn is_scalar(&self) -> bool {
559        matches!(self, Self::Scalar(_))
560    }
561
562    /// Returns the contained scalar without consuming this container.
563    ///
564    /// # Returns
565    ///
566    /// `Some` for scalar storage, or `None` for collection storage.
567    #[must_use]
568    #[inline]
569    pub const fn as_scalar(&self) -> Option<&Value> {
570        match self {
571            Self::Scalar(value) => Some(value),
572            Self::Collection(_) => None,
573        }
574    }
575
576    /// Returns whether this container has collection shape.
577    ///
578    /// # Returns
579    ///
580    /// `true` for [`ValueContainer::Collection`].
581    #[inline]
582    #[must_use]
583    pub const fn is_collection(&self) -> bool {
584        matches!(self, Self::Collection(_))
585    }
586
587    /// Returns the contained collection without consuming this container.
588    ///
589    /// # Returns
590    ///
591    /// `Some` for collection storage, or `None` for scalar storage.
592    #[must_use]
593    #[inline]
594    pub const fn as_collection(&self) -> Option<&MultiValues> {
595        match self {
596            Self::Scalar(_) => None,
597            Self::Collection(values) => Some(values),
598        }
599    }
600
601    /// Returns whether the shape contains no concrete value or collection.
602    ///
603    /// # Returns
604    ///
605    /// `true` when the contained scalar or collection is unset.
606    #[inline(always)]
607    #[must_use]
608    pub fn is_unset(&self) -> bool {
609        match self {
610            Self::Scalar(value) => value.is_unset(),
611            Self::Collection(values) => values.is_unset(),
612        }
613    }
614
615    /// Returns zero for unset storage, one for a concrete scalar, or the
616    /// concrete collection length.
617    ///
618    /// # Returns
619    ///
620    /// The number of concrete values represented by this container.
621    #[inline]
622    #[must_use]
623    #[allow(clippy::len_without_is_empty)]
624    pub fn len(&self) -> usize {
625        match self {
626            Self::Scalar(value) => usize::from(!value.is_unset()),
627            Self::Collection(values) => values.len(),
628        }
629    }
630
631    /// Tests whether this container represents no concrete values.
632    ///
633    /// # Returns
634    ///
635    /// `true` for unset storage or a concrete empty collection.
636    #[inline]
637    #[must_use]
638    pub fn is_empty(&self) -> bool {
639        self.len() == 0
640    }
641
642    /// Strictly reads a scalar or the first collection item as `T`.
643    ///
644    /// # Type Parameters
645    ///
646    /// * `T` - Strict target type.
647    ///
648    /// # Returns
649    ///
650    /// The scalar value or first collection item.
651    ///
652    /// # Errors
653    ///
654    /// Returns [`ValueError::Missing`] for unset or empty matching storage and
655    /// [`ValueError::TypeMismatch`] when the stored data type differs.
656    #[inline(always)]
657    pub fn get_first<T>(&self) -> ValueResult<T>
658    where
659        T: StrictValueRead,
660    {
661        match self {
662            Self::Scalar(value) => T::read_scalar(value),
663            Self::Collection(values) => T::read_collection_first(values),
664        }
665    }
666
667    /// Strictly reads a scalar as a one-item list or all collection items.
668    ///
669    /// # Type Parameters
670    ///
671    /// * `T` - Strict target element type.
672    ///
673    /// # Returns
674    ///
675    /// A one-item scalar list or all collection items.
676    ///
677    /// # Errors
678    ///
679    /// Returns [`ValueError::Missing`] for unset matching storage and
680    /// [`ValueError::TypeMismatch`] when the stored data type differs.
681    #[inline(always)]
682    pub fn get_list<T>(&self) -> ValueResult<Vec<T>>
683    where
684        T: StrictValueRead,
685    {
686        match self {
687            Self::Scalar(value) => T::read_scalar(value).map(|item| vec![item]),
688            Self::Collection(values) => T::read_collection_list(values),
689        }
690    }
691
692    /// Converts a scalar or the first collection item to `T`.
693    ///
694    /// # Type Parameters
695    ///
696    /// * `T` - Target conversion type.
697    ///
698    /// # Returns
699    ///
700    /// The converted scalar or first collection item.
701    ///
702    /// # Errors
703    ///
704    /// Returns the mapped `qubit-datatype` conversion error.
705    #[cfg(feature = "converter")]
706    #[inline(always)]
707    #[cfg_attr(docsrs, doc(cfg(feature = "converter")))]
708    pub fn to_first<T>(&self) -> ValueResult<T>
709    where
710        T: DataConversionTarget,
711    {
712        self.to_first_with(
713            ConversionPolicy::default_ref(),
714            ConversionLimits::default_ref(),
715        )
716    }
717
718    /// Converts a scalar or the first collection item using explicit policy and
719    /// limits.
720    ///
721    /// # Type Parameters
722    ///
723    /// * `T` - Target conversion type.
724    ///
725    /// # Parameters
726    ///
727    /// * `policy` - Conversion policy forwarded to the contained value.
728    /// * `limits` - Conversion limits forwarded to the contained value.
729    ///
730    /// # Returns
731    ///
732    /// The converted scalar or first collection item.
733    ///
734    /// # Errors
735    ///
736    /// Returns the mapped `qubit-datatype` conversion error.
737    #[cfg(feature = "converter")]
738    #[inline(always)]
739    #[cfg_attr(docsrs, doc(cfg(feature = "converter")))]
740    pub fn to_first_with<T>(
741        &self,
742        policy: &ConversionPolicy,
743        limits: &ConversionLimits,
744    ) -> ValueResult<T>
745    where
746        T: DataConversionTarget,
747    {
748        match self {
749            Self::Scalar(value) => value.to_with(policy, limits),
750            Self::Collection(values) => values.to_first_with(policy, limits),
751        }
752    }
753
754    /// Converts the scalar or first collection item using an existing
755    /// conversion session.
756    ///
757    /// # Type Parameters
758    ///
759    /// * `T` - Target conversion type.
760    ///
761    /// # Parameters
762    ///
763    /// * `session` - Caller-owned session providing policy, limits, and budget.
764    ///
765    /// # Returns
766    ///
767    /// The converted scalar or first collection item.
768    ///
769    /// # Errors
770    ///
771    /// Returns the mapped missing, conversion, or budget error.
772    #[cfg(feature = "converter")]
773    #[inline(always)]
774    #[cfg_attr(docsrs, doc(cfg(feature = "converter")))]
775    pub fn to_first_in<T>(&self, session: &mut ConversionSession<'_>) -> ValueResult<T>
776    where
777        T: DataConversionTarget,
778    {
779        match self {
780            Self::Scalar(value) => value.to_in(session),
781            Self::Collection(values) => values.to_first_in(session),
782        }
783    }
784
785    /// Converts a scalar to a list or converts every collection item.
786    ///
787    /// Scalar strings may be split according to collection conversion policy;
788    /// strings already stored in a collection are never split again.
789    ///
790    /// # Type Parameters
791    ///
792    /// * `T` - Target list element type.
793    ///
794    /// # Returns
795    ///
796    /// A converted scalar list or all converted collection items.
797    ///
798    /// # Errors
799    ///
800    /// Returns the mapped single-value or indexed list conversion error.
801    #[cfg(feature = "converter")]
802    #[inline(always)]
803    #[cfg_attr(docsrs, doc(cfg(feature = "converter")))]
804    pub fn to_list<T>(&self) -> ValueResult<Vec<T>>
805    where
806        T: DataConversionTarget,
807    {
808        self.to_list_with(
809            ConversionPolicy::default_ref(),
810            ConversionLimits::default_ref(),
811        )
812    }
813
814    /// Converts to a list using explicit conversion policy and limits.
815    ///
816    /// # Type Parameters
817    ///
818    /// * `T` - Target list element type.
819    ///
820    /// # Parameters
821    ///
822    /// * `policy` - Conversion policy forwarded to the contained value.
823    /// * `limits` - Conversion limits forwarded to the contained value.
824    ///
825    /// # Returns
826    ///
827    /// A converted scalar list or all converted collection items.
828    ///
829    /// # Errors
830    ///
831    /// Returns the mapped single-value or indexed list conversion error.
832    #[cfg(feature = "converter")]
833    #[cfg_attr(docsrs, doc(cfg(feature = "converter")))]
834    pub fn to_list_with<T>(
835        &self,
836        policy: &ConversionPolicy,
837        limits: &ConversionLimits,
838    ) -> ValueResult<Vec<T>>
839    where
840        T: DataConversionTarget,
841    {
842        match self {
843            Self::Scalar(value) => match value.view() {
844                ValueRef::String(value) => ScalarStringDataConverters::from(value)
845                    .to_vec_with(policy, limits)
846                    .map_err(ValueError::from),
847                _ => value.to_with(policy, limits).map(|value| vec![value]),
848            },
849            Self::Collection(values) => values.to_list_with(policy, limits),
850        }
851    }
852
853    /// Converts this container to a list using an existing conversion session.
854    ///
855    /// # Type Parameters
856    ///
857    /// * `T` - Target list element type.
858    ///
859    /// # Parameters
860    ///
861    /// * `session` - Caller-owned session providing policy, limits, and budget.
862    ///
863    /// # Returns
864    ///
865    /// A converted scalar list or all converted collection items.
866    ///
867    /// # Errors
868    ///
869    /// Returns the mapped missing, conversion, indexed-list, or budget error.
870    #[cfg(feature = "converter")]
871    #[cfg_attr(docsrs, doc(cfg(feature = "converter")))]
872    pub fn to_list_in<T>(&self, session: &mut ConversionSession<'_>) -> ValueResult<Vec<T>>
873    where
874        T: DataConversionTarget,
875    {
876        match self {
877            Self::Scalar(value) => match value.view() {
878                ValueRef::String(value) => ScalarStringDataConverters::from(value)
879                    .to_vec_in(session)
880                    .map_err(ValueError::from),
881                _ => value.to_in(session).map(|value| vec![value]),
882            },
883            Self::Collection(values) => values.to_list_in(session),
884        }
885    }
886
887    /// Consumes this container and returns its scalar value.
888    ///
889    /// # Returns
890    ///
891    /// The contained scalar value when this container has scalar shape.
892    ///
893    /// # Errors
894    ///
895    /// Returns the original container unchanged when it has collection shape.
896    #[inline(always)]
897    pub fn into_scalar(self) -> Result<Value, Self> {
898        match self {
899            Self::Scalar(value) => Ok(value),
900            Self::Collection(_) => Err(self),
901        }
902    }
903
904    /// Consumes this container and returns its collection values.
905    ///
906    /// # Returns
907    ///
908    /// The contained values when this container has collection shape.
909    ///
910    /// # Errors
911    ///
912    /// Returns the original container unchanged when it has scalar shape.
913    #[inline(always)]
914    pub fn into_collection(self) -> Result<MultiValues, Self> {
915        match self {
916            Self::Scalar(_) => Err(self),
917            Self::Collection(values) => Ok(values),
918        }
919    }
920
921    /// Replaces this container, including its shape, from a supported input.
922    ///
923    /// # Type Parameters
924    ///
925    /// * `S` - Input type convertible into [`ValueContainer`].
926    ///
927    /// # Parameters
928    ///
929    /// * `value` - New scalar or collection value.
930    #[inline(always)]
931    pub fn set<S>(&mut self, value: S)
932    where
933        S: Into<Self>,
934    {
935        *self = value.into();
936    }
937
938    /// Appends values, promoting scalar storage to collection storage when the
939    /// input contains at least one concrete value. Same-typed empty and unset
940    /// input is a no-op.
941    ///
942    /// # Type Parameters
943    ///
944    /// * `S` - Input type convertible into [`ValueContainer`].
945    ///
946    /// # Parameters
947    ///
948    /// * `values` - Scalar or collection values to append.
949    ///
950    /// # Returns
951    ///
952    /// `Ok(())` after appending or accepting an empty same-typed input.
953    ///
954    /// # Errors
955    ///
956    /// Returns [`ValueError::TypeMismatch`] when the appended values have a
957    /// different data type.
958    pub fn add<S>(&mut self, values: S) -> ValueResult<()>
959    where
960        S: Into<Self>,
961    {
962        let other = values.into();
963        let expected = self.data_type();
964        let actual = other.data_type();
965        if expected != actual {
966            return Err(ValueError::TypeMismatch { expected, actual });
967        }
968        if other.is_empty() {
969            return Ok(());
970        }
971
972        match other {
973            Self::Scalar(value) => {
974                self.add_scalar(value, expected);
975                Ok(())
976            }
977            Self::Collection(other) => match self {
978                Self::Scalar(value) => {
979                    let value = replace(value, Value::new_unset(expected));
980                    let mut collection = MultiValues::from(value);
981                    collection.add(other)?;
982                    *self = Self::Collection(collection);
983                    Ok(())
984                }
985                Self::Collection(collection) => collection.add(other),
986            },
987        }
988    }
989
990    /// Removes concrete storage while preserving its shape and data type.
991    #[inline(always)]
992    pub fn unset(&mut self) {
993        match self {
994            Self::Scalar(value) => value.unset(),
995            Self::Collection(values) => values.unset(),
996        }
997    }
998
999    /// Appends a concrete scalar, promoting scalar storage to a collection.
1000    ///
1001    /// # Parameters
1002    ///
1003    /// * `value` - Concrete scalar to append.
1004    /// * `data_type` - Shared runtime type of `self` and `value`.
1005    ///
1006    /// # Constraints
1007    ///
1008    /// Callers must ensure `value` is concrete and has `data_type`; the public
1009    /// mutation entry points validate those invariants before calling this
1010    /// helper.
1011    #[inline]
1012    fn add_scalar(&mut self, value: Value, data_type: DataType) {
1013        match self {
1014            Self::Scalar(current) => {
1015                let current = replace(current, Value::new_unset(data_type));
1016                let collection = for_each_value_type!(value_container_pair_match, current, value);
1017                *self = Self::Collection(collection);
1018            }
1019            Self::Collection(collection) => {
1020                for_each_value_type!(value_container_push_match, collection, value);
1021            }
1022        }
1023    }
1024}
1025
1026#[cfg(all(feature = "converter", feature = "json"))]
1027#[cfg_attr(docsrs, doc(cfg(all(feature = "converter", feature = "json"))))]
1028impl ValueContainer {
1029    /// Projects this container while preserving concrete collection shape.
1030    ///
1031    /// Scalar storage uses the natural scalar projection; concrete collection
1032    /// storage always uses a JSON array.
1033    ///
1034    /// # Returns
1035    ///
1036    /// The natural JSON representation, except scalar and collection unset
1037    /// values both project to `null`.
1038    ///
1039    /// For natural JSON projection, `max_text_bytes` bounds each string value
1040    /// and each formatted number or rich-value text by its UTF-8 byte length,
1041    /// including strings inside materialized JSON. Object keys are excluded
1042    /// from this per-item bound but still consume applicable key and
1043    /// cumulative input, output, and payload budgets. This is neither a
1044    /// cumulative text limit nor a limit on escaped JSON encoding size.
1045    ///
1046    /// # Errors
1047    ///
1048    /// Returns the same structured projection error as the contained value.
1049    #[inline(always)]
1050    pub fn to_json_value(&self) -> ValueResult<JsonValue> {
1051        self.to_json_value_with(
1052            ConversionPolicy::default_ref(),
1053            ConversionLimits::default_ref(),
1054        )
1055    }
1056
1057    /// Projects this container using explicit conversion policy and limits.
1058    ///
1059    /// # Parameters
1060    ///
1061    /// * `policy` - Controls duration units and precision-loss behavior.
1062    /// * `limits` - Bounds conversion resource consumption.
1063    ///
1064    /// # Returns
1065    ///
1066    /// The natural JSON representation, except scalar and collection unset
1067    /// values both project to `null`.
1068    ///
1069    /// # Errors
1070    ///
1071    /// Returns the same structured projection error as the contained value.
1072    #[inline]
1073    pub fn to_json_value_with(
1074        &self,
1075        policy: &ConversionPolicy,
1076        limits: &ConversionLimits,
1077    ) -> ValueResult<JsonValue> {
1078        crate::json::value_container_to_json_value_with(self, policy, limits)
1079    }
1080}