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 crate::multi_values::MultiValuesRepr;
12#[cfg(feature = "converter")]
13use crate::value::ValueRef;
14use crate::value::ValueRepr;
15use crate::{
16    MultiValues,
17    StrictValueRead,
18    Value,
19    ValueError,
20    ValueResult,
21};
22use qubit_datatype::DataType;
23#[cfg(feature = "converter")]
24use qubit_datatype::{
25    DataConversionOptions,
26    DataConversionTarget,
27    ScalarStringDataConverters,
28};
29
30/// A typed value whose scalar or collection shape is explicit.
31///
32/// The shape is never inferred from collection length. In particular,
33/// `Scalar(Value::Int32(42))` and
34/// `Collection(MultiValues::Int32(vec![42]))` remain distinguishable through
35/// conversion and serialization boundaries.
36#[must_use]
37#[derive(Debug, Clone, PartialEq, Eq, Hash)]
38pub enum ValueContainer {
39    /// One typed value.
40    Scalar(
41        /// Stored scalar value.
42        Value,
43    ),
44    /// A homogeneous typed collection.
45    Collection(
46        /// Stored homogeneous collection.
47        MultiValues,
48    ),
49}
50
51macro_rules! impl_value_container_from_table {
52    (
53        ;
54        $(
55            (
56                [$($cfg:meta),*],
57                $variant:ident,
58                $type:ty,
59                $data_type:expr,
60                $materialization:ident,
61                $json_class:ident,
62                $number_projection:ident,
63                $value_doc:literal,
64                $multi_doc:literal
65            )
66        ),+ $(,)?
67    ) => {
68        $(
69            $(#[$cfg])*
70            impl From<$type> for ValueContainer {
71                #[inline(always)]
72                fn from(value: $type) -> Self {
73                    Self::Scalar(Value::$variant(value))
74                }
75            }
76
77            $(#[$cfg])*
78            impl From<Vec<$type>> for ValueContainer {
79                #[inline(always)]
80                fn from(values: Vec<$type>) -> Self {
81                    Self::Collection(MultiValues::$variant(values))
82                }
83            }
84
85            $(#[$cfg])*
86            impl From<&[$type]> for ValueContainer {
87                #[inline]
88                fn from(values: &[$type]) -> Self {
89                    Self::Collection(MultiValues::$variant(values.to_vec()))
90                }
91            }
92
93            $(#[$cfg])*
94            impl From<&Vec<$type>> for ValueContainer {
95                #[inline]
96                fn from(values: &Vec<$type>) -> Self {
97                    Self::Collection(MultiValues::$variant(values.clone()))
98                }
99            }
100
101            $(#[$cfg])*
102            impl<const N: usize> From<[$type; N]> for ValueContainer {
103                #[inline]
104                fn from(values: [$type; N]) -> Self {
105                    Self::Collection(MultiValues::$variant(Vec::from(values)))
106                }
107            }
108
109            $(#[$cfg])*
110            impl<const N: usize> From<&[$type; N]> for ValueContainer {
111                #[inline]
112                fn from(values: &[$type; N]) -> Self {
113                    Self::Collection(MultiValues::$variant(values.to_vec()))
114                }
115            }
116        )+
117    };
118}
119
120for_each_value_type!(impl_value_container_from_table);
121
122/// Builds a typed collection from one or two same-typed scalar values.
123macro_rules! value_container_pair_match {
124    ($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)),+ $(,)?) => {
125        match ($first.repr, $second.repr) {
126            $(
127                $(#[$cfg])*
128                (ValueRepr::$variant(first), ValueRepr::$variant(second)) => {
129                    MultiValues::$variant(vec![
130                        value_storage_into_multi!($variant, first),
131                        value_storage_into_multi!($variant, second),
132                    ])
133                }
134            )+
135            $(
136                $(#[$cfg])*
137                (ValueRepr::Unset(_), ValueRepr::$variant(second)) => {
138                    MultiValues::$variant(vec![value_storage_into_multi!($variant, second)])
139                }
140            )+
141            _ => unreachable!(),
142        }
143    };
144}
145
146/// Pushes a same-typed scalar directly into collection storage.
147macro_rules! value_container_push_match {
148    ($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)),+ $(,)?) => {
149        match (&mut $collection.repr, $value.repr) {
150            $(
151                $(#[$cfg])*
152                (MultiValuesRepr::$variant(values), ValueRepr::$variant(value)) => {
153                    values.push(value_storage_into_multi!($variant, value))
154                },
155            )+
156            $(
157                $(#[$cfg])*
158                (slot @ MultiValuesRepr::Unset(_), ValueRepr::$variant(value)) => {
159                    *slot = MultiValuesRepr::$variant(vec![value_storage_into_multi!($variant, value)]);
160                }
161            )+
162            _ => unreachable!(),
163        }
164    };
165}
166
167impl From<&str> for ValueContainer {
168    #[inline]
169    fn from(value: &str) -> Self {
170        Self::Scalar(Value::String(value.to_string()))
171    }
172}
173
174impl<'a> From<Vec<&'a str>> for ValueContainer {
175    #[inline]
176    fn from(values: Vec<&'a str>) -> Self {
177        Self::Collection(MultiValues::from(values))
178    }
179}
180
181impl<'a, 'b> From<&'a [&'b str]> for ValueContainer {
182    #[inline]
183    fn from(values: &'a [&'b str]) -> Self {
184        Self::Collection(MultiValues::from(values))
185    }
186}
187
188impl<'a, 'b> From<&'a Vec<&'b str>> for ValueContainer {
189    #[inline]
190    fn from(values: &'a Vec<&'b str>) -> Self {
191        Self::Collection(MultiValues::from(values))
192    }
193}
194
195impl<'a, const N: usize> From<[&'a str; N]> for ValueContainer {
196    #[inline]
197    fn from(values: [&'a str; N]) -> Self {
198        Self::Collection(MultiValues::from(values))
199    }
200}
201
202impl<'a, 'b, const N: usize> From<&'a [&'b str; N]> for ValueContainer {
203    #[inline]
204    fn from(values: &'a [&'b str; N]) -> Self {
205        Self::Collection(MultiValues::from(values))
206    }
207}
208
209impl From<Value> for ValueContainer {
210    #[inline(always)]
211    fn from(value: Value) -> Self {
212        Self::Scalar(value)
213    }
214}
215
216impl From<MultiValues> for ValueContainer {
217    #[inline(always)]
218    fn from(values: MultiValues) -> Self {
219        Self::Collection(values)
220    }
221}
222
223impl ValueContainer {
224    /// Returns the stored or declared data type.
225    ///
226    /// # Returns
227    ///
228    /// The scalar or collection element type, including the declared type of
229    /// unset storage.
230    #[inline(always)]
231    pub fn data_type(&self) -> DataType {
232        match self {
233            Self::Scalar(value) => value.data_type(),
234            Self::Collection(values) => values.data_type(),
235        }
236    }
237
238    /// Creates an unset scalar container for a declared data type.
239    ///
240    /// # Parameters
241    ///
242    /// * `data_type` - Declared scalar type while no value is set.
243    ///
244    /// # Returns
245    ///
246    /// A scalar `ValueContainer` with explicit unset storage.
247    #[inline(always)]
248    pub const fn new_unset_scalar(data_type: DataType) -> Self {
249        Self::Scalar(Value::new_unset(data_type))
250    }
251
252    /// Creates an unset collection container for a declared element type.
253    ///
254    /// # Parameters
255    ///
256    /// * `data_type` - Declared element type while no values are set.
257    ///
258    /// # Returns
259    ///
260    /// A collection `ValueContainer` with explicit unset storage.
261    #[inline(always)]
262    pub const fn new_unset_collection(data_type: DataType) -> Self {
263        Self::Collection(MultiValues::new_unset(data_type))
264    }
265
266    /// Returns whether this container has scalar shape.
267    ///
268    /// # Returns
269    ///
270    /// `true` for [`ValueContainer::Scalar`].
271    #[inline(always)]
272    #[must_use]
273    pub const fn is_scalar(&self) -> bool {
274        matches!(self, Self::Scalar(_))
275    }
276
277    /// Returns the contained scalar without consuming this container.
278    ///
279    /// # Returns
280    ///
281    /// `Some` for scalar storage, or `None` for collection storage.
282    #[inline(always)]
283    pub const fn as_scalar(&self) -> Option<&Value> {
284        match self {
285            Self::Scalar(value) => Some(value),
286            Self::Collection(_) => None,
287        }
288    }
289
290    /// Consumes this container and returns its scalar value.
291    ///
292    /// # Returns
293    ///
294    /// The contained scalar value when this container has scalar shape.
295    ///
296    /// # Errors
297    ///
298    /// Returns the original container unchanged when it has collection shape.
299    #[inline(always)]
300    pub fn into_scalar(self) -> Result<Value, Self> {
301        match self {
302            Self::Scalar(value) => Ok(value),
303            Self::Collection(_) => Err(self),
304        }
305    }
306
307    /// Returns whether this container has collection shape.
308    ///
309    /// # Returns
310    ///
311    /// `true` for [`ValueContainer::Collection`].
312    #[inline(always)]
313    #[must_use]
314    pub const fn is_collection(&self) -> bool {
315        matches!(self, Self::Collection(_))
316    }
317
318    /// Returns the contained collection without consuming this container.
319    ///
320    /// # Returns
321    ///
322    /// `Some` for collection storage, or `None` for scalar storage.
323    #[inline(always)]
324    pub const fn as_collection(&self) -> Option<&MultiValues> {
325        match self {
326            Self::Scalar(_) => None,
327            Self::Collection(values) => Some(values),
328        }
329    }
330
331    /// Consumes this container and returns its collection values.
332    ///
333    /// # Returns
334    ///
335    /// The contained values when this container has collection shape.
336    ///
337    /// # Errors
338    ///
339    /// Returns the original container unchanged when it has scalar shape.
340    #[inline(always)]
341    pub fn into_collection(self) -> Result<MultiValues, Self> {
342        match self {
343            Self::Scalar(_) => Err(self),
344            Self::Collection(values) => Ok(values),
345        }
346    }
347
348    /// Returns whether the shape contains no concrete value or collection.
349    ///
350    /// # Returns
351    ///
352    /// `true` when the contained scalar or collection is unset.
353    #[inline(always)]
354    #[must_use]
355    pub fn is_unset(&self) -> bool {
356        match self {
357            Self::Scalar(value) => value.is_unset(),
358            Self::Collection(values) => values.is_unset(),
359        }
360    }
361
362    /// Returns zero for unset storage, one for a concrete scalar, or the
363    /// concrete collection length.
364    ///
365    /// # Returns
366    ///
367    /// The number of concrete values represented by this container.
368    #[inline(always)]
369    #[must_use]
370    #[allow(clippy::len_without_is_empty)]
371    pub fn len(&self) -> usize {
372        match self {
373            Self::Scalar(value) => usize::from(!value.is_unset()),
374            Self::Collection(values) => values.len(),
375        }
376    }
377
378    /// Tests whether this container represents no concrete values.
379    #[inline(always)]
380    #[must_use]
381    pub fn is_empty(&self) -> bool {
382        self.len() == 0
383    }
384
385    /// Strictly reads a scalar or the first collection item as `T`.
386    ///
387    /// # Type Parameters
388    ///
389    /// * `T` - Strict target type.
390    ///
391    /// # Returns
392    ///
393    /// The scalar value or first collection item.
394    ///
395    /// # Errors
396    ///
397    /// Returns [`ValueError::Missing`] for unset or empty matching storage and
398    /// [`ValueError::TypeMismatch`] when the stored data type differs.
399    #[inline(always)]
400    pub fn get_first<T>(&self) -> ValueResult<T>
401    where
402        T: StrictValueRead,
403    {
404        match self {
405            Self::Scalar(value) => T::read_scalar(value),
406            Self::Collection(values) => T::read_collection_first(values),
407        }
408    }
409
410    /// Strictly reads a scalar as a one-item list or all collection items.
411    ///
412    /// # Type Parameters
413    ///
414    /// * `T` - Strict target element type.
415    ///
416    /// # Returns
417    ///
418    /// A one-item scalar list or all collection items.
419    ///
420    /// # Errors
421    ///
422    /// Returns [`ValueError::Missing`] for unset matching storage and
423    /// [`ValueError::TypeMismatch`] when the stored data type differs.
424    #[inline(always)]
425    pub fn get_list<T>(&self) -> ValueResult<Vec<T>>
426    where
427        T: StrictValueRead,
428    {
429        match self {
430            Self::Scalar(value) => T::read_scalar(value).map(|item| vec![item]),
431            Self::Collection(values) => T::read_collection_list(values),
432        }
433    }
434
435    /// Replaces this container, including its shape, from a supported input.
436    ///
437    /// # Type Parameters
438    ///
439    /// * `S` - Input type convertible into [`ValueContainer`].
440    ///
441    /// # Parameters
442    ///
443    /// * `value` - New scalar or collection value.
444    #[inline(always)]
445    pub fn set<S>(&mut self, value: S)
446    where
447        S: Into<Self>,
448    {
449        *self = value.into();
450    }
451
452    /// Appends values, promoting scalar storage to collection storage when the
453    /// input contains at least one concrete value. Same-typed empty and unset
454    /// input is a no-op.
455    ///
456    /// # Type Parameters
457    ///
458    /// * `S` - Input type convertible into [`ValueContainer`].
459    ///
460    /// # Parameters
461    ///
462    /// * `values` - Scalar or collection values to append.
463    ///
464    /// # Returns
465    ///
466    /// `Ok(())` after appending or accepting an empty same-typed input.
467    ///
468    /// # Errors
469    ///
470    /// Returns [`ValueError::TypeMismatch`] when the appended values have a
471    /// different data type.
472    pub fn add<S>(&mut self, values: S) -> ValueResult<()>
473    where
474        S: Into<Self>,
475    {
476        let other = values.into();
477        let expected = self.data_type();
478        let actual = other.data_type();
479        if expected != actual {
480            return Err(ValueError::TypeMismatch { expected, actual });
481        }
482        if other.is_empty() {
483            return Ok(());
484        }
485
486        match other {
487            Self::Scalar(value) => {
488                self.add_scalar(value, expected);
489                Ok(())
490            }
491            Self::Collection(other) => match self {
492                Self::Scalar(value) => {
493                    let value =
494                        std::mem::replace(value, Value::new_unset(expected));
495                    let mut collection = MultiValues::from(value);
496                    collection.add(other)?;
497                    *self = Self::Collection(collection);
498                    Ok(())
499                }
500                Self::Collection(collection) => collection.add(other),
501            },
502        }
503    }
504
505    /// Removes concrete storage while preserving its shape and data type.
506    #[inline(always)]
507    pub fn unset(&mut self) {
508        match self {
509            Self::Scalar(value) => value.unset(),
510            Self::Collection(values) => values.unset(),
511        }
512    }
513
514    /// Converts a scalar or the first collection item to `T`.
515    ///
516    /// # Type Parameters
517    ///
518    /// * `T` - Target conversion type.
519    ///
520    /// # Returns
521    ///
522    /// The converted scalar or first collection item.
523    ///
524    /// # Errors
525    ///
526    /// Returns the mapped `qubit-datatype` conversion error.
527    #[cfg(feature = "converter")]
528    #[inline(always)]
529    pub fn to_first<T>(&self) -> ValueResult<T>
530    where
531        T: DataConversionTarget,
532    {
533        self.to_first_with(DataConversionOptions::default_ref())
534    }
535
536    /// Converts a scalar or the first collection item using explicit options.
537    ///
538    /// # Type Parameters
539    ///
540    /// * `T` - Target conversion type.
541    ///
542    /// # Parameters
543    ///
544    /// * `options` - Conversion options forwarded to the contained value.
545    ///
546    /// # Returns
547    ///
548    /// The converted scalar or first collection item.
549    ///
550    /// # Errors
551    ///
552    /// Returns the mapped `qubit-datatype` conversion error.
553    #[cfg(feature = "converter")]
554    #[inline(always)]
555    pub fn to_first_with<T>(
556        &self,
557        options: &DataConversionOptions,
558    ) -> ValueResult<T>
559    where
560        T: DataConversionTarget,
561    {
562        match self {
563            Self::Scalar(value) => value.to_with(options),
564            Self::Collection(values) => values.to_first_with(options),
565        }
566    }
567
568    /// Converts a scalar to a list or converts every collection item.
569    ///
570    /// Scalar strings may be split according to collection conversion options;
571    /// strings already stored in a collection are never split again.
572    ///
573    /// # Type Parameters
574    ///
575    /// * `T` - Target list element type.
576    ///
577    /// # Returns
578    ///
579    /// A converted scalar list or all converted collection items.
580    ///
581    /// # Errors
582    ///
583    /// Returns the mapped single-value or indexed list conversion error.
584    #[cfg(feature = "converter")]
585    #[inline(always)]
586    pub fn to_list<T>(&self) -> ValueResult<Vec<T>>
587    where
588        T: DataConversionTarget,
589    {
590        self.to_list_with(DataConversionOptions::default_ref())
591    }
592
593    /// Converts to a list using explicit conversion options.
594    ///
595    /// # Type Parameters
596    ///
597    /// * `T` - Target list element type.
598    ///
599    /// # Parameters
600    ///
601    /// * `options` - Conversion options forwarded to the contained value.
602    ///
603    /// # Returns
604    ///
605    /// A converted scalar list or all converted collection items.
606    ///
607    /// # Errors
608    ///
609    /// Returns the mapped single-value or indexed list conversion error.
610    #[cfg(feature = "converter")]
611    pub fn to_list_with<T>(
612        &self,
613        options: &DataConversionOptions,
614    ) -> ValueResult<Vec<T>>
615    where
616        T: DataConversionTarget,
617    {
618        match self {
619            Self::Scalar(value) => match value.view() {
620                ValueRef::String(value) => {
621                    ScalarStringDataConverters::from(value)
622                        .to_vec_with(options)
623                        .map_err(ValueError::from)
624                }
625                _ => value.to_with(options).map(|value| vec![value]),
626            },
627            Self::Collection(values) => values.to_list_with(options),
628        }
629    }
630
631    /// Appends a concrete scalar, promoting scalar storage to a collection.
632    ///
633    /// # Parameters
634    ///
635    /// * `value` - Concrete scalar to append.
636    /// * `data_type` - Shared runtime type of `self` and `value`.
637    ///
638    /// # Constraints
639    ///
640    /// Callers must ensure `value` is concrete and has `data_type`; the public
641    /// mutation entry points validate those invariants before calling this
642    /// helper.
643    #[inline]
644    fn add_scalar(&mut self, value: Value, data_type: DataType) {
645        match self {
646            Self::Scalar(current) => {
647                let current =
648                    std::mem::replace(current, Value::new_unset(data_type));
649                let collection = for_each_value_type!(
650                    value_container_pair_match,
651                    current,
652                    value
653                );
654                *self = Self::Collection(collection);
655            }
656            Self::Collection(collection) => {
657                for_each_value_type!(
658                    value_container_push_match,
659                    collection,
660                    value
661                );
662            }
663        }
664    }
665}