use crate::core::Ctx;
use crate::operation::OperationDescriptor;
#[derive(Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum AdmissionDecision {
Admit,
Deny {
code: String,
message: String,
},
}
impl AdmissionDecision {
#[must_use]
pub fn deny(code: impl Into<String>, message: impl Into<String>) -> Self {
Self::Deny {
code: code.into(),
message: message.into(),
}
}
#[must_use]
pub const fn is_admit(&self) -> bool {
matches!(self, Self::Admit)
}
}
pub trait AdmissionGuard {
fn admit(
&self,
descriptor: &OperationDescriptor,
input: &[u8],
cx: &mut Ctx<'_>,
) -> AdmissionDecision;
}
impl<F> AdmissionGuard for F
where
F: Fn(&OperationDescriptor, &[u8], &mut Ctx<'_>) -> AdmissionDecision,
{
fn admit(
&self,
descriptor: &OperationDescriptor,
input: &[u8],
cx: &mut Ctx<'_>,
) -> AdmissionDecision {
self(descriptor, input, cx)
}
}
#[cfg(test)]
mod tests {
use super::AdmissionDecision;
#[test]
fn deny_carries_class_and_detail() {
let decision = AdmissionDecision::deny("policy", "blocked");
assert!(!decision.is_admit());
assert_eq!(
decision,
AdmissionDecision::Deny {
code: "policy".to_owned(),
message: "blocked".to_owned(),
}
);
}
#[test]
fn admit_is_admit() {
assert!(AdmissionDecision::Admit.is_admit());
}
}