pub use aranya_crypto::policy::CmdId;
use buggy::{Bug, BugExt as _};
use crate::{MaxCut, Prior};
#[derive(
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
serde::Serialize,
serde::Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
pub enum Priority {
Merge,
Basic(u32),
Finalize,
Init,
}
pub trait Command {
fn priority(&self) -> Priority;
fn id(&self) -> CmdId;
fn parent(&self) -> Prior<Address>;
fn policy(&self) -> Option<&[u8]>;
fn bytes(&self) -> &[u8];
fn max_cut(&self) -> Result<MaxCut, Bug> {
match self.parent() {
Prior::None => Ok(MaxCut::new(0)),
Prior::Single(l) => Ok(l.max_cut.checked_add(1).assume("must not overflow")?),
Prior::Merge(l, r) => Ok(l
.max_cut
.max(r.max_cut)
.checked_add(1)
.assume("must not overflow")?),
}
}
fn address(&self) -> Result<Address, Bug> {
Ok(Address {
id: self.id(),
max_cut: self.max_cut()?,
})
}
}
impl<C: Command> Command for &C {
fn priority(&self) -> Priority {
(*self).priority()
}
fn id(&self) -> CmdId {
(*self).id()
}
fn parent(&self) -> Prior<Address> {
(*self).parent()
}
fn policy(&self) -> Option<&[u8]> {
(*self).policy()
}
fn bytes(&self) -> &[u8] {
(*self).bytes()
}
fn max_cut(&self) -> Result<MaxCut, Bug> {
(*self).max_cut()
}
fn address(&self) -> Result<Address, Bug> {
(*self).address()
}
}
#[derive(
Copy,
Clone,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
serde::Serialize,
serde::Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
rkyv::Portable,
rkyv::bytecheck::CheckBytes,
)]
#[rkyv(as = Self)]
#[bytecheck(crate = rkyv::bytecheck)]
#[repr(C)]
pub struct Address {
pub id: CmdId,
pub max_cut: MaxCut,
}
impl Prior<Address> {
pub fn next_max_cut(&self) -> Result<MaxCut, Bug> {
Ok(match self {
Self::None => MaxCut::new(1),
Self::Single(l) => l.max_cut.checked_add(1).assume("must not overflow")?,
Self::Merge(l, r) => l
.max_cut
.max(r.max_cut)
.checked_add(1)
.assume("must not overflow")?,
})
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn priority_ordering() {
assert!(Priority::Merge < Priority::Basic(0));
assert!(Priority::Basic(0) < Priority::Basic(1));
assert!(Priority::Basic(1) < Priority::Basic(u32::MAX));
assert!(Priority::Basic(u32::MAX) < Priority::Finalize);
assert!(Priority::Finalize < Priority::Init);
}
}