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