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 pub fn hash_for_testing_only(data: &[u8]) -> Self {
22 use aranya_crypto::{hash::Hash, rust::Sha512};
23 Sha512::hash(data).into_array().into()
24 }
25
26 pub fn short_b58(&self) -> String {
27 #![allow(clippy::arithmetic_side_effects)]
28 let b58 = self.to_string();
29 let trimmed = b58.trim_start_matches('1');
30 let len = trimmed.len();
31 if len == 0 {
32 "1".into()
33 } else if len > 8 {
34 format!("..{}", &trimmed[len - 6..])
35 } else {
36 trimmed.into()
37 }
38 }
39}
40
41#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
44pub enum Priority {
45 Merge,
49 Basic(u32),
52 Finalize,
54 Init,
58}
59
60pub trait Command {
68 fn priority(&self) -> Priority;
71
72 fn id(&self) -> CommandId;
74
75 fn parent(&self) -> Prior<Address>;
78
79 fn policy(&self) -> Option<&[u8]>;
81
82 fn bytes(&self) -> &[u8];
84
85 fn max_cut(&self) -> Result<usize, Bug> {
87 match self.parent() {
88 Prior::None => Ok(0),
89 Prior::Single(l) => Ok(l.max_cut.checked_add(1).assume("must not overflow")?),
90 Prior::Merge(l, r) => Ok(l
91 .max_cut
92 .max(r.max_cut)
93 .checked_add(1)
94 .assume("must not overflow")?),
95 }
96 }
97
98 fn address(&self) -> Result<Address, Bug> {
100 Ok(Address {
101 id: self.id(),
102 max_cut: self.max_cut()?,
103 })
104 }
105}
106
107impl<C: Command> Command for &C {
108 fn priority(&self) -> Priority {
109 (*self).priority()
110 }
111
112 fn id(&self) -> CommandId {
113 (*self).id()
114 }
115
116 fn parent(&self) -> Prior<Address> {
117 (*self).parent()
118 }
119
120 fn policy(&self) -> Option<&[u8]> {
121 (*self).policy()
122 }
123
124 fn bytes(&self) -> &[u8] {
125 (*self).bytes()
126 }
127
128 fn max_cut(&self) -> Result<usize, Bug> {
129 (*self).max_cut()
130 }
131
132 fn address(&self) -> Result<Address, Bug> {
133 (*self).address()
134 }
135}
136
137#[derive(Debug, Serialize, Deserialize, Clone, Copy, Ord, PartialEq, PartialOrd, Eq, Default)]
138pub struct Address {
144 pub id: CommandId,
145 pub max_cut: usize,
146}
147
148impl Prior<Address> {
149 pub fn next_max_cut(&self) -> Result<usize, Bug> {
151 Ok(match self {
152 Prior::None => 1,
153 Prior::Single(l) => l.max_cut.checked_add(1).assume("must not overflow")?,
154 Prior::Merge(l, r) => l
155 .max_cut
156 .max(r.max_cut)
157 .checked_add(1)
158 .assume("must not overflow")?,
159 })
160 }
161}
162
163#[cfg(test)]
164mod test {
165 use super::*;
166
167 #[test]
168 fn priority_ordering() {
169 assert!(Priority::Merge < Priority::Basic(0));
170 assert!(Priority::Basic(0) < Priority::Basic(1));
171 assert!(Priority::Basic(1) < Priority::Basic(u32::MAX));
172 assert!(Priority::Basic(u32::MAX) < Priority::Finalize);
173 assert!(Priority::Finalize < Priority::Init);
174 }
175}