1use super::{
24 ADVERTISE, CONNACK, CONNECT, DISCONNECT, GWINFO, PINGREQ, PINGRESP, PUBACK, PUBCOMP, PUBLISH,
25 PUBREC, PUBREL, RC_ACCEPTED, REGACK, REGISTER, SEARCHGW, SUBACK, SUBSCRIBE, TID_PREDEF,
26 TID_SHORT, UNSUBACK, UNSUBSCRIBE, WILLMSG, WILLMSGREQ, WILLMSGRESP, WILLMSGUPD, WILLTOPIC,
27 WILLTOPICREQ, WILLTOPICRESP, WILLTOPICUPD,
28};
29
30#[derive(Debug, Clone)]
35pub struct MqttSnBuilder {
36 msg_type: u8,
38
39 dup: bool,
41 qos: u8,
42 retain: bool,
43 will: bool,
44 cleansess: bool,
45 tid_type: u8,
46
47 gw_id: u8,
49 duration: u16,
50 radius: u8,
51 gw_addr: Vec<u8>,
52 prot_id: u8,
53 client_id: Vec<u8>,
54 return_code: u8,
55 tid: u16,
56 mid: u16,
57 data: Vec<u8>,
58 topic_name: Vec<u8>,
59 will_topic: Vec<u8>,
60 will_msg: Vec<u8>,
61}
62
63impl Default for MqttSnBuilder {
64 fn default() -> Self {
65 Self {
66 msg_type: CONNECT,
67 dup: false,
68 qos: 0,
69 retain: false,
70 will: false,
71 cleansess: false,
72 tid_type: 0,
73 gw_id: 0,
74 duration: 0,
75 radius: 0,
76 gw_addr: Vec::new(),
77 prot_id: 0x01,
78 client_id: Vec::new(),
79 return_code: RC_ACCEPTED,
80 tid: 0,
81 mid: 0,
82 data: Vec::new(),
83 topic_name: Vec::new(),
84 will_topic: Vec::new(),
85 will_msg: Vec::new(),
86 }
87 }
88}
89
90impl MqttSnBuilder {
91 #[must_use]
93 pub fn new() -> Self {
94 Self::default()
95 }
96
97 #[must_use]
103 pub fn advertise() -> Self {
104 Self {
105 msg_type: ADVERTISE,
106 ..Default::default()
107 }
108 }
109
110 #[must_use]
112 pub fn searchgw() -> Self {
113 Self {
114 msg_type: SEARCHGW,
115 ..Default::default()
116 }
117 }
118
119 #[must_use]
121 pub fn gwinfo() -> Self {
122 Self {
123 msg_type: GWINFO,
124 ..Default::default()
125 }
126 }
127
128 #[must_use]
130 pub fn connect() -> Self {
131 Self {
132 msg_type: CONNECT,
133 ..Default::default()
134 }
135 }
136
137 #[must_use]
139 pub fn connack() -> Self {
140 Self {
141 msg_type: CONNACK,
142 ..Default::default()
143 }
144 }
145
146 #[must_use]
148 pub fn willtopicreq() -> Self {
149 Self {
150 msg_type: WILLTOPICREQ,
151 ..Default::default()
152 }
153 }
154
155 #[must_use]
157 pub fn willtopic() -> Self {
158 Self {
159 msg_type: WILLTOPIC,
160 ..Default::default()
161 }
162 }
163
164 #[must_use]
166 pub fn willmsgreq() -> Self {
167 Self {
168 msg_type: WILLMSGREQ,
169 ..Default::default()
170 }
171 }
172
173 #[must_use]
175 pub fn willmsg() -> Self {
176 Self {
177 msg_type: WILLMSG,
178 ..Default::default()
179 }
180 }
181
182 #[must_use]
184 pub fn register() -> Self {
185 Self {
186 msg_type: REGISTER,
187 ..Default::default()
188 }
189 }
190
191 #[must_use]
193 pub fn regack() -> Self {
194 Self {
195 msg_type: REGACK,
196 ..Default::default()
197 }
198 }
199
200 #[must_use]
202 pub fn publish() -> Self {
203 Self {
204 msg_type: PUBLISH,
205 ..Default::default()
206 }
207 }
208
209 #[must_use]
211 pub fn puback() -> Self {
212 Self {
213 msg_type: PUBACK,
214 ..Default::default()
215 }
216 }
217
218 #[must_use]
220 pub fn pubcomp() -> Self {
221 Self {
222 msg_type: PUBCOMP,
223 ..Default::default()
224 }
225 }
226
227 #[must_use]
229 pub fn pubrec() -> Self {
230 Self {
231 msg_type: PUBREC,
232 ..Default::default()
233 }
234 }
235
236 #[must_use]
238 pub fn pubrel() -> Self {
239 Self {
240 msg_type: PUBREL,
241 ..Default::default()
242 }
243 }
244
245 #[must_use]
247 pub fn subscribe() -> Self {
248 Self {
249 msg_type: SUBSCRIBE,
250 ..Default::default()
251 }
252 }
253
254 #[must_use]
256 pub fn suback() -> Self {
257 Self {
258 msg_type: SUBACK,
259 ..Default::default()
260 }
261 }
262
263 #[must_use]
265 pub fn unsubscribe() -> Self {
266 Self {
267 msg_type: UNSUBSCRIBE,
268 ..Default::default()
269 }
270 }
271
272 #[must_use]
274 pub fn unsuback() -> Self {
275 Self {
276 msg_type: UNSUBACK,
277 ..Default::default()
278 }
279 }
280
281 #[must_use]
283 pub fn pingreq() -> Self {
284 Self {
285 msg_type: PINGREQ,
286 ..Default::default()
287 }
288 }
289
290 #[must_use]
292 pub fn pingresp() -> Self {
293 Self {
294 msg_type: PINGRESP,
295 ..Default::default()
296 }
297 }
298
299 #[must_use]
301 pub fn disconnect() -> Self {
302 Self {
303 msg_type: DISCONNECT,
304 ..Default::default()
305 }
306 }
307
308 #[must_use]
310 pub fn willtopicupd() -> Self {
311 Self {
312 msg_type: WILLTOPICUPD,
313 ..Default::default()
314 }
315 }
316
317 #[must_use]
319 pub fn willtopicresp() -> Self {
320 Self {
321 msg_type: WILLTOPICRESP,
322 ..Default::default()
323 }
324 }
325
326 #[must_use]
328 pub fn willmsgupd() -> Self {
329 Self {
330 msg_type: WILLMSGUPD,
331 ..Default::default()
332 }
333 }
334
335 #[must_use]
337 pub fn willmsgresp() -> Self {
338 Self {
339 msg_type: WILLMSGRESP,
340 ..Default::default()
341 }
342 }
343
344 #[must_use]
350 pub fn msg_type(mut self, v: u8) -> Self {
351 self.msg_type = v;
352 self
353 }
354
355 #[must_use]
357 pub fn dup(mut self, v: bool) -> Self {
358 self.dup = v;
359 self
360 }
361
362 #[must_use]
364 pub fn qos(mut self, v: u8) -> Self {
365 self.qos = v & 0x03;
366 self
367 }
368
369 #[must_use]
371 pub fn retain(mut self, v: bool) -> Self {
372 self.retain = v;
373 self
374 }
375
376 #[must_use]
378 pub fn will(mut self, v: bool) -> Self {
379 self.will = v;
380 self
381 }
382
383 #[must_use]
385 pub fn cleansess(mut self, v: bool) -> Self {
386 self.cleansess = v;
387 self
388 }
389
390 #[must_use]
392 pub fn tid_type(mut self, v: u8) -> Self {
393 self.tid_type = v & 0x03;
394 self
395 }
396
397 #[must_use]
399 pub fn gw_id(mut self, v: u8) -> Self {
400 self.gw_id = v;
401 self
402 }
403
404 #[must_use]
406 pub fn duration(mut self, v: u16) -> Self {
407 self.duration = v;
408 self
409 }
410
411 #[must_use]
413 pub fn radius(mut self, v: u8) -> Self {
414 self.radius = v;
415 self
416 }
417
418 #[must_use]
420 pub fn gw_addr(mut self, v: &[u8]) -> Self {
421 self.gw_addr = v.to_vec();
422 self
423 }
424
425 #[must_use]
427 pub fn prot_id(mut self, v: u8) -> Self {
428 self.prot_id = v;
429 self
430 }
431
432 #[must_use]
434 pub fn client_id(mut self, v: &[u8]) -> Self {
435 self.client_id = v.to_vec();
436 self
437 }
438
439 #[must_use]
441 pub fn client_id_str(mut self, v: &str) -> Self {
442 self.client_id = v.as_bytes().to_vec();
443 self
444 }
445
446 #[must_use]
448 pub fn return_code(mut self, v: u8) -> Self {
449 self.return_code = v;
450 self
451 }
452
453 #[must_use]
455 pub fn tid(mut self, v: u16) -> Self {
456 self.tid = v;
457 self
458 }
459
460 #[must_use]
462 pub fn mid(mut self, v: u16) -> Self {
463 self.mid = v;
464 self
465 }
466
467 #[must_use]
469 pub fn data(mut self, v: &[u8]) -> Self {
470 self.data = v.to_vec();
471 self
472 }
473
474 #[must_use]
476 pub fn topic_name(mut self, v: &[u8]) -> Self {
477 self.topic_name = v.to_vec();
478 self
479 }
480
481 #[must_use]
483 pub fn topic_name_str(mut self, v: &str) -> Self {
484 self.topic_name = v.as_bytes().to_vec();
485 self
486 }
487
488 #[must_use]
490 pub fn will_topic_bytes(mut self, v: &[u8]) -> Self {
491 self.will_topic = v.to_vec();
492 self
493 }
494
495 #[must_use]
497 pub fn will_topic_str(mut self, v: &str) -> Self {
498 self.will_topic = v.as_bytes().to_vec();
499 self
500 }
501
502 #[must_use]
504 pub fn will_msg_bytes(mut self, v: &[u8]) -> Self {
505 self.will_msg = v.to_vec();
506 self
507 }
508
509 fn build_flags(&self) -> u8 {
515 let mut flags: u8 = 0;
516 if self.dup {
517 flags |= 1 << 7;
518 }
519 flags |= (self.qos & 0x03) << 5;
520 if self.retain {
521 flags |= 1 << 4;
522 }
523 if self.will {
524 flags |= 1 << 3;
525 }
526 if self.cleansess {
527 flags |= 1 << 2;
528 }
529 flags |= self.tid_type & 0x03;
530 flags
531 }
532
533 fn build_body(&self) -> Vec<u8> {
535 let mut body = Vec::new();
536
537 match self.msg_type {
538 ADVERTISE => {
539 body.push(self.gw_id);
540 body.extend_from_slice(&self.duration.to_be_bytes());
541 },
542 SEARCHGW => {
543 body.push(self.radius);
544 },
545 GWINFO => {
546 body.push(self.gw_id);
547 body.extend_from_slice(&self.gw_addr);
548 },
549 CONNECT => {
550 body.push(self.build_flags());
551 body.push(self.prot_id);
552 body.extend_from_slice(&self.duration.to_be_bytes());
553 body.extend_from_slice(&self.client_id);
554 },
555 CONNACK => {
556 body.push(self.return_code);
557 },
558 WILLTOPICREQ | WILLMSGREQ => {
559 },
561 WILLTOPIC | WILLTOPICUPD => {
562 body.push(self.build_flags());
563 body.extend_from_slice(&self.will_topic);
564 },
565 WILLMSG | WILLMSGUPD => {
566 body.extend_from_slice(&self.will_msg);
567 },
568 REGISTER => {
569 body.extend_from_slice(&self.tid.to_be_bytes());
570 body.extend_from_slice(&self.mid.to_be_bytes());
571 body.extend_from_slice(&self.topic_name);
572 },
573 REGACK => {
574 body.extend_from_slice(&self.tid.to_be_bytes());
575 body.extend_from_slice(&self.mid.to_be_bytes());
576 body.push(self.return_code);
577 },
578 PUBLISH => {
579 body.push(self.build_flags());
580 body.extend_from_slice(&self.tid.to_be_bytes());
581 body.extend_from_slice(&self.mid.to_be_bytes());
582 body.extend_from_slice(&self.data);
583 },
584 PUBACK => {
585 body.extend_from_slice(&self.tid.to_be_bytes());
586 body.extend_from_slice(&self.mid.to_be_bytes());
587 body.push(self.return_code);
588 },
589 PUBCOMP | PUBREC | PUBREL => {
590 body.extend_from_slice(&self.mid.to_be_bytes());
591 },
592 SUBSCRIBE => {
593 body.push(self.build_flags());
594 body.extend_from_slice(&self.mid.to_be_bytes());
595 match self.tid_type {
599 TID_PREDEF => body.extend_from_slice(&self.tid.to_be_bytes()),
600 TID_SHORT => body.extend_from_slice(&self.tid.to_be_bytes()),
601 _ => body.extend_from_slice(&self.topic_name),
602 }
603 },
604 SUBACK => {
605 body.push(self.build_flags());
606 body.extend_from_slice(&self.tid.to_be_bytes());
607 body.extend_from_slice(&self.mid.to_be_bytes());
608 body.push(self.return_code);
609 },
610 UNSUBSCRIBE => {
611 body.push(self.build_flags());
612 body.extend_from_slice(&self.mid.to_be_bytes());
613 match self.tid_type {
614 TID_PREDEF => body.extend_from_slice(&self.tid.to_be_bytes()),
615 TID_SHORT => body.extend_from_slice(&self.tid.to_be_bytes()),
616 _ => body.extend_from_slice(&self.topic_name),
617 }
618 },
619 UNSUBACK => {
620 body.extend_from_slice(&self.mid.to_be_bytes());
621 },
622 PINGREQ => {
623 if !self.client_id.is_empty() {
624 body.extend_from_slice(&self.client_id);
625 }
626 },
627 PINGRESP => {
628 },
630 DISCONNECT => {
631 if self.duration > 0 {
632 body.extend_from_slice(&self.duration.to_be_bytes());
633 }
634 },
635 WILLTOPICRESP | WILLMSGRESP => {
636 body.push(self.return_code);
637 },
638 _ => {},
639 }
640
641 body
642 }
643
644 #[must_use]
654 pub fn build(&self) -> Vec<u8> {
655 let body = self.build_body();
656 let total_short = 2 + body.len();
659
660 if total_short < 256 {
661 let mut pkt = Vec::with_capacity(total_short);
662 pkt.push(total_short as u8);
663 pkt.push(self.msg_type);
664 pkt.extend_from_slice(&body);
665 pkt
666 } else {
667 let total_ext = 3 + 1 + body.len();
669 let mut pkt = Vec::with_capacity(total_ext);
670 pkt.push(0x01);
671 pkt.extend_from_slice(&(total_ext as u16).to_be_bytes());
672 pkt.push(self.msg_type);
673 pkt.extend_from_slice(&body);
674 pkt
675 }
676 }
677
678 pub fn build_into(&self, buf: &mut Vec<u8>) -> usize {
680 let pkt = self.build();
681 let len = pkt.len();
682 buf.extend_from_slice(&pkt);
683 len
684 }
685}
686
687#[cfg(test)]
688mod tests {
689 use super::*;
690 use crate::layer::mqttsn::{MqttSnLayer, RC_REJ_CONGESTION, RC_REJ_INVALID_TID, TID_NORMAL};
691 use crate::layer::{LayerIndex, LayerKind};
692
693 fn make_layer(buf: &[u8]) -> MqttSnLayer {
694 let idx = LayerIndex::new(LayerKind::MqttSn, 0, buf.len());
695 MqttSnLayer::new(idx)
696 }
697
698 #[test]
703 fn test_build_advertise() {
704 let pkt = MqttSnBuilder::advertise()
705 .gw_id(0x98)
706 .duration(0x2b9a)
707 .build();
708 assert_eq!(pkt, b"\x05\x00\x98\x2b\x9a");
709 }
710
711 #[test]
712 fn test_build_searchgw() {
713 let pkt = MqttSnBuilder::searchgw().radius(0xcc).build();
714 assert_eq!(pkt, b"\x03\x01\xcc");
715 }
716
717 #[test]
718 fn test_build_gwinfo() {
719 let pkt = MqttSnBuilder::gwinfo()
720 .gw_id(0x42)
721 .gw_addr(&[192, 168, 1, 1])
722 .build();
723 assert_eq!(pkt.len(), 7); assert_eq!(pkt[0], 7);
725 assert_eq!(pkt[1], GWINFO);
726 assert_eq!(pkt[2], 0x42);
727 assert_eq!(&pkt[3..], &[192, 168, 1, 1]);
728 }
729
730 #[test]
731 fn test_build_connect() {
732 let pkt = MqttSnBuilder::connect()
733 .cleansess(true)
734 .prot_id(0x1a)
735 .duration(0x775b)
736 .client_id(b"test")
737 .build();
738 assert_eq!(pkt, b"\x0a\x04\x04\x1a\x77\x5b\x74\x65\x73\x74");
739 }
740
741 #[test]
742 fn test_build_connack() {
743 let pkt = MqttSnBuilder::connack()
744 .return_code(RC_REJ_INVALID_TID)
745 .build();
746 assert_eq!(pkt, b"\x03\x05\x02");
747 }
748
749 #[test]
750 fn test_build_publish() {
751 let pkt = MqttSnBuilder::publish()
752 .qos(2)
753 .tid(0x197f)
754 .mid(0x6a26)
755 .data(b"test")
756 .build();
757 assert_eq!(
758 pkt,
759 &[
760 0x0b, 0x0c, 0x40, 0x19, 0x7f, 0x6a, 0x26, b't', b'e', b's', b't'
761 ]
762 );
763 }
764
765 #[test]
766 fn test_build_puback() {
767 let pkt = MqttSnBuilder::puback()
768 .tid(0x0001)
769 .mid(0x0002)
770 .return_code(RC_ACCEPTED)
771 .build();
772 assert_eq!(pkt.len(), 7);
773 assert_eq!(pkt[0], 7);
774 assert_eq!(pkt[1], PUBACK);
775 assert_eq!(&pkt[2..4], &[0x00, 0x01]); assert_eq!(&pkt[4..6], &[0x00, 0x02]); assert_eq!(pkt[6], RC_ACCEPTED);
778 }
779
780 #[test]
781 fn test_build_pubcomp() {
782 let pkt = MqttSnBuilder::pubcomp().mid(0x1234).build();
783 assert_eq!(pkt.len(), 4);
784 assert_eq!(pkt[0], 4);
785 assert_eq!(pkt[1], PUBCOMP);
786 assert_eq!(&pkt[2..4], &[0x12, 0x34]);
787 }
788
789 #[test]
790 fn test_build_register() {
791 let pkt = MqttSnBuilder::register()
792 .tid(0x0001)
793 .mid(0x0002)
794 .topic_name(b"test/topic")
795 .build();
796 assert_eq!(pkt.len(), 16); assert_eq!(pkt[0], 16);
798 assert_eq!(pkt[1], REGISTER);
799 assert_eq!(&pkt[2..4], &[0x00, 0x01]); assert_eq!(&pkt[4..6], &[0x00, 0x02]); assert_eq!(&pkt[6..], b"test/topic");
802 }
803
804 #[test]
805 fn test_build_regack() {
806 let pkt = MqttSnBuilder::regack()
807 .tid(0x0010)
808 .mid(0x0020)
809 .return_code(RC_ACCEPTED)
810 .build();
811 assert_eq!(pkt.len(), 7);
812 assert_eq!(pkt[0], 7);
813 assert_eq!(pkt[1], REGACK);
814 assert_eq!(&pkt[2..4], &[0x00, 0x10]); assert_eq!(&pkt[4..6], &[0x00, 0x20]); assert_eq!(pkt[6], RC_ACCEPTED);
817 }
818
819 #[test]
820 fn test_build_subscribe_normal_topic() {
821 let pkt = MqttSnBuilder::subscribe()
822 .qos(1)
823 .tid_type(TID_NORMAL)
824 .mid(0x0001)
825 .topic_name(b"sensors/temp")
826 .build();
827 assert_eq!(pkt[1], SUBSCRIBE);
828 let flags = pkt[2];
829 assert_eq!((flags >> 5) & 0x03, 1); assert_eq!(flags & 0x03, TID_NORMAL);
831 assert_eq!(&pkt[3..5], &[0x00, 0x01]); assert_eq!(&pkt[5..], b"sensors/temp");
833 }
834
835 #[test]
836 fn test_build_subscribe_predef_tid() {
837 let pkt = MqttSnBuilder::subscribe()
838 .qos(1)
839 .tid_type(TID_PREDEF)
840 .mid(0x0001)
841 .tid(0x0042)
842 .build();
843 assert_eq!(pkt[1], SUBSCRIBE);
844 let flags = pkt[2];
845 assert_eq!(flags & 0x03, TID_PREDEF);
846 assert_eq!(&pkt[5..7], &[0x00, 0x42]); }
848
849 #[test]
850 fn test_build_subscribe_short_topic() {
851 let short = u16::from_be_bytes([b'a', b'b']);
853 let pkt = MqttSnBuilder::subscribe()
854 .qos(0)
855 .tid_type(TID_SHORT)
856 .mid(0x0005)
857 .tid(short)
858 .build();
859 assert_eq!(pkt[1], SUBSCRIBE);
860 let flags = pkt[2];
861 assert_eq!(flags & 0x03, TID_SHORT);
862 assert_eq!(&pkt[5..7], &[b'a', b'b']);
863 }
864
865 #[test]
866 fn test_build_suback() {
867 let pkt = MqttSnBuilder::suback()
868 .qos(1)
869 .tid(0x0001)
870 .mid(0x0002)
871 .return_code(RC_ACCEPTED)
872 .build();
873 assert_eq!(pkt.len(), 8);
874 assert_eq!(pkt[0], 8);
875 assert_eq!(pkt[1], SUBACK);
876 let flags = pkt[2];
878 assert_eq!((flags >> 5) & 0x03, 1);
879 assert_eq!(&pkt[3..5], &[0x00, 0x01]); assert_eq!(&pkt[5..7], &[0x00, 0x02]); assert_eq!(pkt[7], RC_ACCEPTED);
882 }
883
884 #[test]
885 fn test_build_unsubscribe_normal() {
886 let pkt = MqttSnBuilder::unsubscribe()
887 .tid_type(TID_NORMAL)
888 .mid(0x0003)
889 .topic_name(b"test/t")
890 .build();
891 assert_eq!(pkt[1], UNSUBSCRIBE);
892 let flags = pkt[2];
893 assert_eq!(flags & 0x03, TID_NORMAL);
894 assert_eq!(&pkt[3..5], &[0x00, 0x03]); assert_eq!(&pkt[5..], b"test/t");
896 }
897
898 #[test]
899 fn test_build_unsuback() {
900 let pkt = MqttSnBuilder::unsuback().mid(0x0003).build();
901 assert_eq!(pkt.len(), 4);
902 assert_eq!(pkt[0], 4);
903 assert_eq!(pkt[1], UNSUBACK);
904 assert_eq!(&pkt[2..4], &[0x00, 0x03]);
905 }
906
907 #[test]
908 fn test_build_pingreq_with_client_id() {
909 let pkt = MqttSnBuilder::pingreq().client_id(b"sensor1").build();
910 assert_eq!(pkt[0] as usize, pkt.len());
911 assert_eq!(pkt[1], PINGREQ);
912 assert_eq!(&pkt[2..], b"sensor1");
913 }
914
915 #[test]
916 fn test_build_pingresp() {
917 let pkt = MqttSnBuilder::pingresp().build();
918 assert_eq!(pkt, b"\x02\x17");
919 }
920
921 #[test]
922 fn test_build_disconnect_no_duration() {
923 let pkt = MqttSnBuilder::disconnect().build();
924 assert_eq!(pkt, b"\x02\x18");
925 }
926
927 #[test]
928 fn test_build_disconnect_with_duration() {
929 let pkt = MqttSnBuilder::disconnect().duration(0x0312).build();
930 assert_eq!(pkt, b"\x04\x18\x03\x12");
931 }
932
933 #[test]
934 fn test_build_willtopic() {
935 let pkt = MqttSnBuilder::willtopic()
936 .qos(1)
937 .retain(true)
938 .will_topic_str("lastwill")
939 .build();
940 assert_eq!(pkt[1], WILLTOPIC);
941 let flags = pkt[2];
942 assert_eq!((flags >> 5) & 0x03, 1); assert_eq!((flags >> 4) & 1, 1); assert_eq!(&pkt[3..], b"lastwill");
945 }
946
947 #[test]
948 fn test_build_willmsg() {
949 let pkt = MqttSnBuilder::willmsg().will_msg_bytes(b"goodbye").build();
950 assert_eq!(pkt[1], WILLMSG);
951 assert_eq!(&pkt[2..], b"goodbye");
952 }
953
954 #[test]
955 fn test_build_willtopicresp() {
956 let pkt = MqttSnBuilder::willtopicresp()
957 .return_code(RC_ACCEPTED)
958 .build();
959 assert_eq!(pkt.len(), 3);
960 assert_eq!(pkt[0], 3);
961 assert_eq!(pkt[1], WILLTOPICRESP);
962 assert_eq!(pkt[2], RC_ACCEPTED);
963 }
964
965 #[test]
966 fn test_build_willmsgresp() {
967 let pkt = MqttSnBuilder::willmsgresp()
968 .return_code(RC_REJ_CONGESTION)
969 .build();
970 assert_eq!(pkt.len(), 3);
971 assert_eq!(pkt[0], 3);
972 assert_eq!(pkt[1], WILLMSGRESP);
973 assert_eq!(pkt[2], RC_REJ_CONGESTION);
974 }
975
976 #[test]
981 fn test_roundtrip_connect() {
982 let pkt = MqttSnBuilder::connect()
983 .cleansess(true)
984 .will(true)
985 .prot_id(0x01)
986 .duration(60)
987 .client_id(b"mydevice")
988 .build();
989 let layer = make_layer(&pkt);
990 assert_eq!(layer.msg_type(&pkt).unwrap(), CONNECT);
991 assert_eq!(layer.cleansess(&pkt).unwrap(), true);
992 assert_eq!(layer.will(&pkt).unwrap(), true);
993 assert_eq!(layer.prot_id(&pkt).unwrap(), 0x01);
994 assert_eq!(layer.duration(&pkt).unwrap(), 60);
995 assert_eq!(layer.client_id(&pkt).unwrap(), "mydevice");
996 }
997
998 #[test]
999 fn test_roundtrip_publish() {
1000 let pkt = MqttSnBuilder::publish()
1001 .dup(true)
1002 .qos(1)
1003 .retain(true)
1004 .tid(0xBEEF)
1005 .mid(0xCAFE)
1006 .data(b"hello world")
1007 .build();
1008 let layer = make_layer(&pkt);
1009 assert_eq!(layer.msg_type(&pkt).unwrap(), PUBLISH);
1010 assert_eq!(layer.dup(&pkt).unwrap(), true);
1011 assert_eq!(layer.qos(&pkt).unwrap(), 1);
1012 assert_eq!(layer.retain(&pkt).unwrap(), true);
1013 assert_eq!(layer.tid(&pkt).unwrap(), 0xBEEF);
1014 assert_eq!(layer.mid(&pkt).unwrap(), 0xCAFE);
1015 assert_eq!(layer.data(&pkt).unwrap(), b"hello world");
1016 }
1017
1018 #[test]
1019 fn test_roundtrip_register() {
1020 let pkt = MqttSnBuilder::register()
1021 .tid(0x0042)
1022 .mid(0x0001)
1023 .topic_name(b"sensors/temp")
1024 .build();
1025 let layer = make_layer(&pkt);
1026 assert_eq!(layer.msg_type(&pkt).unwrap(), REGISTER);
1027 assert_eq!(layer.tid(&pkt).unwrap(), 0x0042);
1028 assert_eq!(layer.mid(&pkt).unwrap(), 0x0001);
1029 assert_eq!(layer.topic_name(&pkt).unwrap(), "sensors/temp");
1030 }
1031
1032 #[test]
1033 fn test_roundtrip_suback() {
1034 let pkt = MqttSnBuilder::suback()
1035 .qos(2)
1036 .tid(0x0010)
1037 .mid(0x0020)
1038 .return_code(RC_ACCEPTED)
1039 .build();
1040 let layer = make_layer(&pkt);
1041 assert_eq!(layer.msg_type(&pkt).unwrap(), SUBACK);
1042 assert_eq!(layer.qos(&pkt).unwrap(), 2);
1043 assert_eq!(layer.tid(&pkt).unwrap(), 0x0010);
1044 assert_eq!(layer.mid(&pkt).unwrap(), 0x0020);
1045 assert_eq!(layer.return_code(&pkt).unwrap(), RC_ACCEPTED);
1046 }
1047
1048 #[test]
1049 fn test_extended_length_builder() {
1050 let big_data = vec![0xAA; 300];
1052 let pkt = MqttSnBuilder::publish()
1053 .qos(0)
1054 .tid(0x0001)
1055 .mid(0x0001)
1056 .data(&big_data)
1057 .build();
1058 assert_eq!(pkt[0], 0x01);
1060 let total_len = u16::from_be_bytes([pkt[1], pkt[2]]);
1061 assert_eq!(total_len as usize, pkt.len());
1062 assert_eq!(pkt[3], PUBLISH);
1063 let layer = make_layer(&pkt);
1064 assert_eq!(layer.msg_type(&pkt).unwrap(), PUBLISH);
1065 assert_eq!(layer.data(&pkt).unwrap().len(), 300);
1066 }
1067
1068 #[test]
1069 fn test_flags_all_set() {
1070 let pkt = MqttSnBuilder::publish()
1071 .dup(true)
1072 .qos(3)
1073 .retain(true)
1074 .tid_type(TID_SHORT)
1075 .tid(0x4142) .mid(0x0001)
1077 .data(b"x")
1078 .build();
1079 let layer = make_layer(&pkt);
1080 let flags = layer.flags(&pkt).unwrap();
1081 assert_eq!(flags & 0x80, 0x80); assert_eq!((flags >> 5) & 0x03, 3); assert_eq!(flags & 0x10, 0x10); assert_eq!(flags & 0x03, TID_SHORT); }
1087
1088 #[test]
1089 fn test_build_into() {
1090 let builder = MqttSnBuilder::pingresp();
1091 let mut buf = Vec::new();
1092 let written = builder.build_into(&mut buf);
1093 assert_eq!(written, 2);
1094 assert_eq!(buf, b"\x02\x17");
1095 }
1096}