#[cfg(all(feature = "converter", feature = "json"))]
use qubit_budget::MeasuredBudgetError;
#[cfg(all(feature = "converter", feature = "json"))]
use qubit_datatype::ConversionResource;
#[cfg(feature = "converter")]
use qubit_datatype::DataConversionError;
#[cfg(feature = "converter")]
use qubit_datatype::DataConversionErrorKind;
#[cfg(feature = "converter")]
use qubit_datatype::DataListConversionError;
use qubit_datatype::DataType;
use thiserror::Error;
use crate::ValueMissing;
#[non_exhaustive]
#[must_use]
#[derive(Debug, Clone, Error)]
pub enum ValueError {
#[cfg(all(feature = "converter", feature = "json"))]
#[error("JSON projection limit for {data_type} at collection index {source_index:?}: {source}")]
JsonProjectionLimit {
data_type: DataType,
source_index: Option<usize>,
#[source]
source: MeasuredBudgetError<ConversionResource, u64>,
},
#[error("Missing value: {0}")]
Missing(
#[source]
ValueMissing,
),
#[error("Type mismatch: expected {expected}, actual {actual}")]
TypeMismatch {
expected: DataType,
actual: DataType,
},
#[cfg(feature = "converter")]
#[error("Conversion error: {0}")]
Conversion(
#[source]
DataConversionError,
),
#[cfg(feature = "converter")]
#[error("List conversion error: {0}")]
ListConversion(
#[source]
DataListConversionError,
),
}
impl PartialEq for ValueError {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Missing(left), Self::Missing(right)) => left == right,
(
Self::TypeMismatch {
expected: le,
actual: la,
},
Self::TypeMismatch {
expected: re,
actual: ra,
},
) => le == re && la == ra,
#[cfg(feature = "converter")]
(Self::Conversion(left), Self::Conversion(right)) => left == right,
#[cfg(feature = "converter")]
(Self::ListConversion(left), Self::ListConversion(right)) => left == right,
#[cfg(all(feature = "converter", feature = "json"))]
(
Self::JsonProjectionLimit {
data_type: lt,
source_index: li,
source: ls,
},
Self::JsonProjectionLimit {
data_type: rt,
source_index: ri,
source: rs,
},
) => {
lt == rt
&& li == ri
&& ls.resource() == rs.resource()
&& ls.budget_error() == rs.budget_error()
&& ls.quantity_error() == rs.quantity_error()
}
_ => false,
}
}
}
impl Eq for ValueError {}
impl ValueError {
#[must_use]
#[inline(always)]
pub const fn is_missing(&self) -> bool {
matches!(self, Self::Missing(_))
}
#[must_use]
#[inline(always)]
pub const fn missing(&self) -> Option<&ValueMissing> {
match self {
Self::Missing(missing) => Some(missing),
Self::TypeMismatch { .. } => None,
#[cfg(all(feature = "converter", feature = "json"))]
Self::JsonProjectionLimit { .. } => None,
#[cfg(feature = "converter")]
Self::Conversion(_) | Self::ListConversion(_) => None,
}
}
}
#[cfg(feature = "converter")]
impl From<DataConversionError> for ValueError {
fn from(error: DataConversionError) -> Self {
if error.is_missing() || error.kind() == DataConversionErrorKind::EmptyCollection {
return Self::Missing(ValueMissing::from_conversion(error, None));
}
Self::Conversion(error)
}
}
#[cfg(feature = "converter")]
impl From<DataListConversionError> for ValueError {
fn from(error: DataListConversionError) -> Self {
let (source_index, source) = error.into_parts();
if source.is_missing() || source.kind() == DataConversionErrorKind::EmptyCollection {
return Self::Missing(ValueMissing::from_conversion(source, Some(source_index)));
}
Self::ListConversion(DataListConversionError::new(source_index, source))
}
}
pub type ValueResult<T> = Result<T, ValueError>;