use crate::store::StorageError;
use amethystate_core::failure::{Because, spelled};
use amethystate_core::path::{StorePath, StorePathError};
use error_stack::Report;
use std::fmt;
pub enum KvWrite {
NotAPath(StorePathError),
Declared {
at: StorePath,
declared_at: StorePath,
by: &'static str,
},
TooDeep { at: StorePath, why: Because },
WillNotEncode { at: StorePath, why: Because },
Closed { at: StorePath },
Store(Because),
}
amethystate_core::what_the_store_said!(KvWrite);
impl fmt::Display for KvWrite {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NotAPath(why) => write!(f, "the write was given no path to land at: {why}"),
Self::Declared {
at,
declared_at,
by,
} if at == declared_at => {
write!(f, "{at} is declared by {by}")
}
Self::Declared {
at,
declared_at,
by,
} if declared_at.starts_with(at) => {
write!(f, "{at} holds {declared_at}, which {by} declares")
}
Self::Declared {
at,
declared_at,
by,
} => {
write!(f, "{at} is inside {declared_at}, which {by} declares")
}
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::Store(why) => write!(f, "{}", why.current_context()),
}
}
}
impl fmt::Debug for KvWrite {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
spelled(self, f)
}
}
impl std::error::Error for KvWrite {
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::Declared { .. } | Self::Closed { .. } => None,
}
}
}
impl From<StorePathError> for KvWrite {
fn from(why: StorePathError) -> Self {
Self::NotAPath(why)
}
}
impl From<Report<StorageError>> for KvWrite {
fn from(why: Report<StorageError>) -> Self {
Self::Store(why.into())
}
}
impl From<KvWrite> for Report<StorageError> {
fn from(why: KvWrite) -> Self {
match why {
KvWrite::Store(report)
| KvWrite::TooDeep { why: report, .. }
| KvWrite::WillNotEncode { why: report, .. } => report.into_report(),
KvWrite::NotAPath(why) => Report::new(why).change_context(StorageError::Path),
KvWrite::Closed { at } => {
Report::new(StorageError::Closed).attach(amethystate_core::facts::Key(at))
}
KvWrite::Declared {
at,
declared_at,
by,
} => Report::new(StorageError::Taken)
.attach(amethystate_core::facts::Key(at))
.attach(crate::store::places::Owner {
path: declared_at,
by,
}),
}
}
}
pub type KvResult<T> = Result<T, KvWrite>;
pub enum Flush {
Closed,
Reentrant,
DidNotLand { why: Because },
}
impl Flush {
pub fn from_store(why: Report<StorageError>) -> Self {
match *why.current_context() {
StorageError::Closed => Self::Closed,
StorageError::Reentrant => Self::Reentrant,
_ => Self::DidNotLand { why: why.into() },
}
}
pub fn explain(&self) -> String {
match self {
Self::DidNotLand { why } => why.explain(),
other => other.to_string(),
}
}
}
impl fmt::Display for Flush {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Closed => f.write_str("the store was already closed, so nothing was flushed"),
Self::Reentrant => {
f.write_str("a flush was asked for from inside what the store is already doing")
}
Self::DidNotLand { .. } => f.write_str("the flush did not land"),
}
}
}
impl fmt::Debug for Flush {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
spelled(self, f)
}
}
impl std::error::Error for Flush {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::DidNotLand { why } => why.caused().map(|under| under as &dyn std::error::Error),
Self::Closed | Self::Reentrant => None,
}
}
}
impl From<Report<StorageError>> for Flush {
fn from(why: Report<StorageError>) -> Self {
Self::from_store(why)
}
}
impl From<Flush> for Report<StorageError> {
fn from(why: Flush) -> Self {
match why {
Flush::DidNotLand { why } => why.into_report(),
Flush::Closed => Report::new(StorageError::Closed),
Flush::Reentrant => Report::new(StorageError::Reentrant),
}
}
}
pub type FlushResult<T> = Result<T, Flush>;