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