use super::env::Env;
use super::error::CapabilityError;
use super::key::CapabilityKey;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
pub trait CapabilitySet {
fn verify(env: &Env) -> Result<(), CapabilityError>;
}
pub trait FromEnv: CapabilitySet + Sized {
fn from_env(env: Env) -> Self;
}
pub trait CapKeys {
fn verify_all(env: &Env) -> Result<(), CapabilityError>;
}
pub struct NoCaps;
impl CapabilitySet for NoCaps {
fn verify(_env: &Env) -> Result<(), CapabilityError> {
Ok(())
}
}
impl FromEnv for NoCaps {
fn from_env(_env: Env) -> Self {
Self
}
}
impl CapabilitySet for () {
fn verify(_env: &Env) -> Result<(), CapabilityError> {
Ok(())
}
}
impl FromEnv for () {
fn from_env(_env: Env) -> Self {}
}
impl CapabilitySet for Env {
fn verify(_env: &Env) -> Result<(), CapabilityError> {
Ok(())
}
}
impl FromEnv for Env {
fn from_env(env: Env) -> Self {
env
}
}
impl CapKeys for () {
fn verify_all(_env: &Env) -> Result<(), CapabilityError> {
Ok(())
}
}
macro_rules! impl_cap_keys {
($($k:ident),*) => {
impl<$($k: CapabilityKey),*> CapKeys for ($($k,)*) {
fn verify_all(env: &Env) -> Result<(), CapabilityError> {
$( env.try_get::<$k>()?; )*
Ok(())
}
}
};
}
impl_cap_keys!(K0);
impl_cap_keys!(K0, K1);
impl_cap_keys!(K0, K1, K2);
impl_cap_keys!(K0, K1, K2, K3);
impl_cap_keys!(K0, K1, K2, K3, K4);
impl_cap_keys!(K0, K1, K2, K3, K4, K5);
impl_cap_keys!(K0, K1, K2, K3, K4, K5, K6);
impl_cap_keys!(K0, K1, K2, K3, K4, K5, K6, K7);
impl_cap_keys!(K0, K1, K2, K3, K4, K5, K6, K7, K8);
impl_cap_keys!(K0, K1, K2, K3, K4, K5, K6, K7, K8, K9);
impl_cap_keys!(K0, K1, K2, K3, K4, K5, K6, K7, K8, K9, K10);
impl_cap_keys!(K0, K1, K2, K3, K4, K5, K6, K7, K8, K9, K10, K11);
impl_cap_keys!(K0, K1, K2, K3, K4, K5, K6, K7, K8, K9, K10, K11, K12);
impl_cap_keys!(K0, K1, K2, K3, K4, K5, K6, K7, K8, K9, K10, K11, K12, K13);
impl_cap_keys!(
K0, K1, K2, K3, K4, K5, K6, K7, K8, K9, K10, K11, K12, K13, K14
);
impl_cap_keys!(
K0, K1, K2, K3, K4, K5, K6, K7, K8, K9, K10, K11, K12, K13, K14, K15
);
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct CapList<Ks> {
inner: Env,
_marker: PhantomData<Ks>,
}
impl<Ks: CapKeys> CapList<Ks> {
#[inline]
pub fn new(inner: Env) -> Self {
Self {
inner,
_marker: PhantomData,
}
}
#[inline]
pub fn env(&self) -> &Env {
&self.inner
}
#[inline]
pub fn env_mut(&mut self) -> &mut Env {
&mut self.inner
}
}
impl<Ks: CapKeys> Deref for CapList<Ks> {
type Target = Env;
fn deref(&self) -> &Env {
&self.inner
}
}
impl<Ks: CapKeys> DerefMut for CapList<Ks> {
fn deref_mut(&mut self) -> &mut Env {
&mut self.inner
}
}
impl<Ks: CapKeys> CapabilitySet for CapList<Ks> {
fn verify(env: &Env) -> Result<(), CapabilityError> {
Ks::verify_all(env)
}
}
impl<Ks: CapKeys> FromEnv for CapList<Ks> {
fn from_env(env: Env) -> Self {
Self::new(env)
}
}
pub trait HasCap<K: CapabilityKey> {}
impl<K: CapabilityKey> HasCap<K> for Env {}
impl<K: CapabilityKey, T: Deref<Target = Env>> HasCap<K> for T {}
pub trait CapWiden<Target> {
fn widen(self) -> Target;
}
impl<Ks: CapKeys> CapWiden<CapList<Ks>> for CapList<Ks> {
fn widen(self) -> CapList<Ks> {
self
}
}
impl<K0: CapabilityKey, K1: CapabilityKey> CapWiden<CapList<(K0,)>> for CapList<(K0, K1)> {
fn widen(self) -> CapList<(K0,)> {
CapList::new(self.inner)
}
}
impl<K0: CapabilityKey> CapList<(K0,)> {
#[inline]
pub fn project_at_0(self) -> CapList<(K0,)> {
CapList::new(self.inner)
}
}
impl<K0: CapabilityKey, K1: CapabilityKey> CapList<(K0, K1)> {
#[inline]
pub fn project_at_0(self) -> CapList<(K0,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_1(self) -> CapList<(K1,)> {
CapList::new(self.inner)
}
}
impl<K0: CapabilityKey, K1: CapabilityKey, K2: CapabilityKey> CapList<(K0, K1, K2)> {
#[inline]
pub fn project_at_0(self) -> CapList<(K0,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_1(self) -> CapList<(K1,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_2(self) -> CapList<(K2,)> {
CapList::new(self.inner)
}
}
impl<K0: CapabilityKey, K1: CapabilityKey, K2: CapabilityKey, K3: CapabilityKey>
CapList<(K0, K1, K2, K3)>
{
#[inline]
pub fn project_at_0(self) -> CapList<(K0,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_1(self) -> CapList<(K1,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_2(self) -> CapList<(K2,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_3(self) -> CapList<(K3,)> {
CapList::new(self.inner)
}
}
impl<K0: CapabilityKey, K1: CapabilityKey, K2: CapabilityKey, K3: CapabilityKey, K4: CapabilityKey>
CapList<(K0, K1, K2, K3, K4)>
{
#[inline]
pub fn project_at_0(self) -> CapList<(K0,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_1(self) -> CapList<(K1,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_2(self) -> CapList<(K2,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_3(self) -> CapList<(K3,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_4(self) -> CapList<(K4,)> {
CapList::new(self.inner)
}
}
impl<
K0: CapabilityKey,
K1: CapabilityKey,
K2: CapabilityKey,
K3: CapabilityKey,
K4: CapabilityKey,
K5: CapabilityKey,
> CapList<(K0, K1, K2, K3, K4, K5)>
{
#[inline]
pub fn project_at_0(self) -> CapList<(K0,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_1(self) -> CapList<(K1,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_2(self) -> CapList<(K2,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_3(self) -> CapList<(K3,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_4(self) -> CapList<(K4,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_5(self) -> CapList<(K5,)> {
CapList::new(self.inner)
}
}
impl<
K0: CapabilityKey,
K1: CapabilityKey,
K2: CapabilityKey,
K3: CapabilityKey,
K4: CapabilityKey,
K5: CapabilityKey,
K6: CapabilityKey,
> CapList<(K0, K1, K2, K3, K4, K5, K6)>
{
#[inline]
pub fn project_at_0(self) -> CapList<(K0,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_1(self) -> CapList<(K1,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_2(self) -> CapList<(K2,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_3(self) -> CapList<(K3,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_4(self) -> CapList<(K4,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_5(self) -> CapList<(K5,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_6(self) -> CapList<(K6,)> {
CapList::new(self.inner)
}
}
impl<
K0: CapabilityKey,
K1: CapabilityKey,
K2: CapabilityKey,
K3: CapabilityKey,
K4: CapabilityKey,
K5: CapabilityKey,
K6: CapabilityKey,
K7: CapabilityKey,
> CapList<(K0, K1, K2, K3, K4, K5, K6, K7)>
{
#[inline]
pub fn project_at_0(self) -> CapList<(K0,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_1(self) -> CapList<(K1,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_2(self) -> CapList<(K2,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_3(self) -> CapList<(K3,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_4(self) -> CapList<(K4,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_5(self) -> CapList<(K5,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_6(self) -> CapList<(K6,)> {
CapList::new(self.inner)
}
#[inline]
pub fn project_at_7(self) -> CapList<(K7,)> {
CapList::new(self.inner)
}
}
impl<K0: CapabilityKey, K1: CapabilityKey, K2: CapabilityKey> CapWiden<CapList<(K0,)>>
for CapList<(K0, K1, K2)>
{
fn widen(self) -> CapList<(K0,)> {
CapList::new(self.inner)
}
}
impl<K0: CapabilityKey, K1: CapabilityKey, K2: CapabilityKey> CapWiden<CapList<(K0, K1)>>
for CapList<(K0, K1, K2)>
{
fn widen(self) -> CapList<(K0, K1)> {
CapList::new(self.inner)
}
}
#[cfg(test)]
#[allow(dead_code, clippy::new_ret_no_self)]
mod tests {
use super::*;
use crate::Cap;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
struct Test(pub u32);
#[test]
fn cap_list_verify_missing() {
let env = Env::new();
let err = CapList::<(Cap<Test>,)>::verify(&env).unwrap_err();
assert!(matches!(err, CapabilityError::Missing(_)));
}
#[test]
fn cap_list_verify_ok() {
let mut env = Env::new();
env.insert::<Cap<Test>>(Test(7u32));
CapList::<(Cap<Test>,)>::verify(&env).unwrap();
}
#[test]
fn cap_list_eight_keys() {
#[derive(Clone, Copy)]
struct Cap0(pub u8);
#[derive(Clone, Copy)]
struct Cap1(pub u8);
#[derive(Clone, Copy)]
struct Cap2(pub u8);
#[derive(Clone, Copy)]
struct Cap3(pub u8);
#[derive(Clone, Copy)]
struct Cap4(pub u8);
#[derive(Clone, Copy)]
struct Cap5(pub u8);
#[derive(Clone, Copy)]
struct Cap6(pub u8);
#[derive(Clone, Copy)]
struct Cap7(pub u8);
let mut env = Env::new();
env.insert::<Cap<Cap0>>(Cap0(0u8));
env.insert::<Cap<Cap1>>(Cap1(1u8));
env.insert::<Cap<Cap2>>(Cap2(2u8));
env.insert::<Cap<Cap3>>(Cap3(3u8));
env.insert::<Cap<Cap4>>(Cap4(4u8));
env.insert::<Cap<Cap5>>(Cap5(5u8));
env.insert::<Cap<Cap6>>(Cap6(6u8));
env.insert::<Cap<Cap7>>(Cap7(7u8));
CapList::<(
Cap<Cap0>,
Cap<Cap1>,
Cap<Cap2>,
Cap<Cap3>,
Cap<Cap4>,
Cap<Cap5>,
Cap<Cap6>,
Cap<Cap7>,
)>::verify(&env)
.unwrap();
}
#[test]
fn no_caps_and_unit_from_env() {
assert!(NoCaps::verify(&Env::new()).is_ok());
assert!(<() as CapabilitySet>::verify(&Env::new()).is_ok());
let _ = NoCaps::from_env(Env::new());
let _ = <() as FromEnv>::from_env(Env::new());
}
#[test]
fn env_as_capability_set() {
let env = Env::new();
assert!(Env::verify(&env).is_ok());
assert_eq!(Env::from_env(env.clone()).len(), env.len());
}
#[test]
fn cap_list_accessors_and_deref() {
let mut env = Env::new();
env.insert::<Cap<Test>>(Test(3u32));
let mut caps = CapList::<(Cap<Test>,)>::from_env(env);
assert_eq!(caps.env().len(), 1);
caps.env_mut().insert::<Cap<Test>>(Test(4u32));
assert_eq!(caps.get::<Cap<Test>>().0, 4);
}
#[test]
fn cap_list_project_four_through_eight() {
#[derive(Clone, Copy)]
struct A(pub i32);
#[derive(Clone, Copy)]
struct B(pub i32);
#[derive(Clone, Copy)]
struct C(pub i32);
#[derive(Clone, Copy)]
struct D(pub i32);
#[derive(Clone, Copy)]
struct E(pub i32);
#[derive(Clone, Copy)]
struct F(pub i32);
#[derive(Clone, Copy)]
struct G(pub i32);
#[derive(Clone, Copy)]
struct H(pub i32);
let mut env = Env::new();
env.insert::<Cap<A>>(A(1));
env.insert::<Cap<B>>(B(2));
env.insert::<Cap<C>>(C(3));
env.insert::<Cap<D>>(D(4));
env.insert::<Cap<E>>(E(5));
env.insert::<Cap<F>>(F(6));
env.insert::<Cap<G>>(G(7));
env.insert::<Cap<H>>(H(8));
CapList::<(Cap<A>, Cap<B>, Cap<C>, Cap<D>, Cap<E>)>::verify(&env).unwrap();
let wide8 = CapList::<(
Cap<A>,
Cap<B>,
Cap<C>,
Cap<D>,
Cap<E>,
Cap<F>,
Cap<G>,
Cap<H>,
)>::from_env(env.clone());
let _ = wide8.clone().project_at_4();
let _ = wide8.clone().project_at_5();
let _ = wide8.clone().project_at_6();
let _ = wide8.clone().project_at_7();
let four = CapList::<(Cap<A>, Cap<B>, Cap<C>, Cap<D>)>::from_env(env);
let _ = four.clone().project_at_0();
let _ = four.clone().project_at_1();
let _ = four.clone().project_at_2();
let _ = four.project_at_3();
}
#[test]
fn cap_widen_subset() {
#[derive(Clone, Copy)]
struct Db(pub u32);
#[derive(Clone, Copy)]
struct Log(pub u32);
let mut env = Env::new();
env.insert::<Cap<Db>>(Db(1u32));
env.insert::<Cap<Log>>(Log(2u32));
let wide = CapList::<(Cap<Db>, Cap<Log>)>::from_env(env);
let _narrow: CapList<(Cap<Db>,)> = wide.widen();
}
}