use std::error::Error;
use std::fmt;
use std::io;
use std::path::PathBuf;
use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum StateError {
#[error("failed to read state template `{path}`")]
TemplateRead {
path: PathBuf,
#[source]
source: io::Error,
},
#[error("failed to parse state template `{path}` as JSON")]
TemplateParse {
path: PathBuf,
#[source]
source: serde_json::Error,
},
#[error("state template field at index {index} has an empty name")]
EmptyFieldName {
index: usize,
},
#[error("state template declares duplicate field `{field}`")]
DuplicateField {
field: String,
},
#[error("state template does not declare field `{field}`")]
UnknownField {
field: String,
},
#[error("coordinated state borrow repeats field `{field}`")]
RepeatedPayloadBorrow {
field: String,
},
#[error("state field `{field}` does not contain a payload")]
MissingPayload {
field: String,
},
#[error(
"state field `{field}` is bound to `{actual}`, but the operation requested `{expected}`"
)]
TypeMismatch {
field: String,
expected: &'static str,
actual: &'static str,
},
#[error("cannot advance state iteration {iteration}: the next iteration exceeds u64::MAX")]
IterationOverflow {
iteration: u64,
},
#[error(
"cannot advance physical time at iteration {iteration}: no physical coordinate is present"
)]
MissingPhysicalTime {
iteration: u64,
},
#[error(
"cannot advance physical time {current} by {delta}: the delta and resulting coordinate must be finite"
)]
InvalidPhysicalAdvance {
current: f64,
delta: f64,
},
}
#[must_use = "the rejected payload remains owned by this error until it is recovered or dropped"]
pub struct PayloadInsertError<T> {
error: StateError,
payload: T,
}
impl<T> PayloadInsertError<T> {
pub(crate) const fn new(error: StateError, payload: T) -> Self {
Self { error, payload }
}
pub const fn error(&self) -> &StateError {
&self.error
}
pub const fn payload(&self) -> &T {
&self.payload
}
pub fn into_parts(self) -> (StateError, T) {
(self.error, self.payload)
}
}
impl<T> fmt::Debug for PayloadInsertError<T> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("PayloadInsertError")
.field("error", &self.error)
.field("payload_type", &std::any::type_name::<T>())
.finish_non_exhaustive()
}
}
impl<T> fmt::Display for PayloadInsertError<T> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.error, formatter)
}
}
impl<T> Error for PayloadInsertError<T> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.error)
}
}