use buggy::Bug;
use rend::u64_le;
use crate::{
Address,
command::{CmdId, Command},
storage::{FactPerspective, Perspective},
};
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum PolicyError {
#[error("read error")]
Read,
#[error("write error")]
Write,
#[error("check error")]
Check,
#[error("panic")]
Panic,
#[error("internal error")]
InternalError,
#[error(transparent)]
Bug(#[from] Bug),
}
impl From<core::convert::Infallible> for PolicyError {
fn from(error: core::convert::Infallible) -> Self {
match error {}
}
}
#[derive(
Copy,
Clone,
Debug,
Ord,
PartialOrd,
Eq,
PartialEq,
serde::Serialize,
serde::Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
rkyv::Portable,
rkyv::bytecheck::CheckBytes,
)]
#[rkyv(as = Self)]
#[bytecheck(crate = rkyv::bytecheck)]
#[serde(transparent)]
#[repr(transparent)]
pub struct PolicyId(#[serde(with = "crate::util::u64_le_serde")] u64_le);
impl PolicyId {
pub fn new(id: u64) -> Self {
Self(id.into())
}
}
pub trait PolicyStore {
type Policy: Policy<Effect = Self::Effect>;
type Effect;
fn add_policy(&mut self, policy: &[u8]) -> Result<PolicyId, PolicyError>;
fn get_policy(&self, id: PolicyId) -> Result<&Self::Policy, PolicyError>;
}
pub trait Sink<Eff> {
fn begin(&mut self);
fn consume(&mut self, effect: Eff);
fn rollback(&mut self);
fn commit(&mut self);
}
pub struct NullSink;
impl<Eff> Sink<Eff> for NullSink {
fn begin(&mut self) {}
fn consume(&mut self, _effect: Eff) {}
fn rollback(&mut self) {}
fn commit(&mut self) {}
}
pub struct MergeIds {
left: Address,
right: Address,
}
impl MergeIds {
pub fn new(a: Address, b: Address) -> Option<Self> {
use core::cmp::Ordering;
match a.id.cmp(&b.id) {
Ordering::Less => Some(Self { left: a, right: b }),
Ordering::Equal => None,
Ordering::Greater => Some(Self { left: b, right: a }),
}
}
}
impl From<MergeIds> for (CmdId, CmdId) {
fn from(value: MergeIds) -> Self {
(value.left.id, value.right.id)
}
}
impl From<MergeIds> for (Address, Address) {
fn from(value: MergeIds) -> Self {
(value.left, value.right)
}
}
pub trait Policy {
type Action<'a>;
type Effect;
type Command<'a>: Command;
fn serial(&self) -> u32;
fn call_rule(
&self,
command: &impl Command,
facts: &mut impl FactPerspective,
sink: &mut impl Sink<Self::Effect>,
placement: CommandPlacement,
) -> Result<(), PolicyError>;
fn call_action(
&self,
action: Self::Action<'_>,
facts: &mut impl Perspective,
sink: &mut impl Sink<Self::Effect>,
placement: ActionPlacement,
) -> Result<(), PolicyError>;
fn merge<'a>(
&self,
target: &'a mut [u8],
ids: MergeIds,
) -> Result<Self::Command<'a>, PolicyError>;
}
#[derive(Copy, Clone, Debug)]
pub enum ActionPlacement {
OnGraph,
OffGraph,
}
#[derive(Copy, Clone, Debug)]
pub enum CommandPlacement {
OnGraphAtOrigin,
OnGraphInBraid,
OffGraph,
}
mod impls {
use alloc::boxed::Box;
use super::{PolicyError, PolicyId, PolicyStore, Sink};
impl<PS: PolicyStore> PolicyStore for &mut PS {
type Policy = PS::Policy;
type Effect = PS::Effect;
fn add_policy(&mut self, policy: &[u8]) -> Result<PolicyId, PolicyError> {
PS::add_policy(self, policy)
}
fn get_policy(&self, id: PolicyId) -> Result<&Self::Policy, PolicyError> {
PS::get_policy(self, id)
}
}
impl<PS: PolicyStore> PolicyStore for Box<PS> {
type Policy = PS::Policy;
type Effect = PS::Effect;
fn add_policy(&mut self, policy: &[u8]) -> Result<PolicyId, PolicyError> {
PS::add_policy(self, policy)
}
fn get_policy(&self, id: PolicyId) -> Result<&Self::Policy, PolicyError> {
PS::get_policy(self, id)
}
}
impl<S: Sink<Eff>, Eff> Sink<Eff> for &mut S {
fn begin(&mut self) {
S::begin(self);
}
fn consume(&mut self, effect: Eff) {
S::consume(self, effect);
}
fn rollback(&mut self) {
S::rollback(self);
}
fn commit(&mut self) {
S::commit(self);
}
}
impl<S: Sink<Eff>, Eff> Sink<Eff> for Box<S> {
fn begin(&mut self) {
S::begin(self);
}
fn consume(&mut self, effect: Eff) {
S::consume(self, effect);
}
fn rollback(&mut self) {
S::rollback(self);
}
fn commit(&mut self) {
S::commit(self);
}
}
}