use crate::failure::{Because, StorageError};
use crate::path::{StorePath, StorePathError};
use error_stack::Report;
use std::fmt;
#[macro_export]
macro_rules! what_the_store_said {
($ty:ident) => {
impl $ty {
pub fn from_store(
at: &$crate::path::StorePath,
why: ::error_stack::Report<$crate::failure::StorageError>,
) -> Self {
match *why.current_context() {
$crate::failure::StorageError::Depth => Self::TooDeep {
at: at.clone(),
why: why.into(),
},
$crate::failure::StorageError::Codec => Self::WillNotEncode {
at: at.clone(),
why: why.into(),
},
$crate::failure::StorageError::Closed => Self::Closed { at: at.clone() },
_ => Self::Store(why.into()),
}
}
pub fn explain(&self) -> String {
match self {
Self::Store(why)
| Self::TooDeep { why, .. }
| Self::WillNotEncode { why, .. } => why.explain(),
other => other.to_string(),
}
}
}
};
}
pub enum WriteValue {
Absent { at: StorePath },
NotAPath(StorePathError),
TooDeep { at: StorePath, why: Because },
WillNotEncode { at: StorePath, why: Because },
Closed { at: StorePath },
SourceGone,
Store(Because),
}
what_the_store_said!(WriteValue);
impl WriteValue {
pub fn from_backend<E>(at: &StorePath, doing: StorageError, why: Report<E>) -> Self
where
E: std::error::Error + Send + Sync + 'static,
{
Self::from_store(at, why.change_context(doing))
}
}
impl fmt::Display for WriteValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Absent { at } => write!(f, "nothing is stored at {at}"),
Self::NotAPath(why) => write!(f, "the write was given no path to land at: {why}"),
Self::TooDeep { at, .. } => write!(f, "{at} is deeper than this store reads back"),
Self::WillNotEncode { at, .. } => {
write!(f, "what was written to {at} will not encode")
}
Self::Closed { at } => {
write!(f, "the store was closed, so nothing was written to {at}")
}
Self::SourceGone => f.write_str(
"the value this cell views is gone: the field or map it came from was dropped",
),
Self::Store(why) => write!(f, "{}", why.current_context()),
}
}
}
impl fmt::Debug for WriteValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
crate::failure::spelled(self, f)
}
}
impl std::error::Error for WriteValue {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::NotAPath(why) => Some(why),
Self::Store(why) | Self::TooDeep { why, .. } | Self::WillNotEncode { why, .. } => {
why.caused().map(|under| under as &dyn std::error::Error)
}
Self::Absent { .. } | Self::Closed { .. } | Self::SourceGone => None,
}
}
}
impl From<StorePathError> for WriteValue {
fn from(why: StorePathError) -> Self {
Self::NotAPath(why)
}
}
impl From<Report<StorageError>> for WriteValue {
fn from(why: Report<StorageError>) -> Self {
Self::Store(why.into())
}
}
impl From<WriteValue> for Report<StorageError> {
fn from(why: WriteValue) -> Self {
match why {
WriteValue::Store(report)
| WriteValue::TooDeep { why: report, .. }
| WriteValue::WillNotEncode { why: report, .. } => report.into_report(),
WriteValue::NotAPath(why) => Report::new(why).change_context(StorageError::Path),
WriteValue::Closed { at } => {
Report::new(StorageError::Closed).attach(crate::facts::Key(at))
}
WriteValue::Absent { at } => Report::new(StorageError::Read)
.attach(crate::facts::Key(at))
.attach("nothing is stored there"),
WriteValue::SourceGone => Report::new(StorageError::Write)
.attach("the field or map this cell viewed was dropped"),
}
}
}
pub type WriteResult<T> = Result<T, WriteValue>;
pub type FieldError = WriteValue;
pub type ReactiveMapError = WriteValue;
pub type ReactiveFieldResult<T> = WriteResult<T>;
pub type ReactiveMapResult<T> = WriteResult<T>;