1use super::layout::{Builder, Message, StructBuilder, StructReader, Target};
5use anyhow::{Context, Result};
6
7pub const MSG_UNIMPLEMENTED: u16 = 0;
8pub const MSG_ABORT: u16 = 1;
9pub const MSG_CALL: u16 = 2;
10pub const MSG_RETURN: u16 = 3;
11pub const MSG_FINISH: u16 = 4;
12pub const MSG_RESOLVE: u16 = 5;
13pub const MSG_RELEASE: u16 = 6;
14pub const MSG_BOOTSTRAP: u16 = 8;
15pub const MSG_DISEMBARGO: u16 = 13;
16
17pub const EXC_FAILED: u16 = 0;
19pub const EXC_OVERLOADED: u16 = 1;
20pub const EXC_UNIMPLEMENTED: u16 = 3;
21
22pub fn exception_type(name: &str) -> Option<u16> {
23 match name {
24 "failed" => Some(EXC_FAILED),
25 "overloaded" => Some(EXC_OVERLOADED),
26 "disconnected" => Some(2),
27 "unimplemented" => Some(EXC_UNIMPLEMENTED),
28 _ => None,
29 }
30}
31
32pub fn exception_name(t: u16) -> &'static str {
33 match t {
34 0 => "failed",
35 1 => "overloaded",
36 2 => "disconnected",
37 3 => "unimplemented",
38 _ => "unknown",
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum CallTarget {
45 Imported(u32),
46 Promised {
48 question: u32,
49 steps: u32,
50 },
51}
52
53pub enum Returned<'a> {
54 Results {
56 content: Target<'a>,
57 caps: Vec<Option<u32>>,
58 },
59 Exception {
60 reason: String,
61 kind: u16,
62 },
63 Other,
64}
65
66pub enum Incoming<'a> {
67 Bootstrap {
68 question: u32,
69 },
70 Call {
71 question: u32,
72 target: CallTarget,
73 interface: u64,
74 method: u16,
75 content: Target<'a>,
76 },
77 Return {
78 answer: u32,
79 returned: Returned<'a>,
80 },
81 Finish {
82 question: u32,
83 },
84 Release,
85 Resolve,
86 Abort {
87 reason: String,
88 },
89 Unimplemented,
90 Other(u16),
92}
93
94fn body<'a>(m: &StructReader<'a>) -> Result<StructReader<'a>> {
95 m.struct_field(0)?.context("message without a body")
96}
97
98pub fn decode(msg: &Message) -> Result<Incoming<'_>> {
99 let m = msg.root_struct()?;
100 let tag = m.u16(0);
101 Ok(match tag {
102 MSG_BOOTSTRAP => Incoming::Bootstrap {
103 question: body(&m)?.u32(0),
104 },
105 MSG_CALL => {
106 let c = body(&m)?;
107 let t = c.struct_field(0)?.context("call without a target")?;
108 let target = match t.u16(2) {
109 0 => CallTarget::Imported(t.u32(0)),
110 _ => {
111 let p = t.struct_field(0)?.context("promised answer missing")?;
112 CallTarget::Promised {
113 question: p.u32(0),
114 steps: p.list_field(0)?.map_or(0, |l| l.len),
115 }
116 }
117 };
118 let content = match c.struct_field(1)? {
119 Some(payload) => payload.pointer(0)?,
120 None => Target::Null,
121 };
122 Incoming::Call {
123 question: c.u32(0),
124 target,
125 interface: c.u64(1),
126 method: c.u16(2),
127 content,
128 }
129 }
130 MSG_RETURN => {
131 let r = body(&m)?;
132 let returned = match r.u16(3) {
133 0 => {
134 let payload = r.struct_field(0)?;
135 let mut caps = Vec::new();
136 if let Some(table) = payload
137 .as_ref()
138 .map(|p| p.list_field(1))
139 .transpose()?
140 .flatten()
141 {
142 for i in 0..table.len {
143 let d = table.struct_at(i)?;
144 caps.push(match d.u16(0) {
145 1 | 2 => Some(d.u32(1)),
146 _ => None,
147 });
148 }
149 }
150 Returned::Results {
151 content: match payload {
152 Some(p) => p.pointer(0)?,
153 None => Target::Null,
154 },
155 caps,
156 }
157 }
158 1 => {
159 let e = r.struct_field(0)?;
160 Returned::Exception {
161 reason: e
162 .as_ref()
163 .map(|e| e.text(0))
164 .transpose()?
165 .flatten()
166 .unwrap_or_default(),
167 kind: e.map_or(0, |e| e.u16(2)),
168 }
169 }
170 _ => Returned::Other,
171 };
172 Incoming::Return {
173 answer: r.u32(0),
174 returned,
175 }
176 }
177 MSG_FINISH => Incoming::Finish {
178 question: body(&m)?.u32(0),
179 },
180 MSG_RELEASE => Incoming::Release,
181 MSG_RESOLVE => Incoming::Resolve,
182 MSG_ABORT => Incoming::Abort {
183 reason: m
184 .struct_field(0)?
185 .map(|e| e.text(0))
186 .transpose()?
187 .flatten()
188 .unwrap_or_default(),
189 },
190 MSG_UNIMPLEMENTED => Incoming::Unimplemented,
191 other => Incoming::Other(other),
192 })
193}
194
195fn message(tag: u16) -> (Builder, StructBuilder) {
196 let (mut b, m) = Builder::with_root(1, 1);
197 b.set_u16(m, 0, tag);
198 (b, m)
199}
200
201pub fn bootstrap(question: u32) -> Result<Vec<u64>> {
202 let (mut b, m) = message(MSG_BOOTSTRAP);
203 let s = b.init_struct(m, 0, 1, 1)?;
204 b.set_u32(s, 0, question);
205 Ok(b.words)
206}
207
208pub fn return_results(
210 answer: u32,
211 fill: impl FnOnce(&mut Builder, StructBuilder) -> Result<()>,
212) -> Result<Vec<u64>> {
213 let (mut b, m) = message(MSG_RETURN);
214 let r = b.init_struct(m, 0, 2, 1)?;
215 b.set_u32(r, 0, answer);
216 let payload = b.init_struct(r, 0, 0, 2)?;
218 fill(&mut b, payload)?;
219 Ok(b.words)
220}
221
222pub fn return_capability(answer: u32, export: u32) -> Result<Vec<u64>> {
224 return_results(answer, |b, payload| {
225 b.set_capability(payload, 0, 0)?;
226 let descriptors = b.init_struct_list(payload, 1, 1, 1, 1)?;
227 b.set_u16(descriptors[0], 0, 1); b.set_u32(descriptors[0], 1, export);
229 Ok(())
230 })
231}
232
233pub fn return_exception(answer: u32, reason: &str, kind: u16) -> Result<Vec<u64>> {
234 let (mut b, m) = message(MSG_RETURN);
235 let r = b.init_struct(m, 0, 2, 1)?;
236 b.set_u32(r, 0, answer);
237 b.set_u16(r, 3, 1);
238 let e = b.init_struct(r, 0, 1, 2)?;
239 b.set_text(e, 0, reason)?;
240 b.set_u16(e, 2, kind);
241 Ok(b.words)
242}
243
244pub fn call(
246 question: u32,
247 import: u32,
248 interface: u64,
249 method: u16,
250 fill: impl FnOnce(&mut Builder, StructBuilder) -> Result<()>,
251) -> Result<Vec<u64>> {
252 let (mut b, m) = message(MSG_CALL);
253 let c = b.init_struct(m, 0, 3, 3)?;
254 b.set_u32(c, 0, question);
255 b.set_u16(c, 2, method);
256 b.set_u64(c, 1, interface);
257 let t = b.init_struct(c, 0, 1, 1)?;
258 b.set_u32(t, 0, import);
259 let payload = b.init_struct(c, 1, 0, 2)?;
260 fill(&mut b, payload)?;
261 Ok(b.words)
262}
263
264pub fn finish(question: u32, release_result_caps: bool) -> Result<Vec<u64>> {
268 let (mut b, m) = message(MSG_FINISH);
269 let f = b.init_struct(m, 0, 1, 0)?;
270 b.set_u32(f, 0, question);
271 b.set_bool(f, 32, !release_result_caps);
272 Ok(b.words)
273}
274
275pub fn abort(reason: &str) -> Result<Vec<u64>> {
276 let (mut b, m) = message(MSG_ABORT);
277 let e = b.init_struct(m, 0, 1, 2)?;
278 b.set_text(e, 0, reason)?;
279 b.set_u16(e, 2, EXC_FAILED);
280 Ok(b.words)
281}
282
283pub fn unimplemented(original: &Message) -> Result<Vec<u64>> {
285 let (mut b, m) = message(MSG_UNIMPLEMENTED);
286 let slot = Builder::pointer_slot_of(m, 0)?;
287 b.copy_into(slot, original.root()?)?;
288 Ok(b.words)
289}