use crate::delegation::{self, DelegateKind, DelegationVerdict, Depth};
use crate::error::{AxCode, AxError, GateRefusal};
use super::GateOutcome;
pub fn spawn(parent: Depth, kind: &DelegateKind) -> GateOutcome {
match delegation::admit(parent, kind) {
DelegationVerdict::Allow => GateOutcome::Allow,
DelegationVerdict::Deny => GateOutcome::Deny {
refusal: Box::new(
AxError::refusal(
AxCode::DelegationDepth,
"spawn delegate",
format!("{kind:?}"),
GateRefusal::new(
"delegates do not delegate: one level deep",
"a delegated position requested a spawn",
"return this subtask to the resident who spawned you; \
that resident can delegate it",
),
)
.with_recovery(
"finish this subtask yourself, or end the turn with what you have so \
the resident who spawned you can delegate the rest",
),
),
},
}
}
#[cfg(test)]
#[allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
reason = "test code"
)]
mod tests {
use super::*;
#[test]
fn the_spawn_door_teaches_the_way_back_up() {
assert!(matches!(
spawn(Depth::Root, &DelegateKind::Ephemeral),
GateOutcome::Allow
));
let GateOutcome::Deny { refusal } = spawn(Depth::Delegated, &DelegateKind::Ephemeral)
else {
panic!("a delegate may not delegate")
};
assert_eq!(refusal.code(), &AxCode::DelegationDepth);
let parts = refusal.gate().expect("gate refusals carry three parts");
assert!(!parts.rule().is_empty());
assert!(!parts.violation().is_empty());
assert!(parts.alternative().contains("spawned you"));
}
}