use crate::atom::Atom;
use crate::native::ProcessContext;
use crate::term::Term;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Capability {
Pure,
Clock,
Entropy,
ExternalIo,
}
pub trait CapabilityPolicy: Send + Sync {
fn is_granted(&self, capability: Capability) -> bool;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct LeastAuthorityPolicy;
impl CapabilityPolicy for LeastAuthorityPolicy {
fn is_granted(&self, capability: Capability) -> bool {
capability == Capability::Pure
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct AllCapabilitiesPolicy;
impl CapabilityPolicy for AllCapabilitiesPolicy {
fn is_granted(&self, _capability: Capability) -> bool {
true
}
}
#[derive(Debug, Clone, Default, Eq, PartialEq)]
pub struct CapabilitySet {
grants: Vec<Capability>,
}
impl CapabilitySet {
#[must_use]
pub fn from_slice(capabilities: &[Capability]) -> Self {
let mut grants = Vec::new();
for capability in capabilities {
if !grants.contains(capability) {
grants.push(*capability);
}
}
Self { grants }
}
#[must_use]
pub fn grants(&self, capability: Capability) -> bool {
self.grants.contains(&capability)
}
}
impl CapabilityPolicy for CapabilitySet {
fn is_granted(&self, capability: Capability) -> bool {
self.grants(capability)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DenialMode {
Undef,
}
pub fn denial_stub(_args: &[Term], _context: &mut ProcessContext) -> Result<Term, Term> {
Err(Term::atom(Atom::UNDEF))
}
#[cfg(test)]
mod tests {
use super::{
AllCapabilitiesPolicy, Capability, CapabilityPolicy, CapabilitySet, LeastAuthorityPolicy,
denial_stub,
};
use crate::native::ProcessContext;
use crate::term::Term;
#[test]
fn least_authority_grants_only_pure() {
let policy = LeastAuthorityPolicy;
assert!(policy.is_granted(Capability::Pure));
assert!(!policy.is_granted(Capability::Clock));
assert!(!policy.is_granted(Capability::Entropy));
assert!(!policy.is_granted(Capability::ExternalIo));
}
#[test]
fn all_capabilities_grants_everything() {
let policy = AllCapabilitiesPolicy;
assert!(policy.is_granted(Capability::Pure));
assert!(policy.is_granted(Capability::Clock));
assert!(policy.is_granted(Capability::Entropy));
assert!(policy.is_granted(Capability::ExternalIo));
}
#[test]
fn capability_set_grants_exact_members() {
let policy = CapabilitySet::from_slice(&[Capability::Pure, Capability::Clock]);
assert!(policy.grants(Capability::Pure));
assert!(policy.grants(Capability::Clock));
assert!(!policy.grants(Capability::Entropy));
assert!(!policy.grants(Capability::ExternalIo));
}
#[test]
fn denial_stub_returns_undef() {
let mut context = ProcessContext::new();
assert_eq!(
denial_stub(&[Term::small_int(1)], &mut context),
Err(Term::atom(crate::atom::Atom::UNDEF))
);
}
}