aranya_runtime/
command.rs1use alloc::{
2 format,
3 string::{String, ToString},
4};
5
6use buggy::{Bug, BugExt};
7use serde::{Deserialize, Serialize};
8
9use crate::Prior;
10
11aranya_crypto::custom_id! {
12 pub struct CommandId;
14}
15
16impl CommandId {
17 #[cfg(feature = "testing")]
19 pub fn hash_for_testing_only(data: &[u8]) -> Self {
20 use aranya_crypto::dangerous::spideroak_crypto::{hash::Hash, rust::Sha256};
21 Sha256::hash(data).into_array().into()
22 }
23
24 pub fn short_b58(&self) -> String {
25 #![allow(clippy::arithmetic_side_effects)]
26 let b58 = self.to_string();
27 let trimmed = b58.trim_start_matches('1');
28 let len = trimmed.len();
29 if len == 0 {
30 "1".into()
31 } else if len > 8 {
32 format!("..{}", &trimmed[len - 6..])
33 } else {
34 trimmed.into()
35 }
36 }
37}
38
39#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
42pub enum Priority {
43 Merge,
47 Basic(u32),
50 Finalize,
52 Init,
56}
57
58pub trait Command {
66 fn priority(&self) -> Priority;
69
70 fn id(&self) -> CommandId;
72
73 fn parent(&self) -> Prior<Address>;
76
77 fn policy(&self) -> Option<&[u8]>;
79
80 fn bytes(&self) -> &[u8];
82
83 fn max_cut(&self) -> Result<usize, Bug> {
85 match self.parent() {
86 Prior::None => Ok(0),
87 Prior::Single(l) => Ok(l.max_cut.checked_add(1).assume("must not overflow")?),
88 Prior::Merge(l, r) => Ok(l
89 .max_cut
90 .max(r.max_cut)
91 .checked_add(1)
92 .assume("must not overflow")?),
93 }
94 }
95
96 fn address(&self) -> Result<Address, Bug> {
98 Ok(Address {
99 id: self.id(),
100 max_cut: self.max_cut()?,
101 })
102 }
103}
104
105impl<C: Command> Command for &C {
106 fn priority(&self) -> Priority {
107 (*self).priority()
108 }
109
110 fn id(&self) -> CommandId {
111 (*self).id()
112 }
113
114 fn parent(&self) -> Prior<Address> {
115 (*self).parent()
116 }
117
118 fn policy(&self) -> Option<&[u8]> {
119 (*self).policy()
120 }
121
122 fn bytes(&self) -> &[u8] {
123 (*self).bytes()
124 }
125
126 fn max_cut(&self) -> Result<usize, Bug> {
127 (*self).max_cut()
128 }
129
130 fn address(&self) -> Result<Address, Bug> {
131 (*self).address()
132 }
133}
134
135#[derive(Debug, Serialize, Deserialize, Clone, Copy, Ord, PartialEq, PartialOrd, Eq, Default)]
136pub struct Address {
142 pub id: CommandId,
143 pub max_cut: usize,
144}
145
146impl Prior<Address> {
147 pub fn next_max_cut(&self) -> Result<usize, Bug> {
149 Ok(match self {
150 Prior::None => 1,
151 Prior::Single(l) => l.max_cut.checked_add(1).assume("must not overflow")?,
152 Prior::Merge(l, r) => l
153 .max_cut
154 .max(r.max_cut)
155 .checked_add(1)
156 .assume("must not overflow")?,
157 })
158 }
159}
160
161#[cfg(test)]
162mod test {
163 use super::*;
164
165 #[test]
166 fn priority_ordering() {
167 assert!(Priority::Merge < Priority::Basic(0));
168 assert!(Priority::Basic(0) < Priority::Basic(1));
169 assert!(Priority::Basic(1) < Priority::Basic(u32::MAX));
170 assert!(Priority::Basic(u32::MAX) < Priority::Finalize);
171 assert!(Priority::Finalize < Priority::Init);
172 }
173}