qubit_value/value/value_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 implementations for value conversion support.
10//!
11//! This module focuses on conversion helpers backed by `qubit_datatype`.
12
13use qubit_datatype::ConversionLimits;
14use qubit_datatype::ConversionPolicy;
15use qubit_datatype::ConversionSession;
16use qubit_datatype::DataConversionError;
17use qubit_datatype::DataConversionTarget;
18use qubit_datatype::DataConverter;
19
20use super::Value;
21use super::ValueRepr;
22use crate::ValueMissingReason;
23use crate::ValueRef;
24use crate::value_error::ValueError;
25use crate::value_error::ValueResult;
26
27/// Converts semantic views without constructing an owned runtime value.
28macro_rules! value_ref_data_converter_match {
29 ($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)*)),+ $(,)?) => {
30 match $value {
31 ValueRef::Unset(data_type) => DataConverter::Unset(data_type),
32 $($(#[$cfg])* ValueRef::$variant(value) => DataConverter::from(value),)+
33 }
34 };
35}
36
37impl<'a> From<ValueRef<'a>> for DataConverter<'a> {
38 /// Borrows rich view payloads and copies primitive conversion sources.
39 fn from(value: ValueRef<'a>) -> Self {
40 for_each_value_type!(value_ref_data_converter_match, value)
41 }
42}
43
44/// Expands the shared value table into a `DataConverter` construction match.
45macro_rules! value_data_converter_match {
46 ($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)*)),+ $(,)?) => {
47 match &$value.repr {
48 ValueRepr::Unset(data_type) => DataConverter::Unset(*data_type),
49 $($(#[$cfg])* ValueRepr::$variant(value) => DataConverter::from(value_storage_ref!($variant, value)),)+
50 }
51 };
52}
53
54/// Wraps a `Value` into the common conversion helper for the `qubit_datatype`
55/// conversion API.
56///
57/// # Parameters
58///
59/// * `value` - Runtime value whose payload is borrowed by the converter.
60///
61/// # Returns
62///
63/// A shared converter view preserving the runtime data type.
64fn data_converter_from_value(value: &Value) -> DataConverter<'_> {
65 for_each_value_type!(value_data_converter_match, value)
66}
67
68impl<'a> From<&'a Value> for DataConverter<'a> {
69 /// Borrows a runtime value as a shared conversion source.
70 ///
71 /// # Parameters
72 ///
73 /// * `value` - Runtime value whose storage is exposed to the converter.
74 ///
75 /// # Returns
76 ///
77 /// A [`DataConverter`] borrowing rich payloads from `value` without
78 /// cloning them.
79 #[inline(always)]
80 fn from(value: &'a Value) -> Self {
81 data_converter_from_value(value)
82 }
83}
84
85/// Converts a single `Value` into `T` using shared conversion helpers,
86/// conversion policy, and resource limits.
87///
88/// # Type Parameters
89///
90/// * `T` - Target type supported by the shared conversion layer.
91///
92/// # Parameters
93///
94/// * `value` - Source value to convert.
95/// * `policy` - Conversion policy forwarded to `qubit_datatype`.
96/// * `limits` - Conversion limits forwarded to `qubit_datatype`.
97///
98/// # Returns
99///
100/// Returns the converted value.
101///
102/// # Errors
103///
104/// Returns a `ValueError` mapped from the shared conversion error when the
105/// source value is missing, unsupported, or invalid for `T`.
106pub(super) fn convert_with_data_converter_with<T>(
107 value: &Value,
108 policy: &ConversionPolicy,
109 limits: &ConversionLimits,
110) -> ValueResult<T>
111where
112 T: DataConversionTarget,
113{
114 data_converter_from_value(value)
115 .to_with::<T>(policy, limits)
116 .map_err(|error| contextual_conversion_error(value, error))
117}
118
119/// Converts a single `Value` into `T` using an existing conversion session.
120///
121/// # Type Parameters
122///
123/// * `T` - Target type supported by the shared conversion layer.
124///
125/// # Parameters
126///
127/// * `value` - Source runtime value.
128/// * `session` - Caller-owned session providing policy, limits, and budget.
129///
130/// # Returns
131///
132/// The converted target value.
133///
134/// # Errors
135///
136/// Returns a mapped missing, conversion, or budget error.
137pub(super) fn convert_with_data_converter_in<T>(value: &Value, session: &mut ConversionSession<'_>) -> ValueResult<T>
138where
139 T: DataConversionTarget,
140{
141 data_converter_from_value(value)
142 .to_in::<T>(session)
143 .map_err(|error| contextual_conversion_error(value, error))
144}
145
146/// Preserves scalar storage facts after the converter has completed admission.
147fn contextual_conversion_error(value: &Value, error: DataConversionError) -> ValueError {
148 match ValueError::from(error) {
149 ValueError::Missing(missing) if value.is_unset() => {
150 ValueError::Missing(missing.with_storage(value.data_type(), ValueMissingReason::UnsetScalar))
151 }
152 error => error,
153 }
154}