mqtt_sn/
defs.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use core::ops::{Deref, DerefMut};
6
7use bitfield::{bitfield_bitrange, bitfield_fields};
8use byte::{check_len, BytesExt, TryRead, TryWrite};
9use heapless::String;
10
11pub trait MsgType {
12    const MSG_TYPE: u8;
13}
14
15#[derive(Clone, Copy, Debug, Default, PartialEq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub struct Flags(u8);
18bitfield_bitrange! {struct Flags(u8)}
19
20impl Flags {
21    bitfield_fields! {
22      u8;
23      pub dup, set_dup: 7;
24      pub qos, set_qos: 6, 5;
25      pub retain, set_retain: 4;
26      pub will, set_will: 3;
27      pub clean_session, set_clean_session: 2;
28      pub topic_id_type, set_topic_id_type: 1, 0;
29    }
30}
31
32impl TryWrite for Flags {
33    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
34        let offset = &mut 0;
35        bytes.write(offset, self.0)?;
36        Ok(*offset)
37    }
38}
39
40impl TryRead<'_> for Flags {
41    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
42        Ok((Flags(bytes.read::<u8>(&mut 0)?), 1))
43    }
44}
45
46#[derive(Clone, Copy, Debug, PartialEq)]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48pub enum ReturnCode {
49    Accepted,
50    Rejected(RejectedReason),
51}
52
53impl From<RejectedReason> for ReturnCode {
54    fn from(reason: RejectedReason) -> Self {
55        Self::Rejected(reason)
56    }
57}
58
59impl TryWrite for ReturnCode {
60    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
61        let offset = &mut 0;
62        bytes.write(
63            offset,
64            match self {
65                ReturnCode::Accepted => 0u8,
66                ReturnCode::Rejected(RejectedReason::Congestion) => 1u8,
67                ReturnCode::Rejected(RejectedReason::InvalidTopicId) => 2u8,
68                ReturnCode::Rejected(RejectedReason::NotSupported) => 3u8,
69                ReturnCode::Rejected(RejectedReason::Reserved(n)) => n,
70            },
71        )?;
72        Ok(*offset)
73    }
74}
75
76impl TryRead<'_> for ReturnCode {
77    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
78        let offset = &mut 0;
79        Ok((
80            match bytes.read::<u8>(offset)? {
81                0 => ReturnCode::Accepted,
82                1 => ReturnCode::Rejected(RejectedReason::Congestion),
83                2 => ReturnCode::Rejected(RejectedReason::InvalidTopicId),
84                3 => ReturnCode::Rejected(RejectedReason::NotSupported),
85                n => ReturnCode::Rejected(RejectedReason::Reserved(n)),
86            },
87            *offset,
88        ))
89    }
90}
91
92#[derive(Clone, Copy, Debug, PartialEq)]
93#[cfg_attr(feature = "defmt", derive(defmt::Format))]
94pub enum RejectedReason {
95    Congestion,
96    InvalidTopicId,
97    NotSupported,
98    Reserved(u8),
99}
100
101#[derive(Clone, Debug, PartialEq)]
102#[cfg_attr(feature = "defmt", derive(defmt::Format))]
103pub enum MaybeForwardedMessage {
104    ForwardedMessage(ForwardedMessage),
105    Message(Message),
106}
107
108impl From<ForwardedMessage> for MaybeForwardedMessage {
109    fn from(msg: ForwardedMessage) -> Self {
110        Self::ForwardedMessage(msg)
111    }
112}
113
114impl<M: Into<Message>> From<M> for MaybeForwardedMessage {
115    fn from(msg: M) -> Self {
116        Self::Message(msg.into())
117    }
118}
119
120impl TryWrite for MaybeForwardedMessage {
121    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
122        let offset = &mut 0;
123        match self {
124            MaybeForwardedMessage::ForwardedMessage(msg) => bytes.write(offset, msg),
125            MaybeForwardedMessage::Message(msg) => bytes.write(offset, msg),
126        }?;
127        Ok(*offset)
128    }
129}
130
131impl TryRead<'_> for MaybeForwardedMessage {
132    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
133        let offset = &mut 0;
134        check_len(bytes, 2)?;
135        let msg_type: u8 = bytes.read(&mut 1usize)?;
136        if msg_type == 0xfe {
137            let fw_msg: ForwardedMessage = bytes.read(offset)?;
138            Ok((fw_msg.into(), *offset))
139        } else {
140            let msg: Message = bytes.read(offset)?;
141            Ok((msg.into(), *offset))
142        }
143    }
144}
145
146#[derive(Clone, Debug, PartialEq)]
147#[cfg_attr(feature = "defmt", derive(defmt::Format))]
148pub struct ForwardedMessage {
149    pub ctrl: u8,
150    pub wireless_node_id: WirelessNodeId,
151    pub message: Message,
152}
153
154impl TryWrite for ForwardedMessage {
155    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
156        let offset = &mut 0;
157        bytes.write(offset, 3 + self.wireless_node_id.len() as u8)?; // len
158        bytes.write(offset, 0xFEu8)?; // msg type
159        bytes.write(offset, self.ctrl)?;
160        bytes.write(offset, self.wireless_node_id.as_str())?;
161        bytes.write(offset, self.message)?;
162        Ok(*offset)
163    }
164}
165
166impl TryRead<'_> for ForwardedMessage {
167    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
168        let offset = &mut 0;
169        let len: u8 = bytes.read(offset)?;
170        bytes.read::<u8>(offset)?; // msg type
171        Ok((
172            ForwardedMessage {
173                ctrl: bytes.read(offset)?,
174                wireless_node_id: bytes.read_with(offset, len as usize - 3)?,
175                message: bytes.read(offset)?,
176            },
177            *offset,
178        ))
179    }
180}
181
182#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
183#[cfg_attr(feature = "defmt", derive(defmt::Format))]
184pub struct WirelessNodeId(heapless::String<16>);
185
186impl WirelessNodeId {
187    pub fn new() -> Self {
188        Self(String::new())
189    }
190}
191
192impl From<&str> for WirelessNodeId {
193    fn from(s: &str) -> Self {
194        Self(String::from(s))
195    }
196}
197
198impl Deref for WirelessNodeId {
199    type Target = heapless::String<16>;
200
201    fn deref(&self) -> &Self::Target {
202        &self.0
203    }
204}
205
206impl DerefMut for WirelessNodeId {
207    fn deref_mut(&mut self) -> &mut Self::Target {
208        &mut self.0
209    }
210}
211
212impl TryWrite for WirelessNodeId {
213    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
214        let offset = &mut 0;
215        bytes.write(offset, self.as_str())?;
216        Ok(*offset)
217    }
218}
219
220impl TryRead<'_, usize> for WirelessNodeId {
221    fn try_read(bytes: &[u8], len: usize) -> byte::Result<(Self, usize)> {
222        let offset = &mut 0;
223        let mut s = String::new();
224        s.push_str(bytes.read_with(offset, byte::ctx::Str::Len(len))?)
225            .map_err(|_e| byte::Error::BadInput {
226                err: "wireless_node_id longer than 16 bytes",
227            })?;
228        Ok((WirelessNodeId(s), *offset))
229    }
230}
231
232#[derive(Clone, Debug, PartialEq)]
233#[cfg_attr(feature = "defmt", derive(defmt::Format))]
234pub enum Message {
235    SearchGw(SearchGw),
236    GwInfo(GwInfo),
237    Connect(Connect),
238    ConnAck(ConnAck),
239    Register(Register),
240    RegAck(RegAck),
241    Publish(Publish),
242    PubAck(PubAck),
243    Subscribe(Subscribe),
244    SubAck(SubAck),
245    Unsubscribe(Unsubscribe),
246    UnsubAck(UnsubAck),
247    PingReq(PingReq),
248    PingResp(PingResp),
249}
250
251impl From<SearchGw> for Message {
252    fn from(msg: SearchGw) -> Self {
253        Message::SearchGw(msg)
254    }
255}
256
257impl From<GwInfo> for Message {
258    fn from(msg: GwInfo) -> Self {
259        Message::GwInfo(msg)
260    }
261}
262
263impl From<Connect> for Message {
264    fn from(msg: Connect) -> Self {
265        Message::Connect(msg)
266    }
267}
268
269impl From<ConnAck> for Message {
270    fn from(msg: ConnAck) -> Self {
271        Message::ConnAck(msg)
272    }
273}
274
275impl From<Register> for Message {
276    fn from(msg: Register) -> Self {
277        Message::Register(msg)
278    }
279}
280
281impl From<RegAck> for Message {
282    fn from(msg: RegAck) -> Self {
283        Message::RegAck(msg)
284    }
285}
286
287impl From<Publish> for Message {
288    fn from(msg: Publish) -> Self {
289        Message::Publish(msg)
290    }
291}
292
293impl From<PubAck> for Message {
294    fn from(msg: PubAck) -> Self {
295        Message::PubAck(msg)
296    }
297}
298
299impl From<Subscribe> for Message {
300    fn from(msg: Subscribe) -> Self {
301        Message::Subscribe(msg)
302    }
303}
304
305impl From<SubAck> for Message {
306    fn from(msg: SubAck) -> Self {
307        Message::SubAck(msg)
308    }
309}
310
311impl From<Unsubscribe> for Message {
312    fn from(msg: Unsubscribe) -> Self {
313        Message::Unsubscribe(msg)
314    }
315}
316
317impl From<UnsubAck> for Message {
318    fn from(msg: UnsubAck) -> Self {
319        Message::UnsubAck(msg)
320    }
321}
322
323impl From<PingReq> for Message {
324    fn from(msg: PingReq) -> Self {
325        Message::PingReq(msg)
326    }
327}
328
329impl From<PingResp> for Message {
330    fn from(msg: PingResp) -> Self {
331        Message::PingResp(msg)
332    }
333}
334
335impl TryWrite for Message {
336    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
337        let offset = &mut 0;
338        match self {
339            Message::SearchGw(msg) => bytes.write(offset, msg),
340            Message::GwInfo(msg) => bytes.write(offset, msg),
341            Message::Connect(msg) => bytes.write(offset, msg),
342            Message::ConnAck(msg) => bytes.write(offset, msg),
343            Message::Register(msg) => bytes.write(offset, msg),
344            Message::RegAck(msg) => bytes.write(offset, msg),
345            Message::Publish(msg) => bytes.write(offset, msg),
346            Message::PubAck(msg) => bytes.write(offset, msg),
347            Message::Subscribe(msg) => bytes.write(offset, msg),
348            Message::SubAck(msg) => bytes.write(offset, msg),
349            Message::Unsubscribe(msg) => bytes.write(offset, msg),
350            Message::UnsubAck(msg) => bytes.write(offset, msg),
351            Message::PingReq(msg) => bytes.write(offset, msg),
352            Message::PingResp(msg) => bytes.write(offset, msg),
353        }?;
354        Ok(*offset)
355    }
356}
357
358impl TryRead<'_> for Message {
359    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
360        let offset = &mut 0;
361        // Not increasing offset because some messages needs access to len.
362        Ok((
363            match bytes.read::<u8>(&mut (*offset + 1))? {
364                0x01 => Message::SearchGw(bytes.read(offset)?),
365                0x02 => Message::GwInfo(bytes.read(offset)?),
366                0x04 => Message::Connect(bytes.read(offset)?),
367                0x05 => Message::ConnAck(bytes.read(offset)?),
368                0x0a => Message::Register(bytes.read(offset)?),
369                0x0b => Message::RegAck(bytes.read(offset)?),
370                0x0c => Message::Publish(bytes.read(offset)?),
371                0x0d => Message::PubAck(bytes.read(offset)?),
372                Subscribe::MSG_TYPE => Message::Subscribe(bytes.read(offset)?),
373                SubAck::MSG_TYPE => Message::SubAck(bytes.read(offset)?),
374                Unsubscribe::MSG_TYPE => Message::Unsubscribe(bytes.read(offset)?),
375                UnsubAck::MSG_TYPE => Message::UnsubAck(bytes.read(offset)?),
376                0x16 => Message::PingReq(bytes.read(offset)?),
377                0x17 => Message::PingResp(bytes.read(offset)?),
378                _t => {
379                    return Err(byte::Error::BadInput {
380                        err: "Recieved a message with unknown type",
381                    })
382                }
383            },
384            *offset,
385        ))
386    }
387}
388
389#[derive(Clone, Copy, Debug, PartialEq)]
390#[cfg_attr(feature = "defmt", derive(defmt::Format))]
391pub struct SearchGw {
392    pub radius: u8,
393}
394
395impl TryWrite for SearchGw {
396    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
397        let offset = &mut 0;
398        bytes.write(offset, 3u8)?; // len
399        bytes.write(offset, 0x01u8)?; // msg type
400        bytes.write(offset, self.radius)?;
401        Ok(*offset)
402    }
403}
404
405impl TryRead<'_> for SearchGw {
406    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
407        let offset = &mut 0;
408        let len: u8 = bytes.read(offset)?;
409        check_len(bytes, len as usize)?;
410        *offset += 1; // msg type
411        Ok((
412            SearchGw {
413                radius: bytes.read(offset)?,
414            },
415            *offset,
416        ))
417    }
418}
419
420#[derive(Clone, Copy, Debug, PartialEq)]
421#[cfg_attr(feature = "defmt", derive(defmt::Format))]
422pub struct GwInfo {
423    pub gw_id: u8,
424}
425
426impl TryWrite for GwInfo {
427    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
428        let offset = &mut 0;
429        bytes.write(offset, 3u8)?; // len
430        bytes.write(offset, 0x02u8)?; // msg type
431        bytes.write(offset, self.gw_id)?;
432        Ok(*offset)
433    }
434}
435
436impl TryRead<'_> for GwInfo {
437    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
438        let offset = &mut 0;
439        let len: u8 = bytes.read(offset)?;
440        check_len(bytes, len as usize)?;
441        *offset += 1; // msg type
442        Ok((
443            GwInfo {
444                gw_id: bytes.read(offset)?,
445            },
446            *offset,
447        ))
448    }
449}
450
451#[derive(Clone, Debug, PartialEq)]
452#[cfg_attr(feature = "defmt", derive(defmt::Format))]
453pub struct Connect {
454    pub flags: Flags,
455    pub duration: u16,
456    pub client_id: ClientId,
457}
458
459impl TryWrite for Connect {
460    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
461        let offset = &mut 0;
462        let len = 6 + self.client_id.len() as u8;
463        bytes.write(offset, len)?;
464        bytes.write(offset, 0x04u8)?; // msg type
465        bytes.write(offset, self.flags)?;
466        bytes.write(offset, 0x01u8)?; // protocol id
467        bytes.write_with(offset, self.duration, byte::ctx::BE)?;
468        bytes.write(offset, self.client_id.as_str())?;
469        Ok(*offset)
470    }
471}
472
473impl TryRead<'_> for Connect {
474    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
475        let offset = &mut 0;
476        let len: u8 = bytes.read(offset)?;
477        check_len(bytes, len as usize)?;
478        if len < 6 {
479            return Err(byte::Error::BadInput {
480                err: "Connect len must be >= 6 bytes",
481            });
482        }
483        *offset += 1; // msg type
484        let flags = bytes.read(offset)?;
485        bytes.read::<u8>(offset)?; // protocol id
486        Ok((
487            Connect {
488                flags,
489                duration: bytes.read_with(offset, byte::ctx::BE)?,
490                client_id: bytes.read_with(offset, len as usize - 6)?,
491            },
492            *offset,
493        ))
494    }
495}
496
497#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
498#[cfg_attr(feature = "defmt", derive(defmt::Format))]
499pub struct ClientId(heapless::String<64>);
500
501impl ClientId {
502    pub fn new() -> Self {
503        Self(String::new())
504    }
505}
506
507impl From<&str> for ClientId {
508    fn from(s: &str) -> Self {
509        Self(String::from(s))
510    }
511}
512
513impl Deref for ClientId {
514    type Target = heapless::String<64>;
515
516    fn deref(&self) -> &Self::Target {
517        &self.0
518    }
519}
520
521impl DerefMut for ClientId {
522    fn deref_mut(&mut self) -> &mut Self::Target {
523        &mut self.0
524    }
525}
526
527impl TryWrite for ClientId {
528    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
529        let offset = &mut 0;
530        bytes.write(offset, self.as_str())?;
531        Ok(*offset)
532    }
533}
534
535impl TryRead<'_, usize> for ClientId {
536    fn try_read(bytes: &[u8], len: usize) -> byte::Result<(Self, usize)> {
537        let offset = &mut 0;
538        let mut s = String::new();
539        s.push_str(bytes.read_with(offset, byte::ctx::Str::Len(len))?)
540            .map_err(|_e| byte::Error::BadInput {
541                err: "client_id longer than 64 bytes",
542            })?;
543        Ok((ClientId(s), *offset))
544    }
545}
546
547#[derive(Clone, Copy, Debug, PartialEq)]
548#[cfg_attr(feature = "defmt", derive(defmt::Format))]
549pub struct ConnAck {
550    pub code: ReturnCode,
551}
552
553impl TryWrite for ConnAck {
554    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
555        let offset = &mut 0;
556        bytes.write(offset, 3u8)?; // len
557        bytes.write(offset, 0x05u8)?; // msg type
558        bytes.write(offset, self.code)?;
559        Ok(*offset)
560    }
561}
562
563impl TryRead<'_> for ConnAck {
564    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
565        let offset = &mut 0;
566        let len: u8 = bytes.read(offset)?;
567        check_len(bytes, len as usize)?;
568        *offset += 1; // msg type
569        Ok((
570            ConnAck {
571                code: bytes.read(offset)?,
572            },
573            *offset,
574        ))
575    }
576}
577
578#[derive(Clone, Debug, PartialEq)]
579#[cfg_attr(feature = "defmt", derive(defmt::Format))]
580pub struct Register {
581    pub topic_id: u16,
582    pub msg_id: u16,
583    pub topic_name: TopicName,
584}
585
586impl TryWrite for Register {
587    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
588        let offset = &mut 0;
589        let len = 6 + self.topic_name.len() as u8;
590        bytes.write(offset, len)?;
591        bytes.write(offset, 0x0Au8)?; // msg type
592        bytes.write_with(offset, self.topic_id, byte::ctx::BE)?;
593        bytes.write_with(offset, self.msg_id, byte::ctx::BE)?;
594        bytes.write(offset, self.topic_name.as_str())?;
595        Ok(*offset)
596    }
597}
598
599impl TryRead<'_> for Register {
600    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
601        let offset = &mut 0;
602        let len: u8 = bytes.read(offset)?;
603        check_len(bytes, len as usize)?;
604        if len < 6 {
605            return Err(byte::Error::BadInput {
606                err: "Register len must be >= 6 bytes",
607            });
608        }
609        *offset += 1; // msg type
610        Ok((
611            Register {
612                topic_id: bytes.read_with(offset, byte::ctx::BE)?,
613                msg_id: bytes.read_with(offset, byte::ctx::BE)?,
614                topic_name: bytes.read_with(offset, len as usize - 6)?,
615            },
616            *offset,
617        ))
618    }
619}
620
621#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
622#[cfg_attr(feature = "defmt", derive(defmt::Format))]
623pub struct TopicName(heapless::String<256>);
624
625impl TopicName {
626    pub fn from(s: &str) -> Self {
627        Self(String::from(s))
628    }
629    pub fn new() -> Self {
630        Self(String::new())
631    }
632}
633
634impl Deref for TopicName {
635    type Target = heapless::String<256>;
636
637    fn deref(&self) -> &Self::Target {
638        &self.0
639    }
640}
641
642impl From<&str> for TopicName {
643    fn from(s: &str) -> Self {
644        Self(String::from(s))
645    }
646}
647
648impl DerefMut for TopicName {
649    fn deref_mut(&mut self) -> &mut Self::Target {
650        &mut self.0
651    }
652}
653
654impl TryWrite for TopicName {
655    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
656        let offset = &mut 0;
657        bytes.write(offset, self.as_str())?;
658        Ok(*offset)
659    }
660}
661
662impl TryRead<'_, usize> for TopicName {
663    fn try_read(bytes: &[u8], len: usize) -> byte::Result<(Self, usize)> {
664        let offset = &mut 0;
665        let mut s = String::new();
666        s.push_str(bytes.read_with(offset, byte::ctx::Str::Len(len))?)
667            .map_err(|_e| byte::Error::BadInput {
668                err: "topic_name longer than 256 bytes",
669            })?;
670        Ok((TopicName(s), *offset))
671    }
672}
673
674#[derive(Clone, Copy, Debug, PartialEq)]
675#[cfg_attr(feature = "defmt", derive(defmt::Format))]
676pub struct RegAck {
677    pub topic_id: u16,
678    pub msg_id: u16,
679    pub code: ReturnCode,
680}
681
682impl TryWrite for RegAck {
683    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
684        let offset = &mut 0;
685        bytes.write(offset, 7u8)?; // len
686        bytes.write(offset, 0xBu8)?; // msg type
687        bytes.write_with(offset, self.topic_id, byte::ctx::BE)?;
688        bytes.write_with(offset, self.msg_id, byte::ctx::BE)?;
689        bytes.write(offset, self.code)?;
690        Ok(*offset)
691    }
692}
693
694impl TryRead<'_> for RegAck {
695    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
696        let offset = &mut 0;
697        let len: u8 = bytes.read(offset)?;
698        check_len(bytes, len as usize)?;
699        *offset += 1; // msg type
700        Ok((
701            RegAck {
702                topic_id: bytes.read_with(offset, byte::ctx::BE)?,
703                msg_id: bytes.read_with(offset, byte::ctx::BE)?,
704                code: bytes.read(offset)?,
705            },
706            *offset,
707        ))
708    }
709}
710
711#[derive(Clone, Debug, PartialEq)]
712#[cfg_attr(feature = "defmt", derive(defmt::Format))]
713pub struct Publish {
714    pub flags: Flags,
715    pub topic_id: u16,
716    pub msg_id: u16,
717    pub data: PublishData,
718}
719
720impl TryWrite for Publish {
721    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
722        let offset = &mut 0;
723        let len = 7 + self.data.len() as u8;
724        bytes.write(offset, len)?;
725        bytes.write(offset, 0x0Cu8)?; // msg type
726        bytes.write(offset, self.flags)?;
727        bytes.write_with(offset, self.topic_id, byte::ctx::BE)?;
728        bytes.write_with(offset, self.msg_id, byte::ctx::BE)?;
729        bytes.write(offset, self.data.as_str())?;
730        Ok(*offset)
731    }
732}
733
734impl TryRead<'_> for Publish {
735    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
736        let offset = &mut 0;
737        let len: u8 = bytes.read(offset)?;
738        check_len(bytes, len as usize)?;
739        if len < 7 {
740            return Err(byte::Error::BadInput {
741                err: "Publish len must be >= 6 bytes",
742            });
743        }
744        *offset += 1; // msg type
745        Ok((
746            Publish {
747                flags: bytes.read(offset)?,
748                topic_id: bytes.read_with(offset, byte::ctx::BE)?,
749                msg_id: bytes.read_with(offset, byte::ctx::BE)?,
750                data: bytes.read_with(offset, len as usize - 7)?,
751            },
752            *offset,
753        ))
754    }
755}
756
757#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
758#[cfg_attr(feature = "defmt", derive(defmt::Format))]
759pub struct PublishData(heapless::String<256>);
760
761impl PublishData {
762    pub fn new() -> Self {
763        Self(String::new())
764    }
765}
766
767impl From<&str> for PublishData {
768    fn from(s: &str) -> Self {
769        Self(String::from(s))
770    }
771}
772
773impl Deref for PublishData {
774    type Target = heapless::String<256>;
775
776    fn deref(&self) -> &Self::Target {
777        &self.0
778    }
779}
780
781impl DerefMut for PublishData {
782    fn deref_mut(&mut self) -> &mut Self::Target {
783        &mut self.0
784    }
785}
786
787impl TryWrite for PublishData {
788    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
789        let offset = &mut 0;
790        bytes.write(offset, self.as_str())?;
791        Ok(*offset)
792    }
793}
794
795impl TryRead<'_, usize> for PublishData {
796    fn try_read(bytes: &[u8], len: usize) -> byte::Result<(Self, usize)> {
797        let offset = &mut 0;
798        let mut s = String::new();
799        s.push_str(bytes.read_with(offset, byte::ctx::Str::Len(len))?)
800            .map_err(|_e| byte::Error::BadInput {
801                err: "data longer than 256 bytes",
802            })?;
803        Ok((PublishData(s), *offset))
804    }
805}
806
807#[derive(Clone, Debug, PartialEq)]
808#[cfg_attr(feature = "defmt", derive(defmt::Format))]
809pub struct PubAck {
810    pub topic_id: u16,
811    pub msg_id: u16,
812    pub code: ReturnCode,
813}
814
815impl TryWrite for PubAck {
816    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
817        let offset = &mut 0;
818        bytes.write(offset, 7u8)?; // len
819        bytes.write(offset, 0x0Du8)?; // msg type
820        bytes.write_with(offset, self.topic_id, byte::ctx::BE)?;
821        bytes.write_with(offset, self.msg_id, byte::ctx::BE)?;
822        bytes.write(offset, self.code)?;
823        Ok(*offset)
824    }
825}
826
827impl TryRead<'_> for PubAck {
828    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
829        let offset = &mut 0;
830        let _len: u8 = bytes.read(offset)?;
831        *offset += 1; // msg type
832        Ok((
833            PubAck {
834                topic_id: bytes.read_with(offset, byte::ctx::BE)?,
835                msg_id: bytes.read_with(offset, byte::ctx::BE)?,
836                code: bytes.read(offset)?,
837            },
838            *offset,
839        ))
840    }
841}
842
843#[derive(Clone, Debug, PartialEq)]
844#[cfg_attr(feature = "defmt", derive(defmt::Format))]
845pub enum TopicNameOrId {
846    Name(TopicName),
847    Id(u16),
848}
849
850impl TryWrite for TopicNameOrId {
851    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
852        let offset = &mut 0;
853        match self {
854            Self::Id(id) => bytes.write_with(offset, id, byte::ctx::BE)?,
855            Self::Name(name) => bytes.write(offset, name)?,
856        }
857        Ok(*offset)
858    }
859}
860
861impl TryRead<'_, (Flags, usize)> for TopicNameOrId {
862    fn try_read(bytes: &[u8], ctx: (Flags, usize)) -> byte::Result<(Self, usize)> {
863        let offset = &mut 0;
864        Ok((
865            if ctx.0.topic_id_type() == 0 {
866                Self::Name(bytes.read_with(offset, ctx.1)?)
867            } else {
868                Self::Id(bytes.read_with(offset, byte::ctx::BE)?)
869            },
870            *offset,
871        ))
872    }
873}
874
875#[derive(Clone, Debug, PartialEq)]
876#[cfg_attr(feature = "defmt", derive(defmt::Format))]
877pub struct Subscribe {
878    pub flags: Flags,
879    pub msg_id: u16,
880    pub topic: TopicNameOrId,
881}
882
883impl MsgType for Subscribe {
884    const MSG_TYPE: u8 = 0x12; 
885}
886
887impl TryWrite for Subscribe {
888    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
889        let offset = &mut 1; // len is written last
890        bytes.write(offset, Self::MSG_TYPE)?;
891        bytes.write(offset, self.flags)?;
892        bytes.write_with(offset, self.msg_id, byte::ctx::BE)?;
893        bytes.write(offset, self.topic)?;
894        bytes.write(&mut 0, *offset as u8)?; // len
895        Ok(*offset)
896    }
897}
898
899impl TryRead<'_> for Subscribe {
900    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
901        let offset = &mut 0;
902        let len: u8 = bytes.read(offset)?;
903        *offset += 1; // msg type
904        let flags = bytes.read(offset)?;
905        Ok((
906            Self {
907                flags,
908                msg_id: bytes.read_with(offset, byte::ctx::BE)?,
909                topic: bytes.read_with(offset, (flags, len as usize - 5))?,
910            },
911            *offset,
912        ))
913    }
914}
915
916#[derive(Clone, Debug, PartialEq)]
917#[cfg_attr(feature = "defmt", derive(defmt::Format))]
918pub struct SubAck {
919    pub flags: Flags,
920    pub msg_id: u16,
921    pub topic_id: u16,
922    pub code: ReturnCode,
923}
924
925impl MsgType for SubAck {
926    const MSG_TYPE: u8 = 0x13; 
927}
928
929impl TryWrite for SubAck {
930    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
931        let offset = &mut 0;
932        bytes.write(offset, 7u8)?; // len
933        bytes.write(offset, Self::MSG_TYPE)?;
934        bytes.write(offset, self.flags)?;
935        bytes.write_with(offset, self.topic_id, byte::ctx::BE)?;
936        bytes.write_with(offset, self.msg_id, byte::ctx::BE)?;
937        bytes.write(offset, self.code)?;
938        Ok(*offset)
939    }
940}
941
942impl TryRead<'_> for SubAck {
943    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
944        let offset = &mut 0;
945        let _len: u8 = bytes.read(offset)?;
946        *offset += 1; // msg type
947        Ok((
948            Self {
949                flags: bytes.read(offset)?,
950                topic_id: bytes.read_with(offset, byte::ctx::BE)?,
951                msg_id: bytes.read_with(offset, byte::ctx::BE)?,
952                code: bytes.read(offset)?,
953            },
954            *offset,
955        ))
956    }
957}
958
959#[derive(Clone, Debug, PartialEq)]
960#[cfg_attr(feature = "defmt", derive(defmt::Format))]
961pub struct Unsubscribe {
962    pub flags: Flags,
963    pub msg_id: u16,
964    pub topic: TopicNameOrId,
965}
966
967impl MsgType for Unsubscribe {
968    const MSG_TYPE: u8 = 0x14; 
969}
970
971impl TryWrite for Unsubscribe {
972    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
973        let offset = &mut 1; // len is written last
974        bytes.write(offset, Self::MSG_TYPE)?;
975        bytes.write(offset, self.flags)?;
976        bytes.write_with(offset, self.msg_id, byte::ctx::BE)?;
977        bytes.write(offset, self.topic)?;
978        bytes.write(&mut 0, *offset as u8)?; // len
979        Ok(*offset)
980    }
981}
982
983impl TryRead<'_> for Unsubscribe {
984    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
985        let offset = &mut 0;
986        let len: u8 = bytes.read(offset)?;
987        *offset += 1; // msg type
988        let flags = bytes.read(offset)?;
989        Ok((
990            Self {
991                flags,
992                msg_id: bytes.read_with(offset, byte::ctx::BE)?,
993                topic: bytes.read_with(offset, (flags, len as usize - 5))?,
994            },
995            *offset,
996        ))
997    }
998}
999
1000#[derive(Clone, Debug, PartialEq)]
1001#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1002pub struct UnsubAck {
1003    pub msg_id: u16,
1004    pub code: ReturnCode,
1005}
1006
1007impl MsgType for UnsubAck {
1008    const MSG_TYPE: u8 = 0x15; 
1009}
1010
1011impl TryWrite for UnsubAck {
1012    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
1013        let offset = &mut 0;
1014        bytes.write(offset, 5u8)?; // len
1015        bytes.write(offset, Self::MSG_TYPE)?;
1016        bytes.write_with(offset, self.msg_id, byte::ctx::BE)?;
1017        bytes.write(offset, self.code)?;
1018        Ok(*offset)
1019    }
1020}
1021
1022impl TryRead<'_> for UnsubAck {
1023    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
1024        let offset = &mut 0;
1025        let _len: u8 = bytes.read(offset)?;
1026        *offset += 1; // msg type
1027        Ok((
1028            Self {
1029                msg_id: bytes.read_with(offset, byte::ctx::BE)?,
1030                code: bytes.read(offset)?,
1031            },
1032            *offset,
1033        ))
1034    }
1035}
1036
1037#[derive(Clone, Debug, PartialEq)]
1038#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1039pub struct PingReq {
1040    pub client_id: ClientId,
1041}
1042
1043impl TryWrite for PingReq {
1044    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
1045        let offset = &mut 0;
1046        let len = 2 + self.client_id.len() as u8;
1047        bytes.write(offset, len)?;
1048        bytes.write(offset, 0x16u8)?; // msg type
1049        bytes.write(offset, self.client_id.as_str())?;
1050        Ok(*offset)
1051    }
1052}
1053
1054impl TryRead<'_> for PingReq {
1055    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
1056        let offset = &mut 0;
1057        let len: u8 = bytes.read(offset)?;
1058        check_len(bytes, len as usize)?;
1059        if len < 2 {
1060            return Err(byte::Error::BadInput {
1061                err: "Len must be at least 2 bytes",
1062            });
1063        }
1064        *offset += 1; // msg type
1065        Ok((
1066            PingReq {
1067                client_id: bytes.read_with(offset, len as usize - 2)?,
1068            },
1069            *offset,
1070        ))
1071    }
1072}
1073
1074#[derive(Clone, Copy, Debug, PartialEq)]
1075#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1076pub struct PingResp {}
1077
1078impl TryWrite for PingResp {
1079    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
1080        let offset = &mut 0;
1081        bytes.write(offset, 2u8)?; // len
1082        bytes.write(offset, 0x17u8)?; // msg type
1083        Ok(*offset)
1084    }
1085}
1086
1087impl TryRead<'_> for PingResp {
1088    fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
1089        let offset = &mut 0;
1090        let len: u8 = bytes.read(offset)?;
1091        check_len(bytes, len as usize)?;
1092        *offset += 1; // msg type
1093        Ok((PingResp {}, *offset))
1094    }
1095}
1096
1097#[cfg(test)]
1098mod tests {
1099    use assert_hex::*;
1100
1101    use super::*;
1102
1103    #[test]
1104    fn forwarded_message_encode_parse() {
1105        let mut bytes = [0u8; 20];
1106        let mut len = 0usize;
1107        let expected = ForwardedMessage {
1108            ctrl: 0,
1109            wireless_node_id: WirelessNodeId::from("test-node"),
1110            message: Message::PingResp(PingResp {}),
1111        };
1112        bytes.write(&mut len, expected.clone()).unwrap();
1113        assert_eq_hex!(
1114            &bytes[..len],
1115            &[12u8, 0xfe, 0x00, b't', b'e', b's', b't', b'-', b'n', b'o', b'd', b'e', 2, 0x17]
1116        );
1117        let actual: ForwardedMessage = bytes.read(&mut 0).unwrap();
1118        assert_eq_hex!(actual, expected);
1119    }
1120
1121    #[test]
1122    fn return_code_encode() {
1123        let mut buf = [0u8; 5];
1124        let mut offset = 0usize;
1125        buf.write(&mut offset, ReturnCode::Accepted).unwrap();
1126        buf.write(
1127            &mut offset,
1128            ReturnCode::Rejected(RejectedReason::Congestion),
1129        )
1130        .unwrap();
1131        buf.write(
1132            &mut offset,
1133            ReturnCode::Rejected(RejectedReason::InvalidTopicId),
1134        )
1135        .unwrap();
1136        buf.write(
1137            &mut offset,
1138            ReturnCode::Rejected(RejectedReason::NotSupported),
1139        )
1140        .unwrap();
1141        buf.write(
1142            &mut offset,
1143            ReturnCode::Rejected(RejectedReason::Reserved(0x12)),
1144        )
1145        .unwrap();
1146        assert_eq_hex!(&buf, &[0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x12u8]);
1147    }
1148
1149    #[test]
1150    fn return_code_parse() {
1151        let buf = &[0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x12u8];
1152        let mut actual = [ReturnCode::Accepted; 5];
1153        let mut offset = 0usize;
1154        for i in 0..5 {
1155            actual[i] = buf.read(&mut offset).unwrap();
1156        }
1157        assert_eq!(
1158            &actual,
1159            &[
1160                ReturnCode::Accepted,
1161                ReturnCode::Rejected(RejectedReason::Congestion),
1162                ReturnCode::Rejected(RejectedReason::InvalidTopicId),
1163                ReturnCode::Rejected(RejectedReason::NotSupported),
1164                ReturnCode::Rejected(RejectedReason::Reserved(0x12)),
1165            ]
1166        );
1167    }
1168
1169    #[test]
1170    fn searchgw_encode_parse() {
1171        let bytes = &mut [0u8; 10];
1172        let mut len = 0usize;
1173        let expected = Message::SearchGw(SearchGw { radius: 5 });
1174        bytes.write(&mut len, expected.clone()).unwrap();
1175        assert_eq_hex!(&bytes[..len], [0x03u8, 0x01, 0x05]);
1176        let actual: Message = bytes.read(&mut 0).unwrap();
1177        assert_eq!(actual, expected);
1178    }
1179
1180    #[test]
1181    fn gwinfo_encode_parse() {
1182        let mut bytes = [0u8; 20];
1183        let mut len = 0usize;
1184        let expected = Message::GwInfo(GwInfo { gw_id: 0x12 });
1185        bytes.write(&mut len, expected.clone()).unwrap();
1186        assert_eq_hex!(&bytes[..len], [0x03u8, 0x02, 0x12]);
1187        let actual: Message = bytes.read(&mut 0).unwrap();
1188        assert_eq!(actual, expected);
1189    }
1190
1191    #[test]
1192    fn connect_encode_parse() {
1193        let mut bytes = [0u8; 20];
1194        let mut len = 0usize;
1195        let expected = Message::Connect(Connect {
1196            flags: Flags(0x12),
1197            duration: 0x3456,
1198            client_id: ClientId::from("test-client"),
1199        });
1200        bytes.write(&mut len, expected.clone()).unwrap();
1201        assert_eq_hex!(
1202            &bytes[..len],
1203            [
1204                0x11u8, 0x04, 0x12, 0x01, 0x34, 0x56, b't', b'e', b's', b't', b'-', b'c', b'l',
1205                b'i', b'e', b'n', b't'
1206            ]
1207        );
1208        let actual: Message = bytes.read(&mut 0).unwrap();
1209        assert_eq!(actual, expected);
1210    }
1211
1212    #[test]
1213    fn register_encode_parse() {
1214        let mut bytes = [0u8; 20];
1215        let mut len = 0usize;
1216        let expected = Message::Register(Register {
1217            topic_id: 0x1234,
1218            msg_id: 0x5678,
1219            topic_name: TopicName::from("test"),
1220        });
1221        bytes.write(&mut len, expected.clone()).unwrap();
1222        assert_eq_hex!(
1223            &bytes[..len],
1224            [0x0au8, 0x0a, 0x12, 0x34, 0x56, 0x78, b't', b'e', b's', b't']
1225        );
1226        let actual: Message = bytes.read(&mut 0).unwrap();
1227        assert_eq!(actual, expected);
1228    }
1229
1230    #[test]
1231    fn regack_encode_parse() {
1232        let mut bytes = [0u8; 20];
1233        let mut len = 0usize;
1234        let expected = Message::RegAck(RegAck {
1235            topic_id: 0x1234,
1236            msg_id: 0x5678,
1237            code: ReturnCode::Rejected(RejectedReason::Congestion),
1238        });
1239        bytes.write(&mut len, expected.clone()).unwrap();
1240        assert_eq_hex!(&bytes[..len], [0x07u8, 0x0b, 0x12, 0x34, 0x56, 0x78, 0x1]);
1241        let actual: Message = bytes.read(&mut 0).unwrap();
1242        assert_eq!(actual, expected);
1243    }
1244
1245    #[test]
1246    fn publish_encode_parse() {
1247        let mut bytes = [0u8; 20];
1248        let mut len = 0usize;
1249        let expected = Message::Publish(Publish {
1250            flags: Flags(0x12),
1251            topic_id: 0x1234,
1252            msg_id: 0x5678,
1253            data: PublishData::from("test"),
1254        });
1255        bytes.write(&mut len, expected.clone()).unwrap();
1256        assert_eq_hex!(
1257            &bytes[..len],
1258            [0x0bu8, 0x0c, 0x12, 0x12, 0x34, 0x56, 0x78, b't', b'e', b's', b't']
1259        );
1260        let actual: Message = bytes.read(&mut 0).unwrap();
1261        assert_eq!(actual, expected);
1262    }
1263
1264    #[test]
1265    fn puback_encode_parse() {
1266        let mut bytes = [0u8; 20];
1267        let mut len = 0usize;
1268        let expected = Message::PubAck(PubAck {
1269            topic_id: 0x1234,
1270            msg_id: 0x5678,
1271            code: RejectedReason::InvalidTopicId.into(),
1272        });
1273        bytes.write(&mut len, expected.clone()).unwrap();
1274        assert_eq_hex!(&bytes[..len], [0x07u8, 0x0d, 0x12, 0x34, 0x56, 0x78, 0x02]);
1275        let actual: Message = bytes.read(&mut 0).unwrap();
1276        assert_eq!(actual, expected);
1277    }
1278
1279    #[test]
1280    fn subscribe_encode_parse_id() {
1281        let mut bytes = [0u8; 20];
1282        let mut len = 0usize;
1283        let mut flags = Flags::default();
1284        flags.set_topic_id_type(0x2); // topic_id
1285        let expected = Message::Subscribe(Subscribe {
1286            flags,
1287            msg_id: 0x1234,
1288            topic: TopicNameOrId::Id(0x5678),
1289        });
1290        bytes.write(&mut len, expected.clone()).unwrap();
1291        assert_eq_hex!(&bytes[..len], [0x07u8, 0x12, 0x02, 0x12, 0x34, 0x56, 0x78]);
1292        let actual: Message = bytes.read(&mut 0).unwrap();
1293        assert_eq!(actual, expected);
1294    }
1295
1296    #[test]
1297    fn subscribe_encode_parse_name() {
1298        let mut bytes = [0u8; 20];
1299        let mut len = 0usize;
1300        let expected = Message::Subscribe(Subscribe {
1301            flags: Flags::default(),
1302            msg_id: 0x1234,
1303            topic: TopicNameOrId::Name("test".into()),
1304        });
1305        bytes.write(&mut len, expected.clone()).unwrap();
1306        assert_eq_hex!(&bytes[..len], [0x09u8, 0x12, 0x00, 0x12, 0x34, b't', b'e', b's', b't']);
1307        let actual: Message = bytes.read(&mut 0).unwrap();
1308        assert_eq!(actual, expected);
1309    }
1310
1311    #[test]
1312    fn suback_encode_parse() {
1313        let mut bytes = [0u8; 20];
1314        let mut len = 0usize;
1315        let expected = Message::SubAck(SubAck {
1316            flags: Flags::default(),
1317            topic_id: 0x1234,
1318            msg_id: 0x5678,
1319            code: RejectedReason::InvalidTopicId.into(),
1320        });
1321        bytes.write(&mut len, expected.clone()).unwrap();
1322        assert_eq_hex!(&bytes[..len], [0x07u8, 0x13, 0x00, 0x12, 0x34, 0x56, 0x78, 0x02]);
1323        let actual: Message = bytes.read(&mut 0).unwrap();
1324        assert_eq!(actual, expected);
1325    }
1326    #[test]
1327    fn unsubscribe_encode_parse_id() {
1328        let mut bytes = [0u8; 20];
1329        let mut len = 0usize;
1330        let mut flags = Flags::default();
1331        flags.set_topic_id_type(0x2); // topic_id
1332        let expected = Message::Unsubscribe(Unsubscribe {
1333            flags,
1334            msg_id: 0x1234,
1335            topic: TopicNameOrId::Id(0x5678),
1336        });
1337        bytes.write(&mut len, expected.clone()).unwrap();
1338        assert_eq_hex!(&bytes[..len], [0x07u8, 0x14, 0x02, 0x12, 0x34, 0x56, 0x78]);
1339        let actual: Message = bytes.read(&mut 0).unwrap();
1340        assert_eq!(actual, expected);
1341    }
1342
1343    #[test]
1344    fn unsubscribe_encode_parse_name() {
1345        let mut bytes = [0u8; 20];
1346        let mut len = 0usize;
1347        let expected = Message::Unsubscribe(Unsubscribe {
1348            flags: Flags::default(),
1349            msg_id: 0x1234,
1350            topic: TopicNameOrId::Name("test".into()),
1351        });
1352        bytes.write(&mut len, expected.clone()).unwrap();
1353        assert_eq_hex!(&bytes[..len], [0x09u8, 0x14, 0x00, 0x12, 0x34, b't', b'e', b's', b't']);
1354        let actual: Message = bytes.read(&mut 0).unwrap();
1355        assert_eq!(actual, expected);
1356    }
1357
1358    #[test]
1359    fn unsuback_encode_parse() {
1360        let mut bytes = [0u8; 20];
1361        let mut len = 0usize;
1362        let expected = Message::UnsubAck(UnsubAck {
1363            msg_id: 0x1234,
1364            code: RejectedReason::InvalidTopicId.into(),
1365        });
1366        bytes.write(&mut len, expected.clone()).unwrap();
1367        assert_eq_hex!(&bytes[..len], [0x05u8, 0x15, 0x12, 0x34, 0x02]);
1368        let actual: Message = bytes.read(&mut 0).unwrap();
1369        assert_eq!(actual, expected);
1370    }
1371
1372    #[test]
1373    fn pingreq_encode_parse() {
1374        let mut bytes = [0u8; 20];
1375        let mut len = 0usize;
1376        let expected = Message::PingReq(PingReq {
1377            client_id: ClientId::from("test-client"),
1378        });
1379        bytes.write(&mut len, expected.clone()).unwrap();
1380        assert_eq_hex!(
1381            &bytes[..len],
1382            [0xdu8, 0x16, b't', b'e', b's', b't', b'-', b'c', b'l', b'i', b'e', b'n', b't']
1383        );
1384        let actual: Message = bytes.read(&mut 0).unwrap();
1385        assert_eq!(actual, expected);
1386    }
1387
1388    #[test]
1389    fn pingresp_encode_parse() {
1390        let mut bytes = [0u8; 20];
1391        let _len = 0usize;
1392        let expected = Message::PingResp(PingResp {});
1393        let mut len = 0usize;
1394        bytes.write(&mut len, expected.clone()).unwrap();
1395        assert_eq_hex!(&bytes[..len], &[0x02u8, 0x17]);
1396        let actual: Message = bytes.read(&mut 0).unwrap();
1397        assert_eq!(actual, expected);
1398    }
1399}