use crate::kind::Kind;
use core::fmt;
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TransitionError<S, E> {
TerminalState {
state: S,
event: E,
},
EventKindRejected {
state: S,
event: E,
expected_kinds: &'static [Kind],
event_kind: Option<&'static [Kind]>,
},
NoTransition {
state: S,
event: E,
},
}
impl<S, E> TransitionError<S, E> {
pub fn state(&self) -> &S {
match self {
Self::TerminalState { state, .. }
| Self::EventKindRejected { state, .. }
| Self::NoTransition { state, .. } => state,
}
}
pub fn event(&self) -> &E {
match self {
Self::TerminalState { event, .. }
| Self::EventKindRejected { event, .. }
| Self::NoTransition { event, .. } => event,
}
}
pub fn into_event(self) -> E {
match self {
Self::TerminalState { event, .. }
| Self::EventKindRejected { event, .. }
| Self::NoTransition { event, .. } => event,
}
}
}
impl<S: fmt::Debug, E: fmt::Debug> fmt::Display for TransitionError<S, E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::TerminalState { state, event } => write!(
f,
"event {event:?} was rejected because {state:?} is a terminal state.\n\
Terminal states have no outbound transitions.\n\
To leave this state you must start a new machine or model the recovery \
as a non-terminal state.",
),
Self::EventKindRejected {
state,
event,
expected_kinds,
event_kind,
} => write!(
f,
"event {event:?} was rejected by {state:?} because of an event-kind \
mismatch.\n\
{state:?} only accepts events of kind {expected_kinds:?}, but {event:?} \
carries kind {event_kind:?}.\n\
Annotate the event with a matching `#[event_kind = …]`, or relax the \
state's `#[only_accepts(kind = …)]`.",
),
Self::NoTransition { state, event } => write!(
f,
"event {event:?} was rejected because no transition is defined from \
{state:?}.\n\
The transition function returned `None` for this state/event pair.\n\
Add a match arm `({state:?}, {event:?}) => Some(…)` if this transition \
should be legal.",
),
}
}
}
impl<S: fmt::Debug, E: fmt::Debug> std::error::Error for TransitionError<S, E> {}
#[non_exhaustive]
#[derive(Debug)]
pub enum RestoreError {
NewerThanBinary {
found: u32,
supports: u32,
},
UnknownVersion {
found: u32,
},
Decode {
version: u32,
source: Box<dyn std::error::Error + Send + Sync>,
},
}
impl fmt::Display for RestoreError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NewerThanBinary { found, supports } => write!(
f,
"stored version {found} is newer than this binary supports \
(max {supports}).\n\
The data was written by a newer release.\n\
Upgrade the binary, or migrate the data down before loading it here.",
),
Self::UnknownVersion { found } => write!(
f,
"stored version {found} is not in this type's migration history.\n\
Versions start at 1 and must be listed in `history` to be loadable.\n\
Check the envelope was written by this type, and that `history` \
covers every version that may still exist on disk.",
),
Self::Decode { version, source } => write!(
f,
"the payload for version {version} failed to decode: {source}.\n\
The bytes did not match the type recorded for that version.\n\
Confirm the serde format matches the one used to write the data.",
),
}
}
}
impl std::error::Error for RestoreError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Decode { source, .. } => Some(source.as_ref()),
_ => None,
}
}
}