aranya_runtime/vm_policy/
protocol.rs1extern crate alloc;
2
3use alloc::{borrow::Cow, collections::BTreeMap, string::String, sync::Arc};
4use core::fmt;
5
6use aranya_crypto::UserId;
7use aranya_policy_vm::{Struct, Value};
8use serde::{Deserialize, Serialize};
9
10use crate::{
11 command::{Command, CommandId, Priority},
12 Address, Prior,
13};
14
15#[derive(Debug, Serialize, Deserialize)]
17pub enum VmProtocolData<'a> {
18 Init {
19 policy: [u8; 8],
20 author_id: UserId,
21 #[serde(borrow)]
22 kind: &'a str,
23 #[serde(borrow)]
24 serialized_fields: &'a [u8],
25 #[serde(borrow)]
26 signature: &'a [u8],
27 },
28 Merge {
29 left: Address,
30 right: Address,
31 },
32 Basic {
33 parent: Address,
34 author_id: UserId,
35 #[serde(borrow)]
36 kind: &'a str,
37 #[serde(borrow)]
38 serialized_fields: &'a [u8],
39 #[serde(borrow)]
40 signature: &'a [u8],
41 },
42}
43
44#[derive(Debug)]
48pub struct VmProtocol<'a> {
49 data: &'a [u8],
51 id: CommandId,
53 unpacked: VmProtocolData<'a>,
55 priority_map: Arc<BTreeMap<String, u32>>,
58}
59
60impl<'a> VmProtocol<'a> {
61 pub fn new(
62 data: &'a [u8],
63 id: CommandId,
64 unpacked: VmProtocolData<'a>,
65 priority_map: Arc<BTreeMap<String, u32>>,
66 ) -> VmProtocol<'a> {
67 VmProtocol {
68 data,
69 id,
70 unpacked,
71 priority_map,
72 }
73 }
74}
75
76impl Command for VmProtocol<'_> {
77 fn priority(&self) -> Priority {
78 match self.unpacked {
79 VmProtocolData::Init { .. } => Priority::Init,
80 VmProtocolData::Merge { .. } => Priority::Merge,
81 VmProtocolData::Basic { kind, .. } => {
82 Priority::Basic(self.priority_map.get(kind).copied().unwrap_or_default())
83 }
84 }
85 }
86
87 fn id(&self) -> CommandId {
88 self.id
89 }
90
91 fn parent(&self) -> Prior<Address> {
92 match self.unpacked {
93 VmProtocolData::Init { .. } => Prior::None,
94 VmProtocolData::Merge { left, right, .. } => Prior::Merge(left, right),
95 VmProtocolData::Basic { parent, .. } => Prior::Single(parent),
96 }
97 }
98
99 fn policy(&self) -> Option<&[u8]> {
100 match self.unpacked {
101 VmProtocolData::Init { ref policy, .. } => Some(policy),
102 _ => None,
103 }
104 }
105
106 fn bytes(&self) -> &[u8] {
107 self.data
108 }
109}
110
111#[derive(Clone, Debug)]
112pub struct Envelope<'a> {
113 pub parent_id: CommandId,
114 pub author_id: UserId,
115 pub command_id: CommandId,
116 pub payload: Cow<'a, [u8]>,
117 pub signature: Cow<'a, [u8]>,
118}
119
120impl From<Envelope<'_>> for Struct {
121 fn from(e: Envelope<'_>) -> Self {
122 Self::new(
123 "Envelope",
124 [
125 ("parent_id".into(), e.parent_id.into_id().into()),
126 ("author_id".into(), e.author_id.into_id().into()),
127 ("command_id".into(), e.command_id.into_id().into()),
128 ("payload".into(), e.payload.into_owned().into()),
129 ("signature".into(), e.signature.into_owned().into()),
130 ],
131 )
132 }
133}
134
135impl TryFrom<Struct> for Envelope<'_> {
136 type Error = EnvelopeError;
137
138 fn try_from(
139 Struct {
140 name,
141 ref mut fields,
142 }: Struct,
143 ) -> Result<Self, Self::Error> {
144 if name != "Envelope" {
145 return Err(EnvelopeError::InvalidName(name));
146 }
147
148 Ok(Self {
149 parent_id: get::<aranya_crypto::Id>(fields, "parent_id")?.into(),
150 author_id: get::<aranya_crypto::Id>(fields, "author_id")?.into(),
151 command_id: get::<aranya_crypto::Id>(fields, "command_id")?.into(),
152 payload: Cow::Owned(get(fields, "payload")?),
153 signature: Cow::Owned(get(fields, "signature")?),
154 })
155 }
156}
157
158fn get<T: TryFrom<Value>>(
159 fields: &mut BTreeMap<String, Value>,
160 key: &'static str,
161) -> Result<T, EnvelopeError> {
162 fields
163 .remove(key)
164 .ok_or(EnvelopeError::MissingField(key))?
165 .try_into()
166 .map_err(|_| EnvelopeError::InvalidType(key))
167}
168
169#[derive(Clone, Debug, PartialEq, Eq)]
170pub enum EnvelopeError {
171 InvalidName(String),
172 MissingField(&'static str),
173 InvalidType(&'static str),
174}
175
176impl fmt::Display for EnvelopeError {
177 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178 match self {
179 Self::InvalidName(name) => write!(f, "invalid struct name {name:?}"),
180 Self::MissingField(field) => write!(f, "missing field {field:?}"),
181 Self::InvalidType(field) => write!(f, "invalid type for field {field:?}"),
182 }
183 }
184}
185
186impl core::error::Error for EnvelopeError {}