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