use qubit_datatype::ConversionLimits;
use qubit_datatype::ConversionPolicy;
use qubit_datatype::ConversionSession;
use qubit_datatype::DataConversionError;
use qubit_datatype::DataConversionTarget;
use qubit_datatype::DataConverter;
use super::Value;
use super::ValueRepr;
use crate::ValueMissingReason;
use crate::ValueRef;
use crate::value_error::ValueError;
use crate::value_error::ValueResult;
macro_rules! value_ref_data_converter_match {
($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)*)),+ $(,)?) => {
match $value {
ValueRef::Unset(data_type) => DataConverter::Unset(data_type),
$($(#[$cfg])* ValueRef::$variant(value) => DataConverter::from(value),)+
}
};
}
impl<'a> From<ValueRef<'a>> for DataConverter<'a> {
fn from(value: ValueRef<'a>) -> Self {
for_each_value_type!(value_ref_data_converter_match, value)
}
}
macro_rules! value_data_converter_match {
($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)*)),+ $(,)?) => {
match &$value.repr {
ValueRepr::Unset(data_type) => DataConverter::Unset(*data_type),
$($(#[$cfg])* ValueRepr::$variant(value) => DataConverter::from(value_storage_ref!($variant, value)),)+
}
};
}
fn data_converter_from_value(value: &Value) -> DataConverter<'_> {
for_each_value_type!(value_data_converter_match, value)
}
impl<'a> From<&'a Value> for DataConverter<'a> {
#[inline(always)]
fn from(value: &'a Value) -> Self {
data_converter_from_value(value)
}
}
pub(super) fn convert_with_data_converter_with<T>(
value: &Value,
policy: &ConversionPolicy,
limits: &ConversionLimits,
) -> ValueResult<T>
where
T: DataConversionTarget,
{
data_converter_from_value(value)
.to_with::<T>(policy, limits)
.map_err(|error| contextual_conversion_error(value, error))
}
pub(super) fn convert_with_data_converter_in<T>(value: &Value, session: &mut ConversionSession<'_>) -> ValueResult<T>
where
T: DataConversionTarget,
{
data_converter_from_value(value)
.to_in::<T>(session)
.map_err(|error| contextual_conversion_error(value, error))
}
fn contextual_conversion_error(value: &Value, error: DataConversionError) -> ValueError {
match ValueError::from(error) {
ValueError::Missing(missing) if value.is_unset() => {
ValueError::Missing(missing.with_storage(value.data_type(), ValueMissingReason::UnsetScalar))
}
error => error,
}
}