#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum EffectClass {
Idempotent,
AtLeastOnce,
ExactlyOnceGuarded,
}
impl EffectClass {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
Self::Idempotent => "idempotent",
Self::AtLeastOnce => "at_least_once",
Self::ExactlyOnceGuarded => "exactly_once_guarded",
}
}
pub(crate) fn from_tag(tag: &str) -> Option<Self> {
match tag {
"idempotent" => Some(Self::Idempotent),
"at_least_once" => Some(Self::AtLeastOnce),
"exactly_once_guarded" => Some(Self::ExactlyOnceGuarded),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum EffectIntentSubClass {
CostBearingOrBoundaryIdempotent,
Destructive,
SecurityRelevant,
MoneyMoving,
Custom,
}
impl EffectIntentSubClass {
#[must_use]
pub fn requires_explicit_policy(self) -> bool {
!matches!(self, Self::CostBearingOrBoundaryIdempotent)
}
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
Self::CostBearingOrBoundaryIdempotent => "cost_bearing_or_boundary_idempotent",
Self::Destructive => "destructive",
Self::SecurityRelevant => "security_relevant",
Self::MoneyMoving => "money_moving",
Self::Custom => "custom",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum OnAmbiguous {
Skip,
Fail,
Rerun,
}
impl OnAmbiguous {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
Self::Skip => "skip",
Self::Fail => "fail",
Self::Rerun => "rerun",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn effect_class_as_str_is_stable() {
assert_eq!(EffectClass::Idempotent.as_str(), "idempotent");
assert_eq!(EffectClass::AtLeastOnce.as_str(), "at_least_once");
assert_eq!(
EffectClass::ExactlyOnceGuarded.as_str(),
"exactly_once_guarded"
);
}
#[test]
fn only_cost_bearing_subclass_has_a_default_policy() {
assert!(!EffectIntentSubClass::CostBearingOrBoundaryIdempotent.requires_explicit_policy());
for sub in [
EffectIntentSubClass::Destructive,
EffectIntentSubClass::SecurityRelevant,
EffectIntentSubClass::MoneyMoving,
EffectIntentSubClass::Custom,
] {
assert!(
sub.requires_explicit_policy(),
"{} must require an explicit ambiguity policy",
sub.as_str()
);
}
}
#[test]
fn subclass_and_policy_strings_are_stable() {
assert_eq!(
EffectIntentSubClass::CostBearingOrBoundaryIdempotent.as_str(),
"cost_bearing_or_boundary_idempotent"
);
assert_eq!(EffectIntentSubClass::Destructive.as_str(), "destructive");
assert_eq!(OnAmbiguous::Skip.as_str(), "skip");
assert_eq!(OnAmbiguous::Fail.as_str(), "fail");
assert_eq!(OnAmbiguous::Rerun.as_str(), "rerun");
}
}