Skip to main content

protocol/
message.rs

1//! The message envelope (design D4): hello, welcome, request, response,
2//! event, ping and pong.
3//!
4//! Every message except an event is a map keyed by small integers whose key 0
5//! is the message kind ([`kind`]); an event is a positional array whose first
6//! element is the kind.
7
8use core::fmt;
9
10use minicbor::data::Type;
11use minicbor::decode::{self, Decoder};
12use minicbor::encode::{self, Encoder, Write};
13use minicbor::{Decode, Encode};
14
15use crate::capability::Capabilities;
16use crate::cbor::{self, Elements};
17use crate::error::Error;
18use crate::event::{Event, Stream};
19use crate::snapshot::{Bounds, Snapshot};
20
21/// Message kinds: key 0 of a map-shaped message, element 0 of an event.
22pub mod kind {
23    pub const HELLO: u8 = 0;
24    pub const WELCOME: u8 = 1;
25    pub const REQUEST: u8 = 2;
26    pub const RESPONSE: u8 = 3;
27    pub const EVENT: u8 = 4;
28    pub const PING: u8 = 5;
29    pub const PONG: u8 = 6;
30
31    /// The name of a kind, for messages about frames.
32    pub fn name(kind: u8) -> &'static str {
33        match kind {
34            HELLO => "hello",
35            WELCOME => "welcome",
36            REQUEST => "request",
37            RESPONSE => "response",
38            EVENT => "event",
39            PING => "ping",
40            PONG => "pong",
41            _ => "unknown kind",
42        }
43    }
44}
45
46/// One message, the payload of one frame.
47#[derive(Clone, Debug, PartialEq, Eq)]
48pub enum Message {
49    Hello(Hello),
50    Welcome(Welcome),
51    Request(Request),
52    Response(Response),
53    Event(Event),
54    Ping(Ping),
55    Pong(Pong),
56}
57
58impl Message {
59    /// The kind this message carries on the wire.
60    pub fn kind(&self) -> u8 {
61        match self {
62            Message::Hello(_) => kind::HELLO,
63            Message::Welcome(_) => kind::WELCOME,
64            Message::Request(_) => kind::REQUEST,
65            Message::Response(_) => kind::RESPONSE,
66            Message::Event(_) => kind::EVENT,
67            Message::Ping(_) => kind::PING,
68            Message::Pong(_) => kind::PONG,
69        }
70    }
71
72    /// Appends the message's CBOR encoding to `out`.
73    pub fn encode(&self, out: &mut Vec<u8>) {
74        minicbor::encode(self, out).expect("encoding into a Vec cannot fail");
75    }
76
77    /// The message's CBOR encoding.
78    pub fn to_vec(&self) -> Vec<u8> {
79        let mut out = Vec::new();
80        self.encode(&mut out);
81        out
82    }
83
84    /// Decodes one message that fills all of `bytes`.
85    pub fn decode(bytes: &[u8]) -> Result<Message, DecodeError> {
86        let mut d = Decoder::new(bytes);
87        let msg = match peek_kind(&d)? {
88            kind::HELLO => Message::Hello(d.decode()?),
89            kind::WELCOME => Message::Welcome(d.decode()?),
90            kind::REQUEST => Message::Request(d.decode()?),
91            kind::RESPONSE => Message::Response(d.decode()?),
92            kind::EVENT => Message::Event(d.decode()?),
93            kind::PING => Message::Ping(d.decode()?),
94            kind::PONG => Message::Pong(d.decode()?),
95            other => return Err(DecodeError::UnknownKind(other)),
96        };
97        if d.position() != bytes.len() {
98            return Err(DecodeError::TrailingBytes {
99                consumed: d.position(),
100                len: bytes.len(),
101            });
102        }
103        Ok(msg)
104    }
105}
106
107/// Reads the kind of the message at the decoder's position without moving it:
108/// element 0 of an array, key 0 of a map.
109fn peek_kind(d: &Decoder<'_>) -> Result<u8, decode::Error> {
110    let mut p = d.clone();
111    match p.datatype()? {
112        Type::Array | Type::ArrayIndef => {
113            let mut items = Elements::begin(&mut p)?;
114            items.require(&mut p, 0, "kind", |d| d.u8())
115        }
116        Type::Map | Type::MapIndef => {
117            // Key 0 comes first in the encoders' layout; look further for others.
118            let len = p.map()?;
119            let mut seen = 0;
120            loop {
121                let more = match len {
122                    Some(n) => seen < n,
123                    None => p.datatype()? != Type::Break,
124                };
125                if !more {
126                    return Err(cbor::missing(0, "kind").at(d.position()));
127                }
128                if p.i64()? == 0 {
129                    return p.u8();
130                }
131                p.skip()?;
132                seen += 1;
133            }
134        }
135        other => Err(decode::Error::type_mismatch(other)
136            .with_message("a message is a map or an array")
137            .at(d.position())),
138    }
139}
140
141impl<C> Encode<C> for Message {
142    fn encode<W: Write>(
143        &self,
144        e: &mut Encoder<W>,
145        ctx: &mut C,
146    ) -> Result<(), encode::Error<W::Error>> {
147        match self {
148            Message::Hello(m) => m.encode(e, ctx),
149            Message::Welcome(m) => m.encode(e, ctx),
150            Message::Request(m) => m.encode(e, ctx),
151            Message::Response(m) => m.encode(e, ctx),
152            Message::Event(m) => m.encode(e, ctx),
153            Message::Ping(m) => m.encode(e, ctx),
154            Message::Pong(m) => m.encode(e, ctx),
155        }
156    }
157}
158
159impl From<Hello> for Message {
160    fn from(m: Hello) -> Message {
161        Message::Hello(m)
162    }
163}
164
165impl From<Welcome> for Message {
166    fn from(m: Welcome) -> Message {
167        Message::Welcome(m)
168    }
169}
170
171impl From<Request> for Message {
172    fn from(m: Request) -> Message {
173        Message::Request(m)
174    }
175}
176
177impl From<Response> for Message {
178    fn from(m: Response) -> Message {
179        Message::Response(m)
180    }
181}
182
183impl From<Event> for Message {
184    fn from(m: Event) -> Message {
185        Message::Event(m)
186    }
187}
188
189/// Why a payload could not be decoded.
190#[derive(Debug)]
191pub enum DecodeError {
192    /// Malformed CBOR, or a value of the wrong type or shape.
193    Cbor(minicbor::decode::Error),
194    /// A message kind this version does not know. Sessions skip these.
195    UnknownKind(u8),
196    /// The message ended before the payload did.
197    TrailingBytes { consumed: usize, len: usize },
198}
199
200impl fmt::Display for DecodeError {
201    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202        match self {
203            DecodeError::Cbor(e) => write!(f, "invalid message: {e}"),
204            DecodeError::UnknownKind(k) => write!(f, "unknown message kind {k}"),
205            DecodeError::TrailingBytes { consumed, len } => write!(
206                f,
207                "{} bytes after the message, which ends at byte {consumed} of {len}",
208                len - consumed
209            ),
210        }
211    }
212}
213
214impl std::error::Error for DecodeError {}
215
216impl From<minicbor::decode::Error> for DecodeError {
217    fn from(e: minicbor::decode::Error) -> DecodeError {
218        DecodeError::Cbor(e)
219    }
220}
221
222/// The agent's first message on every connection.
223///
224/// On the wire: `{0: 0, 1: versions, 2: capabilities, 3: max_frame, 4: agent, ?5: token}`.
225#[derive(Clone, Debug, PartialEq, Eq)]
226pub struct Hello {
227    /// Protocol versions the agent speaks.
228    pub versions: Vec<u16>,
229    pub capabilities: Capabilities,
230    /// The largest frame payload the agent accepts, in bytes.
231    pub max_frame: u32,
232    /// Agent name and version, such as `mobile-agent-android 0.1.0`.
233    pub agent: String,
234    /// The per-launch token the host passed when it started the agent.
235    pub token: Option<String>,
236}
237
238/// The host's answer to a hello: the negotiated version and frame size, or
239/// the reason it refuses the connection before closing it.
240///
241/// On the wire: `{0: 1, 1: versions, ?2: version, 3: max_frame, ?4: error}`.
242#[derive(Clone, Debug, PartialEq, Eq)]
243pub struct Welcome {
244    /// Protocol versions the host speaks.
245    pub versions: Vec<u16>,
246    /// The selected version: the highest both sides speak. Absent on refusal.
247    pub version: Option<u16>,
248    /// The negotiated maximum frame payload: the smaller of both sides'.
249    pub max_frame: u32,
250    /// Why the host refuses the connection.
251    pub error: Option<Error>,
252}
253
254/// A request from the host.
255///
256/// On the wire: `{0: 2, 1: id, 2: method, ?3: deadline_ms, 4: params}`, where
257/// params is a map, empty for methods without parameters.
258#[derive(Clone, Debug, PartialEq, Eq)]
259pub struct Request {
260    /// Assigned by the host; the response echoes it.
261    pub id: u32,
262    /// Relative deadline in milliseconds.
263    pub deadline_ms: Option<u32>,
264    /// The method and its parameters.
265    pub call: Call,
266}
267
268/// The answer to one request.
269///
270/// On the wire: `{0: 3, 1: id, 2: method, 3: result}` or
271/// `{0: 3, 1: id, 2: method, 4: error}`; an empty result is an empty map.
272#[derive(Clone, Debug, PartialEq, Eq)]
273pub struct Response {
274    /// The request's id.
275    pub id: u32,
276    /// The request's method, echoed so the result decodes on its own.
277    pub method: Method,
278    pub result: Result<Reply, Error>,
279}
280
281/// A liveness probe; the peer answers with a [`Pong`] carrying the same nonce.
282///
283/// On the wire: `{0: 5, 1: nonce}`.
284#[derive(Clone, Copy, Debug, PartialEq, Eq)]
285pub struct Ping {
286    pub nonce: u64,
287}
288
289/// The answer to a [`Ping`].
290///
291/// On the wire: `{0: 6, 1: nonce}`.
292#[derive(Clone, Copy, Debug, PartialEq, Eq)]
293pub struct Pong {
294    pub nonce: u64,
295}
296
297wire_enum! {
298    /// A request method, `u16` on the wire.
299    pub struct Method(u16);
300    /// Read the UI tree ([`SnapshotParams`] to [`Snapshot`]); needs `tree`.
301    SNAPSHOT = 1, "snapshot";
302    /// Capture the screen ([`ScreenshotParams`] to [`Screenshot`]); needs `screenshot`.
303    SCREENSHOT = 2, "screenshot";
304    /// Tap or long-press ([`TapParams`] to [`InputAck`]); needs `input`.
305    TAP = 3, "tap";
306    /// Swipe ([`SwipeParams`] to [`InputAck`]); needs `input`.
307    SWIPE = 4, "swipe";
308    /// Press a key ([`KeyParams`] to [`InputAck`]); needs `input`.
309    KEY = 5, "key";
310    /// Set text in a field ([`TextParams`] to [`TextAck`]); needs `text_set`.
311    TEXT_SET = 6, "text_set";
312    /// Start frame streaming ([`FramesParams`] to an empty result); needs `frames`.
313    FRAMES_START = 7, "frames_start";
314    /// Stop frame streaming (no parameters, empty result); needs `frames`.
315    FRAMES_STOP = 8, "frames_stop";
316    /// Resynchronize a stream ([`ResyncParams`] to [`ResyncAck`]); needs `events`.
317    RESYNC = 9, "resync";
318    /// Exit cleanly (no parameters, empty result); needs nothing.
319    SHUTDOWN = 10, "shutdown";
320    /// Read nodes' bounds again past the platform's node cache
321    /// ([`BoundsParams`] to [`Probed`]); needs `bounds`.
322    BOUNDS = 11, "bounds";
323}
324
325impl Method {
326    /// The capability an agent must advertise before the host sends this
327    /// method; empty for `shutdown` and for methods this version does not know.
328    pub fn required_capability(self) -> Capabilities {
329        match self {
330            Method::SNAPSHOT => Capabilities::TREE,
331            Method::SCREENSHOT => Capabilities::SCREENSHOT,
332            Method::TAP | Method::SWIPE | Method::KEY => Capabilities::INPUT,
333            Method::TEXT_SET => Capabilities::TEXT_SET,
334            Method::FRAMES_START | Method::FRAMES_STOP => Capabilities::FRAMES,
335            Method::RESYNC => Capabilities::EVENTS,
336            Method::BOUNDS => Capabilities::BOUNDS,
337            _ => Capabilities::NONE,
338        }
339    }
340}
341
342/// A method with its parameters.
343#[derive(Clone, Debug, PartialEq, Eq)]
344pub enum Call {
345    Snapshot(SnapshotParams),
346    Screenshot(ScreenshotParams),
347    Tap(TapParams),
348    Swipe(SwipeParams),
349    Key(KeyParams),
350    TextSet(TextParams),
351    FramesStart(FramesParams),
352    FramesStop,
353    Resync(ResyncParams),
354    Shutdown,
355    Bounds(BoundsParams),
356    /// A method this version does not know; its parameters were skipped and
357    /// are sent as an empty map.
358    Unknown(Method),
359}
360
361impl Call {
362    pub fn method(&self) -> Method {
363        match self {
364            Call::Snapshot(_) => Method::SNAPSHOT,
365            Call::Screenshot(_) => Method::SCREENSHOT,
366            Call::Tap(_) => Method::TAP,
367            Call::Swipe(_) => Method::SWIPE,
368            Call::Key(_) => Method::KEY,
369            Call::TextSet(_) => Method::TEXT_SET,
370            Call::FramesStart(_) => Method::FRAMES_START,
371            Call::FramesStop => Method::FRAMES_STOP,
372            Call::Resync(_) => Method::RESYNC,
373            Call::Shutdown => Method::SHUTDOWN,
374            Call::Bounds(_) => Method::BOUNDS,
375            Call::Unknown(method) => *method,
376        }
377    }
378}
379
380/// The result of a successful request.
381#[derive(Clone, Debug, PartialEq, Eq)]
382pub enum Reply {
383    /// For `snapshot`.
384    Snapshot(Snapshot),
385    /// For `screenshot`.
386    Screenshot(Screenshot),
387    /// For `tap`, `swipe` and `key`.
388    Input(InputAck),
389    /// For `text_set`.
390    Text(TextAck),
391    /// For `resync`.
392    Resync(ResyncAck),
393    /// For `bounds`.
394    Bounds(Probed),
395    /// For `frames_start`, `frames_stop` and `shutdown`: an empty map.
396    Empty,
397}
398
399/// Parameters of `snapshot`. Absent fields take the agent's defaults.
400#[derive(Clone, Debug, Default, PartialEq, Eq, Encode, Decode)]
401#[cbor(map)]
402pub struct SnapshotParams {
403    /// Deepest node level to read below each window root.
404    #[n(0)]
405    pub max_depth: Option<u32>,
406    /// Most nodes to read across all windows.
407    #[n(1)]
408    pub max_nodes: Option<u32>,
409    /// Longest wait for the UI to go idle before reading; 0 skips the wait.
410    #[n(2)]
411    pub idle_ms: Option<u32>,
412    /// Evict the platform's node cache of the windows that send no change
413    /// events before reading: input the agent did not inject, such as the
414    /// emulator controller's, left them stale. The tree stream and every
415    /// other window's cache are left alone, unlike a resync. An agent that
416    /// does not know the key skips it and reads with its cache.
417    #[n(3)]
418    pub evict_event_less: Option<bool>,
419    /// Windows whose nodes the agent evicts from the platform's node cache
420    /// before reading, by window id: bounds probes found their nodes moved
421    /// without a change event, which leaves the cache holding the old
422    /// bounds. An agent that does not know the key skips it and reads with
423    /// its cache.
424    #[n(4)]
425    pub evict: Option<Vec<u32>>,
426}
427
428/// Parameters of `screenshot`.
429#[derive(Clone, Debug, Default, PartialEq, Eq, Encode, Decode)]
430#[cbor(map)]
431pub struct ScreenshotParams {
432    #[n(0)]
433    pub format: Option<ImageFormat>,
434    /// JPEG quality, 1 to 100.
435    #[n(1)]
436    pub quality: Option<u8>,
437    /// Longest side of the returned image; larger screens are scaled down.
438    #[n(2)]
439    pub max_dimension: Option<u32>,
440}
441
442/// Parameters of `tap`: a long press when `duration_ms` is present.
443#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)]
444#[cbor(map)]
445pub struct TapParams {
446    #[n(0)]
447    pub x: i32,
448    #[n(1)]
449    pub y: i32,
450    #[n(2)]
451    pub duration_ms: Option<u32>,
452}
453
454/// Parameters of `swipe`: the pointer goes down at `(x1, y1)`, moves along
455/// the line to `(x2, y2)` over `duration_ms` and lifts there, moving, so
456/// the content flings on.
457#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)]
458#[cbor(map)]
459pub struct SwipeParams {
460    #[n(0)]
461    pub x1: i32,
462    #[n(1)]
463    pub y1: i32,
464    #[n(2)]
465    pub x2: i32,
466    #[n(3)]
467    pub y2: i32,
468    #[n(4)]
469    pub duration_ms: u32,
470    /// How long the pointer rests at `(x2, y2)` before it lifts, after
471    /// which it moves one pixel on along the line and lifts there (task
472    /// 10.16). Android's velocity tracker takes a pointer that has not
473    /// moved for 40 ms as stopped when its next event comes, so the content
474    /// stops with the pointer instead of flinging.
475    #[n(5)]
476    pub rest_ms: Option<u32>,
477}
478
479/// Parameters of `key`.
480#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)]
481#[cbor(map)]
482pub struct KeyParams {
483    /// Platform key code, such as Android's `KEYCODE_ENTER` (66).
484    #[n(0)]
485    pub code: u32,
486    /// Platform meta-state bits.
487    #[n(1)]
488    pub meta: Option<u32>,
489}
490
491/// Parameters of `text_set`.
492#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)]
493#[cbor(map)]
494pub struct TextParams {
495    #[n(0)]
496    pub text: String,
497    /// The node to set; absent for the focused field.
498    #[n(1)]
499    pub node: Option<u32>,
500    /// How to enter the text; absent lets the agent choose.
501    #[n(2)]
502    pub mode: Option<TextMethod>,
503}
504
505/// Parameters of `frames_start`.
506#[derive(Clone, Debug, Default, PartialEq, Eq, Encode, Decode)]
507#[cbor(map)]
508pub struct FramesParams {
509    #[n(0)]
510    pub max_fps: Option<u32>,
511    #[n(1)]
512    pub max_dimension: Option<u32>,
513}
514
515/// Parameters of `resync`.
516#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)]
517#[cbor(map)]
518pub struct ResyncParams {
519    #[n(0)]
520    pub stream: Stream,
521}
522
523/// Parameters of `bounds`: nodes of the last snapshot, by id, whose bounds
524/// the agent reads again past the platform's node cache.
525#[derive(Clone, Debug, Default, PartialEq, Eq, Encode, Decode)]
526#[cbor(map)]
527pub struct BoundsParams {
528    #[cbor(n(0), decode_with = "crate::cbor::decode_vec")]
529    pub nodes: Vec<u32>,
530}
531
532/// The result of `bounds`: each node still on screen with its bounds as the
533/// app reports them now, in the request's order; a node that is gone, or
534/// that the last snapshot did not hold, is left out.
535#[derive(Clone, Debug, Default, PartialEq, Eq, Encode, Decode)]
536#[cbor(map)]
537pub struct Probed {
538    #[cbor(n(0), decode_with = "crate::cbor::decode_vec")]
539    pub nodes: Vec<NodeBounds>,
540}
541
542/// One node of a [`Probed`], on the wire `[node, bounds]`.
543#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encode, Decode)]
544#[cbor(array)]
545pub struct NodeBounds {
546    /// The node's id in the last snapshot.
547    #[n(0)]
548    pub node: u32,
549    /// Its bounds in screen pixels.
550    #[n(1)]
551    pub bounds: Bounds,
552}
553
554/// The result of `screenshot`.
555#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)]
556#[cbor(map)]
557pub struct Screenshot {
558    #[n(0)]
559    pub format: ImageFormat,
560    #[n(1)]
561    pub width: u32,
562    #[n(2)]
563    pub height: u32,
564    /// Display rotation when the image was taken.
565    #[n(3)]
566    pub rotation: Rotation,
567    /// The encoded image.
568    #[cbor(n(4), with = "minicbor::bytes")]
569    pub data: Vec<u8>,
570}
571
572/// The result of an input method: whether the platform accepted the events.
573#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)]
574#[cbor(map)]
575pub struct InputAck {
576    #[n(0)]
577    pub accepted: bool,
578}
579
580/// The result of `text_set`: which way the text went in.
581#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)]
582#[cbor(map)]
583pub struct TextAck {
584    #[n(0)]
585    pub method: TextMethod,
586}
587
588/// The result of `resync`: the stream is in sync again from `seq + 1`.
589#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)]
590#[cbor(map)]
591pub struct ResyncAck {
592    #[n(0)]
593    pub stream: Stream,
594    /// The last sequence number the agent sent on the stream before answering.
595    #[n(1)]
596    pub seq: u64,
597}
598
599wire_enum! {
600    /// Image encodings.
601    pub struct ImageFormat(u8);
602    PNG = 0, "png";
603    JPEG = 1, "jpeg";
604}
605
606wire_enum! {
607    /// Display rotation, with Android's `Surface.ROTATION_*` values.
608    pub struct Rotation(u8);
609    R0 = 0, "0";
610    R90 = 1, "90";
611    R180 = 2, "180";
612    R270 = 3, "270";
613}
614
615wire_enum! {
616    /// How text is entered.
617    pub struct TextMethod(u8);
618    /// Let the agent choose (requests only).
619    AUTO = 0, "auto";
620    /// Set the field's text directly.
621    DIRECT = 1, "direct";
622    /// Type it as key events.
623    KEYS = 2, "keys";
624}
625
626impl<C> Encode<C> for Hello {
627    fn encode<W: Write>(
628        &self,
629        e: &mut Encoder<W>,
630        ctx: &mut C,
631    ) -> Result<(), encode::Error<W::Error>> {
632        e.map(5 + u64::from(self.token.is_some()))?;
633        e.u8(0)?.u8(kind::HELLO)?;
634        e.u8(1)?.encode_with(&self.versions, ctx)?;
635        e.u8(2)?.encode_with(self.capabilities, ctx)?;
636        e.u8(3)?.u32(self.max_frame)?;
637        e.u8(4)?.str(&self.agent)?;
638        if let Some(token) = &self.token {
639            e.u8(5)?.str(token)?;
640        }
641        Ok(())
642    }
643}
644
645impl<'b, C> Decode<'b, C> for Hello {
646    fn decode(d: &mut Decoder<'b>, ctx: &mut C) -> Result<Hello, decode::Error> {
647        let at = d.position();
648        let mut k = None;
649        let mut versions = None;
650        let mut capabilities = None;
651        let mut max_frame = None;
652        let mut agent = None;
653        let mut token = None;
654        cbor::map_entries(d, |d, key| {
655            match key {
656                0 => k = Some(d.u8()?),
657                1 => versions = Some(cbor::decode_vec(d, &mut *ctx)?),
658                2 => capabilities = Some(Capabilities::decode(d, &mut *ctx)?),
659                3 => max_frame = Some(d.u32()?),
660                4 => agent = Some(d.str()?.to_owned()),
661                5 => token = Option::<String>::decode(d, &mut *ctx)?,
662                _ => d.skip()?,
663            }
664            Ok(())
665        })?;
666        cbor::expect_kind(k, kind::HELLO, at)?;
667        Ok(Hello {
668            versions: versions.ok_or_else(|| cbor::missing(1, "versions").at(at))?,
669            capabilities: capabilities.ok_or_else(|| cbor::missing(2, "capabilities").at(at))?,
670            max_frame: max_frame.ok_or_else(|| cbor::missing(3, "max_frame").at(at))?,
671            agent: agent.ok_or_else(|| cbor::missing(4, "agent").at(at))?,
672            token,
673        })
674    }
675}
676
677impl<C> Encode<C> for Welcome {
678    fn encode<W: Write>(
679        &self,
680        e: &mut Encoder<W>,
681        ctx: &mut C,
682    ) -> Result<(), encode::Error<W::Error>> {
683        e.map(3 + u64::from(self.version.is_some()) + u64::from(self.error.is_some()))?;
684        e.u8(0)?.u8(kind::WELCOME)?;
685        e.u8(1)?.encode_with(&self.versions, ctx)?;
686        if let Some(version) = self.version {
687            e.u8(2)?.u16(version)?;
688        }
689        e.u8(3)?.u32(self.max_frame)?;
690        if let Some(error) = &self.error {
691            e.u8(4)?.encode_with(error, ctx)?;
692        }
693        Ok(())
694    }
695}
696
697impl<'b, C> Decode<'b, C> for Welcome {
698    fn decode(d: &mut Decoder<'b>, ctx: &mut C) -> Result<Welcome, decode::Error> {
699        let at = d.position();
700        let mut k = None;
701        let mut versions = None;
702        let mut version = None;
703        let mut max_frame = None;
704        let mut error = None;
705        cbor::map_entries(d, |d, key| {
706            match key {
707                0 => k = Some(d.u8()?),
708                1 => versions = Some(cbor::decode_vec(d, &mut *ctx)?),
709                2 => version = Option::<u16>::decode(d, &mut *ctx)?,
710                3 => max_frame = Some(d.u32()?),
711                4 => error = Option::<Error>::decode(d, &mut *ctx)?,
712                _ => d.skip()?,
713            }
714            Ok(())
715        })?;
716        cbor::expect_kind(k, kind::WELCOME, at)?;
717        Ok(Welcome {
718            versions: versions.ok_or_else(|| cbor::missing(1, "versions").at(at))?,
719            version,
720            max_frame: max_frame.ok_or_else(|| cbor::missing(3, "max_frame").at(at))?,
721            error,
722        })
723    }
724}
725
726impl<C> Encode<C> for Request {
727    fn encode<W: Write>(
728        &self,
729        e: &mut Encoder<W>,
730        ctx: &mut C,
731    ) -> Result<(), encode::Error<W::Error>> {
732        e.map(4 + u64::from(self.deadline_ms.is_some()))?;
733        e.u8(0)?.u8(kind::REQUEST)?;
734        e.u8(1)?.u32(self.id)?;
735        e.u8(2)?.u16(self.call.method().0)?;
736        if let Some(ms) = self.deadline_ms {
737            e.u8(3)?.u32(ms)?;
738        }
739        e.u8(4)?;
740        match &self.call {
741            Call::Snapshot(p) => p.encode(e, ctx)?,
742            Call::Screenshot(p) => p.encode(e, ctx)?,
743            Call::Tap(p) => p.encode(e, ctx)?,
744            Call::Swipe(p) => p.encode(e, ctx)?,
745            Call::Key(p) => p.encode(e, ctx)?,
746            Call::TextSet(p) => p.encode(e, ctx)?,
747            Call::FramesStart(p) => p.encode(e, ctx)?,
748            Call::Resync(p) => p.encode(e, ctx)?,
749            Call::Bounds(p) => p.encode(e, ctx)?,
750            Call::FramesStop | Call::Shutdown | Call::Unknown(_) => {
751                e.map(0)?;
752            }
753        }
754        Ok(())
755    }
756}
757
758impl<'b, C> Decode<'b, C> for Request {
759    fn decode(d: &mut Decoder<'b>, ctx: &mut C) -> Result<Request, decode::Error> {
760        let at = d.position();
761        let mut k = None;
762        let mut id = None;
763        let mut method = None;
764        let mut deadline_ms = None;
765        let mut params_at = None;
766        cbor::map_entries(d, |d, key| {
767            match key {
768                0 => k = Some(d.u8()?),
769                1 => id = Some(d.u32()?),
770                2 => method = Some(Method(d.u16()?)),
771                3 => deadline_ms = Option::<u32>::decode(d, &mut *ctx)?,
772                // Decoded below, once the method is known whatever the key order.
773                4 => {
774                    params_at = Some(d.position());
775                    d.skip()?;
776                }
777                _ => d.skip()?,
778            }
779            Ok(())
780        })?;
781        cbor::expect_kind(k, kind::REQUEST, at)?;
782        let id = id.ok_or_else(|| cbor::missing(1, "id").at(at))?;
783        let method = method.ok_or_else(|| cbor::missing(2, "method").at(at))?;
784        let params_at = params_at.ok_or_else(|| cbor::missing(4, "params").at(at))?;
785        let mut params = d.clone();
786        params.set_position(params_at);
787        let call = Call::decode_params(method, &mut params, ctx)?;
788        Ok(Request {
789            id,
790            deadline_ms,
791            call,
792        })
793    }
794}
795
796impl Call {
797    fn decode_params<'b, C>(
798        method: Method,
799        d: &mut Decoder<'b>,
800        ctx: &mut C,
801    ) -> Result<Call, decode::Error> {
802        Ok(match method {
803            Method::SNAPSHOT => Call::Snapshot(Decode::decode(d, ctx)?),
804            Method::SCREENSHOT => Call::Screenshot(Decode::decode(d, ctx)?),
805            Method::TAP => Call::Tap(Decode::decode(d, ctx)?),
806            Method::SWIPE => Call::Swipe(Decode::decode(d, ctx)?),
807            Method::KEY => Call::Key(Decode::decode(d, ctx)?),
808            Method::TEXT_SET => Call::TextSet(Decode::decode(d, ctx)?),
809            Method::FRAMES_START => Call::FramesStart(Decode::decode(d, ctx)?),
810            Method::FRAMES_STOP => {
811                cbor::skip_map(d)?;
812                Call::FramesStop
813            }
814            Method::RESYNC => Call::Resync(Decode::decode(d, ctx)?),
815            Method::SHUTDOWN => {
816                cbor::skip_map(d)?;
817                Call::Shutdown
818            }
819            Method::BOUNDS => Call::Bounds(Decode::decode(d, ctx)?),
820            other => {
821                d.skip()?;
822                Call::Unknown(other)
823            }
824        })
825    }
826}
827
828impl Reply {
829    /// Whether this is the result type of `method`.
830    pub fn answers(&self, method: Method) -> bool {
831        matches!(
832            (self, method),
833            (Reply::Snapshot(_), Method::SNAPSHOT)
834                | (Reply::Screenshot(_), Method::SCREENSHOT)
835                | (Reply::Input(_), Method::TAP | Method::SWIPE | Method::KEY)
836                | (Reply::Text(_), Method::TEXT_SET)
837                | (Reply::Resync(_), Method::RESYNC)
838                | (Reply::Bounds(_), Method::BOUNDS)
839                | (
840                    Reply::Empty,
841                    Method::FRAMES_START | Method::FRAMES_STOP | Method::SHUTDOWN
842                )
843        )
844    }
845
846    fn decode_for<'b, C>(
847        method: Method,
848        d: &mut Decoder<'b>,
849        ctx: &mut C,
850    ) -> Result<Reply, decode::Error> {
851        Ok(match method {
852            Method::SNAPSHOT => Reply::Snapshot(Decode::decode(d, ctx)?),
853            Method::SCREENSHOT => Reply::Screenshot(Decode::decode(d, ctx)?),
854            Method::TAP | Method::SWIPE | Method::KEY => Reply::Input(Decode::decode(d, ctx)?),
855            Method::TEXT_SET => Reply::Text(Decode::decode(d, ctx)?),
856            Method::RESYNC => Reply::Resync(Decode::decode(d, ctx)?),
857            Method::BOUNDS => Reply::Bounds(Decode::decode(d, ctx)?),
858            Method::FRAMES_START | Method::FRAMES_STOP | Method::SHUTDOWN => {
859                cbor::skip_map(d)?;
860                Reply::Empty
861            }
862            other => {
863                return Err(decode::Error::message(format!(
864                    "a result for {other}, which this version does not know"
865                ))
866                .at(d.position()));
867            }
868        })
869    }
870}
871
872impl<C> Encode<C> for Reply {
873    fn encode<W: Write>(
874        &self,
875        e: &mut Encoder<W>,
876        ctx: &mut C,
877    ) -> Result<(), encode::Error<W::Error>> {
878        match self {
879            Reply::Snapshot(r) => r.encode(e, ctx),
880            Reply::Screenshot(r) => r.encode(e, ctx),
881            Reply::Input(r) => r.encode(e, ctx),
882            Reply::Text(r) => r.encode(e, ctx),
883            Reply::Resync(r) => r.encode(e, ctx),
884            Reply::Bounds(r) => r.encode(e, ctx),
885            Reply::Empty => {
886                e.map(0)?;
887                Ok(())
888            }
889        }
890    }
891}
892
893impl<C> Encode<C> for Response {
894    fn encode<W: Write>(
895        &self,
896        e: &mut Encoder<W>,
897        ctx: &mut C,
898    ) -> Result<(), encode::Error<W::Error>> {
899        e.map(4)?;
900        e.u8(0)?.u8(kind::RESPONSE)?;
901        e.u8(1)?.u32(self.id)?;
902        e.u8(2)?.u16(self.method.0)?;
903        match &self.result {
904            Ok(reply) => {
905                debug_assert!(reply.answers(self.method), "{reply:?} for {}", self.method);
906                e.u8(3)?.encode_with(reply, ctx)?;
907            }
908            Err(error) => {
909                e.u8(4)?.encode_with(error, ctx)?;
910            }
911        }
912        Ok(())
913    }
914}
915
916impl<'b, C> Decode<'b, C> for Response {
917    fn decode(d: &mut Decoder<'b>, ctx: &mut C) -> Result<Response, decode::Error> {
918        let at = d.position();
919        let mut k = None;
920        let mut id = None;
921        let mut method = None;
922        let mut result_at = None;
923        let mut error = None;
924        cbor::map_entries(d, |d, key| {
925            match key {
926                0 => k = Some(d.u8()?),
927                1 => id = Some(d.u32()?),
928                2 => method = Some(Method(d.u16()?)),
929                // Decoded below, once the method is known whatever the key order.
930                3 => {
931                    result_at = Some(d.position());
932                    d.skip()?;
933                }
934                4 => error = Option::<Error>::decode(d, &mut *ctx)?,
935                _ => d.skip()?,
936            }
937            Ok(())
938        })?;
939        cbor::expect_kind(k, kind::RESPONSE, at)?;
940        let id = id.ok_or_else(|| cbor::missing(1, "id").at(at))?;
941        let method = method.ok_or_else(|| cbor::missing(2, "method").at(at))?;
942        let result = match (result_at, error) {
943            (Some(result_at), None) => {
944                let mut result = d.clone();
945                result.set_position(result_at);
946                Ok(Reply::decode_for(method, &mut result, ctx)?)
947            }
948            (None, Some(error)) => Err(error),
949            (Some(_), Some(_)) => {
950                return Err(
951                    decode::Error::message("a response with both a result and an error").at(at),
952                );
953            }
954            (None, None) => {
955                return Err(decode::Error::message(
956                    "a response with neither a result nor an error",
957                )
958                .at(at));
959            }
960        };
961        Ok(Response { id, method, result })
962    }
963}
964
965impl<C> Encode<C> for Ping {
966    fn encode<W: Write>(
967        &self,
968        e: &mut Encoder<W>,
969        _: &mut C,
970    ) -> Result<(), encode::Error<W::Error>> {
971        e.map(2)?.u8(0)?.u8(kind::PING)?.u8(1)?.u64(self.nonce)?;
972        Ok(())
973    }
974}
975
976impl<'b, C> Decode<'b, C> for Ping {
977    fn decode(d: &mut Decoder<'b>, _: &mut C) -> Result<Ping, decode::Error> {
978        decode_nonce(d, kind::PING).map(|nonce| Ping { nonce })
979    }
980}
981
982impl<C> Encode<C> for Pong {
983    fn encode<W: Write>(
984        &self,
985        e: &mut Encoder<W>,
986        _: &mut C,
987    ) -> Result<(), encode::Error<W::Error>> {
988        e.map(2)?.u8(0)?.u8(kind::PONG)?.u8(1)?.u64(self.nonce)?;
989        Ok(())
990    }
991}
992
993impl<'b, C> Decode<'b, C> for Pong {
994    fn decode(d: &mut Decoder<'b>, _: &mut C) -> Result<Pong, decode::Error> {
995        decode_nonce(d, kind::PONG).map(|nonce| Pong { nonce })
996    }
997}
998
999fn decode_nonce(d: &mut Decoder<'_>, expected: u8) -> Result<u64, decode::Error> {
1000    let at = d.position();
1001    let mut k = None;
1002    let mut nonce = None;
1003    cbor::map_entries(d, |d, key| {
1004        match key {
1005            0 => k = Some(d.u8()?),
1006            1 => nonce = Some(d.u64()?),
1007            _ => d.skip()?,
1008        }
1009        Ok(())
1010    })?;
1011    cbor::expect_kind(k, expected, at)?;
1012    nonce.ok_or_else(|| cbor::missing(1, "nonce").at(at))
1013}