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::{LayerIndex, LayerKind};
691
692 fn make_layer(buf: &[u8]) -> MqttSnLayer {
693 let idx = LayerIndex::new(LayerKind::MqttSn, 0, buf.len());
694 MqttSnLayer::new(idx)
695 }
696
697 #[test]
702 fn test_build_advertise() {
703 let pkt = MqttSnBuilder::advertise()
704 .gw_id(0x98)
705 .duration(0x2b9a)
706 .build();
707 assert_eq!(pkt, b"\x05\x00\x98\x2b\x9a");
708 }
709
710 #[test]
711 fn test_build_searchgw() {
712 let pkt = MqttSnBuilder::searchgw().radius(0xcc).build();
713 assert_eq!(pkt, b"\x03\x01\xcc");
714 }
715
716 #[test]
717 fn test_build_gwinfo() {
718 let pkt = MqttSnBuilder::gwinfo()
719 .gw_id(0x42)
720 .gw_addr(&[192, 168, 1, 1])
721 .build();
722 assert_eq!(pkt.len(), 7); assert_eq!(pkt[0], 7);
724 assert_eq!(pkt[1], GWINFO);
725 assert_eq!(pkt[2], 0x42);
726 assert_eq!(&pkt[3..], &[192, 168, 1, 1]);
727 }
728
729 #[test]
730 fn test_build_connect() {
731 let pkt = MqttSnBuilder::connect()
732 .cleansess(true)
733 .prot_id(0x1a)
734 .duration(0x775b)
735 .client_id(b"test")
736 .build();
737 assert_eq!(pkt, b"\x0a\x04\x04\x1a\x77\x5b\x74\x65\x73\x74");
738 }
739
740 #[test]
741 fn test_build_connack() {
742 let pkt = MqttSnBuilder::connack()
743 .return_code(RC_REJ_INVALID_TID)
744 .build();
745 assert_eq!(pkt, b"\x03\x05\x02");
746 }
747
748 #[test]
749 fn test_build_publish() {
750 let pkt = MqttSnBuilder::publish()
751 .qos(2)
752 .tid(0x197f)
753 .mid(0x6a26)
754 .data(b"test")
755 .build();
756 assert_eq!(
757 pkt,
758 &[
759 0x0b, 0x0c, 0x40, 0x19, 0x7f, 0x6a, 0x26, b't', b'e', b's', b't'
760 ]
761 );
762 }
763
764 #[test]
765 fn test_build_puback() {
766 let pkt = MqttSnBuilder::puback()
767 .tid(0x0001)
768 .mid(0x0002)
769 .return_code(RC_ACCEPTED)
770 .build();
771 assert_eq!(pkt.len(), 7);
772 assert_eq!(pkt[0], 7);
773 assert_eq!(pkt[1], PUBACK);
774 assert_eq!(&pkt[2..4], &[0x00, 0x01]); assert_eq!(&pkt[4..6], &[0x00, 0x02]); assert_eq!(pkt[6], RC_ACCEPTED);
777 }
778
779 #[test]
780 fn test_build_pubcomp() {
781 let pkt = MqttSnBuilder::pubcomp().mid(0x1234).build();
782 assert_eq!(pkt.len(), 4);
783 assert_eq!(pkt[0], 4);
784 assert_eq!(pkt[1], PUBCOMP);
785 assert_eq!(&pkt[2..4], &[0x12, 0x34]);
786 }
787
788 #[test]
789 fn test_build_register() {
790 let pkt = MqttSnBuilder::register()
791 .tid(0x0001)
792 .mid(0x0002)
793 .topic_name(b"test/topic")
794 .build();
795 assert_eq!(pkt.len(), 16); assert_eq!(pkt[0], 16);
797 assert_eq!(pkt[1], REGISTER);
798 assert_eq!(&pkt[2..4], &[0x00, 0x01]); assert_eq!(&pkt[4..6], &[0x00, 0x02]); assert_eq!(&pkt[6..], b"test/topic");
801 }
802
803 #[test]
804 fn test_build_regack() {
805 let pkt = MqttSnBuilder::regack()
806 .tid(0x0010)
807 .mid(0x0020)
808 .return_code(RC_ACCEPTED)
809 .build();
810 assert_eq!(pkt.len(), 7);
811 assert_eq!(pkt[0], 7);
812 assert_eq!(pkt[1], REGACK);
813 assert_eq!(&pkt[2..4], &[0x00, 0x10]); assert_eq!(&pkt[4..6], &[0x00, 0x20]); assert_eq!(pkt[6], RC_ACCEPTED);
816 }
817
818 #[test]
819 fn test_build_subscribe_normal_topic() {
820 let pkt = MqttSnBuilder::subscribe()
821 .qos(1)
822 .tid_type(TID_NORMAL)
823 .mid(0x0001)
824 .topic_name(b"sensors/temp")
825 .build();
826 assert_eq!(pkt[1], SUBSCRIBE);
827 let flags = pkt[2];
828 assert_eq!((flags >> 5) & 0x03, 1); assert_eq!(flags & 0x03, TID_NORMAL);
830 assert_eq!(&pkt[3..5], &[0x00, 0x01]); assert_eq!(&pkt[5..], b"sensors/temp");
832 }
833
834 #[test]
835 fn test_build_subscribe_predef_tid() {
836 let pkt = MqttSnBuilder::subscribe()
837 .qos(1)
838 .tid_type(TID_PREDEF)
839 .mid(0x0001)
840 .tid(0x0042)
841 .build();
842 assert_eq!(pkt[1], SUBSCRIBE);
843 let flags = pkt[2];
844 assert_eq!(flags & 0x03, TID_PREDEF);
845 assert_eq!(&pkt[5..7], &[0x00, 0x42]); }
847
848 #[test]
849 fn test_build_subscribe_short_topic() {
850 let short = u16::from_be_bytes([b'a', b'b']);
852 let pkt = MqttSnBuilder::subscribe()
853 .qos(0)
854 .tid_type(TID_SHORT)
855 .mid(0x0005)
856 .tid(short)
857 .build();
858 assert_eq!(pkt[1], SUBSCRIBE);
859 let flags = pkt[2];
860 assert_eq!(flags & 0x03, TID_SHORT);
861 assert_eq!(&pkt[5..7], &[b'a', b'b']);
862 }
863
864 #[test]
865 fn test_build_suback() {
866 let pkt = MqttSnBuilder::suback()
867 .qos(1)
868 .tid(0x0001)
869 .mid(0x0002)
870 .return_code(RC_ACCEPTED)
871 .build();
872 assert_eq!(pkt.len(), 8);
873 assert_eq!(pkt[0], 8);
874 assert_eq!(pkt[1], SUBACK);
875 let flags = pkt[2];
877 assert_eq!((flags >> 5) & 0x03, 1);
878 assert_eq!(&pkt[3..5], &[0x00, 0x01]); assert_eq!(&pkt[5..7], &[0x00, 0x02]); assert_eq!(pkt[7], RC_ACCEPTED);
881 }
882
883 #[test]
884 fn test_build_unsubscribe_normal() {
885 let pkt = MqttSnBuilder::unsubscribe()
886 .tid_type(TID_NORMAL)
887 .mid(0x0003)
888 .topic_name(b"test/t")
889 .build();
890 assert_eq!(pkt[1], UNSUBSCRIBE);
891 let flags = pkt[2];
892 assert_eq!(flags & 0x03, TID_NORMAL);
893 assert_eq!(&pkt[3..5], &[0x00, 0x03]); assert_eq!(&pkt[5..], b"test/t");
895 }
896
897 #[test]
898 fn test_build_unsuback() {
899 let pkt = MqttSnBuilder::unsuback().mid(0x0003).build();
900 assert_eq!(pkt.len(), 4);
901 assert_eq!(pkt[0], 4);
902 assert_eq!(pkt[1], UNSUBACK);
903 assert_eq!(&pkt[2..4], &[0x00, 0x03]);
904 }
905
906 #[test]
907 fn test_build_pingreq_with_client_id() {
908 let pkt = MqttSnBuilder::pingreq().client_id(b"sensor1").build();
909 assert_eq!(pkt[0] as usize, pkt.len());
910 assert_eq!(pkt[1], PINGREQ);
911 assert_eq!(&pkt[2..], b"sensor1");
912 }
913
914 #[test]
915 fn test_build_pingresp() {
916 let pkt = MqttSnBuilder::pingresp().build();
917 assert_eq!(pkt, b"\x02\x17");
918 }
919
920 #[test]
921 fn test_build_disconnect_no_duration() {
922 let pkt = MqttSnBuilder::disconnect().build();
923 assert_eq!(pkt, b"\x02\x18");
924 }
925
926 #[test]
927 fn test_build_disconnect_with_duration() {
928 let pkt = MqttSnBuilder::disconnect().duration(0x0312).build();
929 assert_eq!(pkt, b"\x04\x18\x03\x12");
930 }
931
932 #[test]
933 fn test_build_willtopic() {
934 let pkt = MqttSnBuilder::willtopic()
935 .qos(1)
936 .retain(true)
937 .will_topic_str("lastwill")
938 .build();
939 assert_eq!(pkt[1], WILLTOPIC);
940 let flags = pkt[2];
941 assert_eq!((flags >> 5) & 0x03, 1); assert_eq!((flags >> 4) & 1, 1); assert_eq!(&pkt[3..], b"lastwill");
944 }
945
946 #[test]
947 fn test_build_willmsg() {
948 let pkt = MqttSnBuilder::willmsg().will_msg_bytes(b"goodbye").build();
949 assert_eq!(pkt[1], WILLMSG);
950 assert_eq!(&pkt[2..], b"goodbye");
951 }
952
953 #[test]
954 fn test_build_willtopicresp() {
955 let pkt = MqttSnBuilder::willtopicresp()
956 .return_code(RC_ACCEPTED)
957 .build();
958 assert_eq!(pkt.len(), 3);
959 assert_eq!(pkt[0], 3);
960 assert_eq!(pkt[1], WILLTOPICRESP);
961 assert_eq!(pkt[2], RC_ACCEPTED);
962 }
963
964 #[test]
965 fn test_build_willmsgresp() {
966 let pkt = MqttSnBuilder::willmsgresp()
967 .return_code(RC_REJ_CONGESTION)
968 .build();
969 assert_eq!(pkt.len(), 3);
970 assert_eq!(pkt[0], 3);
971 assert_eq!(pkt[1], WILLMSGRESP);
972 assert_eq!(pkt[2], RC_REJ_CONGESTION);
973 }
974
975 #[test]
980 fn test_roundtrip_connect() {
981 let pkt = MqttSnBuilder::connect()
982 .cleansess(true)
983 .will(true)
984 .prot_id(0x01)
985 .duration(60)
986 .client_id(b"mydevice")
987 .build();
988 let layer = make_layer(&pkt);
989 assert_eq!(layer.msg_type(&pkt).unwrap(), CONNECT);
990 assert_eq!(layer.cleansess(&pkt).unwrap(), true);
991 assert_eq!(layer.will(&pkt).unwrap(), true);
992 assert_eq!(layer.prot_id(&pkt).unwrap(), 0x01);
993 assert_eq!(layer.duration(&pkt).unwrap(), 60);
994 assert_eq!(layer.client_id(&pkt).unwrap(), "mydevice");
995 }
996
997 #[test]
998 fn test_roundtrip_publish() {
999 let pkt = MqttSnBuilder::publish()
1000 .dup(true)
1001 .qos(1)
1002 .retain(true)
1003 .tid(0xBEEF)
1004 .mid(0xCAFE)
1005 .data(b"hello world")
1006 .build();
1007 let layer = make_layer(&pkt);
1008 assert_eq!(layer.msg_type(&pkt).unwrap(), PUBLISH);
1009 assert_eq!(layer.dup(&pkt).unwrap(), true);
1010 assert_eq!(layer.qos(&pkt).unwrap(), 1);
1011 assert_eq!(layer.retain(&pkt).unwrap(), true);
1012 assert_eq!(layer.tid(&pkt).unwrap(), 0xBEEF);
1013 assert_eq!(layer.mid(&pkt).unwrap(), 0xCAFE);
1014 assert_eq!(layer.data(&pkt).unwrap(), b"hello world");
1015 }
1016
1017 #[test]
1018 fn test_roundtrip_register() {
1019 let pkt = MqttSnBuilder::register()
1020 .tid(0x0042)
1021 .mid(0x0001)
1022 .topic_name(b"sensors/temp")
1023 .build();
1024 let layer = make_layer(&pkt);
1025 assert_eq!(layer.msg_type(&pkt).unwrap(), REGISTER);
1026 assert_eq!(layer.tid(&pkt).unwrap(), 0x0042);
1027 assert_eq!(layer.mid(&pkt).unwrap(), 0x0001);
1028 assert_eq!(layer.topic_name(&pkt).unwrap(), "sensors/temp");
1029 }
1030
1031 #[test]
1032 fn test_roundtrip_suback() {
1033 let pkt = MqttSnBuilder::suback()
1034 .qos(2)
1035 .tid(0x0010)
1036 .mid(0x0020)
1037 .return_code(RC_ACCEPTED)
1038 .build();
1039 let layer = make_layer(&pkt);
1040 assert_eq!(layer.msg_type(&pkt).unwrap(), SUBACK);
1041 assert_eq!(layer.qos(&pkt).unwrap(), 2);
1042 assert_eq!(layer.tid(&pkt).unwrap(), 0x0010);
1043 assert_eq!(layer.mid(&pkt).unwrap(), 0x0020);
1044 assert_eq!(layer.return_code(&pkt).unwrap(), RC_ACCEPTED);
1045 }
1046
1047 #[test]
1048 fn test_extended_length_builder() {
1049 let big_data = vec![0xAA; 300];
1051 let pkt = MqttSnBuilder::publish()
1052 .qos(0)
1053 .tid(0x0001)
1054 .mid(0x0001)
1055 .data(&big_data)
1056 .build();
1057 assert_eq!(pkt[0], 0x01);
1059 let total_len = u16::from_be_bytes([pkt[1], pkt[2]]);
1060 assert_eq!(total_len as usize, pkt.len());
1061 assert_eq!(pkt[3], PUBLISH);
1062 let layer = make_layer(&pkt);
1063 assert_eq!(layer.msg_type(&pkt).unwrap(), PUBLISH);
1064 assert_eq!(layer.data(&pkt).unwrap().len(), 300);
1065 }
1066
1067 #[test]
1068 fn test_flags_all_set() {
1069 let pkt = MqttSnBuilder::publish()
1070 .dup(true)
1071 .qos(3)
1072 .retain(true)
1073 .tid_type(TID_SHORT)
1074 .tid(0x4142) .mid(0x0001)
1076 .data(b"x")
1077 .build();
1078 let layer = make_layer(&pkt);
1079 let flags = layer.flags(&pkt).unwrap();
1080 assert_eq!(flags & 0x80, 0x80); assert_eq!((flags >> 5) & 0x03, 3); assert_eq!(flags & 0x10, 0x10); assert_eq!(flags & 0x03, TID_SHORT); }
1086
1087 #[test]
1088 fn test_build_into() {
1089 let builder = MqttSnBuilder::pingresp();
1090 let mut buf = Vec::new();
1091 let written = builder.build_into(&mut buf);
1092 assert_eq!(written, 2);
1093 assert_eq!(buf, b"\x02\x17");
1094 }
1095}