Skip to main content

qubit_value/multi_values/
multi_values_converters.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10
11//! Internal conversion and interoperability implementations for `MultiValues`.
12//!
13//! This module keeps generic conversion logic (`to`, `to_list`, `to_value`, etc.)
14//! while dispatch traits are implemented in dedicated `multi_values_*` modules.
15
16use qubit_datatype::{
17    DataConversionError,
18    DataConversionOptions,
19    DataConvertTo,
20    DataConverter,
21    DataConverters,
22    DataListConversionError,
23    DataType,
24    ScalarStringDataConverters,
25};
26
27use crate::value_error::{
28    ValueError,
29    ValueResult,
30};
31use crate::{
32    IntoValueDefault,
33    Value,
34};
35
36use super::multi_values::MultiValues;
37
38macro_rules! multi_values_to_value_match {
39    ($value:expr; $(($variant:ident, $type:ty, $data_type:expr)),+ $(,)?) => {
40        match $value {
41            MultiValues::Empty(data_type) => Value::Empty(*data_type),
42            $(
43                MultiValues::$variant(values) => values
44                    .first()
45                    .cloned()
46                    .map(Value::$variant)
47                    .unwrap_or(Value::Empty($data_type)),
48            )+
49        }
50    };
51}
52
53macro_rules! multi_values_merge_match {
54    ($left:expr, $right:expr; $(($variant:ident, $type:ty, $data_type:expr)),+ $(,)?) => {
55        match ($left, $right) {
56            $(
57                (MultiValues::$variant(values), MultiValues::$variant(other_values)) => {
58                    values.extend_from_slice(other_values)
59                }
60            )+
61            (slot @ MultiValues::Empty(_), other_values) => *slot = other_values.clone(),
62            _ => unreachable!(),
63        }
64    };
65}
66
67// ============================================================================
68// Inherent conversion APIs and `Value` interop
69// ============================================================================
70
71/// Maps a shared single-value conversion error into `ValueError`.
72///
73/// # Parameters
74///
75/// * `error` - Error returned by `DataConverter`.
76///
77/// # Returns
78///
79/// Returns the corresponding `ValueError` variant.
80fn map_data_conversion_error(error: DataConversionError) -> ValueError {
81    match error {
82        DataConversionError::NoValue => ValueError::NoValue,
83        DataConversionError::ConversionFailed { from, to } => {
84            ValueError::ConversionFailed { from, to }
85        }
86        DataConversionError::ConversionError(message) => ValueError::ConversionError(message),
87        DataConversionError::JsonSerializationError(message) => {
88            ValueError::JsonSerializationError(message)
89        }
90        DataConversionError::JsonDeserializationError(message) => {
91            ValueError::JsonDeserializationError(message)
92        }
93    }
94}
95
96/// Maps a shared batch conversion error into `ValueError`.
97///
98/// # Parameters
99///
100/// * `error` - Error returned by `DataConverters`.
101///
102/// # Returns
103///
104/// Returns a `ValueError::ConversionError` whose message includes the failing
105/// source element index and the underlying conversion error.
106#[inline]
107fn map_data_list_conversion_error(error: DataListConversionError) -> ValueError {
108    let source = map_data_conversion_error(error.source);
109    ValueError::ConversionError(format!(
110        "Cannot convert value at index {}: {}",
111        error.index, source
112    ))
113}
114
115/// Converts the first item from a batch converter using conversion options.
116///
117/// # Type Parameters
118///
119/// * `T` - Target type.
120/// * `I` - Iterator type wrapped by `DataConverters`.
121///
122/// # Parameters
123///
124/// * `values` - Batch converter containing source values.
125/// * `options` - Conversion options forwarded to `qubit_datatype`.
126///
127/// # Returns
128///
129/// Returns the converted first value.
130///
131/// # Errors
132///
133/// Returns `ValueError::NoValue` for empty sources or the mapped single-value
134/// conversion error for an invalid first source value.
135#[inline]
136fn convert_first_with<'a, T, I>(
137    values: DataConverters<'a, I>,
138    options: &DataConversionOptions,
139) -> ValueResult<T>
140where
141    DataConverter<'a>: DataConvertTo<T>,
142    I: Iterator,
143    I::Item: Into<DataConverter<'a>>,
144{
145    values
146        .to_first_with(options)
147        .map_err(map_data_conversion_error)
148}
149
150/// Converts every item from a batch converter using conversion options.
151///
152/// # Type Parameters
153///
154/// * `T` - Target element type.
155/// * `I` - Iterator type wrapped by `DataConverters`.
156///
157/// # Parameters
158///
159/// * `values` - Batch converter containing source values.
160/// * `options` - Conversion options forwarded to `qubit_datatype`.
161///
162/// # Returns
163///
164/// Returns converted values in the original order.
165///
166/// # Errors
167///
168/// Returns a mapped batch conversion error containing the failing source index.
169#[inline]
170fn convert_values_with<'a, T, I>(
171    values: DataConverters<'a, I>,
172    options: &DataConversionOptions,
173) -> ValueResult<Vec<T>>
174where
175    DataConverter<'a>: DataConvertTo<T>,
176    I: Iterator,
177    I::Item: Into<DataConverter<'a>>,
178{
179    values
180        .to_vec_with(options)
181        .map_err(map_data_list_conversion_error)
182}
183
184impl MultiValues {
185    /// Converts the first stored value to `T`.
186    ///
187    /// Unlike [`Self::get_first`], this method uses shared `DataConverter`
188    /// conversion rules instead of strict type matching. For example, a stored
189    /// `String("1")` can be converted to `bool`.
190    ///
191    /// # Type Parameters
192    ///
193    /// * `T` - Target type.
194    ///
195    /// # Returns
196    ///
197    /// The converted first value.
198    ///
199    /// # Errors
200    ///
201    /// Returns [`ValueError::NoValue`] when no value is stored, or a conversion
202    /// error when the first value cannot be converted to `T`.
203    #[inline]
204    pub fn to<T>(&self) -> ValueResult<T>
205    where
206        for<'a> DataConverter<'a>: DataConvertTo<T>,
207    {
208        self.to_with(&DataConversionOptions::default())
209    }
210
211    /// Converts the first stored value to `T`, or returns `default` when no
212    /// value is stored.
213    #[inline]
214    pub fn to_or<T>(&self, default: impl IntoValueDefault<T>) -> ValueResult<T>
215    where
216        for<'a> DataConverter<'a>: DataConvertTo<T>,
217    {
218        match self.to() {
219            Err(ValueError::NoValue) => Ok(default.into_value_default()),
220            result => result,
221        }
222    }
223
224    /// Converts the first stored value to `T` using conversion options.
225    ///
226    /// A `MultiValues::String` containing exactly one string is treated as a
227    /// scalar string source, so collection options can split it before taking
228    /// the first converted item. Multiple stored string values are treated as
229    /// an already-materialized list and are converted element by element.
230    ///
231    /// # Type Parameters
232    ///
233    /// * `T` - Target type.
234    ///
235    /// # Parameters
236    ///
237    /// * `options` - Conversion options forwarded to `qubit_datatype`.
238    ///
239    /// # Returns
240    ///
241    /// The converted first value.
242    ///
243    /// # Errors
244    ///
245    /// Returns [`ValueError::NoValue`] when no value is stored, or a conversion
246    /// error when the first value cannot be converted to `T`.
247    #[inline]
248    pub fn to_with<T>(&self, options: &DataConversionOptions) -> ValueResult<T>
249    where
250        for<'a> DataConverter<'a>: DataConvertTo<T>,
251    {
252        match self {
253            MultiValues::Empty(_) => Err(ValueError::NoValue),
254            MultiValues::Bool(v) => convert_first_with(DataConverters::from(v), options),
255            MultiValues::Char(v) => convert_first_with(DataConverters::from(v), options),
256            MultiValues::Int8(v) => convert_first_with(DataConverters::from(v), options),
257            MultiValues::Int16(v) => convert_first_with(DataConverters::from(v), options),
258            MultiValues::Int32(v) => convert_first_with(DataConverters::from(v), options),
259            MultiValues::Int64(v) => convert_first_with(DataConverters::from(v), options),
260            MultiValues::Int128(v) => convert_first_with(DataConverters::from(v), options),
261            MultiValues::UInt8(v) => convert_first_with(DataConverters::from(v), options),
262            MultiValues::UInt16(v) => convert_first_with(DataConverters::from(v), options),
263            MultiValues::UInt32(v) => convert_first_with(DataConverters::from(v), options),
264            MultiValues::UInt64(v) => convert_first_with(DataConverters::from(v), options),
265            MultiValues::UInt128(v) => convert_first_with(DataConverters::from(v), options),
266            MultiValues::IntSize(v) => convert_first_with(DataConverters::from(v), options),
267            MultiValues::UIntSize(v) => convert_first_with(DataConverters::from(v), options),
268            MultiValues::Float32(v) => convert_first_with(DataConverters::from(v), options),
269            MultiValues::Float64(v) => convert_first_with(DataConverters::from(v), options),
270            MultiValues::BigInteger(v) => convert_first_with(DataConverters::from(v), options),
271            MultiValues::BigDecimal(v) => convert_first_with(DataConverters::from(v), options),
272            MultiValues::String(v) if v.len() == 1 => {
273                ScalarStringDataConverters::from(v[0].as_str())
274                    .to_first_with(options)
275                    .map_err(map_data_conversion_error)
276            }
277            MultiValues::String(v) => convert_first_with(DataConverters::from(v), options),
278            MultiValues::Date(v) => convert_first_with(DataConverters::from(v), options),
279            MultiValues::Time(v) => convert_first_with(DataConverters::from(v), options),
280            MultiValues::DateTime(v) => convert_first_with(DataConverters::from(v), options),
281            MultiValues::Instant(v) => convert_first_with(DataConverters::from(v), options),
282            MultiValues::Duration(v) => convert_first_with(DataConverters::from(v), options),
283            MultiValues::Url(v) => convert_first_with(DataConverters::from(v), options),
284            MultiValues::StringMap(v) => convert_first_with(DataConverters::from(v), options),
285            MultiValues::Json(v) => convert_first_with(DataConverters::from(v), options),
286        }
287    }
288
289    /// Converts the first stored value to `T` using conversion options, or
290    /// returns `default` when no value is stored.
291    #[inline]
292    pub fn to_or_with<T>(
293        &self,
294        default: impl IntoValueDefault<T>,
295        options: &DataConversionOptions,
296    ) -> ValueResult<T>
297    where
298        for<'a> DataConverter<'a>: DataConvertTo<T>,
299    {
300        match self.to_with(options) {
301            Err(ValueError::NoValue) => Ok(default.into_value_default()),
302            result => result,
303        }
304    }
305
306    /// Converts all stored values to `T`.
307    ///
308    /// Unlike [`Self::get`], this method uses shared `DataConverter` conversion
309    /// rules for every element instead of strict type matching. Empty values
310    /// return an empty vector.
311    ///
312    /// # Type Parameters
313    ///
314    /// * `T` - Target element type.
315    ///
316    /// # Returns
317    ///
318    /// A vector containing all converted values in the original order.
319    ///
320    /// # Errors
321    ///
322    /// Returns the first conversion error encountered while converting an
323    /// element.
324    pub fn to_list<T>(&self) -> ValueResult<Vec<T>>
325    where
326        for<'a> DataConverter<'a>: DataConvertTo<T>,
327    {
328        self.to_list_with(&DataConversionOptions::default())
329    }
330
331    /// Converts all stored values to `T`, or returns `default` when the
332    /// converted list is empty.
333    #[inline]
334    pub fn to_list_or<T>(&self, default: impl IntoValueDefault<Vec<T>>) -> ValueResult<Vec<T>>
335    where
336        for<'a> DataConverter<'a>: DataConvertTo<T>,
337    {
338        let values = self.to_list()?;
339        if values.is_empty() {
340            Ok(default.into_value_default())
341        } else {
342            Ok(values)
343        }
344    }
345
346    /// Converts all stored values to `T` using conversion options.
347    ///
348    /// A `MultiValues::String` containing exactly one string is treated as a
349    /// scalar string source, so collection options can split it into items.
350    /// Multiple stored string values are treated as an already-materialized
351    /// list and are converted element by element.
352    ///
353    /// # Type Parameters
354    ///
355    /// * `T` - Target element type.
356    ///
357    /// # Parameters
358    ///
359    /// * `options` - Conversion options forwarded to `qubit_datatype`.
360    ///
361    /// # Returns
362    ///
363    /// A vector containing all converted values in the original order.
364    ///
365    /// # Errors
366    ///
367    /// Returns the first conversion error encountered while converting an
368    /// element.
369    pub fn to_list_with<T>(&self, options: &DataConversionOptions) -> ValueResult<Vec<T>>
370    where
371        for<'a> DataConverter<'a>: DataConvertTo<T>,
372    {
373        match self {
374            MultiValues::Empty(_) => Ok(Vec::new()),
375            MultiValues::Bool(v) => convert_values_with(DataConverters::from(v), options),
376            MultiValues::Char(v) => convert_values_with(DataConverters::from(v), options),
377            MultiValues::Int8(v) => convert_values_with(DataConverters::from(v), options),
378            MultiValues::Int16(v) => convert_values_with(DataConverters::from(v), options),
379            MultiValues::Int32(v) => convert_values_with(DataConverters::from(v), options),
380            MultiValues::Int64(v) => convert_values_with(DataConverters::from(v), options),
381            MultiValues::Int128(v) => convert_values_with(DataConverters::from(v), options),
382            MultiValues::UInt8(v) => convert_values_with(DataConverters::from(v), options),
383            MultiValues::UInt16(v) => convert_values_with(DataConverters::from(v), options),
384            MultiValues::UInt32(v) => convert_values_with(DataConverters::from(v), options),
385            MultiValues::UInt64(v) => convert_values_with(DataConverters::from(v), options),
386            MultiValues::UInt128(v) => convert_values_with(DataConverters::from(v), options),
387            MultiValues::IntSize(v) => convert_values_with(DataConverters::from(v), options),
388            MultiValues::UIntSize(v) => convert_values_with(DataConverters::from(v), options),
389            MultiValues::Float32(v) => convert_values_with(DataConverters::from(v), options),
390            MultiValues::Float64(v) => convert_values_with(DataConverters::from(v), options),
391            MultiValues::BigInteger(v) => convert_values_with(DataConverters::from(v), options),
392            MultiValues::BigDecimal(v) => convert_values_with(DataConverters::from(v), options),
393            MultiValues::String(v) if v.len() == 1 => {
394                ScalarStringDataConverters::from(v[0].as_str())
395                    .to_vec_with(options)
396                    .map_err(map_data_list_conversion_error)
397            }
398            MultiValues::String(v) => convert_values_with(DataConverters::from(v), options),
399            MultiValues::Date(v) => convert_values_with(DataConverters::from(v), options),
400            MultiValues::Time(v) => convert_values_with(DataConverters::from(v), options),
401            MultiValues::DateTime(v) => convert_values_with(DataConverters::from(v), options),
402            MultiValues::Instant(v) => convert_values_with(DataConverters::from(v), options),
403            MultiValues::Duration(v) => convert_values_with(DataConverters::from(v), options),
404            MultiValues::Url(v) => convert_values_with(DataConverters::from(v), options),
405            MultiValues::StringMap(v) => convert_values_with(DataConverters::from(v), options),
406            MultiValues::Json(v) => convert_values_with(DataConverters::from(v), options),
407        }
408    }
409
410    /// Converts all stored values to `T` using conversion options, or returns
411    /// `default` when the converted list is empty.
412    #[inline]
413    pub fn to_list_or_with<T>(
414        &self,
415        default: impl IntoValueDefault<Vec<T>>,
416        options: &DataConversionOptions,
417    ) -> ValueResult<Vec<T>>
418    where
419        for<'a> DataConverter<'a>: DataConvertTo<T>,
420    {
421        let values = self.to_list_with(options)?;
422        if values.is_empty() {
423            Ok(default.into_value_default())
424        } else {
425            Ok(values)
426        }
427    }
428
429    /// Convert to a single [`Value`] by taking the first element.
430    ///
431    /// If there is no element, returns `Value::Empty(self.data_type())`.
432    ///
433    /// # Returns
434    ///
435    /// Returns the first element wrapped as [`Value`], or an empty value
436    /// preserving the current data type.
437    pub fn to_value(&self) -> Value {
438        for_each_multi_value_type!(multi_values_to_value_match, self)
439    }
440
441    /// Merge another multiple values
442    ///
443    /// Append all values from another multiple values to the current multiple values
444    ///
445    /// # Parameters
446    ///
447    /// * `other` - The multiple values to merge
448    ///
449    /// # Returns
450    ///
451    /// If types match, returns `Ok(())`; otherwise returns an error
452    ///
453    /// # Example
454    ///
455    /// ```rust
456    /// use qubit_value::MultiValues;
457    ///
458    /// let mut a = MultiValues::Int32(vec![1, 2]);
459    /// let b = MultiValues::Int32(vec![3, 4]);
460    /// a.merge(&b).unwrap();
461    /// assert_eq!(a.get_int32s().unwrap(), &[1, 2, 3, 4]);
462    /// ```
463    pub fn merge(&mut self, other: &MultiValues) -> ValueResult<()> {
464        if self.data_type() != other.data_type() {
465            return Err(ValueError::TypeMismatch {
466                expected: self.data_type(),
467                actual: other.data_type(),
468            });
469        }
470        if other.count() == 0 {
471            return Ok(());
472        }
473
474        for_each_multi_value_type!(multi_values_merge_match, self, other);
475
476        Ok(())
477    }
478}
479
480impl Default for MultiValues {
481    #[inline]
482    fn default() -> Self {
483        MultiValues::Empty(DataType::String)
484    }
485}
486
487impl From<Value> for MultiValues {
488    fn from(value: Value) -> Self {
489        match value {
490            Value::Empty(dt) => MultiValues::Empty(dt),
491            Value::Bool(v) => MultiValues::Bool(vec![v]),
492            Value::Char(v) => MultiValues::Char(vec![v]),
493            Value::Int8(v) => MultiValues::Int8(vec![v]),
494            Value::Int16(v) => MultiValues::Int16(vec![v]),
495            Value::Int32(v) => MultiValues::Int32(vec![v]),
496            Value::Int64(v) => MultiValues::Int64(vec![v]),
497            Value::Int128(v) => MultiValues::Int128(vec![v]),
498            Value::UInt8(v) => MultiValues::UInt8(vec![v]),
499            Value::UInt16(v) => MultiValues::UInt16(vec![v]),
500            Value::UInt32(v) => MultiValues::UInt32(vec![v]),
501            Value::UInt64(v) => MultiValues::UInt64(vec![v]),
502            Value::UInt128(v) => MultiValues::UInt128(vec![v]),
503            Value::Float32(v) => MultiValues::Float32(vec![v]),
504            Value::Float64(v) => MultiValues::Float64(vec![v]),
505            Value::String(v) => MultiValues::String(vec![v]),
506            Value::Date(v) => MultiValues::Date(vec![v]),
507            Value::Time(v) => MultiValues::Time(vec![v]),
508            Value::DateTime(v) => MultiValues::DateTime(vec![v]),
509            Value::Instant(v) => MultiValues::Instant(vec![v]),
510            Value::BigInteger(v) => MultiValues::BigInteger(vec![v]),
511            Value::BigDecimal(v) => MultiValues::BigDecimal(vec![v]),
512            Value::IntSize(v) => MultiValues::IntSize(vec![v]),
513            Value::UIntSize(v) => MultiValues::UIntSize(vec![v]),
514            Value::Duration(v) => MultiValues::Duration(vec![v]),
515            Value::Url(v) => MultiValues::Url(vec![v]),
516            Value::StringMap(v) => MultiValues::StringMap(vec![v]),
517            Value::Json(v) => MultiValues::Json(vec![v]),
518        }
519    }
520}