Skip to main content

qubit_value/multi_values/
multi_values_converters.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//! Internal conversion and interoperability implementations for `MultiValues`.
10//!
11//! This module keeps generic conversion logic (`to_first` and `to_list`).
12
13use qubit_datatype::{
14    DataConversionError,
15    DataConversionOptions,
16    DataConversionTarget,
17    DataConverter,
18    DataConverters,
19};
20
21use crate::IntoValueDefault;
22use crate::value_error::{
23    ValueError,
24    ValueResult,
25};
26
27use super::multi_values::{
28    MultiValues,
29    MultiValuesRepr,
30};
31
32macro_rules! multi_values_convert_first_match {
33    ($value:expr, $options:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal)),+ $(,)?) => {
34        match &$value.repr {
35            MultiValuesRepr::Unset(from) => {
36                Err(DataConversionError::missing(*from, T::DATA_TYPE).into())
37            }
38            $(
39                $(#[$cfg])*
40                MultiValuesRepr::$variant(values) => {
41                    convert_first_with(DataConverters::from(values), $options)
42                }
43            )+
44        }
45    };
46}
47
48macro_rules! multi_values_convert_list_match {
49    ($value:expr, $options:expr; $(([$($cfg:meta),*], $variant:ident, $type:ty, $data_type:expr, $materialization:ident, $json_class:ident, $number_projection:ident, $value_doc:literal, $multi_doc:literal)),+ $(,)?) => {
50        match &$value.repr {
51            MultiValuesRepr::Unset(from) => {
52                Err(DataConversionError::missing(*from, T::DATA_TYPE).into())
53            }
54            $(
55                $(#[$cfg])*
56                MultiValuesRepr::$variant(values) => {
57                    convert_values_with(DataConverters::from(values), $options)
58                }
59            )+
60        }
61    };
62}
63
64// ============================================================================
65// Inherent conversion APIs
66// ============================================================================
67
68/// Converts the first item from a batch converter using conversion options.
69///
70/// # Type Parameters
71///
72/// * `T` - Target type.
73/// * `I` - Iterator type wrapped by `DataConverters`.
74///
75/// # Parameters
76///
77/// * `values` - Batch converter containing source values.
78/// * `options` - Conversion options forwarded to `qubit_datatype`.
79///
80/// # Returns
81///
82/// Returns the converted first value.
83///
84/// # Errors
85///
86/// Returns the mapped single-value conversion error for an empty source or an
87/// invalid first source value.
88#[inline(always)]
89fn convert_first_with<'a, T, I>(
90    values: DataConverters<I>,
91    options: &DataConversionOptions,
92) -> ValueResult<T>
93where
94    T: DataConversionTarget,
95    I: Iterator,
96    I::Item: Into<DataConverter<'a>>,
97{
98    values.to_first_with(options).map_err(ValueError::from)
99}
100
101/// Converts every item from a batch converter using conversion options.
102///
103/// # Type Parameters
104///
105/// * `T` - Target element type.
106/// * `I` - Iterator type wrapped by `DataConverters`.
107///
108/// # Parameters
109///
110/// * `values` - Batch converter containing source values.
111/// * `options` - Conversion options forwarded to `qubit_datatype`.
112///
113/// # Returns
114///
115/// Returns converted values in the original order.
116///
117/// # Errors
118///
119/// Returns a mapped batch conversion error containing the failing source index.
120#[inline(always)]
121fn convert_values_with<'a, T, I>(
122    values: DataConverters<I>,
123    options: &DataConversionOptions,
124) -> ValueResult<Vec<T>>
125where
126    T: DataConversionTarget,
127    I: Iterator,
128    I::Item: Into<DataConverter<'a>>,
129{
130    values.to_vec_with(options).map_err(ValueError::from)
131}
132
133impl MultiValues {
134    /// Converts the first stored value to `T`.
135    ///
136    /// Unlike [`Self::get_first`], this method uses shared `DataConverter`
137    /// conversion rules instead of strict type matching. For example, a stored
138    /// `String("1")` can be converted to `bool`.
139    ///
140    /// # Type Parameters
141    ///
142    /// * `T` - Target type.
143    ///
144    /// # Returns
145    ///
146    /// The converted first value.
147    ///
148    /// # Errors
149    ///
150    /// Returns a structured missing-value conversion error when the container
151    /// is unset, an empty-collection error for a concrete empty vector, or a
152    /// conversion error when the first value cannot be converted to `T`.
153    #[inline(always)]
154    pub fn to_first<T>(&self) -> ValueResult<T>
155    where
156        T: DataConversionTarget,
157    {
158        self.to_first_with(DataConversionOptions::default_ref())
159    }
160
161    /// Converts the first stored value to `T`, or returns `default` when the
162    /// container is unset or conversion reports a missing value.
163    ///
164    /// A concrete empty collection remains an error and does not use the
165    /// default.
166    ///
167    /// # Type Parameters
168    ///
169    /// * `T` - Target type.
170    ///
171    /// # Parameters
172    ///
173    /// * `default` - Value returned for unset storage or a conversion-missing
174    ///   result.
175    ///
176    /// # Returns
177    ///
178    /// The converted first value, or `default` for unset or conversion-missing
179    /// storage.
180    ///
181    /// # Errors
182    ///
183    /// Returns an empty-collection error for a concrete empty vector, or a
184    /// conversion error when the first value cannot be converted to `T`.
185    #[inline]
186    pub fn to_first_or<T>(
187        &self,
188        default: impl IntoValueDefault<T>,
189    ) -> ValueResult<T>
190    where
191        T: DataConversionTarget,
192    {
193        match self.to_first() {
194            Err(ValueError::Missing(missing))
195                if missing.is_defaultable_for_conversion() =>
196            {
197                Ok(default.into_value_default())
198            }
199            result => result,
200        }
201    }
202
203    /// Converts the first value or calls `default` when storage is unset or
204    /// conversion reports a missing value.
205    ///
206    /// # Type Parameters
207    ///
208    /// * `T` - Target conversion type.
209    /// * `F` - Deferred fallback producing `T`.
210    ///
211    /// # Parameters
212    ///
213    /// * `default` - Callback invoked for unset storage or a conversion-missing
214    ///   result.
215    ///
216    /// # Returns
217    ///
218    /// The converted first item or the callback result.
219    ///
220    /// # Errors
221    ///
222    /// Preserves empty-collection and concrete-value conversion errors without
223    /// invoking the callback.
224    #[inline]
225    pub fn to_first_or_else<T, F>(&self, default: F) -> ValueResult<T>
226    where
227        T: DataConversionTarget,
228        F: FnOnce() -> T,
229    {
230        match self.to_first() {
231            Err(ValueError::Missing(missing))
232                if missing.is_defaultable_for_conversion() =>
233            {
234                Ok(default())
235            }
236            result => result,
237        }
238    }
239
240    /// Converts the first stored value to `T` using conversion options.
241    ///
242    /// Stored strings are collection items and are never split again by scalar
243    /// string collection options.
244    ///
245    /// # Type Parameters
246    ///
247    /// * `T` - Target type.
248    ///
249    /// # Parameters
250    ///
251    /// * `options` - Conversion options forwarded to `qubit_datatype`.
252    ///
253    /// # Returns
254    ///
255    /// The converted first value.
256    ///
257    /// # Errors
258    ///
259    /// Returns a structured missing-value conversion error when the container
260    /// is unset, an empty-collection error for a concrete empty vector, or a
261    /// conversion error when the first value cannot be converted to `T`.
262    pub fn to_first_with<T>(
263        &self,
264        options: &DataConversionOptions,
265    ) -> ValueResult<T>
266    where
267        T: DataConversionTarget,
268    {
269        for_each_value_type!(multi_values_convert_first_match, self, options)
270    }
271
272    /// Converts the first stored value to `T` using conversion options, or
273    /// returns `default` when storage is unset or conversion reports a missing
274    /// value.
275    ///
276    /// # Type Parameters
277    ///
278    /// * `T` - Target conversion type.
279    ///
280    /// # Parameters
281    ///
282    /// * `default` - Lazily materialized value used for unset storage or a
283    ///   conversion-missing result.
284    /// * `options` - Conversion options forwarded to `qubit_datatype`.
285    ///
286    /// # Returns
287    ///
288    /// The converted first item, or `default` for unset or conversion-missing
289    /// storage.
290    ///
291    /// # Errors
292    ///
293    /// Returns an empty-collection error or a conversion error for concrete
294    /// values that cannot be converted under `options`.
295    #[inline]
296    pub fn to_first_or_with<T>(
297        &self,
298        default: impl IntoValueDefault<T>,
299        options: &DataConversionOptions,
300    ) -> ValueResult<T>
301    where
302        T: DataConversionTarget,
303    {
304        match self.to_first_with(options) {
305            Err(ValueError::Missing(missing))
306                if missing.is_defaultable_for_conversion() =>
307            {
308                Ok(default.into_value_default())
309            }
310            result => result,
311        }
312    }
313
314    /// Converts the first value with `options`, or calls `default` when storage
315    /// is unset or conversion reports a missing value.
316    ///
317    /// # Type Parameters
318    ///
319    /// * `T` - Target conversion type.
320    /// * `F` - Deferred fallback producing `T`.
321    ///
322    /// # Parameters
323    ///
324    /// * `default` - Callback invoked for unset storage or a conversion-missing
325    ///   result.
326    /// * `options` - Conversion options forwarded to the shared converter.
327    ///
328    /// # Returns
329    ///
330    /// The converted first item or the callback result.
331    ///
332    /// # Errors
333    ///
334    /// Preserves concrete-value conversion errors without invoking the
335    /// callback.
336    #[inline]
337    pub fn to_first_or_else_with<T, F>(
338        &self,
339        default: F,
340        options: &DataConversionOptions,
341    ) -> ValueResult<T>
342    where
343        T: DataConversionTarget,
344        F: FnOnce() -> T,
345    {
346        match self.to_first_with(options) {
347            Err(ValueError::Missing(missing))
348                if missing.is_defaultable_for_conversion() =>
349            {
350                Ok(default())
351            }
352            result => result,
353        }
354    }
355
356    /// Converts all stored values to `T`.
357    ///
358    /// Unlike [`Self::get`], this method uses shared `DataConverter` conversion
359    /// rules for every element instead of strict type matching. A concrete
360    /// empty vector returns an empty vector; an unset container reports a
361    /// missing-value conversion error.
362    ///
363    /// # Type Parameters
364    ///
365    /// * `T` - Target element type.
366    ///
367    /// # Returns
368    ///
369    /// A vector containing all converted values in the original order.
370    ///
371    /// # Errors
372    ///
373    /// Returns the first conversion error encountered while converting an
374    /// element.
375    pub fn to_list<T>(&self) -> ValueResult<Vec<T>>
376    where
377        T: DataConversionTarget,
378    {
379        self.to_list_with(DataConversionOptions::default_ref())
380    }
381
382    /// Converts all stored values to `T`, or returns `default` when storage is
383    /// unset or conversion reports a missing value.
384    ///
385    /// # Type Parameters
386    ///
387    /// * `T` - Target element type.
388    ///
389    /// # Parameters
390    ///
391    /// * `default` - Lazily materialized list used for unset storage or a
392    ///   conversion-missing result.
393    ///
394    /// # Returns
395    ///
396    /// All converted items, or `default` for unset or conversion-missing
397    /// storage.
398    ///
399    /// # Errors
400    ///
401    /// Returns the first item conversion error for concrete storage.
402    #[inline]
403    pub fn to_list_or<T>(
404        &self,
405        default: impl IntoValueDefault<Vec<T>>,
406    ) -> ValueResult<Vec<T>>
407    where
408        T: DataConversionTarget,
409    {
410        match self.to_list() {
411            Err(ValueError::Missing(missing))
412                if missing.is_defaultable_for_conversion() =>
413            {
414                Ok(default.into_value_default())
415            }
416            result => result,
417        }
418    }
419
420    /// Converts all values or calls `default` when storage is unset or
421    /// conversion reports a missing value.
422    ///
423    /// # Type Parameters
424    ///
425    /// * `T` - Target element conversion type.
426    /// * `F` - Deferred fallback producing the complete list.
427    ///
428    /// # Parameters
429    ///
430    /// * `default` - Callback invoked for unset storage or a conversion-missing
431    ///   result.
432    ///
433    /// # Returns
434    ///
435    /// The converted list or the callback result.
436    ///
437    /// # Errors
438    ///
439    /// Preserves concrete-value conversion errors without invoking the
440    /// callback.
441    #[inline]
442    pub fn to_list_or_else<T, F>(&self, default: F) -> ValueResult<Vec<T>>
443    where
444        T: DataConversionTarget,
445        F: FnOnce() -> Vec<T>,
446    {
447        match self.to_list() {
448            Err(ValueError::Missing(missing))
449                if missing.is_defaultable_for_conversion() =>
450            {
451                Ok(default())
452            }
453            result => result,
454        }
455    }
456
457    /// Converts all stored values to `T` using conversion options.
458    ///
459    /// Stored strings are collection items and are never split again by scalar
460    /// string collection options.
461    ///
462    /// # Type Parameters
463    ///
464    /// * `T` - Target element type.
465    ///
466    /// # Parameters
467    ///
468    /// * `options` - Conversion options forwarded to `qubit_datatype`.
469    ///
470    /// # Returns
471    ///
472    /// A vector containing all converted values in the original order.
473    ///
474    /// # Errors
475    ///
476    /// Returns the first conversion error encountered while converting an
477    /// element.
478    pub fn to_list_with<T>(
479        &self,
480        options: &DataConversionOptions,
481    ) -> ValueResult<Vec<T>>
482    where
483        T: DataConversionTarget,
484    {
485        for_each_value_type!(multi_values_convert_list_match, self, options)
486    }
487
488    /// Converts all stored values to `T` using conversion options, or returns
489    /// `default` when storage is unset or conversion reports a missing value.
490    ///
491    /// # Type Parameters
492    ///
493    /// * `T` - Target element type.
494    ///
495    /// # Parameters
496    ///
497    /// * `default` - Lazily materialized list used for unset storage or a
498    ///   conversion-missing result.
499    /// * `options` - Conversion options forwarded to `qubit_datatype`.
500    ///
501    /// # Returns
502    ///
503    /// All converted items, or `default` for unset or conversion-missing
504    /// storage.
505    ///
506    /// # Errors
507    ///
508    /// Returns the first item conversion error for concrete storage.
509    #[inline]
510    pub fn to_list_or_with<T>(
511        &self,
512        default: impl IntoValueDefault<Vec<T>>,
513        options: &DataConversionOptions,
514    ) -> ValueResult<Vec<T>>
515    where
516        T: DataConversionTarget,
517    {
518        match self.to_list_with(options) {
519            Err(ValueError::Missing(missing))
520                if missing.is_defaultable_for_conversion() =>
521            {
522                Ok(default.into_value_default())
523            }
524            result => result,
525        }
526    }
527
528    /// Converts all values with `options`, or calls `default` when storage is
529    /// unset or conversion reports a missing value.
530    ///
531    /// # Type Parameters
532    ///
533    /// * `T` - Target element conversion type.
534    /// * `F` - Deferred fallback producing the complete list.
535    ///
536    /// # Parameters
537    ///
538    /// * `default` - Callback invoked for unset storage or a conversion-missing
539    ///   result.
540    /// * `options` - Conversion options forwarded to the shared converter.
541    ///
542    /// # Returns
543    ///
544    /// The converted list or the callback result.
545    ///
546    /// # Errors
547    ///
548    /// Preserves concrete-value conversion errors without invoking the
549    /// callback.
550    #[inline]
551    pub fn to_list_or_else_with<T, F>(
552        &self,
553        default: F,
554        options: &DataConversionOptions,
555    ) -> ValueResult<Vec<T>>
556    where
557        T: DataConversionTarget,
558        F: FnOnce() -> Vec<T>,
559    {
560        match self.to_list_with(options) {
561            Err(ValueError::Missing(missing))
562                if missing.is_defaultable_for_conversion() =>
563            {
564                Ok(default())
565            }
566            result => result,
567        }
568    }
569}