From 44cfb08351dc37786d412e9abf5c2b4dec1358c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Mar 2024 11:12:17 +0100 Subject: [PATCH 01/90] Add v5 module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/lib.rs | 1 + mqtt-format/src/v5/mod.rs | 0 2 files changed, 1 insertion(+) create mode 100644 mqtt-format/src/v5/mod.rs diff --git a/mqtt-format/src/lib.rs b/mqtt-format/src/lib.rs index f7690773..4d1b8fcf 100644 --- a/mqtt-format/src/lib.rs +++ b/mqtt-format/src/lib.rs @@ -8,3 +8,4 @@ #![deny(clippy::disallowed_types)] pub mod v3; +pub mod v5; diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs new file mode 100644 index 00000000..e69de29b From a0e161af1d1eeec6da2a1d7096d2ab2413f6e370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Mar 2024 11:19:07 +0100 Subject: [PATCH 02/90] Add winnow crate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- Cargo.lock | 10 ++++++++++ mqtt-format/Cargo.toml | 1 + 2 files changed, 11 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 103f98bc..96f41c8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -607,6 +607,7 @@ dependencies = [ "pretty_assertions", "thiserror", "tokio", + "winnow", "yoke", ] @@ -1355,6 +1356,15 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "winnow" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +dependencies = [ + "memchr", +] + [[package]] name = "yansi" version = "0.5.1" diff --git a/mqtt-format/Cargo.toml b/mqtt-format/Cargo.toml index 5f9bf052..2be9b874 100644 --- a/mqtt-format/Cargo.toml +++ b/mqtt-format/Cargo.toml @@ -19,6 +19,7 @@ futures = "0.3.28" nom = "7.1.3" nom-supreme = "0.8.0" thiserror = "1.0.40" +winnow = "0.6.5" yoke = { version = "0.7.0", features = ["derive"], optional = true } [dev-dependencies] From e9c87fca36deb1a0a9f74ab82a44718222c75d44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Mar 2024 11:59:30 +0100 Subject: [PATCH 03/90] Hide MQTTv3 behind feature flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/mqtt-format/src/lib.rs b/mqtt-format/src/lib.rs index 4d1b8fcf..c82d7c33 100644 --- a/mqtt-format/src/lib.rs +++ b/mqtt-format/src/lib.rs @@ -7,5 +7,6 @@ #![deny(clippy::disallowed_methods)] #![deny(clippy::disallowed_types)] +#[cfg(mqttv3)] pub mod v3; pub mod v5; From 51ca0da6925f174ff1dc9354d21d8a7621576731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Mar 2024 11:59:43 +0100 Subject: [PATCH 04/90] Add integers parsing module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/integers.rs | 103 +++++++++++++++++++++++++++++++++ mqtt-format/src/v5/mod.rs | 3 + 2 files changed, 106 insertions(+) create mode 100644 mqtt-format/src/v5/integers.rs diff --git a/mqtt-format/src/v5/integers.rs b/mqtt-format/src/v5/integers.rs new file mode 100644 index 00000000..9eeedb96 --- /dev/null +++ b/mqtt-format/src/v5/integers.rs @@ -0,0 +1,103 @@ +use winnow::{token::take_while, Bytes, Parser}; + +use super::IMResult; + +pub fn parse_u16(input: &Bytes) -> IMResult<&Bytes, u16> { + winnow::binary::u16(winnow::binary::Endianness::Big).parse_peek(input) +} + +pub fn parse_u32(input: &Bytes) -> IMResult<&Bytes, u32> { + winnow::binary::u32(winnow::binary::Endianness::Big).parse_peek(input) +} + +pub fn parse_variable(input: &Bytes) -> IMResult<&Bytes, u32> { + let var_bytes = ( + take_while(0..=3, |b| b & 0b1000_0000 != 0), + winnow::binary::u8.verify(|b: &u8| b & 0b1000_0000 == 0), + ); + let (input, bytes) = var_bytes.recognize().parse_peek(input)?; + + let mut output: u32 = 0; + + for (exp, val) in bytes.iter().enumerate() { + output += (*val as u32 & 0b0111_1111) * 128u32.pow(exp as u32); + } + + Ok((input, output)) +} + +#[cfg(test)] +mod tests { + use winnow::Bytes; + + use crate::v5::integers::{parse_u16, parse_u32, parse_variable}; + + #[test] + fn check_integer_parsing() { + let input = 15u16.to_be_bytes(); + assert_eq!( + parse_u16(Bytes::new(&input)).unwrap(), + (Bytes::new(&[]), 15) + ); + + let input = 42u32.to_be_bytes(); + assert_eq!( + parse_u32(Bytes::new(&input)).unwrap(), + (Bytes::new(&[]), 42) + ); + } + + #[test] + fn check_variable_integers() { + let input = [0x0]; + assert_eq!( + parse_variable(Bytes::new(&input)).unwrap(), + (Bytes::new(&[]), 0) + ); + + let input = [0x7F]; + assert_eq!( + parse_variable(Bytes::new(&input)).unwrap(), + (Bytes::new(&[]), 127) + ); + + let input = [0x80, 0x01]; + assert_eq!( + parse_variable(Bytes::new(&input)).unwrap(), + (Bytes::new(&[]), 128) + ); + + let input = [0xFF, 0x7F]; + assert_eq!( + parse_variable(Bytes::new(&input)).unwrap(), + (Bytes::new(&[]), 16_383) + ); + + let input = [0x80, 0x80, 0x01]; + assert_eq!( + parse_variable(Bytes::new(&input)).unwrap(), + (Bytes::new(&[]), 16_384) + ); + + let input = [0xFF, 0xFF, 0x7F]; + assert_eq!( + parse_variable(Bytes::new(&input)).unwrap(), + (Bytes::new(&[]), 2_097_151) + ); + + let input = [0x80, 0x80, 0x80, 0x01]; + assert_eq!( + parse_variable(Bytes::new(&input)).unwrap(), + (Bytes::new(&[]), 2_097_152) + ); + + let input = [0xFF, 0xFF, 0xFF, 0x7F]; + assert_eq!( + parse_variable(Bytes::new(&input)).unwrap(), + (Bytes::new(&[]), 268_435_455) + ); + + let input = [0xFF, 0xFF, 0xFF, 0x8F]; + parse_variable(Bytes::new(&input)).unwrap_err(); + } +} diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index e69de29b..dc12d9cd 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -0,0 +1,3 @@ +mod integers; + +pub type IMResult = winnow::IResult; From b56e5b49cbf5017c6d14787bbc242b027ebae34c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Mar 2024 12:29:37 +0100 Subject: [PATCH 05/90] Use mutable inputs and PResult instead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit winnow uses mutable inputs, this is in contrast to nom which return the new slice every time. Signed-off-by: Marcel Müller --- mqtt-format/src/v5/integers.rs | 67 ++++++++++------------------------ mqtt-format/src/v5/mod.rs | 3 +- 2 files changed, 22 insertions(+), 48 deletions(-) diff --git a/mqtt-format/src/v5/integers.rs b/mqtt-format/src/v5/integers.rs index 9eeedb96..80157a7d 100644 --- a/mqtt-format/src/v5/integers.rs +++ b/mqtt-format/src/v5/integers.rs @@ -1,21 +1,21 @@ use winnow::{token::take_while, Bytes, Parser}; -use super::IMResult; +use super::MResult; -pub fn parse_u16(input: &Bytes) -> IMResult<&Bytes, u16> { - winnow::binary::u16(winnow::binary::Endianness::Big).parse_peek(input) +pub fn parse_u16<'i>(input: &mut &'i Bytes) -> MResult { + winnow::binary::u16(winnow::binary::Endianness::Big).parse_next(input) } -pub fn parse_u32(input: &Bytes) -> IMResult<&Bytes, u32> { - winnow::binary::u32(winnow::binary::Endianness::Big).parse_peek(input) +pub fn parse_u32<'i>(input: &mut &'i Bytes) -> MResult { + winnow::binary::u32(winnow::binary::Endianness::Big).parse_next(input) } -pub fn parse_variable(input: &Bytes) -> IMResult<&Bytes, u32> { +pub fn parse_variable<'i>(input: &mut &'i Bytes) -> MResult { let var_bytes = ( take_while(0..=3, |b| b & 0b1000_0000 != 0), winnow::binary::u8.verify(|b: &u8| b & 0b1000_0000 == 0), ); - let (input, bytes) = var_bytes.recognize().parse_peek(input)?; + let bytes = var_bytes.recognize().parse_next(input)?; let mut output: u32 = 0; @@ -23,7 +23,7 @@ pub fn parse_variable(input: &Bytes) -> IMResult<&Bytes, u32> { output += (*val as u32 & 0b0111_1111) * 128u32.pow(exp as u32); } - Ok((input, output)) + Ok(output) } #[cfg(test)] @@ -35,69 +35,42 @@ mod tests { #[test] fn check_integer_parsing() { let input = 15u16.to_be_bytes(); - assert_eq!( - parse_u16(Bytes::new(&input)).unwrap(), - (Bytes::new(&[]), 15) - ); + assert_eq!(parse_u16(&mut Bytes::new(&input)).unwrap(), 15); let input = 42u32.to_be_bytes(); - assert_eq!( - parse_u32(Bytes::new(&input)).unwrap(), - (Bytes::new(&[]), 42) - ); + assert_eq!(parse_u32(&mut Bytes::new(&input)).unwrap(), 42); } #[test] fn check_variable_integers() { let input = [0x0]; - assert_eq!( - parse_variable(Bytes::new(&input)).unwrap(), - (Bytes::new(&[]), 0) - ); + assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 0); let input = [0x7F]; - assert_eq!( - parse_variable(Bytes::new(&input)).unwrap(), - (Bytes::new(&[]), 127) - ); + assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 127); let input = [0x80, 0x01]; - assert_eq!( - parse_variable(Bytes::new(&input)).unwrap(), - (Bytes::new(&[]), 128) - ); + assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 128); let input = [0xFF, 0x7F]; - assert_eq!( - parse_variable(Bytes::new(&input)).unwrap(), - (Bytes::new(&[]), 16_383) - ); + assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 16_383); let input = [0x80, 0x80, 0x01]; - assert_eq!( - parse_variable(Bytes::new(&input)).unwrap(), - (Bytes::new(&[]), 16_384) - ); + assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 16_384); let input = [0xFF, 0xFF, 0x7F]; - assert_eq!( - parse_variable(Bytes::new(&input)).unwrap(), - (Bytes::new(&[]), 2_097_151) - ); + assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 2_097_151); let input = [0x80, 0x80, 0x80, 0x01]; - assert_eq!( - parse_variable(Bytes::new(&input)).unwrap(), - (Bytes::new(&[]), 2_097_152) - ); + assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 2_097_152); let input = [0xFF, 0xFF, 0xFF, 0x7F]; assert_eq!( - parse_variable(Bytes::new(&input)).unwrap(), - (Bytes::new(&[]), 268_435_455) + parse_variable(&mut Bytes::new(&input)).unwrap(), + 268_435_455 ); let input = [0xFF, 0xFF, 0xFF, 0x8F]; - parse_variable(Bytes::new(&input)).unwrap_err(); + parse_variable(&mut Bytes::new(&input)).unwrap_err(); } } diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index dc12d9cd..5dce6a25 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -1,3 +1,4 @@ mod integers; +mod strings; -pub type IMResult = winnow::IResult; +pub type MResult = winnow::PResult; From a49831b197098e38962fcf42cff1b07984c8c622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Mar 2024 13:19:17 +0100 Subject: [PATCH 06/90] Add strings module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/strings.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 mqtt-format/src/v5/strings.rs diff --git a/mqtt-format/src/v5/strings.rs b/mqtt-format/src/v5/strings.rs new file mode 100644 index 00000000..fc5d6d91 --- /dev/null +++ b/mqtt-format/src/v5/strings.rs @@ -0,0 +1,35 @@ +use winnow::{ + binary::length_take, + error::{ErrMode, FromExternalError}, + Bytes, Parser, +}; + +use super::{integers::parse_u16, MResult}; + +pub fn parse_string<'i>(input: &mut &'i Bytes) -> MResult<&'i str> { + let maybe_str = length_take(parse_u16).parse_next(input)?; + + std::str::from_utf8(maybe_str) + .map_err(|e| ErrMode::from_external_error(input, winnow::error::ErrorKind::Verify, e)) +} + +pub fn string_pair<'i>(input: &mut &'i Bytes) -> MResult<(&'i str, &'i str)> { + let first = parse_string(input)?; + let second = parse_string(input)?; + + Ok((first, second)) +} + +#[cfg(test)] +mod tests { + use winnow::Bytes; + + use crate::v5::strings::parse_string; + + #[test] + fn check_simple_string() { + let input = [0x0, 0x5, 0x41, 0xF0, 0xAA, 0x9B, 0x94]; + + assert_eq!(parse_string(&mut Bytes::new(&input)).unwrap(), "A𪛔"); + } +} From c3adb3fe470642399a1784969ffcc96ec3c8dc81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Mar 2024 13:22:17 +0100 Subject: [PATCH 07/90] Add binary data module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/bytes.rs | 21 +++++++++++++++++++++ mqtt-format/src/v5/mod.rs | 1 + 2 files changed, 22 insertions(+) create mode 100644 mqtt-format/src/v5/bytes.rs diff --git a/mqtt-format/src/v5/bytes.rs b/mqtt-format/src/v5/bytes.rs new file mode 100644 index 00000000..96413f1d --- /dev/null +++ b/mqtt-format/src/v5/bytes.rs @@ -0,0 +1,21 @@ +use winnow::{binary::length_take, Bytes, Parser}; + +use super::MResult; + +pub fn parse_data<'i>(input: &mut &'i Bytes) -> MResult<&'i [u8]> { + length_take(super::integers::parse_u16).parse_next(input) +} + +#[cfg(test)] +mod tests { + use winnow::Bytes; + + use crate::v5::bytes::parse_data; + + #[test] + fn check_binary_data() { + let input = &[0x0, 0x2, 0x4, 0x2]; + + assert_eq!(parse_data(&mut Bytes::new(input)).unwrap(), &[0x4, 0x2]); + } +} diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index 5dce6a25..868e80e9 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -1,4 +1,5 @@ mod integers; mod strings; +mod bytes; pub type MResult = winnow::PResult; From f2b75d86849ed1b4cbdd27af05f2c128a5301ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Mar 2024 14:07:56 +0100 Subject: [PATCH 08/90] Add fixed header parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/header.rs | 129 +++++++++++++++++++++++++++++++++++ mqtt-format/src/v5/mod.rs | 1 + 2 files changed, 130 insertions(+) create mode 100644 mqtt-format/src/v5/header.rs diff --git a/mqtt-format/src/v5/header.rs b/mqtt-format/src/v5/header.rs new file mode 100644 index 00000000..82e42b9e --- /dev/null +++ b/mqtt-format/src/v5/header.rs @@ -0,0 +1,129 @@ +use winnow::{ + binary::bits::bits, + error::{ErrMode, InputError, ParserError}, + Bytes, Parser, +}; + +use super::{integers::parse_variable, MResult}; + +#[derive(Debug, PartialEq)] +pub enum QualityOfService { + AtMostOnce, + AtLeastOnce, + ExactlyOnce, +} + +#[derive(Debug, PartialEq)] +pub enum PacketType { + Connect, + Connack, + Publish { + dup: bool, + qos: QualityOfService, + retain: bool, + }, + Puback, + Pubrec, + Pubrel, + Pubcomp, + Subscribe, + Suback, + Unsubscribe, + Unsuback, + Pingreq, + Pingresp, + Disconnect, + Auth, +} + +#[derive(Debug, PartialEq)] +pub struct MFixedHeader { + packet_type: PacketType, + remaining_length: u32, +} + +pub fn parse_fixed_header<'i>(input: &mut &'i Bytes) -> MResult { + let (packet_type, packet_flags): (u8, u8) = bits::<_, _, InputError<(_, usize)>, _, _>(( + winnow::binary::bits::take(4usize), + winnow::binary::bits::take(4usize), + )) + .parse_next(input) + .map_err(|_: ErrMode>| { + ErrMode::from_error_kind(input, winnow::error::ErrorKind::Slice) + })?; + + let packet_type = match (packet_type, packet_flags) { + (0, _) => { + return Err(ErrMode::from_error_kind( + input, + winnow::error::ErrorKind::Verify, + )) + } + (1, 0) => PacketType::Connect, + (2, 0) => PacketType::Connect, + (3, flags) => PacketType::Publish { + dup: (0b1000 & flags) != 0, + qos: match (flags & 0b0110) >> 1 { + 0 => QualityOfService::AtMostOnce, + 1 => QualityOfService::AtLeastOnce, + 2 => QualityOfService::ExactlyOnce, + _ => { + return Err(ErrMode::from_error_kind( + input, + winnow::error::ErrorKind::Verify, + )) + } + }, + retain: (0b0001 & flags) != 0, + }, + (4, 0) => PacketType::Puback, + (5, 0) => PacketType::Pubrec, + (6, 0b0010) => PacketType::Pubrel, + (7, 0) => PacketType::Pubcomp, + (8, 0b0010) => PacketType::Subscribe, + (9, 0) => PacketType::Suback, + (10, 0b0010) => PacketType::Unsubscribe, + (11, 0) => PacketType::Unsuback, + (12, 0) => PacketType::Pingreq, + (13, 0) => PacketType::Pingresp, + (14, 0) => PacketType::Disconnect, + (15, 0) => PacketType::Auth, + _ => { + return Err(ErrMode::from_error_kind( + input, + winnow::error::ErrorKind::Verify, + )) + } + }; + + let remaining_length = parse_variable(input)?; + + Ok(MFixedHeader { + packet_type, + remaining_length, + }) +} + +#[cfg(test)] +mod tests { + use winnow::Bytes; + + use crate::v5::fixed_header::{parse_fixed_header, MFixedHeader}; + + #[test] + fn check_fixed_header() { + let input = &[0b0011_1010, 0xA]; + + assert_eq!( + parse_fixed_header(&mut Bytes::new(&input)).unwrap(), + MFixedHeader { + packet_type: crate::v5::fixed_header::PacketType::Publish { + dup: true, + qos: crate::v5::fixed_header::QualityOfService::AtLeastOnce, + retain: false + }, + remaining_length: 10, + } + ) + } +} diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index 868e80e9..058d4c0a 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -1,5 +1,6 @@ mod integers; mod strings; mod bytes; +mod header; pub type MResult = winnow::PResult; From 501bffa1466b682c8972222f3478c344211bb71d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Mar 2024 14:51:29 +0100 Subject: [PATCH 09/90] Make all modules public MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They were made private before for no particular reason. Making them public should be fine as well. Signed-off-by: Marcel Müller --- mqtt-format/src/v5/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index 058d4c0a..726744cc 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -1,6 +1,6 @@ -mod integers; -mod strings; -mod bytes; -mod header; +pub mod bytes; +pub mod header; +pub mod integers; +pub mod strings; pub type MResult = winnow::PResult; From 6d96d70c4b6e58c4bd8db2f8f71fd89f7b52181b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Mar 2024 14:52:29 +0100 Subject: [PATCH 10/90] Rename header to fixed header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/{header.rs => fixed_header.rs} | 0 mqtt-format/src/v5/mod.rs | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename mqtt-format/src/v5/{header.rs => fixed_header.rs} (100%) diff --git a/mqtt-format/src/v5/header.rs b/mqtt-format/src/v5/fixed_header.rs similarity index 100% rename from mqtt-format/src/v5/header.rs rename to mqtt-format/src/v5/fixed_header.rs diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index 726744cc..73502bf7 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -1,5 +1,5 @@ pub mod bytes; -pub mod header; +pub mod fixed_header; pub mod integers; pub mod strings; From c28bdc88e9ef3633b7439a9657f54844ad1e109e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Mon, 18 Mar 2024 15:30:25 +0100 Subject: [PATCH 11/90] Impl variable header datatypes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Matthias Beyer Signed-off-by: Marcel Müller --- mqtt-format/src/v5/mod.rs | 1 + mqtt-format/src/v5/variable_header.rs | 96 +++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 mqtt-format/src/v5/variable_header.rs diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index 73502bf7..3deea5ce 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -1,5 +1,6 @@ pub mod bytes; pub mod fixed_header; +pub mod variable_header; pub mod integers; pub mod strings; diff --git a/mqtt-format/src/v5/variable_header.rs b/mqtt-format/src/v5/variable_header.rs new file mode 100644 index 00000000..99c9654c --- /dev/null +++ b/mqtt-format/src/v5/variable_header.rs @@ -0,0 +1,96 @@ +use winnow::Bytes; + +use super::{integers::parse_u16, integers::parse_u32, MResult}; + +pub struct PacketIdentifier(pub u16); + +pub fn parse_packet_identifier<'i>(input: &mut &'i Bytes) -> MResult { + parse_u16(input).map(PacketIdentifier) +} + +macro_rules! define_properties { + ($name:ident $(< $tylt:lifetime >)? as $id:expr => parse with $parser:path as $($lt:lifetime)? $kind:ty) => { + define_properties!(@impl $name $($tylt)? as $id => $kind => |input: &mut &Bytes| -> MResult { + Ok(Self($parser(input)?)) + }); + }; + + ($name:ident $(< $tylt:lifetime >)? as $id:expr => parser: $parser:path as $($lt:lifetime)? $kind:ty) => { + define_properties!(@impl $name $($tylt)? as $id => $kind => |input: &mut & $($tylt)? Bytes| -> MResult { + #[allow(unused_imports)] + use winnow::Parser; + + Ok(Self($parser.parse_next(input)?)) + }); + }; + + (@impl $name:ident $($tylt:lifetime)? as $id:expr => $($lt:lifetime)? $kind:ty => $fun:expr) => { + pub struct $name < $($tylt)? >(pub $(& $lt)? $kind); + + impl<$($tylt)?> $name < $($tylt)? > { + const IDENTIFIER: u32 = $id; + + pub fn parse(input: &mut & $($tylt)? Bytes) -> MResult<$name <$($tylt)?>> { + $fun(input) + } + } + } +} + +pub enum Property<'i> { + PayloadFormatIndicator(PayloadFormatIndicator), + MessageExpiryInterval(MessageExpiryInterval), + ContentType(ContentType<'i>), + ResponseTopic(ResponseTopic<'i>), + CorrelationData(CorrelationData<'i>), + SubscriptionIdentifier(SubscriptionIdentifier), + SessionExpiryInterval(SessionExpiryInterval), + AssignedClientIdentifier(AssignedClientIdentifier<'i>), + ServerKeepAlive(ServerKeepAlive), + AuthenticationMethod(AuthenticationMethod<'i>), + AuthenticationData(AuthenticationData<'i>), + RequestProblemInformation(RequestProblemInformation), + WillDelayInterval(WillDelayInterval), + RequestResponseInformation(RequestResponseInformation), + ResponseInformation(ResponseInformation<'i>), + ServerReference(ServerReference<'i>), + ReasonString(ReasonString<'i>), + ReceiveMaximum(ReceiveMaximum), + TopicAliasMaximum(TopicAliasMaximum), + TopicAlias(TopicAlias), + MaximumQoS(MaximumQoS), + RetainAvailable(RetainAvailable), + UserProperty(UserProperty<'i>), + MaximumPacketSize(MaximumPacketSize), + WildcardSubscriptionAvailable(WildcardSubscriptionAvailable), + SubscriptionIdentifiersAvailable(SubscriptionIdentifiersAvailable), + SharedSubscriptionAvailable(SharedSubscriptionAvailable), +} + +define_properties!(PayloadFormatIndicator as 0x01 => parse with winnow::binary::u8 as u8); +define_properties!(MessageExpiryInterval as 0x02 => parser: parse_u32 as u32); +define_properties!(ContentType<'i> as 0x03 => parser: super::strings::parse_string as &'i str); +define_properties!(ResponseTopic<'i> as 0x08 => parser: super::strings::parse_string as &'i str); +define_properties!(CorrelationData<'i> as 0x09 => parser: super::bytes::parse_data as &'i [u8]); +define_properties!(SubscriptionIdentifier as 0x0B => parser: parse_u32 as u32); +define_properties!(SessionExpiryInterval as 0x11 => parser: parse_u32 as u32); +define_properties!(AssignedClientIdentifier<'i> as 0x12 => parser: super::strings::parse_string as &'i str); +define_properties!(ServerKeepAlive as 0x13 => parser: parse_u32 as u32); +define_properties!(AuthenticationMethod<'i> as 0x15 => parser: super::strings::parse_string as &'i str); +define_properties!(AuthenticationData<'i> as 0x16 => parser: super::bytes::parse_data as &'i [u8]); +define_properties!(RequestProblemInformation as 0x17 => parse with winnow::binary::u8 as u8); +define_properties!(WillDelayInterval as 0x18 => parser: parse_u32 as u32); +define_properties!(RequestResponseInformation as 0x19 => parse with winnow::binary::u8 as u8); +define_properties!(ResponseInformation<'i> as 0x1A => parser: super::strings::parse_string as &'i str); +define_properties!(ServerReference<'i> as 0x1C => parser: super::strings::parse_string as &'i str); +define_properties!(ReasonString<'i> as 0x1F => parser: super::strings::parse_string as &'i str); +define_properties!(ReceiveMaximum as 0x21 => parser: parse_u32 as u32); +define_properties!(TopicAliasMaximum as 0x22 => parser: parse_u32 as u32); +define_properties!(TopicAlias as 0x23 => parser: parse_u32 as u32); +define_properties!(MaximumQoS as 0x24 => parse with winnow::binary::u8 as u8); +define_properties!(RetainAvailable as 0x25 => parse with winnow::binary::u8 as u8); +define_properties!(UserProperty<'i> as 0x26 => parser: super::strings::string_pair as (&'i str, &'i str )); +define_properties!(MaximumPacketSize as 0x27 => parser: parse_u32 as u32); +define_properties!(WildcardSubscriptionAvailable as 0x28 => parse with winnow::binary::u8 as u8); +define_properties!(SubscriptionIdentifiersAvailable as 0x29 => parse with winnow::binary::u8 as u8); +define_properties!(SharedSubscriptionAvailable as 0x2A => parse with winnow::binary::u8 as u8); From d625c3fbf4a8c0e20c79c43644c3fd90bca3518c Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 18 Mar 2024 16:09:37 +0100 Subject: [PATCH 12/90] Add parser for ReasonCode Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/mod.rs | 3 +- mqtt-format/src/v5/reason_code.rs | 169 ++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 mqtt-format/src/v5/reason_code.rs diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index 3deea5ce..362a6e33 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -1,7 +1,8 @@ pub mod bytes; pub mod fixed_header; -pub mod variable_header; pub mod integers; +pub mod reason_code; pub mod strings; +pub mod variable_header; pub type MResult = winnow::PResult; diff --git a/mqtt-format/src/v5/reason_code.rs b/mqtt-format/src/v5/reason_code.rs new file mode 100644 index 00000000..473d6d68 --- /dev/null +++ b/mqtt-format/src/v5/reason_code.rs @@ -0,0 +1,169 @@ +use winnow::{ + error::{ErrMode, ParserError}, + Bytes, +}; + +use super::{fixed_header::PacketType, MResult}; + +#[derive(Debug, PartialEq)] +pub enum MReasonCode { + Success, + NormalDisconnection, + GrantedQoS0, + GrantedQoS1, + GrantedQoS2, + DisconnectWithWillMessage, + NoMatchingSubscribers, + NoSubscriptionExisted, + ContinueAuthentication, + ReAuthenticate, + UnspecifiedError, + MalformedPacket, + ProtocolError, + ImplementationSpecificError, + UnsupportedProtocolVersion, + ClientIdentifierNotValid, + BadUsernameOrPassword, + NotAuthorized, + ServerUnavailable, + ServerBusy, + Banned, + ServerShuttingDown, + BadAuthenticationMethod, + KeepAliveTimeout, + SessionTakenOver, + TopicFilterInvalid, + TopicNameInvalid, + PacketIdentifierInUse, + PacketIdentifierNotFound, + ReceiveMaximumExceeded, + TopicAliasInvalid, + PacketTooLarge, + MessageRateTooHigh, + QuotaExceeded, + AdministrativeAction, + PayloadFormatInvalid, + RetainNotSupported, + QoSNotSupported, + UseAnotherServer, + ServerMoved, + SharedSubscriptionsNotSupported, + ConnectionRateExceeded, + MaximumConnectTime, + SubscriptionIdentifiersNotSupported, + WildcardSubscriptionsNotSupported, +} + +impl MReasonCode { + pub fn parse_for_packet_type<'i>( + input: &mut &'i Bytes, + packet_type: &PacketType, + ) -> MResult { + let byte = winnow::binary::u8(input)?; + + let code = match (byte, packet_type) { + (0x00, PacketType::Connack) => MReasonCode::Success, + (0x00, PacketType::Puback) => MReasonCode::Success, + (0x00, PacketType::Pubrec) => MReasonCode::Success, + (0x00, PacketType::Pubrel) => MReasonCode::Success, + (0x00, PacketType::Pubcomp) => MReasonCode::Success, + (0x00, PacketType::Unsuback) => MReasonCode::Success, + (0x00, PacketType::Auth) => MReasonCode::Success, + (0x00, PacketType::Disconnect) => MReasonCode::NormalDisconnection, + (0x00, PacketType::Suback) => MReasonCode::GrantedQoS0, + (0x01, PacketType::Suback) => MReasonCode::GrantedQoS1, + (0x02, PacketType::Suback) => MReasonCode::GrantedQoS2, + (0x04, PacketType::Disconnect) => MReasonCode::DisconnectWithWillMessage, + (0x10, PacketType::Puback) => MReasonCode::NoMatchingSubscribers, + (0x10, PacketType::Pubrec) => MReasonCode::NoMatchingSubscribers, + (0x11, PacketType::Unsuback) => MReasonCode::NoSubscriptionExisted, + (0x18, PacketType::Auth) => MReasonCode::ContinueAuthentication, + (0x19, PacketType::Auth) => MReasonCode::ReAuthenticate, + (0x80, PacketType::Connack) => MReasonCode::UnspecifiedError, + (0x80, PacketType::Puback) => MReasonCode::UnspecifiedError, + (0x80, PacketType::Pubrec) => MReasonCode::UnspecifiedError, + (0x80, PacketType::Suback) => MReasonCode::UnspecifiedError, + (0x80, PacketType::Unsuback) => MReasonCode::UnspecifiedError, + (0x80, PacketType::Disconnect) => MReasonCode::UnspecifiedError, + (0x81, PacketType::Connack) => MReasonCode::MalformedPacket, + (0x81, PacketType::Disconnect) => MReasonCode::MalformedPacket, + (0x82, PacketType::Connack) => MReasonCode::ProtocolError, + (0x82, PacketType::Disconnect) => MReasonCode::ProtocolError, + (0x83, PacketType::Connack) => MReasonCode::ImplementationSpecificError, + (0x83, PacketType::Puback) => MReasonCode::ImplementationSpecificError, + (0x83, PacketType::Pubrec) => MReasonCode::ImplementationSpecificError, + (0x83, PacketType::Suback) => MReasonCode::ImplementationSpecificError, + (0x83, PacketType::Unsuback) => MReasonCode::ImplementationSpecificError, + (0x83, PacketType::Disconnect) => MReasonCode::ImplementationSpecificError, + (0x84, PacketType::Connack) => MReasonCode::UnsupportedProtocolVersion, + (0x85, PacketType::Connack) => MReasonCode::ClientIdentifierNotValid, + (0x86, PacketType::Connack) => MReasonCode::BadUsernameOrPassword, + (0x87, PacketType::Connack) => MReasonCode::NotAuthorized, + (0x87, PacketType::Puback) => MReasonCode::NotAuthorized, + (0x87, PacketType::Pubrec) => MReasonCode::NotAuthorized, + (0x87, PacketType::Suback) => MReasonCode::NotAuthorized, + (0x87, PacketType::Unsuback) => MReasonCode::NotAuthorized, + (0x87, PacketType::Disconnect) => MReasonCode::NotAuthorized, + (0x88, PacketType::Connack) => MReasonCode::ServerUnavailable, + (0x89, PacketType::Connack) => MReasonCode::ServerBusy, + (0x89, PacketType::Disconnect) => MReasonCode::ServerBusy, + (0x8A, PacketType::Connack) => MReasonCode::Banned, + (0x8B, PacketType::Disconnect) => MReasonCode::ServerShuttingDown, + (0x8C, PacketType::Connack) => MReasonCode::BadAuthenticationMethod, + (0x8C, PacketType::Disconnect) => MReasonCode::BadAuthenticationMethod, + (0x8D, PacketType::Disconnect) => MReasonCode::KeepAliveTimeout, + (0x8E, PacketType::Disconnect) => MReasonCode::SessionTakenOver, + (0x8F, PacketType::Suback) => MReasonCode::TopicFilterInvalid, + (0x8F, PacketType::Unsuback) => MReasonCode::TopicFilterInvalid, + (0x8F, PacketType::Disconnect) => MReasonCode::TopicFilterInvalid, + (0x90, PacketType::Connack) => MReasonCode::TopicNameInvalid, + (0x90, PacketType::Puback) => MReasonCode::TopicNameInvalid, + (0x90, PacketType::Pubrec) => MReasonCode::TopicNameInvalid, + (0x90, PacketType::Disconnect) => MReasonCode::TopicNameInvalid, + (0x91, PacketType::Puback) => MReasonCode::PacketIdentifierInUse, + (0x91, PacketType::Pubrec) => MReasonCode::PacketIdentifierInUse, + (0x91, PacketType::Suback) => MReasonCode::PacketIdentifierInUse, + (0x91, PacketType::Unsuback) => MReasonCode::PacketIdentifierInUse, + (0x92, PacketType::Pubrel) => MReasonCode::PacketIdentifierNotFound, + (0x92, PacketType::Pubcomp) => MReasonCode::PacketIdentifierNotFound, + (0x93, PacketType::Disconnect) => MReasonCode::ReceiveMaximumExceeded, + (0x94, PacketType::Disconnect) => MReasonCode::TopicAliasInvalid, + (0x95, PacketType::Connack) => MReasonCode::PacketTooLarge, + (0x95, PacketType::Disconnect) => MReasonCode::PacketTooLarge, + (0x96, PacketType::Disconnect) => MReasonCode::MessageRateTooHigh, + (0x97, PacketType::Connack) => MReasonCode::QuotaExceeded, + (0x97, PacketType::Puback) => MReasonCode::QuotaExceeded, + (0x97, PacketType::Pubrec) => MReasonCode::QuotaExceeded, + (0x97, PacketType::Suback) => MReasonCode::QuotaExceeded, + (0x97, PacketType::Disconnect) => MReasonCode::QuotaExceeded, + (0x98, PacketType::Disconnect) => MReasonCode::AdministrativeAction, + (0x99, PacketType::Connack) => MReasonCode::PayloadFormatInvalid, + (0x99, PacketType::Puback) => MReasonCode::PayloadFormatInvalid, + (0x99, PacketType::Pubrec) => MReasonCode::PayloadFormatInvalid, + (0x99, PacketType::Disconnect) => MReasonCode::PayloadFormatInvalid, + (0x9A, PacketType::Connack) => MReasonCode::RetainNotSupported, + (0x9A, PacketType::Disconnect) => MReasonCode::RetainNotSupported, + (0x9B, PacketType::Connack) => MReasonCode::QoSNotSupported, + (0x9B, PacketType::Disconnect) => MReasonCode::QoSNotSupported, + (0x9C, PacketType::Connack) => MReasonCode::UseAnotherServer, + (0x9C, PacketType::Disconnect) => MReasonCode::UseAnotherServer, + (0x9D, PacketType::Connack) => MReasonCode::ServerMoved, + (0x9D, PacketType::Disconnect) => MReasonCode::ServerMoved, + (0x9E, PacketType::Suback) => MReasonCode::SharedSubscriptionsNotSupported, + (0x9E, PacketType::Disconnect) => MReasonCode::SharedSubscriptionsNotSupported, + (0x9F, PacketType::Connack) => MReasonCode::ConnectionRateExceeded, + (0x9F, PacketType::Disconnect) => MReasonCode::ConnectionRateExceeded, + (0xA0, PacketType::Disconnect) => MReasonCode::MaximumConnectTime, + (0xA1, PacketType::Suback) => MReasonCode::SubscriptionIdentifiersNotSupported, + (0xA1, PacketType::Disconnect) => MReasonCode::SubscriptionIdentifiersNotSupported, + (0xA2, PacketType::Suback) => MReasonCode::WildcardSubscriptionsNotSupported, + (0xA2, PacketType::Disconnect) => MReasonCode::WildcardSubscriptionsNotSupported, + (_, _) => return Err(ErrMode::from_error_kind( + input, + winnow::error::ErrorKind::Verify, + )), + }; + + Ok(code) + } +} From f04399b1ca382c28fa7019fd13cbf7fd73117ff6 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 19 Mar 2024 08:26:28 +0100 Subject: [PATCH 13/90] Outsource QualityOfService parsing to helper fn Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/fixed_header.rs | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/mqtt-format/src/v5/fixed_header.rs b/mqtt-format/src/v5/fixed_header.rs index 82e42b9e..c33f090d 100644 --- a/mqtt-format/src/v5/fixed_header.rs +++ b/mqtt-format/src/v5/fixed_header.rs @@ -13,6 +13,20 @@ pub enum QualityOfService { ExactlyOnce, } +impl QualityOfService { + pub fn from_byte(u: u8, input: &mut &Bytes) -> MResult { + match u { + 0 => Ok(QualityOfService::AtMostOnce), + 1 => Ok(QualityOfService::AtLeastOnce), + 2 => Ok(QualityOfService::ExactlyOnce), + _ => Err(ErrMode::from_error_kind( + input, + winnow::error::ErrorKind::Verify, + )), + } + } +} + #[derive(Debug, PartialEq)] pub enum PacketType { Connect, @@ -63,17 +77,7 @@ pub fn parse_fixed_header<'i>(input: &mut &'i Bytes) -> MResult { (2, 0) => PacketType::Connect, (3, flags) => PacketType::Publish { dup: (0b1000 & flags) != 0, - qos: match (flags & 0b0110) >> 1 { - 0 => QualityOfService::AtMostOnce, - 1 => QualityOfService::AtLeastOnce, - 2 => QualityOfService::ExactlyOnce, - _ => { - return Err(ErrMode::from_error_kind( - input, - winnow::error::ErrorKind::Verify, - )) - } - }, + qos: QualityOfService::from_byte((flags & 0b0110) >> 1, input)?, retain: (0b0001 & flags) != 0, }, (4, 0) => PacketType::Puback, From 41fb3e993d1a2477b06674d835030673134d0ac2 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 19 Mar 2024 08:30:10 +0100 Subject: [PATCH 14/90] Add helper type for parsing protocol level Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/level.rs | 23 +++++++++++++++++++++++ mqtt-format/src/v5/mod.rs | 1 + 2 files changed, 24 insertions(+) create mode 100644 mqtt-format/src/v5/level.rs diff --git a/mqtt-format/src/v5/level.rs b/mqtt-format/src/v5/level.rs new file mode 100644 index 00000000..52c62589 --- /dev/null +++ b/mqtt-format/src/v5/level.rs @@ -0,0 +1,23 @@ +use winnow::error::{ErrMode, ParserError}; +use winnow::Bytes; + +use super::MResult; + +#[derive(PartialEq)] +pub enum ProtocolLevel { + V3, + V5, +} + +impl ProtocolLevel { + pub fn parse<'i>(input: &mut &'i Bytes) -> MResult { + match winnow::binary::u8(input)? { + 3 => Ok(Self::V3), + 5 => Ok(Self::V5), + _ => Err(ErrMode::from_error_kind( + input, + winnow::error::ErrorKind::Verify, + )), + } + } +} diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index 362a6e33..5c63c086 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -4,5 +4,6 @@ pub mod integers; pub mod reason_code; pub mod strings; pub mod variable_header; +pub mod level; pub type MResult = winnow::PResult; From cb1186903027b2c423d6ea274909d45497fe7bc2 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 19 Mar 2024 08:30:34 +0100 Subject: [PATCH 15/90] Add MControlVariableHeader type Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/mod.rs | 1 + mqtt-format/src/v5/packet/connect.rs | 42 ++++++++++++++++++++++++++++ mqtt-format/src/v5/packet/mod.rs | 1 + 3 files changed, 44 insertions(+) create mode 100644 mqtt-format/src/v5/packet/connect.rs create mode 100644 mqtt-format/src/v5/packet/mod.rs diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index 5c63c086..93d7036a 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -4,6 +4,7 @@ pub mod integers; pub mod reason_code; pub mod strings; pub mod variable_header; +pub mod packet; pub mod level; pub type MResult = winnow::PResult; diff --git a/mqtt-format/src/v5/packet/connect.rs b/mqtt-format/src/v5/packet/connect.rs new file mode 100644 index 00000000..a5fb17ea --- /dev/null +++ b/mqtt-format/src/v5/packet/connect.rs @@ -0,0 +1,42 @@ +use winnow::Bytes; + +use crate::v5::{fixed_header::QualityOfService, level::ProtocolLevel, MResult}; + +pub struct MControlVariableHeader<'i> { + protocol_name: &'i str, + protocol_level: ProtocolLevel, + + user_name_flag: bool, + password_flag: bool, + will_retain: bool, + will_qos: QualityOfService, + will_flag: bool, + clean_start: bool, +} + +impl<'i> MControlVariableHeader<'i> { + pub fn parse(input: &mut &'i Bytes) -> MResult> { + let protocol_name = crate::v5::strings::parse_string(input)?; + let protocol_level = ProtocolLevel::parse(input)?; + let connect_flags = winnow::binary::u8(input)?; + + let user_name_flag = 0b1000_0000 & connect_flags != 0; + let password_flag = 0b0100_0000 & connect_flags != 0; + let will_retain = 0b0010_0000 & connect_flags != 0; + let will_qos = QualityOfService::from_byte((0b0001_1000 & connect_flags) >> 3, input)?; + let will_flag = 0b0000_0100 & connect_flags != 0; + let clean_start = 0b0000_0001 & connect_flags != 0; + + Ok(Self { + protocol_name, + protocol_level, + + user_name_flag, + password_flag, + will_retain, + will_qos, + will_flag, + clean_start, + }) + } +} diff --git a/mqtt-format/src/v5/packet/mod.rs b/mqtt-format/src/v5/packet/mod.rs new file mode 100644 index 00000000..be684351 --- /dev/null +++ b/mqtt-format/src/v5/packet/mod.rs @@ -0,0 +1 @@ +pub mod connect; From a436f7a6e57bb1e74826801987c5e4073a741ba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Tue, 19 Mar 2024 09:30:38 +0100 Subject: [PATCH 16/90] Add connack packet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- Cargo.lock | 89 ++++++++++++++++++++++++++-- mqtt-format/Cargo.toml | 1 + mqtt-format/src/v5/packet/connack.rs | 70 ++++++++++++++++++++++ mqtt-format/src/v5/packet/mod.rs | 1 + 4 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 mqtt-format/src/v5/packet/connack.rs diff --git a/Cargo.lock b/Cargo.lock index 96f41c8d..caaac20a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -277,7 +277,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ "cfg-if", - "hashbrown", + "hashbrown 0.12.3", "lock_api", "once_cell", "parking_lot_core", @@ -289,6 +289,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.1" @@ -425,6 +431,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "heck" version = "0.4.0" @@ -452,6 +464,16 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cfe9645a18782869361d9c8732246be7b410ad4e919d3609ebabdac00ba12c3" +[[package]] +name = "indexmap" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + [[package]] name = "io-lifetimes" version = "1.0.3" @@ -604,10 +626,11 @@ dependencies = [ "futures", "nom", "nom-supreme", + "num_enum", "pretty_assertions", "thiserror", "tokio", - "winnow", + "winnow 0.6.5", "yoke", ] @@ -673,6 +696,27 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.13", +] + [[package]] name = "object" version = "0.30.1" @@ -746,11 +790,20 @@ dependencies = [ "yansi", ] +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" -version = "1.0.55" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0dd4be24fcdcfeaa12a432d588dc59bbad6cad3510c67e74a2b6b2fc950564" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -1073,6 +1126,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + [[package]] name = "tracing" version = "0.1.37" @@ -1147,7 +1217,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137" dependencies = [ - "hashbrown", + "hashbrown 0.12.3", "regex", ] @@ -1356,6 +1426,15 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "0.6.5" diff --git a/mqtt-format/Cargo.toml b/mqtt-format/Cargo.toml index 2be9b874..795eb812 100644 --- a/mqtt-format/Cargo.toml +++ b/mqtt-format/Cargo.toml @@ -18,6 +18,7 @@ yoke = ["dep:yoke"] futures = "0.3.28" nom = "7.1.3" nom-supreme = "0.8.0" +num_enum = "0.7.2" thiserror = "1.0.40" winnow = "0.6.5" yoke = { version = "0.7.0", features = ["derive"], optional = true } diff --git a/mqtt-format/src/v5/packet/connack.rs b/mqtt-format/src/v5/packet/connack.rs new file mode 100644 index 00000000..7aa6281a --- /dev/null +++ b/mqtt-format/src/v5/packet/connack.rs @@ -0,0 +1,70 @@ +use winnow::{ + error::{ErrMode, InputError, ParserError}, + Bytes, Parser, +}; + +use crate::v5::{fixed_header::PacketType, MResult}; + +#[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)] +#[repr(u8)] +pub enum ConnectReasonCode { + Success = 0, + UnspecifiedError = 0x80, + MalformedPacket = 0x81, + ProtocolError = 0x82, + ImplementationSpecificError = 0x84, + ClientIdentifierNotValid = 0x85, + BadUsernameOrPassword = 0x86, + NotAuthorized = 0x87, + ServerUnavailable = 0x88, + ServerBusy = 0x89, + Banned = 0x8A, + BadAuthenticationMethod = 0x8C, + TopicNameInvalid = 0x90, + PacketTooLarge = 0x95, + QuotaExceeded = 0x97, + PayloadFormatInvalid = 0x99, + RetainNotSupported = 0x9A, + QoSNotSupported = 0x9B, + UseAnotherServer = 0x9C, + ServerMoved = 0x9D, + ConnectionRateExceeded = 0x9F, +} + +impl ConnectReasonCode { + fn parse<'i>(input: &mut &'i Bytes) -> MResult { + winnow::binary::u8 + .try_map(ConnectReasonCode::try_from) + .parse_next(input) + } +} + +pub struct MConnack<'i> { + pub session_present: bool, + pub reason_code: ConnectReasonCode, + pd: &'i (), +} + +impl<'i> MConnack<'i> { + pub const PACKET_TYPE: PacketType = PacketType::Connack; + + pub fn parse(input: &mut &'i Bytes) -> MResult> { + let (session_present, _) = + winnow::binary::bits::bits::<_, _, InputError<(_, usize)>, _, _>(( + winnow::binary::bits::take(1usize).map(|b: u8| b == 1), + winnow::binary::bits::pattern(0b0000_000, 7usize), + )) + .parse_next(input) + .map_err(|_: ErrMode>| { + ErrMode::from_error_kind(input, winnow::error::ErrorKind::Slice) + })?; + + let reason_code = ConnectReasonCode::parse(input)?; + + Ok(MConnack { + session_present, + reason_code, + pd: &(), + }) + } +} diff --git a/mqtt-format/src/v5/packet/mod.rs b/mqtt-format/src/v5/packet/mod.rs index be684351..57e96c91 100644 --- a/mqtt-format/src/v5/packet/mod.rs +++ b/mqtt-format/src/v5/packet/mod.rs @@ -1 +1,2 @@ pub mod connect; +pub mod connack; From 5c49b76138c917b0590f274708cae1f51876cd66 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 19 Mar 2024 13:32:30 +0100 Subject: [PATCH 17/90] Define Property enum Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/variable_header.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mqtt-format/src/v5/variable_header.rs b/mqtt-format/src/v5/variable_header.rs index 99c9654c..acab080e 100644 --- a/mqtt-format/src/v5/variable_header.rs +++ b/mqtt-format/src/v5/variable_header.rs @@ -34,6 +34,12 @@ macro_rules! define_properties { $fun(input) } } + + impl<'i> From< $name <$($tylt)?> > for Property<'i> { + fn from(value: $name) -> Property<'i> { + Property::$name(value) + } + } } } From 001342b2e3c9b4adbce625b9adde3e09fe167f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Tue, 19 Mar 2024 15:32:20 +0100 Subject: [PATCH 18/90] Allow defining property sets from Properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/mod.rs | 1 + mqtt-format/src/v5/properties.rs | 92 +++++++++++++++++++++++++++ mqtt-format/src/v5/variable_header.rs | 60 ++++++++++++++--- 3 files changed, 144 insertions(+), 9 deletions(-) create mode 100644 mqtt-format/src/v5/properties.rs diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index 93d7036a..53387e4e 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -5,6 +5,7 @@ pub mod reason_code; pub mod strings; pub mod variable_header; pub mod packet; +pub mod properties; pub mod level; pub type MResult = winnow::PResult; diff --git a/mqtt-format/src/v5/properties.rs b/mqtt-format/src/v5/properties.rs new file mode 100644 index 00000000..c03e14e1 --- /dev/null +++ b/mqtt-format/src/v5/properties.rs @@ -0,0 +1,92 @@ +use winnow::{ + error::{ErrMode, ParserError}, + Bytes, +}; + +use super::MResult; + +pub struct MqttPropertySlot { + allow_repeat: bool, + slot: Option, +} + +impl MqttPropertySlot { + pub(crate) const fn new(allow_repeat: bool) -> MqttPropertySlot { + MqttPropertySlot { + allow_repeat, + slot: None, + } + } + + pub(crate) fn use_slot(&mut self, input: &mut &Bytes, new_slot: T) -> MResult<()> { + if self.slot.is_some() { + if self.allow_repeat { + return Ok(()); + } else { + return Err(ErrMode::from_error_kind( + input, + winnow::error::ErrorKind::Verify, + )); + } + } else { + self.slot = Some(new_slot); + } + + Ok(()) + } + + pub(crate) fn take_inner(self) -> Option { + self.slot + } +} + +macro_rules! define_properties { + (pub struct $name:ident <$lt:lifetime> { + $($prop_name:ident : $prop:ty),* $(,)? + }) => { + pub struct $name < $lt > { + $($prop_name: Option<$prop>),* + } + + impl<$lt> $name <$lt> { + pub fn parse(input: &mut & $lt winnow::Bytes) -> crate::v5::MResult<$name<$lt>> { + use winnow::Parser; + use winnow::error::ErrMode; + use winnow::error::ParserError; + use winnow::stream::Stream; + use $crate::v5::properties::MqttPropertySlot; + + $( + let mut $prop_name: MqttPropertySlot<$prop> = MqttPropertySlot::new(<$prop as crate::v5::variable_header::MqttProperties>::ALLOW_REPEATING); + )* + + let mut properties_bytes = winnow::Bytes::new(winnow::binary::length_take(crate::v5::integers::parse_variable).parse_next(input)?); + + while !properties_bytes.is_empty() { + let checkpoint = properties_bytes.checkpoint(); + let id = crate::v5::integers::parse_variable(&mut properties_bytes)?; + + $( + if <$prop as crate::v5::variable_header::MqttProperties>::IDENTIFIER == id { + let slot = <$prop as crate::v5::variable_header::MqttProperties>::parse(&mut properties_bytes)?; + $prop_name.use_slot(&mut properties_bytes, slot)?; + continue + } + )* + + input.reset(&checkpoint); + return Err(ErrMode::from_error_kind( + input, + winnow::error::ErrorKind::Verify, + )); + } + + + Ok( $name { + $($prop_name: $prop_name.take_inner()),* + }) + } + } + }; +} +pub(crate) use define_properties; diff --git a/mqtt-format/src/v5/variable_header.rs b/mqtt-format/src/v5/variable_header.rs index acab080e..7cec2767 100644 --- a/mqtt-format/src/v5/variable_header.rs +++ b/mqtt-format/src/v5/variable_header.rs @@ -1,4 +1,4 @@ -use winnow::Bytes; +use winnow::{Bytes, Parser}; use super::{integers::parse_u16, integers::parse_u32, MResult}; @@ -8,15 +8,27 @@ pub fn parse_packet_identifier<'i>(input: &mut &'i Bytes) -> MResult: Sized { + const IDENTIFIER: u32; + const ALLOW_REPEATING: bool; + + fn parse<'input>(input: &mut &'input Bytes) -> MResult + where + 'input: 'lt; +} + macro_rules! define_properties { + (@ignore $lt:lifetime $($rest:tt)*) => { + $lt + }; ($name:ident $(< $tylt:lifetime >)? as $id:expr => parse with $parser:path as $($lt:lifetime)? $kind:ty) => { - define_properties!(@impl $name $($tylt)? as $id => $kind => |input: &mut &Bytes| -> MResult { + define_properties!(@impl $name $($tylt)? as $id => $kind => input { Ok(Self($parser(input)?)) }); }; ($name:ident $(< $tylt:lifetime >)? as $id:expr => parser: $parser:path as $($lt:lifetime)? $kind:ty) => { - define_properties!(@impl $name $($tylt)? as $id => $kind => |input: &mut & $($tylt)? Bytes| -> MResult { + define_properties!(@impl $name $($tylt)? as $id => $kind => input { #[allow(unused_imports)] use winnow::Parser; @@ -24,19 +36,25 @@ macro_rules! define_properties { }); }; - (@impl $name:ident $($tylt:lifetime)? as $id:expr => $($lt:lifetime)? $kind:ty => $fun:expr) => { + (@impl $name:ident $($tylt:lifetime)? as $id:expr => $($lt:lifetime)? $kind:ty => $input:ident $fun:block) => { pub struct $name < $($tylt)? >(pub $(& $lt)? $kind); - impl<$($tylt)?> $name < $($tylt)? > { + impl<'lt $(, $tylt)?> MqttProperties<'lt> for $name < $($tylt)? > + $(where $tylt: 'lt, 'lt: $tylt)? + { const IDENTIFIER: u32 = $id; + const ALLOW_REPEATING: bool = false; - pub fn parse(input: &mut & $($tylt)? Bytes) -> MResult<$name <$($tylt)?>> { - $fun(input) + fn parse<'input>($input: &mut &'input Bytes) -> MResult<$name <$($tylt)?>> + where + 'input: 'lt + { + $fun } } impl<'i> From< $name <$($tylt)?> > for Property<'i> { - fn from(value: $name) -> Property<'i> { + fn from(value: $name <$($tylt)?>) -> Property<'i> { Property::$name(value) } } @@ -95,8 +113,32 @@ define_properties!(TopicAliasMaximum as 0x22 => parser: parse_u32 as u32); define_properties!(TopicAlias as 0x23 => parser: parse_u32 as u32); define_properties!(MaximumQoS as 0x24 => parse with winnow::binary::u8 as u8); define_properties!(RetainAvailable as 0x25 => parse with winnow::binary::u8 as u8); -define_properties!(UserProperty<'i> as 0x26 => parser: super::strings::string_pair as (&'i str, &'i str )); define_properties!(MaximumPacketSize as 0x27 => parser: parse_u32 as u32); define_properties!(WildcardSubscriptionAvailable as 0x28 => parse with winnow::binary::u8 as u8); define_properties!(SubscriptionIdentifiersAvailable as 0x29 => parse with winnow::binary::u8 as u8); define_properties!(SharedSubscriptionAvailable as 0x2A => parse with winnow::binary::u8 as u8); + +pub struct UserProperty<'i>(pub &'i [u8]); + +impl<'i> MqttProperties<'i> for UserProperty<'i> { + const IDENTIFIER: u32 = 0x26; + const ALLOW_REPEATING: bool = true; + + fn parse<'input>(input: &mut &'input Bytes) -> MResult + where + 'input: 'i, + { + let checkpoint = *input; + + // We only need to verify there is a correct string pair + let _ = crate::v5::strings::string_pair.parse_peek(input)?; + + Ok(Self(checkpoint.as_ref())) + } +} + +impl<'i> From> for Property<'i> { + fn from(value: UserProperty<'i>) -> Property<'i> { + Property::UserProperty(value) + } +} From 63e6e04d9550b19f1a8bc056331b820e4e349afb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 19 Mar 2024 09:34:49 +0100 Subject: [PATCH 19/90] Implement MConnect Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packet/connect.rs | 101 ++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 19 deletions(-) diff --git a/mqtt-format/src/v5/packet/connect.rs b/mqtt-format/src/v5/packet/connect.rs index a5fb17ea..ce74c74a 100644 --- a/mqtt-format/src/v5/packet/connect.rs +++ b/mqtt-format/src/v5/packet/connect.rs @@ -1,21 +1,39 @@ use winnow::Bytes; -use crate::v5::{fixed_header::QualityOfService, level::ProtocolLevel, MResult}; +use crate::v5::{ + bytes::parse_data, fixed_header::{PacketType, QualityOfService}, integers::{parse_u16, parse_u32, parse_variable}, level::ProtocolLevel, strings::parse_string, variable_header::{AuthenticationData, AuthenticationMethod, ContentType, CorrelationData, MaximumPacketSize, MessageExpiryInterval, PayloadFormatIndicator, ReceiveMaximum, RequestProblemInformation, RequestResponseInformation, ResponseTopic, SessionExpiryInterval, TopicAliasMaximum, UserProperty, WillDelayInterval}, MResult +}; -pub struct MControlVariableHeader<'i> { - protocol_name: &'i str, - protocol_level: ProtocolLevel, +use super::payload::ApplicationMessagePayload; - user_name_flag: bool, - password_flag: bool, - will_retain: bool, - will_qos: QualityOfService, - will_flag: bool, +pub struct MConnect<'i> { + client_identifier: &'i str, + username: Option<&'i str>, + password: Option<&'i [u8]>, clean_start: bool, + will: Option>, + properties: ConnectProperties<'i>, } -impl<'i> MControlVariableHeader<'i> { - pub fn parse(input: &mut &'i Bytes) -> MResult> { +crate::v5::properties::define_properties! { + pub struct ConnectProperties<'i> { + session_expiry_interval: SessionExpiryInterval, + receive_maximum: ReceiveMaximum, + maximum_packet_size: MaximumPacketSize, + topic_alias_maximum: TopicAliasMaximum, + request_response_information: RequestResponseInformation, + request_problem_information: RequestProblemInformation, + user_property: UserProperty<'i>, + authentication_method: AuthenticationMethod<'i>, + authentication_data: AuthenticationData<'i>, + } +} + +impl<'i> MConnect<'i> { + const PACKET_TYPE: PacketType = PacketType::Connect; + + pub fn parse(input: &mut &'i Bytes) -> MResult { + // parse header let protocol_name = crate::v5::strings::parse_string(input)?; let protocol_level = ProtocolLevel::parse(input)?; let connect_flags = winnow::binary::u8(input)?; @@ -27,16 +45,61 @@ impl<'i> MControlVariableHeader<'i> { let will_flag = 0b0000_0100 & connect_flags != 0; let clean_start = 0b0000_0001 & connect_flags != 0; + let keep_alive = parse_u16(input)?; + + let properties = ConnectProperties::parse(input)?; + + // finished parsing header, now parse payload + + let client_identifier = { + let client_identifier = parse_string(input)?; + if client_identifier.len() == 0 { + // Generate client ID? + } + client_identifier + }; + + let will = will_flag + .then(|| { + let properties = ConnectWillProperties::parse(input)?; + let topic = parse_string(input)?; + let payload = ApplicationMessagePayload::parse(input)?; + + Ok(Will { + properties, + topic, + payload, + }) + }) + .transpose()?; + + let username = user_name_flag.then(|| parse_string(input)).transpose()?; + let password = password_flag.then(|| parse_data(input)).transpose()?; + Ok(Self { - protocol_name, - protocol_level, - - user_name_flag, - password_flag, - will_retain, - will_qos, - will_flag, + client_identifier, + username, + password, + will, clean_start, + properties, }) } } + +pub struct Will<'i> { + properties: ConnectWillProperties<'i>, + topic: &'i str, + payload: ApplicationMessagePayload<'i>, +} + +crate::v5::properties::define_properties! { + pub struct ConnectWillProperties<'i> { + will_delay_interval: WillDelayInterval, + payload_format_indicator: PayloadFormatIndicator, + message_expiry_interval: MessageExpiryInterval, + content_type: ContentType<'i>, + response_topic: ResponseTopic<'i>, + correlation_data: CorrelationData<'i>, + } +} From 85e624479f7b051705f77edf914b061c110a4b31 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Tue, 19 Mar 2024 09:55:52 +0100 Subject: [PATCH 20/90] Add ApplicationMessagePayload helper type Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packet/mod.rs | 1 + mqtt-format/src/v5/packet/payload.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 mqtt-format/src/v5/packet/payload.rs diff --git a/mqtt-format/src/v5/packet/mod.rs b/mqtt-format/src/v5/packet/mod.rs index 57e96c91..fc4f1029 100644 --- a/mqtt-format/src/v5/packet/mod.rs +++ b/mqtt-format/src/v5/packet/mod.rs @@ -1,2 +1,3 @@ pub mod connect; pub mod connack; +pub mod payload; diff --git a/mqtt-format/src/v5/packet/payload.rs b/mqtt-format/src/v5/packet/payload.rs new file mode 100644 index 00000000..e39aeee4 --- /dev/null +++ b/mqtt-format/src/v5/packet/payload.rs @@ -0,0 +1,15 @@ +use winnow::Bytes; + +use crate::v5::MResult; + +pub struct ApplicationMessagePayload<'i> { + payload: &'i [u8] +} + +impl<'i> ApplicationMessagePayload<'i> { + pub fn parse(input: &mut &'i Bytes) -> MResult { + crate::v5::bytes::parse_data(input).map(|payload| Self { payload }) + } +} + + From 66ce78cf3981797489be452da215587608733627 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 07:03:12 +0100 Subject: [PATCH 21/90] Implement MPublish Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packet/mod.rs | 1 + mqtt-format/src/v5/packet/publish.rs | 61 ++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 mqtt-format/src/v5/packet/publish.rs diff --git a/mqtt-format/src/v5/packet/mod.rs b/mqtt-format/src/v5/packet/mod.rs index fc4f1029..59cd984d 100644 --- a/mqtt-format/src/v5/packet/mod.rs +++ b/mqtt-format/src/v5/packet/mod.rs @@ -1,3 +1,4 @@ pub mod connect; pub mod connack; pub mod payload; +pub mod publish; diff --git a/mqtt-format/src/v5/packet/publish.rs b/mqtt-format/src/v5/packet/publish.rs new file mode 100644 index 00000000..c70aae1f --- /dev/null +++ b/mqtt-format/src/v5/packet/publish.rs @@ -0,0 +1,61 @@ +use winnow::{ + error::{ErrMode, ParserError}, + stream::Stream, + Bytes, +}; + +use crate::v5::{ + variable_header::{ + ContentType, CorrelationData, MessageExpiryInterval, PayloadFormatIndicator, ResponseTopic, + SubscriptionIdentifier, TopicAlias, UserProperty, + }, + MResult, +}; + +pub struct MPublish<'i> { + topic_name: &'i str, + packet_identifier: crate::v5::variable_header::PacketIdentifier, + properties: PublishProperties<'i>, + payload: &'i [u8], +} + +crate::v5::properties::define_properties! { + pub struct PublishProperties<'i> { + payload_format_indicator: PayloadFormatIndicator, + message_expiry_interval: MessageExpiryInterval, + topic_alias: TopicAlias, + response_topic: ResponseTopic<'i>, + correlation_data: CorrelationData<'i>, + user_property: UserProperty<'i>, + subscription_identifier: SubscriptionIdentifier, + content_type: ContentType<'i>, + } +} + +impl<'i> MPublish<'i> { + pub fn parse(input: &mut &'i Bytes) -> MResult { + let topic_name = crate::v5::strings::parse_string(input)?; + if !sanity_check_topic_name(&topic_name) { + return Err(ErrMode::from_error_kind( + input, + winnow::error::ErrorKind::Verify, + )); + } + + let packet_identifier = crate::v5::variable_header::parse_packet_identifier(input)?; + let properties = PublishProperties::parse(input)?; + + let payload = input.finish(); + + Ok(Self { + topic_name, + packet_identifier, + properties, + payload, + }) + } +} + +fn sanity_check_topic_name(topic_name: &str) -> bool { + topic_name.chars().all(|c| c != '#' && c != '*') +} From 3e9f0f7e73e1df9c7a686152ac6e95130d6c448b Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 08:42:13 +0100 Subject: [PATCH 22/90] Redefine how reason codes are constructed Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/reason_code.rs | 236 +++++++++--------------------- 1 file changed, 72 insertions(+), 164 deletions(-) diff --git a/mqtt-format/src/v5/reason_code.rs b/mqtt-format/src/v5/reason_code.rs index 473d6d68..38426f60 100644 --- a/mqtt-format/src/v5/reason_code.rs +++ b/mqtt-format/src/v5/reason_code.rs @@ -1,169 +1,77 @@ -use winnow::{ - error::{ErrMode, ParserError}, - Bytes, -}; +macro_rules! make_combined_reason_code { + (pub enum $name:ident { + $($reason_code_name:ident = $reason_code_type:ty),* $(,)? + }) => { + #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)] + #[repr(u8)] + pub enum $name { + $( $reason_code_name = <$reason_code_type>::CODE ),* + } -use super::{fixed_header::PacketType, MResult}; - -#[derive(Debug, PartialEq)] -pub enum MReasonCode { - Success, - NormalDisconnection, - GrantedQoS0, - GrantedQoS1, - GrantedQoS2, - DisconnectWithWillMessage, - NoMatchingSubscribers, - NoSubscriptionExisted, - ContinueAuthentication, - ReAuthenticate, - UnspecifiedError, - MalformedPacket, - ProtocolError, - ImplementationSpecificError, - UnsupportedProtocolVersion, - ClientIdentifierNotValid, - BadUsernameOrPassword, - NotAuthorized, - ServerUnavailable, - ServerBusy, - Banned, - ServerShuttingDown, - BadAuthenticationMethod, - KeepAliveTimeout, - SessionTakenOver, - TopicFilterInvalid, - TopicNameInvalid, - PacketIdentifierInUse, - PacketIdentifierNotFound, - ReceiveMaximumExceeded, - TopicAliasInvalid, - PacketTooLarge, - MessageRateTooHigh, - QuotaExceeded, - AdministrativeAction, - PayloadFormatInvalid, - RetainNotSupported, - QoSNotSupported, - UseAnotherServer, - ServerMoved, - SharedSubscriptionsNotSupported, - ConnectionRateExceeded, - MaximumConnectTime, - SubscriptionIdentifiersNotSupported, - WildcardSubscriptionsNotSupported, + impl $name { + pub fn parse(input: &mut &winnow::Bytes) -> crate::v5::MResult { + use winnow::Parser; + winnow::binary::u8 + .try_map($name::try_from) + .parse_next(input) + } + } + } } +pub(crate) use make_combined_reason_code; -impl MReasonCode { - pub fn parse_for_packet_type<'i>( - input: &mut &'i Bytes, - packet_type: &PacketType, - ) -> MResult { - let byte = winnow::binary::u8(input)?; - - let code = match (byte, packet_type) { - (0x00, PacketType::Connack) => MReasonCode::Success, - (0x00, PacketType::Puback) => MReasonCode::Success, - (0x00, PacketType::Pubrec) => MReasonCode::Success, - (0x00, PacketType::Pubrel) => MReasonCode::Success, - (0x00, PacketType::Pubcomp) => MReasonCode::Success, - (0x00, PacketType::Unsuback) => MReasonCode::Success, - (0x00, PacketType::Auth) => MReasonCode::Success, - (0x00, PacketType::Disconnect) => MReasonCode::NormalDisconnection, - (0x00, PacketType::Suback) => MReasonCode::GrantedQoS0, - (0x01, PacketType::Suback) => MReasonCode::GrantedQoS1, - (0x02, PacketType::Suback) => MReasonCode::GrantedQoS2, - (0x04, PacketType::Disconnect) => MReasonCode::DisconnectWithWillMessage, - (0x10, PacketType::Puback) => MReasonCode::NoMatchingSubscribers, - (0x10, PacketType::Pubrec) => MReasonCode::NoMatchingSubscribers, - (0x11, PacketType::Unsuback) => MReasonCode::NoSubscriptionExisted, - (0x18, PacketType::Auth) => MReasonCode::ContinueAuthentication, - (0x19, PacketType::Auth) => MReasonCode::ReAuthenticate, - (0x80, PacketType::Connack) => MReasonCode::UnspecifiedError, - (0x80, PacketType::Puback) => MReasonCode::UnspecifiedError, - (0x80, PacketType::Pubrec) => MReasonCode::UnspecifiedError, - (0x80, PacketType::Suback) => MReasonCode::UnspecifiedError, - (0x80, PacketType::Unsuback) => MReasonCode::UnspecifiedError, - (0x80, PacketType::Disconnect) => MReasonCode::UnspecifiedError, - (0x81, PacketType::Connack) => MReasonCode::MalformedPacket, - (0x81, PacketType::Disconnect) => MReasonCode::MalformedPacket, - (0x82, PacketType::Connack) => MReasonCode::ProtocolError, - (0x82, PacketType::Disconnect) => MReasonCode::ProtocolError, - (0x83, PacketType::Connack) => MReasonCode::ImplementationSpecificError, - (0x83, PacketType::Puback) => MReasonCode::ImplementationSpecificError, - (0x83, PacketType::Pubrec) => MReasonCode::ImplementationSpecificError, - (0x83, PacketType::Suback) => MReasonCode::ImplementationSpecificError, - (0x83, PacketType::Unsuback) => MReasonCode::ImplementationSpecificError, - (0x83, PacketType::Disconnect) => MReasonCode::ImplementationSpecificError, - (0x84, PacketType::Connack) => MReasonCode::UnsupportedProtocolVersion, - (0x85, PacketType::Connack) => MReasonCode::ClientIdentifierNotValid, - (0x86, PacketType::Connack) => MReasonCode::BadUsernameOrPassword, - (0x87, PacketType::Connack) => MReasonCode::NotAuthorized, - (0x87, PacketType::Puback) => MReasonCode::NotAuthorized, - (0x87, PacketType::Pubrec) => MReasonCode::NotAuthorized, - (0x87, PacketType::Suback) => MReasonCode::NotAuthorized, - (0x87, PacketType::Unsuback) => MReasonCode::NotAuthorized, - (0x87, PacketType::Disconnect) => MReasonCode::NotAuthorized, - (0x88, PacketType::Connack) => MReasonCode::ServerUnavailable, - (0x89, PacketType::Connack) => MReasonCode::ServerBusy, - (0x89, PacketType::Disconnect) => MReasonCode::ServerBusy, - (0x8A, PacketType::Connack) => MReasonCode::Banned, - (0x8B, PacketType::Disconnect) => MReasonCode::ServerShuttingDown, - (0x8C, PacketType::Connack) => MReasonCode::BadAuthenticationMethod, - (0x8C, PacketType::Disconnect) => MReasonCode::BadAuthenticationMethod, - (0x8D, PacketType::Disconnect) => MReasonCode::KeepAliveTimeout, - (0x8E, PacketType::Disconnect) => MReasonCode::SessionTakenOver, - (0x8F, PacketType::Suback) => MReasonCode::TopicFilterInvalid, - (0x8F, PacketType::Unsuback) => MReasonCode::TopicFilterInvalid, - (0x8F, PacketType::Disconnect) => MReasonCode::TopicFilterInvalid, - (0x90, PacketType::Connack) => MReasonCode::TopicNameInvalid, - (0x90, PacketType::Puback) => MReasonCode::TopicNameInvalid, - (0x90, PacketType::Pubrec) => MReasonCode::TopicNameInvalid, - (0x90, PacketType::Disconnect) => MReasonCode::TopicNameInvalid, - (0x91, PacketType::Puback) => MReasonCode::PacketIdentifierInUse, - (0x91, PacketType::Pubrec) => MReasonCode::PacketIdentifierInUse, - (0x91, PacketType::Suback) => MReasonCode::PacketIdentifierInUse, - (0x91, PacketType::Unsuback) => MReasonCode::PacketIdentifierInUse, - (0x92, PacketType::Pubrel) => MReasonCode::PacketIdentifierNotFound, - (0x92, PacketType::Pubcomp) => MReasonCode::PacketIdentifierNotFound, - (0x93, PacketType::Disconnect) => MReasonCode::ReceiveMaximumExceeded, - (0x94, PacketType::Disconnect) => MReasonCode::TopicAliasInvalid, - (0x95, PacketType::Connack) => MReasonCode::PacketTooLarge, - (0x95, PacketType::Disconnect) => MReasonCode::PacketTooLarge, - (0x96, PacketType::Disconnect) => MReasonCode::MessageRateTooHigh, - (0x97, PacketType::Connack) => MReasonCode::QuotaExceeded, - (0x97, PacketType::Puback) => MReasonCode::QuotaExceeded, - (0x97, PacketType::Pubrec) => MReasonCode::QuotaExceeded, - (0x97, PacketType::Suback) => MReasonCode::QuotaExceeded, - (0x97, PacketType::Disconnect) => MReasonCode::QuotaExceeded, - (0x98, PacketType::Disconnect) => MReasonCode::AdministrativeAction, - (0x99, PacketType::Connack) => MReasonCode::PayloadFormatInvalid, - (0x99, PacketType::Puback) => MReasonCode::PayloadFormatInvalid, - (0x99, PacketType::Pubrec) => MReasonCode::PayloadFormatInvalid, - (0x99, PacketType::Disconnect) => MReasonCode::PayloadFormatInvalid, - (0x9A, PacketType::Connack) => MReasonCode::RetainNotSupported, - (0x9A, PacketType::Disconnect) => MReasonCode::RetainNotSupported, - (0x9B, PacketType::Connack) => MReasonCode::QoSNotSupported, - (0x9B, PacketType::Disconnect) => MReasonCode::QoSNotSupported, - (0x9C, PacketType::Connack) => MReasonCode::UseAnotherServer, - (0x9C, PacketType::Disconnect) => MReasonCode::UseAnotherServer, - (0x9D, PacketType::Connack) => MReasonCode::ServerMoved, - (0x9D, PacketType::Disconnect) => MReasonCode::ServerMoved, - (0x9E, PacketType::Suback) => MReasonCode::SharedSubscriptionsNotSupported, - (0x9E, PacketType::Disconnect) => MReasonCode::SharedSubscriptionsNotSupported, - (0x9F, PacketType::Connack) => MReasonCode::ConnectionRateExceeded, - (0x9F, PacketType::Disconnect) => MReasonCode::ConnectionRateExceeded, - (0xA0, PacketType::Disconnect) => MReasonCode::MaximumConnectTime, - (0xA1, PacketType::Suback) => MReasonCode::SubscriptionIdentifiersNotSupported, - (0xA1, PacketType::Disconnect) => MReasonCode::SubscriptionIdentifiersNotSupported, - (0xA2, PacketType::Suback) => MReasonCode::WildcardSubscriptionsNotSupported, - (0xA2, PacketType::Disconnect) => MReasonCode::WildcardSubscriptionsNotSupported, - (_, _) => return Err(ErrMode::from_error_kind( - input, - winnow::error::ErrorKind::Verify, - )), - }; - - Ok(code) +macro_rules! define_reason_code { + ($name:ident => $code:literal) => { + pub struct $name; + impl $name { + pub const CODE: u8 = $code; + } } } + +define_reason_code!(GrantedQoS0 => 0x00); +define_reason_code!(NormalDisconnection => 0x00); +define_reason_code!(Success => 0x00); +define_reason_code!(GrantedQoS1 => 0x01); +define_reason_code!(GrantedQoS2 => 0x02); +define_reason_code!(DisconnectWithWillMessage => 0x04); +define_reason_code!(NoMatchingSubscribers => 0x10); +define_reason_code!(NoSubscriptionExisted => 0x11); +define_reason_code!(ContinueAuthentication => 0x18); +define_reason_code!(ReAuthenticate => 0x19); +define_reason_code!(UnspecifiedError => 0x80); +define_reason_code!(MalformedPacket => 0x81); +define_reason_code!(ProtocolError => 0x82); +define_reason_code!(ImplementationSpecificError => 0x83); +define_reason_code!(UnsupportedProtocolVersion => 0x84); +define_reason_code!(ClientIdentifierNotValid => 0x85); +define_reason_code!(BadUsernameOrPassword => 0x86); +define_reason_code!(NotAuthorized => 0x87); +define_reason_code!(ServerUnavailable => 0x88); +define_reason_code!(ServerBusy => 0x89); +define_reason_code!(Banned => 0x8A); +define_reason_code!(ServerShuttingDown => 0x8B); +define_reason_code!(BadAuthenticationMethod => 0x8C); +define_reason_code!(KeepAliveTimeout => 0x8D); +define_reason_code!(SessionTakenOver => 0x8E); +define_reason_code!(TopicFilterInvalid => 0x8F); +define_reason_code!(TopicNameInvalid => 0x90); +define_reason_code!(PacketIdentifierInUse => 0x91); +define_reason_code!(PacketIdentifierNotFound => 0x92); +define_reason_code!(ReceiveMaximumExceeded => 0x93); +define_reason_code!(TopicAliasInvalid => 0x94); +define_reason_code!(PacketTooLarge => 0x95); +define_reason_code!(MessageRateTooHigh => 0x96); +define_reason_code!(QuotaExceeded => 0x97); +define_reason_code!(AdministrativeAction => 0x98); +define_reason_code!(PayloadFormatInvalid => 0x99); +define_reason_code!(RetainNotSupported => 0x9A); +define_reason_code!(QoSNotSupported => 0x9B); +define_reason_code!(UseAnotherServer => 0x9C); +define_reason_code!(ServerMoved => 0x9D); +define_reason_code!(SharedSubscriptionsNotSupported => 0x9E); +define_reason_code!(ConnectionRateExceeded => 0x9F); +define_reason_code!(MaximumConnectTime => 0xA0); +define_reason_code!(SubscriptionIdentifiersNotSupported => 0xA1); +define_reason_code!(WildcardSubscriptionsNotSupported => 0xA2); + From 712a9548327ff7efb2e3e76064efdd6f017d2b92 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 08:42:25 +0100 Subject: [PATCH 23/90] Replace ConnectReasonCode with generated type Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packet/connack.rs | 54 ++++++++++++---------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/mqtt-format/src/v5/packet/connack.rs b/mqtt-format/src/v5/packet/connack.rs index 7aa6281a..52063fb8 100644 --- a/mqtt-format/src/v5/packet/connack.rs +++ b/mqtt-format/src/v5/packet/connack.rs @@ -5,37 +5,29 @@ use winnow::{ use crate::v5::{fixed_header::PacketType, MResult}; -#[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)] -#[repr(u8)] -pub enum ConnectReasonCode { - Success = 0, - UnspecifiedError = 0x80, - MalformedPacket = 0x81, - ProtocolError = 0x82, - ImplementationSpecificError = 0x84, - ClientIdentifierNotValid = 0x85, - BadUsernameOrPassword = 0x86, - NotAuthorized = 0x87, - ServerUnavailable = 0x88, - ServerBusy = 0x89, - Banned = 0x8A, - BadAuthenticationMethod = 0x8C, - TopicNameInvalid = 0x90, - PacketTooLarge = 0x95, - QuotaExceeded = 0x97, - PayloadFormatInvalid = 0x99, - RetainNotSupported = 0x9A, - QoSNotSupported = 0x9B, - UseAnotherServer = 0x9C, - ServerMoved = 0x9D, - ConnectionRateExceeded = 0x9F, -} - -impl ConnectReasonCode { - fn parse<'i>(input: &mut &'i Bytes) -> MResult { - winnow::binary::u8 - .try_map(ConnectReasonCode::try_from) - .parse_next(input) +crate::v5::reason_code::make_combined_reason_code! { + pub enum ConnectReasonCode { + Success = crate::v5::reason_code::Success, + UnspecifiedError = crate::v5::reason_code::UnspecifiedError, + MalformedPacket = crate::v5::reason_code::MalformedPacket, + ProtocolError = crate::v5::reason_code::ProtocolError, + ImplementationSpecificError = crate::v5::reason_code::ImplementationSpecificError, + ClientIdentifierNotValid = crate::v5::reason_code::ClientIdentifierNotValid, + BadUsernameOrPassword = crate::v5::reason_code::BadUsernameOrPassword, + NotAuthorized = crate::v5::reason_code::NotAuthorized, + ServerUnavailable = crate::v5::reason_code::ServerUnavailable, + ServerBusy = crate::v5::reason_code::ServerBusy, + Banned = crate::v5::reason_code::Banned, + BadAuthenticationMethod = crate::v5::reason_code::BadAuthenticationMethod, + TopicNameInvalid = crate::v5::reason_code::TopicNameInvalid, + PacketTooLarge = crate::v5::reason_code::PacketTooLarge, + QuotaExceeded = crate::v5::reason_code::QuotaExceeded, + PayloadFormatInvalid = crate::v5::reason_code::PayloadFormatInvalid, + RetainNotSupported = crate::v5::reason_code::RetainNotSupported, + QoSNotSupported = crate::v5::reason_code::QoSNotSupported, + UseAnotherServer = crate::v5::reason_code::UseAnotherServer, + ServerMoved = crate::v5::reason_code::ServerMoved, + ConnectionRateExceeded = crate::v5::reason_code::ConnectionRateExceeded, } } From ed865aceb2215e5cb6d1f6824aa36cd844e2171b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 08:56:53 +0100 Subject: [PATCH 24/90] Add ConnackProperties to Connack packet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packet/connack.rs | 40 +++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/mqtt-format/src/v5/packet/connack.rs b/mqtt-format/src/v5/packet/connack.rs index 52063fb8..8654be0f 100644 --- a/mqtt-format/src/v5/packet/connack.rs +++ b/mqtt-format/src/v5/packet/connack.rs @@ -3,7 +3,18 @@ use winnow::{ Bytes, Parser, }; -use crate::v5::{fixed_header::PacketType, MResult}; +use crate::v5::{ + fixed_header::PacketType, + properties::define_properties, + variable_header::{ + AssignedClientIdentifier, AuthenticationData, AuthenticationMethod, MaximumPacketSize, + MaximumQoS, ReasonString, ReceiveMaximum, ResponseInformation, RetainAvailable, + ServerKeepAlive, ServerReference, SessionExpiryInterval, SharedSubscriptionAvailable, + SubscriptionIdentifiersAvailable, TopicAliasMaximum, UserProperty, + WildcardSubscriptionAvailable, + }, + MResult, +}; crate::v5::reason_code::make_combined_reason_code! { pub enum ConnectReasonCode { @@ -31,10 +42,32 @@ crate::v5::reason_code::make_combined_reason_code! { } } +define_properties![ + pub struct ConnackProperties<'i> { + session_expiry_interval: SessionExpiryInterval, + receive_maximum: ReceiveMaximum, + maximum_qos: MaximumQoS, + retain_available: RetainAvailable, + maximum_packet_size: MaximumPacketSize, + assigned_client_identifier: AssignedClientIdentifier<'i>, + topic_alias_maximum: TopicAliasMaximum, + reason_string: ReasonString<'i>, + user_property: UserProperty<'i>, + wildcard_subscription_available: WildcardSubscriptionAvailable, + subscription_identifiers_available: SubscriptionIdentifiersAvailable, + shared_scubscription_available: SharedSubscriptionAvailable, + server_keep_alive: ServerKeepAlive, + response_information: ResponseInformation<'i>, + server_reference: ServerReference<'i>, + authentication_method: AuthenticationMethod<'i>, + authentication_data: AuthenticationData<'i>, + } +]; + pub struct MConnack<'i> { pub session_present: bool, pub reason_code: ConnectReasonCode, - pd: &'i (), + pub properties: ConnackProperties<'i>, } impl<'i> MConnack<'i> { @@ -52,11 +85,12 @@ impl<'i> MConnack<'i> { })?; let reason_code = ConnectReasonCode::parse(input)?; + let properties = ConnackProperties::parse(input)?; Ok(MConnack { session_present, reason_code, - pd: &(), + properties, }) } } From 3be668060981d62bb68be86d49f02312a31acfda Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 08:49:29 +0100 Subject: [PATCH 25/90] Define all reason code types Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/mod.rs | 6 ++--- mqtt-format/src/v5/packet/auth.rs | 7 +++++ mqtt-format/src/v5/packet/connect.rs | 13 +++++++++- mqtt-format/src/v5/packet/disconnect.rs | 34 +++++++++++++++++++++++++ mqtt-format/src/v5/packet/mod.rs | 9 ++++++- mqtt-format/src/v5/packet/payload.rs | 4 +-- mqtt-format/src/v5/packet/puback.rs | 13 ++++++++++ mqtt-format/src/v5/packet/pubcomp.rs | 6 +++++ mqtt-format/src/v5/packet/pubrec.rs | 14 ++++++++++ mqtt-format/src/v5/packet/suback.rs | 16 ++++++++++++ mqtt-format/src/v5/packet/unsuback.rs | 11 ++++++++ mqtt-format/src/v5/reason_code.rs | 3 +-- 12 files changed, 126 insertions(+), 10 deletions(-) create mode 100644 mqtt-format/src/v5/packet/auth.rs create mode 100644 mqtt-format/src/v5/packet/disconnect.rs create mode 100644 mqtt-format/src/v5/packet/puback.rs create mode 100644 mqtt-format/src/v5/packet/pubcomp.rs create mode 100644 mqtt-format/src/v5/packet/pubrec.rs create mode 100644 mqtt-format/src/v5/packet/suback.rs create mode 100644 mqtt-format/src/v5/packet/unsuback.rs diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index 53387e4e..f0233dee 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -1,11 +1,11 @@ pub mod bytes; pub mod fixed_header; pub mod integers; +pub mod level; +pub mod packet; +pub mod properties; pub mod reason_code; pub mod strings; pub mod variable_header; -pub mod packet; -pub mod properties; -pub mod level; pub type MResult = winnow::PResult; diff --git a/mqtt-format/src/v5/packet/auth.rs b/mqtt-format/src/v5/packet/auth.rs new file mode 100644 index 00000000..4af9be1f --- /dev/null +++ b/mqtt-format/src/v5/packet/auth.rs @@ -0,0 +1,7 @@ +crate::v5::reason_code::make_combined_reason_code! { + pub enum AuthReasonCode { + ContinueAuthentication = crate::v5::reason_code::ContinueAuthentication, + ReAuthenticate = crate::v5::reason_code::ReAuthenticate, + Success = crate::v5::reason_code::Success, + } +} diff --git a/mqtt-format/src/v5/packet/connect.rs b/mqtt-format/src/v5/packet/connect.rs index ce74c74a..39eec36a 100644 --- a/mqtt-format/src/v5/packet/connect.rs +++ b/mqtt-format/src/v5/packet/connect.rs @@ -1,7 +1,18 @@ use winnow::Bytes; use crate::v5::{ - bytes::parse_data, fixed_header::{PacketType, QualityOfService}, integers::{parse_u16, parse_u32, parse_variable}, level::ProtocolLevel, strings::parse_string, variable_header::{AuthenticationData, AuthenticationMethod, ContentType, CorrelationData, MaximumPacketSize, MessageExpiryInterval, PayloadFormatIndicator, ReceiveMaximum, RequestProblemInformation, RequestResponseInformation, ResponseTopic, SessionExpiryInterval, TopicAliasMaximum, UserProperty, WillDelayInterval}, MResult + bytes::parse_data, + fixed_header::{PacketType, QualityOfService}, + integers::{parse_u16, parse_u32, parse_variable}, + level::ProtocolLevel, + strings::parse_string, + variable_header::{ + AuthenticationData, AuthenticationMethod, ContentType, CorrelationData, MaximumPacketSize, + MessageExpiryInterval, PayloadFormatIndicator, ReceiveMaximum, RequestProblemInformation, + RequestResponseInformation, ResponseTopic, SessionExpiryInterval, TopicAliasMaximum, + UserProperty, WillDelayInterval, + }, + MResult, }; use super::payload::ApplicationMessagePayload; diff --git a/mqtt-format/src/v5/packet/disconnect.rs b/mqtt-format/src/v5/packet/disconnect.rs new file mode 100644 index 00000000..15bea513 --- /dev/null +++ b/mqtt-format/src/v5/packet/disconnect.rs @@ -0,0 +1,34 @@ +crate::v5::reason_code::make_combined_reason_code! { + pub enum DisconnectReasonCode { + AdministrativeAction = crate::v5::reason_code::AdministrativeAction, + BadAuthenticationMethod = crate::v5::reason_code::BadAuthenticationMethod, + ConnectionRateExceeded = crate::v5::reason_code::ConnectionRateExceeded, + DisconnectWithWillMessage = crate::v5::reason_code::DisconnectWithWillMessage, + ImplementationSpecificError = crate::v5::reason_code::ImplementationSpecificError, + KeepAliveTimeout = crate::v5::reason_code::KeepAliveTimeout, + MalformedPacket = crate::v5::reason_code::MalformedPacket, + MaximumConnectTime = crate::v5::reason_code::MaximumConnectTime, + MessageRateTooHigh = crate::v5::reason_code::MessageRateTooHigh, + NormalDisconnection = crate::v5::reason_code::NormalDisconnection, + NotAuthorized = crate::v5::reason_code::NotAuthorized, + PacketTooLarge = crate::v5::reason_code::PacketTooLarge, + PayloadFormatInvalid = crate::v5::reason_code::PayloadFormatInvalid, + ProtocolError = crate::v5::reason_code::ProtocolError, + QoSNotSupported = crate::v5::reason_code::QoSNotSupported, + QuotaExceeded = crate::v5::reason_code::QuotaExceeded, + ReceiveMaximumExceeded = crate::v5::reason_code::ReceiveMaximumExceeded, + RetainNotSupported = crate::v5::reason_code::RetainNotSupported, + ServerBusy = crate::v5::reason_code::ServerBusy, + ServerMoved = crate::v5::reason_code::ServerMoved, + ServerShuttingDown = crate::v5::reason_code::ServerShuttingDown, + SessionTakenOver = crate::v5::reason_code::SessionTakenOver, + SharedSubscriptionsNotSupported = crate::v5::reason_code::SharedSubscriptionsNotSupported, + SubscriptionIdentifiersNotSupported = crate::v5::reason_code::SubscriptionIdentifiersNotSupported, + TopicAliasInvalid = crate::v5::reason_code::TopicAliasInvalid, + TopicFilterInvalid = crate::v5::reason_code::TopicFilterInvalid, + TopicNameInvalid = crate::v5::reason_code::TopicNameInvalid, + UnspecifiedError = crate::v5::reason_code::UnspecifiedError, + UseAnotherServer = crate::v5::reason_code::UseAnotherServer, + WildcardSubscriptionsNotSupported = crate::v5::reason_code::WildcardSubscriptionsNotSupported, + } +} diff --git a/mqtt-format/src/v5/packet/mod.rs b/mqtt-format/src/v5/packet/mod.rs index 59cd984d..43224795 100644 --- a/mqtt-format/src/v5/packet/mod.rs +++ b/mqtt-format/src/v5/packet/mod.rs @@ -1,4 +1,11 @@ -pub mod connect; +pub mod auth; pub mod connack; +pub mod connect; +pub mod disconnect; pub mod payload; +pub mod puback; +pub mod pubcomp; pub mod publish; +pub mod pubrec; +pub mod suback; +pub mod unsuback; diff --git a/mqtt-format/src/v5/packet/payload.rs b/mqtt-format/src/v5/packet/payload.rs index e39aeee4..fba89284 100644 --- a/mqtt-format/src/v5/packet/payload.rs +++ b/mqtt-format/src/v5/packet/payload.rs @@ -3,7 +3,7 @@ use winnow::Bytes; use crate::v5::MResult; pub struct ApplicationMessagePayload<'i> { - payload: &'i [u8] + payload: &'i [u8], } impl<'i> ApplicationMessagePayload<'i> { @@ -11,5 +11,3 @@ impl<'i> ApplicationMessagePayload<'i> { crate::v5::bytes::parse_data(input).map(|payload| Self { payload }) } } - - diff --git a/mqtt-format/src/v5/packet/puback.rs b/mqtt-format/src/v5/packet/puback.rs new file mode 100644 index 00000000..2d7d032f --- /dev/null +++ b/mqtt-format/src/v5/packet/puback.rs @@ -0,0 +1,13 @@ +crate::v5::reason_code::make_combined_reason_code! { + pub enum PubackReasonCode { + ImplementationSpecificError = crate::v5::reason_code::ImplementationSpecificError, + NoMatchingSubscribers = crate::v5::reason_code::NoMatchingSubscribers, + NotAuthorized = crate::v5::reason_code::NotAuthorized, + PacketIdentifierInUse = crate::v5::reason_code::PacketIdentifierInUse, + PayloadFormatInvalid = crate::v5::reason_code::PayloadFormatInvalid, + QuotaExceeded = crate::v5::reason_code::QuotaExceeded, + Success = crate::v5::reason_code::Success, + TopicNameInvalid = crate::v5::reason_code::TopicNameInvalid, + UnspecifiedError = crate::v5::reason_code::UnspecifiedError, + } +} diff --git a/mqtt-format/src/v5/packet/pubcomp.rs b/mqtt-format/src/v5/packet/pubcomp.rs new file mode 100644 index 00000000..dba01649 --- /dev/null +++ b/mqtt-format/src/v5/packet/pubcomp.rs @@ -0,0 +1,6 @@ +crate::v5::reason_code::make_combined_reason_code! { + pub enum PubcompReasonCode { + PacketIdentifierNotFound = crate::v5::reason_code::PacketIdentifierNotFound, + Success = crate::v5::reason_code::Success, + } +} diff --git a/mqtt-format/src/v5/packet/pubrec.rs b/mqtt-format/src/v5/packet/pubrec.rs new file mode 100644 index 00000000..2e1f3290 --- /dev/null +++ b/mqtt-format/src/v5/packet/pubrec.rs @@ -0,0 +1,14 @@ +crate::v5::reason_code::make_combined_reason_code! { + pub enum PubrecReasonCode { + ImplementationSpecificError = crate::v5::reason_code::ImplementationSpecificError, + NoMatchingSubscribers = crate::v5::reason_code::NoMatchingSubscribers, + NotAuthorized = crate::v5::reason_code::NotAuthorized, + PacketIdentifierInUse = crate::v5::reason_code::PacketIdentifierInUse, + PacketIdentifierNotFound = crate::v5::reason_code::PacketIdentifierNotFound, + PayloadFormatInvalid = crate::v5::reason_code::PayloadFormatInvalid, + QuotaExceeded = crate::v5::reason_code::QuotaExceeded, + Success = crate::v5::reason_code::Success, + TopicNameInvalid = crate::v5::reason_code::TopicNameInvalid, + UnspecifiedError = crate::v5::reason_code::UnspecifiedError, + } +} diff --git a/mqtt-format/src/v5/packet/suback.rs b/mqtt-format/src/v5/packet/suback.rs new file mode 100644 index 00000000..7ce580da --- /dev/null +++ b/mqtt-format/src/v5/packet/suback.rs @@ -0,0 +1,16 @@ +crate::v5::reason_code::make_combined_reason_code! { + pub enum SubackReasonCode { + GrantedQoS0 = crate::v5::reason_code::GrantedQoS0, + GrantedQoS1 = crate::v5::reason_code::GrantedQoS1, + GrantedQoS2 = crate::v5::reason_code::GrantedQoS2, + ImplementationSpecificError = crate::v5::reason_code::ImplementationSpecificError, + NotAuthorized = crate::v5::reason_code::NotAuthorized, + PacketIdentifierInUse = crate::v5::reason_code::PacketIdentifierInUse, + QuotaExceeded = crate::v5::reason_code::QuotaExceeded, + SharedSubscriptionsNotSupported = crate::v5::reason_code::SharedSubscriptionsNotSupported, + SubscriptionIdentifiersNotSupported = crate::v5::reason_code::SubscriptionIdentifiersNotSupported, + TopicFilterInvalid = crate::v5::reason_code::TopicFilterInvalid, + UnspecifiedError = crate::v5::reason_code::UnspecifiedError, + WildcardSubscriptionsNotSupported = crate::v5::reason_code::WildcardSubscriptionsNotSupported, + } +} diff --git a/mqtt-format/src/v5/packet/unsuback.rs b/mqtt-format/src/v5/packet/unsuback.rs new file mode 100644 index 00000000..8a58d09d --- /dev/null +++ b/mqtt-format/src/v5/packet/unsuback.rs @@ -0,0 +1,11 @@ +crate::v5::reason_code::make_combined_reason_code! { + pub enum UnsubackReasonCode { + ImplementationSpecificError = crate::v5::reason_code::ImplementationSpecificError, + NoSubscriptionExisted = crate::v5::reason_code::NoSubscriptionExisted, + NotAuthorized = crate::v5::reason_code::NotAuthorized, + PacketIdentifierInUse = crate::v5::reason_code::PacketIdentifierInUse, + Success = crate::v5::reason_code::Success, + TopicFilterInvalid = crate::v5::reason_code::TopicFilterInvalid, + UnspecifiedError = crate::v5::reason_code::UnspecifiedError, + } +} diff --git a/mqtt-format/src/v5/reason_code.rs b/mqtt-format/src/v5/reason_code.rs index 38426f60..934884a3 100644 --- a/mqtt-format/src/v5/reason_code.rs +++ b/mqtt-format/src/v5/reason_code.rs @@ -26,7 +26,7 @@ macro_rules! define_reason_code { impl $name { pub const CODE: u8 = $code; } - } + }; } define_reason_code!(GrantedQoS0 => 0x00); @@ -74,4 +74,3 @@ define_reason_code!(ConnectionRateExceeded => 0x9F); define_reason_code!(MaximumConnectTime => 0xA0); define_reason_code!(SubscriptionIdentifiersNotSupported => 0xA1); define_reason_code!(WildcardSubscriptionsNotSupported => 0xA2); - From 54d2882a91961f0359bc17800a365a4b4ae81841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 09:09:00 +0100 Subject: [PATCH 26/90] Rename parse_variable to parse_variable_u32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/fixed_header.rs | 4 ++-- mqtt-format/src/v5/integers.rs | 28 +++++++++++++++++----------- mqtt-format/src/v5/packet/connect.rs | 2 +- mqtt-format/src/v5/properties.rs | 4 ++-- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/mqtt-format/src/v5/fixed_header.rs b/mqtt-format/src/v5/fixed_header.rs index c33f090d..4cf543c1 100644 --- a/mqtt-format/src/v5/fixed_header.rs +++ b/mqtt-format/src/v5/fixed_header.rs @@ -4,7 +4,7 @@ use winnow::{ Bytes, Parser, }; -use super::{integers::parse_variable, MResult}; +use super::{integers::parse_variable_u32, MResult}; #[derive(Debug, PartialEq)] pub enum QualityOfService { @@ -100,7 +100,7 @@ pub fn parse_fixed_header<'i>(input: &mut &'i Bytes) -> MResult { } }; - let remaining_length = parse_variable(input)?; + let remaining_length = parse_variable_u32(input)?; Ok(MFixedHeader { packet_type, diff --git a/mqtt-format/src/v5/integers.rs b/mqtt-format/src/v5/integers.rs index 80157a7d..11a16812 100644 --- a/mqtt-format/src/v5/integers.rs +++ b/mqtt-format/src/v5/integers.rs @@ -10,7 +10,7 @@ pub fn parse_u32<'i>(input: &mut &'i Bytes) -> MResult { winnow::binary::u32(winnow::binary::Endianness::Big).parse_next(input) } -pub fn parse_variable<'i>(input: &mut &'i Bytes) -> MResult { +pub fn parse_variable_u32<'i>(input: &mut &'i Bytes) -> MResult { let var_bytes = ( take_while(0..=3, |b| b & 0b1000_0000 != 0), winnow::binary::u8.verify(|b: &u8| b & 0b1000_0000 == 0), @@ -30,7 +30,7 @@ pub fn parse_variable<'i>(input: &mut &'i Bytes) -> MResult { mod tests { use winnow::Bytes; - use crate::v5::integers::{parse_u16, parse_u32, parse_variable}; + use crate::v5::integers::{parse_u16, parse_u32, parse_variable_u32}; #[test] fn check_integer_parsing() { @@ -44,33 +44,39 @@ mod tests { #[test] fn check_variable_integers() { let input = [0x0]; - assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 0); + assert_eq!(parse_variable_u32(&mut Bytes::new(&input)).unwrap(), 0); let input = [0x7F]; - assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 127); + assert_eq!(parse_variable_u32(&mut Bytes::new(&input)).unwrap(), 127); let input = [0x80, 0x01]; - assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 128); + assert_eq!(parse_variable_u32(&mut Bytes::new(&input)).unwrap(), 128); let input = [0xFF, 0x7F]; - assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 16_383); + assert_eq!(parse_variable_u32(&mut Bytes::new(&input)).unwrap(), 16_383); let input = [0x80, 0x80, 0x01]; - assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 16_384); + assert_eq!(parse_variable_u32(&mut Bytes::new(&input)).unwrap(), 16_384); let input = [0xFF, 0xFF, 0x7F]; - assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 2_097_151); + assert_eq!( + parse_variable_u32(&mut Bytes::new(&input)).unwrap(), + 2_097_151 + ); let input = [0x80, 0x80, 0x80, 0x01]; - assert_eq!(parse_variable(&mut Bytes::new(&input)).unwrap(), 2_097_152); + assert_eq!( + parse_variable_u32(&mut Bytes::new(&input)).unwrap(), + 2_097_152 + ); let input = [0xFF, 0xFF, 0xFF, 0x7F]; assert_eq!( - parse_variable(&mut Bytes::new(&input)).unwrap(), + parse_variable_u32(&mut Bytes::new(&input)).unwrap(), 268_435_455 ); let input = [0xFF, 0xFF, 0xFF, 0x8F]; - parse_variable(&mut Bytes::new(&input)).unwrap_err(); + parse_variable_u32(&mut Bytes::new(&input)).unwrap_err(); } } diff --git a/mqtt-format/src/v5/packet/connect.rs b/mqtt-format/src/v5/packet/connect.rs index 39eec36a..a87c73fd 100644 --- a/mqtt-format/src/v5/packet/connect.rs +++ b/mqtt-format/src/v5/packet/connect.rs @@ -3,7 +3,7 @@ use winnow::Bytes; use crate::v5::{ bytes::parse_data, fixed_header::{PacketType, QualityOfService}, - integers::{parse_u16, parse_u32, parse_variable}, + integers::{parse_u16, parse_u32, parse_variable_u32}, level::ProtocolLevel, strings::parse_string, variable_header::{ diff --git a/mqtt-format/src/v5/properties.rs b/mqtt-format/src/v5/properties.rs index c03e14e1..dbc9b190 100644 --- a/mqtt-format/src/v5/properties.rs +++ b/mqtt-format/src/v5/properties.rs @@ -60,11 +60,11 @@ macro_rules! define_properties { let mut $prop_name: MqttPropertySlot<$prop> = MqttPropertySlot::new(<$prop as crate::v5::variable_header::MqttProperties>::ALLOW_REPEATING); )* - let mut properties_bytes = winnow::Bytes::new(winnow::binary::length_take(crate::v5::integers::parse_variable).parse_next(input)?); + let mut properties_bytes = winnow::Bytes::new(winnow::binary::length_take(crate::v5::integers::parse_variable_u32).parse_next(input)?); while !properties_bytes.is_empty() { let checkpoint = properties_bytes.checkpoint(); - let id = crate::v5::integers::parse_variable(&mut properties_bytes)?; + let id = crate::v5::integers::parse_variable_u32(&mut properties_bytes)?; $( if <$prop as crate::v5::variable_header::MqttProperties>::IDENTIFIER == id { From 634bbc5bddd67a4cef46c07b56cce85db965b68b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 09:25:35 +0100 Subject: [PATCH 27/90] Rewrite define_properties to define all at the same time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch also defines the Property enum through the macro and adds a parse method for easy access. Signed-off-by: Marcel Müller --- mqtt-format/src/v5/variable_header.rs | 161 ++++++++++++-------------- 1 file changed, 71 insertions(+), 90 deletions(-) diff --git a/mqtt-format/src/v5/variable_header.rs b/mqtt-format/src/v5/variable_header.rs index 7cec2767..7b8385aa 100644 --- a/mqtt-format/src/v5/variable_header.rs +++ b/mqtt-format/src/v5/variable_header.rs @@ -18,105 +18,86 @@ pub trait MqttProperties<'lt>: Sized { } macro_rules! define_properties { - (@ignore $lt:lifetime $($rest:tt)*) => { - $lt - }; - ($name:ident $(< $tylt:lifetime >)? as $id:expr => parse with $parser:path as $($lt:lifetime)? $kind:ty) => { - define_properties!(@impl $name $($tylt)? as $id => $kind => input { - Ok(Self($parser(input)?)) - }); - }; - - ($name:ident $(< $tylt:lifetime >)? as $id:expr => parser: $parser:path as $($lt:lifetime)? $kind:ty) => { - define_properties!(@impl $name $($tylt)? as $id => $kind => input { - #[allow(unused_imports)] - use winnow::Parser; - - Ok(Self($parser.parse_next(input)?)) - }); - }; - - (@impl $name:ident $($tylt:lifetime)? as $id:expr => $($lt:lifetime)? $kind:ty => $input:ident $fun:block) => { - pub struct $name < $($tylt)? >(pub $(& $lt)? $kind); - - impl<'lt $(, $tylt)?> MqttProperties<'lt> for $name < $($tylt)? > - $(where $tylt: 'lt, 'lt: $tylt)? - { - const IDENTIFIER: u32 = $id; - const ALLOW_REPEATING: bool = false; - - fn parse<'input>($input: &mut &'input Bytes) -> MResult<$name <$($tylt)?>> - where - 'input: 'lt + ([ + $( + $name:ident $(< $tylt:lifetime >)? as $id:expr => parse with $parser:path as $($lt:lifetime)? $kind:ty + ),* + $(,)? + ]) => { + $( + pub struct $name < $($tylt)? >(pub $(& $lt)? $kind); + + impl<'lt $(, $tylt)?> MqttProperties<'lt> for $name < $($tylt)? > + $(where $tylt: 'lt, 'lt: $tylt)? { - $fun + const IDENTIFIER: u32 = $id; + const ALLOW_REPEATING: bool = false; + + fn parse<'input>(input: &mut &'input Bytes) -> MResult<$name <$($tylt)?>> + where + 'input: 'lt + { + use winnow::Parser; + + Ok(Self($parser.parse_next(input)?)) + } + } + + impl<'i> From< $name <$($tylt)?> > for Property<'i> { + fn from(value: $name <$($tylt)?>) -> Property<'i> { + Property::$name(value) + } } + )* + + pub enum Property<'i> { + $( + $name ( $name $(< $tylt >)? ), + )* + UserProperty(UserProperty<'i>), } - impl<'i> From< $name <$($tylt)?> > for Property<'i> { - fn from(value: $name <$($tylt)?>) -> Property<'i> { - Property::$name(value) + impl<'i> Property<'i> { + pub fn parse(input: &mut &'i Bytes) -> MResult> { + winnow::combinator::dispatch! { crate::v5::integers::parse_variable_u32; + $( + $id => $name::parse.map(Property::from), + )* + _ => winnow::combinator::fail + }.parse_next(input) } } } } -pub enum Property<'i> { - PayloadFormatIndicator(PayloadFormatIndicator), - MessageExpiryInterval(MessageExpiryInterval), - ContentType(ContentType<'i>), - ResponseTopic(ResponseTopic<'i>), - CorrelationData(CorrelationData<'i>), - SubscriptionIdentifier(SubscriptionIdentifier), - SessionExpiryInterval(SessionExpiryInterval), - AssignedClientIdentifier(AssignedClientIdentifier<'i>), - ServerKeepAlive(ServerKeepAlive), - AuthenticationMethod(AuthenticationMethod<'i>), - AuthenticationData(AuthenticationData<'i>), - RequestProblemInformation(RequestProblemInformation), - WillDelayInterval(WillDelayInterval), - RequestResponseInformation(RequestResponseInformation), - ResponseInformation(ResponseInformation<'i>), - ServerReference(ServerReference<'i>), - ReasonString(ReasonString<'i>), - ReceiveMaximum(ReceiveMaximum), - TopicAliasMaximum(TopicAliasMaximum), - TopicAlias(TopicAlias), - MaximumQoS(MaximumQoS), - RetainAvailable(RetainAvailable), - UserProperty(UserProperty<'i>), - MaximumPacketSize(MaximumPacketSize), - WildcardSubscriptionAvailable(WildcardSubscriptionAvailable), - SubscriptionIdentifiersAvailable(SubscriptionIdentifiersAvailable), - SharedSubscriptionAvailable(SharedSubscriptionAvailable), -} - -define_properties!(PayloadFormatIndicator as 0x01 => parse with winnow::binary::u8 as u8); -define_properties!(MessageExpiryInterval as 0x02 => parser: parse_u32 as u32); -define_properties!(ContentType<'i> as 0x03 => parser: super::strings::parse_string as &'i str); -define_properties!(ResponseTopic<'i> as 0x08 => parser: super::strings::parse_string as &'i str); -define_properties!(CorrelationData<'i> as 0x09 => parser: super::bytes::parse_data as &'i [u8]); -define_properties!(SubscriptionIdentifier as 0x0B => parser: parse_u32 as u32); -define_properties!(SessionExpiryInterval as 0x11 => parser: parse_u32 as u32); -define_properties!(AssignedClientIdentifier<'i> as 0x12 => parser: super::strings::parse_string as &'i str); -define_properties!(ServerKeepAlive as 0x13 => parser: parse_u32 as u32); -define_properties!(AuthenticationMethod<'i> as 0x15 => parser: super::strings::parse_string as &'i str); -define_properties!(AuthenticationData<'i> as 0x16 => parser: super::bytes::parse_data as &'i [u8]); -define_properties!(RequestProblemInformation as 0x17 => parse with winnow::binary::u8 as u8); -define_properties!(WillDelayInterval as 0x18 => parser: parse_u32 as u32); -define_properties!(RequestResponseInformation as 0x19 => parse with winnow::binary::u8 as u8); -define_properties!(ResponseInformation<'i> as 0x1A => parser: super::strings::parse_string as &'i str); -define_properties!(ServerReference<'i> as 0x1C => parser: super::strings::parse_string as &'i str); -define_properties!(ReasonString<'i> as 0x1F => parser: super::strings::parse_string as &'i str); -define_properties!(ReceiveMaximum as 0x21 => parser: parse_u32 as u32); -define_properties!(TopicAliasMaximum as 0x22 => parser: parse_u32 as u32); -define_properties!(TopicAlias as 0x23 => parser: parse_u32 as u32); -define_properties!(MaximumQoS as 0x24 => parse with winnow::binary::u8 as u8); -define_properties!(RetainAvailable as 0x25 => parse with winnow::binary::u8 as u8); -define_properties!(MaximumPacketSize as 0x27 => parser: parse_u32 as u32); -define_properties!(WildcardSubscriptionAvailable as 0x28 => parse with winnow::binary::u8 as u8); -define_properties!(SubscriptionIdentifiersAvailable as 0x29 => parse with winnow::binary::u8 as u8); -define_properties!(SharedSubscriptionAvailable as 0x2A => parse with winnow::binary::u8 as u8); +define_properties! {[ + PayloadFormatIndicator as 0x01 => parse with winnow::binary::u8 as u8, + MessageExpiryInterval as 0x02 => parse with parse_u32 as u32, + ContentType<'i> as 0x03 => parse with super::strings::parse_string as &'i str, + ResponseTopic<'i> as 0x08 => parse with super::strings::parse_string as &'i str, + CorrelationData<'i> as 0x09 => parse with super::bytes::parse_data as &'i [u8], + SubscriptionIdentifier as 0x0B => parse with parse_u32 as u32, + SessionExpiryInterval as 0x11 => parse with parse_u32 as u32, + AssignedClientIdentifier<'i> as 0x12 => parse with super::strings::parse_string as &'i str, + ServerKeepAlive as 0x13 => parse with parse_u32 as u32, + AuthenticationMethod<'i> as 0x15 => parse with super::strings::parse_string as &'i str, + AuthenticationData<'i> as 0x16 => parse with super::bytes::parse_data as &'i [u8], + RequestProblemInformation as 0x17 => parse with winnow::binary::u8 as u8, + WillDelayInterval as 0x18 => parse with parse_u32 as u32, + RequestResponseInformation as 0x19 => parse with winnow::binary::u8 as u8, + ResponseInformation<'i> as 0x1A => parse with super::strings::parse_string as &'i str, + ServerReference<'i> as 0x1C => parse with super::strings::parse_string as &'i str, + ReasonString<'i> as 0x1F => parse with super::strings::parse_string as &'i str, + ReceiveMaximum as 0x21 => parse with parse_u32 as u32, + TopicAliasMaximum as 0x22 => parse with parse_u32 as u32, + TopicAlias as 0x23 => parse with parse_u32 as u32, + MaximumQoS as 0x24 => parse with winnow::binary::u8 as u8, + RetainAvailable as 0x25 => parse with winnow::binary::u8 as u8, + MaximumPacketSize as 0x27 => parse with parse_u32 as u32, + WildcardSubscriptionAvailable as 0x28 => parse with winnow::binary::u8 as u8, + SubscriptionIdentifiersAvailable as 0x29 => parse with winnow::binary::u8 as u8, + SharedSubscriptionAvailable as 0x2A => parse with winnow::binary::u8 as u8, +]} pub struct UserProperty<'i>(pub &'i [u8]); From ddc24ee64cc9a77c995395d4deeb62343127924e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 09:35:30 +0100 Subject: [PATCH 28/90] Add iteration of UserProperties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/variable_header.rs | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/mqtt-format/src/v5/variable_header.rs b/mqtt-format/src/v5/variable_header.rs index 7b8385aa..99d06bc8 100644 --- a/mqtt-format/src/v5/variable_header.rs +++ b/mqtt-format/src/v5/variable_header.rs @@ -123,3 +123,36 @@ impl<'i> From> for Property<'i> { Property::UserProperty(value) } } + +impl<'i> UserProperty<'i> { + pub fn iter(&'i self) -> UserPropertyIterator<'i> { + UserPropertyIterator { + // This is amazing. + // + // Bytes is unsized, so we can create it like this + current: &Bytes::new(&self.0), + } + } +} + +pub struct UserPropertyIterator<'i> { + current: &'i Bytes, +} + +impl<'i> Iterator for UserPropertyIterator<'i> { + type Item = UserProperty<'i>; + + fn next(&mut self) -> Option { + while !self.current.is_empty() { + let property = Property::parse(&mut self.current) + .expect("This has already been parsed, and should be valid."); + + match property { + Property::UserProperty(prop) => return Some(prop), + _ => continue, + } + } + + None + } +} From fc5079efc70ae39ef71ca63d7b4b0535409a93ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 10:04:25 +0100 Subject: [PATCH 29/90] Add debug feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- Cargo.lock | 741 +++++++++++++++++++---------------------- mqtt-format/Cargo.toml | 1 + 2 files changed, 346 insertions(+), 396 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index caaac20a..d29b7499 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.19.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -17,22 +17,11 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -48,49 +37,82 @@ dependencies = [ [[package]] name = "anstream" -version = "0.2.6" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" dependencies = [ "anstyle", "anstyle-parse", - "anstyle-wincon", - "concolor-override", - "concolor-query", + "anstyle-query", + "anstyle-wincon 1.0.2", + "colorchoice", "is-terminal", "utf8parse", ] +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon 3.0.2", + "colorchoice", + "utf8parse", +] + [[package]] name = "anstyle" -version = "0.3.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" -version = "0.1.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "anstyle-wincon" -version = "0.2.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa" +checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" dependencies = [ "anstyle", - "windows-sys 0.45.0", + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", ] [[package]] name = "arc-swap" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f" [[package]] name = "archery" @@ -103,19 +125,19 @@ dependencies = [ [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn", ] [[package]] @@ -126,9 +148,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -165,15 +187,15 @@ dependencies = [ [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.78" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cfg-if" @@ -183,45 +205,43 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.2.1" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3" +checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.2.1" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ - "anstream", + "anstream 0.6.13", "anstyle", - "bitflags", "clap_lex", "strsim", ] [[package]] name = "clap_derive" -version = "4.2.0" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" +checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.13", + "syn", ] [[package]] name = "clap_lex" -version = "0.4.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "cloudmqtt" @@ -246,38 +266,19 @@ dependencies = [ ] [[package]] -name = "concolor-override" +name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f" - -[[package]] -name = "concolor-query" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf" -dependencies = [ - "windows-sys 0.45.0", -] - -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn 1.0.107", -] +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "dashmap" -version = "5.4.0" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.12.3", + "hashbrown", "lock_api", "once_cell", "parking_lot_core", @@ -297,30 +298,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] name = "futures" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -333,9 +323,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -343,15 +333,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -360,38 +350,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -405,31 +395,11 @@ dependencies = [ "slab", ] -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - [[package]] name = "gimli" -version = "0.27.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "hashbrown" @@ -439,24 +409,15 @@ checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -name = "hermit-abi" -version = "0.2.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "indent_write" @@ -471,36 +432,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown", ] [[package]] name = "io-lifetimes" -version = "1.0.3" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ + "hermit-abi", "libc", - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys 0.48.0", + "hermit-abi", + "libc", + "windows-sys 0.52.0", ] [[package]] name = "is_ci" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" [[package]] name = "joinery" @@ -516,21 +477,21 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "linux-raw-sys" -version = "0.3.1" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -538,12 +499,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "matchers" @@ -551,20 +509,20 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "miette" -version = "5.7.0" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abdc09c381c9336b9f2e9bd6067a9a5290d20e2d2e2296f275456121c33ae89" +checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" dependencies = [ "backtrace", "backtrace-ext", @@ -575,7 +533,7 @@ dependencies = [ "supports-color", "supports-hyperlinks", "supports-unicode", - "terminal_size", + "terminal_size 0.1.17", "textwrap 0.15.2", "thiserror", "unicode-width", @@ -583,13 +541,13 @@ dependencies = [ [[package]] name = "miette-derive" -version = "5.7.0" +version = "5.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8842972f23939443013dfd3720f46772b743e86f1a81d120d4b6fb090f87de1c" +checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn", ] [[package]] @@ -600,23 +558,22 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.5" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", - "log", "wasi", - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] @@ -647,7 +604,7 @@ dependencies = [ "mqtt-format", "nom", "static_assertions", - "textwrap 0.16.0", + "textwrap 0.16.1", "tokio", "tracing", "tracing-subscriber", @@ -688,11 +645,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] @@ -714,32 +671,23 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.13", + "syn", ] [[package]] name = "object" -version = "0.30.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d864c91689fdc196779b98dba0aceac6118594c2df6ee5d943eb6a8df4d107a" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" - -[[package]] -name = "output_vt100" -version = "0.1.3" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "overload" @@ -755,22 +703,22 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "parking_lot_core" -version = "0.9.5" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-targets 0.48.5", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -780,13 +728,11 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pretty_assertions" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ - "ctor", "diff", - "output_vt100", "yansi", ] @@ -810,31 +756,32 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.26" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.7.0" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-automata 0.4.6", + "regex-syntax 0.8.2", ] [[package]] @@ -843,14 +790,31 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", ] [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rpds" @@ -863,83 +827,97 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.37.3" +version = "0.37.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b24138615de35e32031d041a09032ef3487a616d901ca4db224e7d557efae2" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.152" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] [[package]] name = "slab" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "smawk" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" -version = "0.4.9" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -956,15 +934,15 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" [[package]] name = "supports-color" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4950e7174bffabe99455511c39707310e7e9b440364a2fcb1cc21521be57b354" +checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" dependencies = [ "is-terminal", "is_ci", @@ -972,38 +950,27 @@ dependencies = [ [[package]] name = "supports-hyperlinks" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b4806e0b03b9906e76b018a5d821ebf198c8e9dc0829ed3328eeeb5094aed60" +checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d" dependencies = [ "is-terminal", ] [[package]] name = "supports-unicode" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6c2cb240ab5dd21ed4906895ee23fe5a48acdbd15a3ce388e7b62a9b66baf7" +checksum = "f850c19edd184a205e883199a261ed44471c81e39bd95b1357f5febbef00e77a" dependencies = [ "is-terminal", ] [[package]] name = "syn" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.13" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -1012,14 +979,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.12.6" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", - "unicode-xid", + "syn", ] [[package]] @@ -1032,6 +998,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "textwrap" version = "0.15.2" @@ -1045,9 +1021,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" dependencies = [ "smawk", "unicode-linebreak", @@ -1056,40 +1032,41 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn", ] [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ + "cfg-if", "once_cell", ] [[package]] name = "tokio" -version = "1.27.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -1098,25 +1075,25 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.0.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn", ] [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -1145,11 +1122,10 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1157,20 +1133,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -1178,20 +1154,20 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.16" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -1207,31 +1183,21 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-linebreak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5faade31a542b8b35855fff6e8def199853b2da8da256da52f52f1316ee3137" -dependencies = [ - "hashbrown 0.12.3", - "regex", -] +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "utf8parse" @@ -1245,12 +1211,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1281,150 +1241,135 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.1", - "windows_aarch64_msvc 0.42.1", - "windows_i686_gnu 0.42.1", - "windows_i686_msvc 0.42.1", - "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm 0.42.1", - "windows_x86_64_msvc 0.42.1", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.42.1", + "windows-targets 0.48.5", ] [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.52.4", ] [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.42.1", - "windows_aarch64_msvc 0.42.1", - "windows_i686_gnu 0.42.1", - "windows_i686_msvc 0.42.1", - "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm 0.42.1", - "windows_x86_64_msvc 0.42.1", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winnow" @@ -1441,7 +1386,11 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" dependencies = [ + "anstream 0.3.2", + "anstyle", + "is-terminal", "memchr", + "terminal_size 0.2.6", ] [[package]] @@ -1452,9 +1401,9 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "yoke" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222180af14a6b54ef2c33493c1eff77ae95a3687a21b243e752624006fb8f26e" +checksum = "65e71b2e4f287f467794c671e2b8f8a5f3716b3c829079a1c44740148eff07e4" dependencies = [ "serde", "stable_deref_trait", @@ -1464,33 +1413,33 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca800d73d6b7a7ee54f2608205c98b549fca71c9500c1abcb3abdc7708b4a8cb" +checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn", "synstructure", ] [[package]] name = "zerofrom" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e9355fccf72b04b7deaa99ce7a0f6630530acf34045391b74460fcd714de54" +checksum = "655b0814c5c0b19ade497851070c640773304939a6c0fd5f5fb43da0696d05b7" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e8aa86add9ddbd2409c1ed01e033cd457d79b1b1229b64922c25095c595e829" +checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn", "synstructure", ] diff --git a/mqtt-format/Cargo.toml b/mqtt-format/Cargo.toml index 795eb812..cc31638d 100644 --- a/mqtt-format/Cargo.toml +++ b/mqtt-format/Cargo.toml @@ -13,6 +13,7 @@ categories = ["embedded", "parsing"] [features] yoke = ["dep:yoke"] +debug = ["winnow/debug"] [dependencies] futures = "0.3.28" From 39afa72082737859415d9fa811b47d5934bb22a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 10:04:36 +0100 Subject: [PATCH 30/90] Add traces to integer parsers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/integers.rs | 37 ++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/mqtt-format/src/v5/integers.rs b/mqtt-format/src/v5/integers.rs index 11a16812..4d3e63ba 100644 --- a/mqtt-format/src/v5/integers.rs +++ b/mqtt-format/src/v5/integers.rs @@ -1,29 +1,40 @@ -use winnow::{token::take_while, Bytes, Parser}; +use winnow::{combinator::trace, token::take_while, Bytes, Parser}; use super::MResult; pub fn parse_u16<'i>(input: &mut &'i Bytes) -> MResult { - winnow::binary::u16(winnow::binary::Endianness::Big).parse_next(input) + trace( + "parse_u16", + winnow::binary::u16(winnow::binary::Endianness::Big), + ) + .parse_next(input) } pub fn parse_u32<'i>(input: &mut &'i Bytes) -> MResult { - winnow::binary::u32(winnow::binary::Endianness::Big).parse_next(input) + trace( + "parse_u32", + winnow::binary::u32(winnow::binary::Endianness::Big), + ) + .parse_next(input) } pub fn parse_variable_u32<'i>(input: &mut &'i Bytes) -> MResult { - let var_bytes = ( - take_while(0..=3, |b| b & 0b1000_0000 != 0), - winnow::binary::u8.verify(|b: &u8| b & 0b1000_0000 == 0), - ); - let bytes = var_bytes.recognize().parse_next(input)?; + trace("parse_variable_u32", |input: &mut &Bytes| { + let var_bytes = ( + take_while(0..=3, |b| b & 0b1000_0000 != 0), + winnow::binary::u8.verify(|b: &u8| b & 0b1000_0000 == 0), + ); + let bytes: &[u8] = var_bytes.recognize().parse_next(input)?; - let mut output: u32 = 0; + let mut output: u32 = 0; - for (exp, val) in bytes.iter().enumerate() { - output += (*val as u32 & 0b0111_1111) * 128u32.pow(exp as u32); - } + for (exp, val) in bytes.iter().enumerate() { + output += (*val as u32 & 0b0111_1111) * 128u32.pow(exp as u32); + } - Ok(output) + Ok(output) + }) + .parse_next(input) } #[cfg(test)] From 19971461530fc252a7e131b7dd78d2f559fed6e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 10:04:56 +0100 Subject: [PATCH 31/90] Add traces for properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/variable_header.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mqtt-format/src/v5/variable_header.rs b/mqtt-format/src/v5/variable_header.rs index 99d06bc8..9b455268 100644 --- a/mqtt-format/src/v5/variable_header.rs +++ b/mqtt-format/src/v5/variable_header.rs @@ -39,7 +39,9 @@ macro_rules! define_properties { { use winnow::Parser; - Ok(Self($parser.parse_next(input)?)) + Ok(Self( + winnow::combinator::trace(stringify!($name), $parser).parse_next(input)? + )) } } @@ -59,12 +61,14 @@ macro_rules! define_properties { impl<'i> Property<'i> { pub fn parse(input: &mut &'i Bytes) -> MResult> { - winnow::combinator::dispatch! { crate::v5::integers::parse_variable_u32; + let disp = winnow::combinator::dispatch! { crate::v5::integers::parse_variable_u32; $( $id => $name::parse.map(Property::from), )* _ => winnow::combinator::fail - }.parse_next(input) + }; + + winnow::combinator::trace("Property", disp).parse_next(input) } } } From 78621cd48e9934f5ccc20cba55167a60fcb6b212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 10:29:35 +0100 Subject: [PATCH 32/90] Add UserProperties iterator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packet/connack.rs | 4 +- mqtt-format/src/v5/packet/connect.rs | 4 +- mqtt-format/src/v5/packet/publish.rs | 4 +- mqtt-format/src/v5/variable_header.rs | 99 +++++++++++++++++++++++---- 4 files changed, 93 insertions(+), 18 deletions(-) diff --git a/mqtt-format/src/v5/packet/connack.rs b/mqtt-format/src/v5/packet/connack.rs index 8654be0f..bd5c79b6 100644 --- a/mqtt-format/src/v5/packet/connack.rs +++ b/mqtt-format/src/v5/packet/connack.rs @@ -10,7 +10,7 @@ use crate::v5::{ AssignedClientIdentifier, AuthenticationData, AuthenticationMethod, MaximumPacketSize, MaximumQoS, ReasonString, ReceiveMaximum, ResponseInformation, RetainAvailable, ServerKeepAlive, ServerReference, SessionExpiryInterval, SharedSubscriptionAvailable, - SubscriptionIdentifiersAvailable, TopicAliasMaximum, UserProperty, + SubscriptionIdentifiersAvailable, TopicAliasMaximum, UserProperties, WildcardSubscriptionAvailable, }, MResult, @@ -52,7 +52,7 @@ define_properties![ assigned_client_identifier: AssignedClientIdentifier<'i>, topic_alias_maximum: TopicAliasMaximum, reason_string: ReasonString<'i>, - user_property: UserProperty<'i>, + user_properties: UserProperties<'i>, wildcard_subscription_available: WildcardSubscriptionAvailable, subscription_identifiers_available: SubscriptionIdentifiersAvailable, shared_scubscription_available: SharedSubscriptionAvailable, diff --git a/mqtt-format/src/v5/packet/connect.rs b/mqtt-format/src/v5/packet/connect.rs index a87c73fd..47d36052 100644 --- a/mqtt-format/src/v5/packet/connect.rs +++ b/mqtt-format/src/v5/packet/connect.rs @@ -10,7 +10,7 @@ use crate::v5::{ AuthenticationData, AuthenticationMethod, ContentType, CorrelationData, MaximumPacketSize, MessageExpiryInterval, PayloadFormatIndicator, ReceiveMaximum, RequestProblemInformation, RequestResponseInformation, ResponseTopic, SessionExpiryInterval, TopicAliasMaximum, - UserProperty, WillDelayInterval, + UserProperties, WillDelayInterval, }, MResult, }; @@ -34,7 +34,7 @@ crate::v5::properties::define_properties! { topic_alias_maximum: TopicAliasMaximum, request_response_information: RequestResponseInformation, request_problem_information: RequestProblemInformation, - user_property: UserProperty<'i>, + user_properties: UserProperties<'i>, authentication_method: AuthenticationMethod<'i>, authentication_data: AuthenticationData<'i>, } diff --git a/mqtt-format/src/v5/packet/publish.rs b/mqtt-format/src/v5/packet/publish.rs index c70aae1f..f2f0deec 100644 --- a/mqtt-format/src/v5/packet/publish.rs +++ b/mqtt-format/src/v5/packet/publish.rs @@ -7,7 +7,7 @@ use winnow::{ use crate::v5::{ variable_header::{ ContentType, CorrelationData, MessageExpiryInterval, PayloadFormatIndicator, ResponseTopic, - SubscriptionIdentifier, TopicAlias, UserProperty, + SubscriptionIdentifier, TopicAlias, UserProperties, }, MResult, }; @@ -26,7 +26,7 @@ crate::v5::properties::define_properties! { topic_alias: TopicAlias, response_topic: ResponseTopic<'i>, correlation_data: CorrelationData<'i>, - user_property: UserProperty<'i>, + user_properties: UserProperties<'i>, subscription_identifier: SubscriptionIdentifier, content_type: ContentType<'i>, } diff --git a/mqtt-format/src/v5/variable_header.rs b/mqtt-format/src/v5/variable_header.rs index 9b455268..7b184f2e 100644 --- a/mqtt-format/src/v5/variable_header.rs +++ b/mqtt-format/src/v5/variable_header.rs @@ -56,7 +56,7 @@ macro_rules! define_properties { $( $name ( $name $(< $tylt >)? ), )* - UserProperty(UserProperty<'i>), + UserProperties(UserProperties<'i>), } impl<'i> Property<'i> { @@ -65,6 +65,7 @@ macro_rules! define_properties { $( $id => $name::parse.map(Property::from), )* + 0x26 => UserProperties::parse.map(Property::from), _ => winnow::combinator::fail }; @@ -103,9 +104,9 @@ define_properties! {[ SharedSubscriptionAvailable as 0x2A => parse with winnow::binary::u8 as u8, ]} -pub struct UserProperty<'i>(pub &'i [u8]); +pub struct UserProperties<'i>(pub &'i [u8]); -impl<'i> MqttProperties<'i> for UserProperty<'i> { +impl<'i> MqttProperties<'i> for UserProperties<'i> { const IDENTIFIER: u32 = 0x26; const ALLOW_REPEATING: bool = true; @@ -113,46 +114,77 @@ impl<'i> MqttProperties<'i> for UserProperty<'i> { where 'input: 'i, { - let checkpoint = *input; - // We only need to verify there is a correct string pair - let _ = crate::v5::strings::string_pair.parse_peek(input)?; + let prop = crate::v5::strings::string_pair + .recognize() + .parse_next(input)?; - Ok(Self(checkpoint.as_ref())) + Ok(Self(prop)) } } -impl<'i> From> for Property<'i> { - fn from(value: UserProperty<'i>) -> Property<'i> { - Property::UserProperty(value) +impl<'i> From> for Property<'i> { + fn from(value: UserProperties<'i>) -> Property<'i> { + Property::UserProperties(value) } } -impl<'i> UserProperty<'i> { +impl<'i> UserProperties<'i> { pub fn iter(&'i self) -> UserPropertyIterator<'i> { + // UserProperties (note the plural) points to the start of the first _valid_ UserProperty. + // This means that the iterator first needs to consume that property before searching for + // the next! UserPropertyIterator { // This is amazing. // // Bytes is unsized, so we can create it like this current: &Bytes::new(&self.0), + first_prop: true, } } } +#[derive(Debug, PartialEq)] +pub struct UserProperty<'i> { + pub key: &'i str, + pub value: &'i str, +} + +impl<'i> UserProperty<'i> { + pub fn parse(input: &mut &'i Bytes) -> MResult> { + crate::v5::strings::string_pair + .map(|(k, v)| UserProperty { key: k, value: v }) + .parse_next(input) + } +} + pub struct UserPropertyIterator<'i> { current: &'i Bytes, + first_prop: bool, } impl<'i> Iterator for UserPropertyIterator<'i> { type Item = UserProperty<'i>; fn next(&mut self) -> Option { + if self.first_prop { + self.first_prop = false; + return Some(UserProperty::parse(&mut self.current).expect( + "This has already been parsed and the first item should be a UserProperty", + )); + } + while !self.current.is_empty() { let property = Property::parse(&mut self.current) .expect("This has already been parsed, and should be valid."); match property { - Property::UserProperty(prop) => return Some(prop), + Property::UserProperties(prop) => { + return Some( + UserProperty::parse(&mut Bytes::new(prop.0)) + .expect("This has already been parsed and should be valid"), + ) + } _ => continue, } } @@ -160,3 +192,46 @@ impl<'i> Iterator for UserPropertyIterator<'i> { None } } + +#[cfg(test)] +mod tests { + use crate::v5::variable_header::{MqttProperties, RetainAvailable, UserProperty}; + + use super::UserProperties; + + #[test] + fn check_iteration() { + #[rustfmt::skip] + let input = &[ + // First the string pair of the UserProp + 0x0, 0x1, b'a', + 0x0, 0x2, b'b', b'c', + // Retain Available + RetainAvailable::IDENTIFIER as u8, + 0x1, + // User Property + UserProperties::IDENTIFIER as u8, + // Now a string pair + 0x0, 0x1, b'f', + 0x0, 0x2, b'h', b'j', + ]; + + let result = UserProperties(input); + let props = result.iter().collect::>(); + assert_eq!(props.len(), 2); + assert_eq!( + props[0], + UserProperty { + key: "a", + value: "bc" + } + ); + assert_eq!( + props[1], + UserProperty { + key: "f", + value: "hj" + } + ); + } +} From 7666c5c6a106e733efe9195c7f51bbeda59e2a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 10:54:40 +0100 Subject: [PATCH 33/90] Add crate-private new to properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows the format crate to create new properties, but not users Signed-off-by: Marcel Müller --- mqtt-format/src/v5/properties.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mqtt-format/src/v5/properties.rs b/mqtt-format/src/v5/properties.rs index dbc9b190..8701e8df 100644 --- a/mqtt-format/src/v5/properties.rs +++ b/mqtt-format/src/v5/properties.rs @@ -49,6 +49,12 @@ macro_rules! define_properties { } impl<$lt> $name <$lt> { + pub(crate) fn new() -> Self { + $name { + $($prop_name: None),* + } + } + pub fn parse(input: &mut & $lt winnow::Bytes) -> crate::v5::MResult<$name<$lt>> { use winnow::Parser; use winnow::error::ErrMode; From c4b412f11812d401dff64adf9fee6b18c5d93ba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 11:39:08 +0100 Subject: [PATCH 34/90] Use num_enum for QoS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/fixed_header.rs | 28 +++++++++------------------- mqtt-format/src/v5/packet/connect.rs | 10 ++++++++-- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/mqtt-format/src/v5/fixed_header.rs b/mqtt-format/src/v5/fixed_header.rs index 4cf543c1..dc266dba 100644 --- a/mqtt-format/src/v5/fixed_header.rs +++ b/mqtt-format/src/v5/fixed_header.rs @@ -1,30 +1,18 @@ use winnow::{ binary::bits::bits, - error::{ErrMode, InputError, ParserError}, + error::{ErrMode, FromExternalError, InputError, ParserError}, Bytes, Parser, }; use super::{integers::parse_variable_u32, MResult}; +#[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)] +#[repr(u8)] #[derive(Debug, PartialEq)] pub enum QualityOfService { - AtMostOnce, - AtLeastOnce, - ExactlyOnce, -} - -impl QualityOfService { - pub fn from_byte(u: u8, input: &mut &Bytes) -> MResult { - match u { - 0 => Ok(QualityOfService::AtMostOnce), - 1 => Ok(QualityOfService::AtLeastOnce), - 2 => Ok(QualityOfService::ExactlyOnce), - _ => Err(ErrMode::from_error_kind( - input, - winnow::error::ErrorKind::Verify, - )), - } - } + AtMostOnce = 0, + AtLeastOnce = 1, + ExactlyOnce = 2, } #[derive(Debug, PartialEq)] @@ -77,7 +65,9 @@ pub fn parse_fixed_header<'i>(input: &mut &'i Bytes) -> MResult { (2, 0) => PacketType::Connect, (3, flags) => PacketType::Publish { dup: (0b1000 & flags) != 0, - qos: QualityOfService::from_byte((flags & 0b0110) >> 1, input)?, + qos: QualityOfService::try_from((flags & 0b0110) >> 1).map_err(|e| { + ErrMode::from_external_error(input, winnow::error::ErrorKind::Verify, e) + })?, retain: (0b0001 & flags) != 0, }, (4, 0) => PacketType::Puback, diff --git a/mqtt-format/src/v5/packet/connect.rs b/mqtt-format/src/v5/packet/connect.rs index 47d36052..0a1b250e 100644 --- a/mqtt-format/src/v5/packet/connect.rs +++ b/mqtt-format/src/v5/packet/connect.rs @@ -1,4 +1,7 @@ -use winnow::Bytes; +use winnow::{ + error::{ErrMode, FromExternalError}, + Bytes, +}; use crate::v5::{ bytes::parse_data, @@ -52,7 +55,10 @@ impl<'i> MConnect<'i> { let user_name_flag = 0b1000_0000 & connect_flags != 0; let password_flag = 0b0100_0000 & connect_flags != 0; let will_retain = 0b0010_0000 & connect_flags != 0; - let will_qos = QualityOfService::from_byte((0b0001_1000 & connect_flags) >> 3, input)?; + let will_qos = + QualityOfService::try_from((0b0001_1000 & connect_flags) >> 3).map_err(|e| { + ErrMode::from_external_error(input, winnow::error::ErrorKind::Verify, e) + })?; let will_flag = 0b0000_0100 & connect_flags != 0; let clean_start = 0b0000_0001 & connect_flags != 0; From 30f284066450a455fd6d3d9fd722ae3df87729c2 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 13:04:46 +0100 Subject: [PATCH 35/90] Implement MAuth Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packet/auth.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/mqtt-format/src/v5/packet/auth.rs b/mqtt-format/src/v5/packet/auth.rs index 4af9be1f..a35141c3 100644 --- a/mqtt-format/src/v5/packet/auth.rs +++ b/mqtt-format/src/v5/packet/auth.rs @@ -1,3 +1,10 @@ +use winnow::Bytes; + +use crate::v5::{ + variable_header::{AuthenticationData, AuthenticationMethod, ReasonString, UserProperties}, + MResult, +}; + crate::v5::reason_code::make_combined_reason_code! { pub enum AuthReasonCode { ContinueAuthentication = crate::v5::reason_code::ContinueAuthentication, @@ -5,3 +12,26 @@ crate::v5::reason_code::make_combined_reason_code! { Success = crate::v5::reason_code::Success, } } + +crate::v5::properties::define_properties! { + pub struct AuthProperties<'i> { + authentication_method: AuthenticationMethod<'i>, + authentication_data: AuthenticationData<'i>, + reason_string: ReasonString<'i>, + user_properties: UserProperties<'i>, + } +} + +pub struct MAuth<'i> { + reason: AuthReasonCode, + properties: AuthProperties<'i>, +} + +impl<'i> MAuth<'i> { + pub fn parse(input: &mut &'i Bytes) -> MResult { + let reason = AuthReasonCode::parse(input)?; + let properties = AuthProperties::parse(input)?; + + Ok(Self { reason, properties }) + } +} From 80a38fe9ffbdf432433968293fa12f30e31e8b24 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 13:04:55 +0100 Subject: [PATCH 36/90] Implement MPubcomp Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packet/pubcomp.rs | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/mqtt-format/src/v5/packet/pubcomp.rs b/mqtt-format/src/v5/packet/pubcomp.rs index dba01649..f67d3482 100644 --- a/mqtt-format/src/v5/packet/pubcomp.rs +++ b/mqtt-format/src/v5/packet/pubcomp.rs @@ -1,6 +1,39 @@ +use winnow::Bytes; + +use crate::v5::{ + variable_header::{parse_packet_identifier, PacketIdentifier, ReasonString, UserProperties}, + MResult, +}; + crate::v5::reason_code::make_combined_reason_code! { pub enum PubcompReasonCode { PacketIdentifierNotFound = crate::v5::reason_code::PacketIdentifierNotFound, Success = crate::v5::reason_code::Success, } } + +crate::v5::properties::define_properties! { + pub struct PubcompProperties <'i> { + reason_string: ReasonString<'i>, + user_properties: UserProperties<'i>, + } +} + +pub struct MPubcomp<'i> { + packet_identifier: PacketIdentifier, + reason: PubcompReasonCode, + properties: PubcompProperties<'i>, +} + +impl<'i> MPubcomp<'i> { + pub fn parse(input: &mut &'i Bytes) -> MResult { + let packet_identifier = parse_packet_identifier(input)?; + let reason = PubcompReasonCode::parse(input)?; + let properties = PubcompProperties::parse(input)?; + Ok(Self { + packet_identifier, + reason, + properties, + }) + } +} From c0c037a1760eddc78a9e58c116651cb1a2f8ef3f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 13:05:07 +0100 Subject: [PATCH 37/90] Implement MPubrec Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packet/pubrec.rs | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/mqtt-format/src/v5/packet/pubrec.rs b/mqtt-format/src/v5/packet/pubrec.rs index 2e1f3290..d588fb76 100644 --- a/mqtt-format/src/v5/packet/pubrec.rs +++ b/mqtt-format/src/v5/packet/pubrec.rs @@ -1,3 +1,11 @@ +use winnow::Bytes; + +use crate::v5::{ + fixed_header::PacketType, + variable_header::{parse_packet_identifier, PacketIdentifier, ReasonString, UserProperties}, + MResult, +}; + crate::v5::reason_code::make_combined_reason_code! { pub enum PubrecReasonCode { ImplementationSpecificError = crate::v5::reason_code::ImplementationSpecificError, @@ -12,3 +20,31 @@ crate::v5::reason_code::make_combined_reason_code! { UnspecifiedError = crate::v5::reason_code::UnspecifiedError, } } + +crate::v5::properties::define_properties![ + pub struct PubrecProperties<'i> { + reason_string: ReasonString<'i>, + user_properties: UserProperties<'i>, + } +]; + +pub struct MPubrec<'i> { + packet_identifier: PacketIdentifier, + reason: PubrecReasonCode, + properties: PubrecProperties<'i>, +} + +impl<'i> MPubrec<'i> { + pub const PACKET_TYPE: PacketType = PacketType::Pubrec; + + pub fn parse(input: &mut &'i Bytes) -> MResult { + let packet_identifier = parse_packet_identifier(input)?; + let reason = PubrecReasonCode::parse(input)?; + let properties = PubrecProperties::parse(input)?; + Ok(Self { + packet_identifier, + reason, + properties, + }) + } +} From 50ab152d03a1defbe959f002c95adb6808a4fa53 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 13:05:25 +0100 Subject: [PATCH 38/90] Implement MSuback Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packet/suback.rs | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/mqtt-format/src/v5/packet/suback.rs b/mqtt-format/src/v5/packet/suback.rs index 7ce580da..ce8ade24 100644 --- a/mqtt-format/src/v5/packet/suback.rs +++ b/mqtt-format/src/v5/packet/suback.rs @@ -1,3 +1,10 @@ +use winnow::{Bytes, Parser}; + +use crate::v5::{ + variable_header::{parse_packet_identifier, PacketIdentifier, ReasonString, UserProperties}, + MResult, +}; + crate::v5::reason_code::make_combined_reason_code! { pub enum SubackReasonCode { GrantedQoS0 = crate::v5::reason_code::GrantedQoS0, @@ -14,3 +21,42 @@ crate::v5::reason_code::make_combined_reason_code! { WildcardSubscriptionsNotSupported = crate::v5::reason_code::WildcardSubscriptionsNotSupported, } } + +crate::v5::properties::define_properties! { + pub struct SubackProperties<'i> { + reason_string: ReasonString<'i>, + user_properties: UserProperties<'i>, + } +} + +pub struct MSuback<'i> { + packet_identifier: PacketIdentifier, + properties: SubackProperties<'i>, + reasons: &'i [SubackReasonCode], +} + +impl<'i> MSuback<'i> { + pub fn parse(input: &mut &'i Bytes) -> MResult { + let packet_identifier = parse_packet_identifier(input)?; + let properties = SubackProperties::parse(input)?; + + // Verify that the payload only contains valid reason codes + let payload: &[u8] = winnow::combinator::repeat_till::<_, _, (), _, _, _, _>( + 0.., + SubackReasonCode::parse, + winnow::combinator::eof, + ) + .recognize() + .parse_next(input)?; + + // SAFETY: We verified above that the payload slice only contains valid SubackReasonCode + // bytes + let reasons: &[SubackReasonCode] = unsafe { std::mem::transmute(payload) }; + + Ok(Self { + packet_identifier, + properties, + reasons, + }) + } +} From 7876faa609a793fe2f9e39d15bc24902aad077ee Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 13:05:31 +0100 Subject: [PATCH 39/90] Implement MUnsuback Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packet/unsuback.rs | 47 +++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/mqtt-format/src/v5/packet/unsuback.rs b/mqtt-format/src/v5/packet/unsuback.rs index 8a58d09d..61fa654d 100644 --- a/mqtt-format/src/v5/packet/unsuback.rs +++ b/mqtt-format/src/v5/packet/unsuback.rs @@ -1,3 +1,11 @@ +use winnow::Bytes; +use winnow::Parser; + +use crate::v5::{ + variable_header::{parse_packet_identifier, PacketIdentifier, ReasonString, UserProperties}, + MResult, +}; + crate::v5::reason_code::make_combined_reason_code! { pub enum UnsubackReasonCode { ImplementationSpecificError = crate::v5::reason_code::ImplementationSpecificError, @@ -9,3 +17,42 @@ crate::v5::reason_code::make_combined_reason_code! { UnspecifiedError = crate::v5::reason_code::UnspecifiedError, } } + +crate::v5::properties::define_properties! { + pub struct UnsubackProperties<'i> { + reason_string: ReasonString<'i>, + user_properties: UserProperties<'i>, + } +} + +pub struct MUnsuback<'i> { + packet_identifier: PacketIdentifier, + properties: UnsubackProperties<'i>, + reasons: &'i [UnsubackReasonCode], +} + +impl<'i> MUnsuback<'i> { + pub fn parse(input: &mut &'i Bytes) -> MResult { + let packet_identifier = parse_packet_identifier(input)?; + let properties = UnsubackProperties::parse(input)?; + + // Verify that the payload only contains valid reason codes + let payload: &[u8] = winnow::combinator::repeat_till::<_, _, (), _, _, _, _>( + 0.., + UnsubackReasonCode::parse, + winnow::combinator::eof, + ) + .recognize() + .parse_next(input)?; + + // SAFETY: We verified above that the payload slice only contains valid UnsubackReasonCode + // bytes + let reasons: &[UnsubackReasonCode] = unsafe { std::mem::transmute(payload) }; + + Ok(Self { + packet_identifier, + properties, + reasons, + }) + } +} From f83cf24fba1c02f54d91eec6ffb7ed1d3910f8b6 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 09:56:10 +0100 Subject: [PATCH 40/90] Implement MPingresp Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packet/mod.rs | 1 + mqtt-format/src/v5/packet/pingresp.rs | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 mqtt-format/src/v5/packet/pingresp.rs diff --git a/mqtt-format/src/v5/packet/mod.rs b/mqtt-format/src/v5/packet/mod.rs index 43224795..2cbf08e8 100644 --- a/mqtt-format/src/v5/packet/mod.rs +++ b/mqtt-format/src/v5/packet/mod.rs @@ -3,6 +3,7 @@ pub mod connack; pub mod connect; pub mod disconnect; pub mod payload; +pub mod pingresp; pub mod puback; pub mod pubcomp; pub mod publish; diff --git a/mqtt-format/src/v5/packet/pingresp.rs b/mqtt-format/src/v5/packet/pingresp.rs new file mode 100644 index 00000000..0cef50ae --- /dev/null +++ b/mqtt-format/src/v5/packet/pingresp.rs @@ -0,0 +1,11 @@ +use winnow::Bytes; + +use crate::v5::MResult; + +pub struct MPingresp; + +impl MPingresp { + pub fn parse(input: &mut &Bytes) -> MResult { + winnow::combinator::eof(input).map(|_| Self) + } +} From b6b5fbdc0596075042ede04994109a7504a22d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 11:01:52 +0100 Subject: [PATCH 41/90] Implement MPuback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packet/puback.rs | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/mqtt-format/src/v5/packet/puback.rs b/mqtt-format/src/v5/packet/puback.rs index 2d7d032f..c478a86f 100644 --- a/mqtt-format/src/v5/packet/puback.rs +++ b/mqtt-format/src/v5/packet/puback.rs @@ -1,3 +1,12 @@ +use winnow::Bytes; + +use crate::v5::{ + fixed_header::PacketType, + properties::define_properties, + variable_header::{parse_packet_identifier, PacketIdentifier, ReasonString, UserProperties}, + MResult, +}; + crate::v5::reason_code::make_combined_reason_code! { pub enum PubackReasonCode { ImplementationSpecificError = crate::v5::reason_code::ImplementationSpecificError, @@ -11,3 +20,40 @@ crate::v5::reason_code::make_combined_reason_code! { UnspecifiedError = crate::v5::reason_code::UnspecifiedError, } } + +define_properties!( + pub struct PubackProperties<'i> { + reason_string: ReasonString<'i>, + user_properties: UserProperties<'i>, + } +); + +pub struct MPuback<'i> { + packet_identifier: PacketIdentifier, + reason: PubackReasonCode, + properties: PubackProperties<'i>, +} + +impl<'i> MPuback<'i> { + pub const PACKET_TYPE: PacketType = PacketType::Puback; + + pub fn parse(input: &mut &'i Bytes) -> MResult { + let packet_identifier = parse_packet_identifier(input)?; + + if input.is_empty() { + Ok(Self { + packet_identifier, + reason: PubackReasonCode::Success, + properties: PubackProperties::new(), + }) + } else { + let reason = PubackReasonCode::parse(input)?; + let properties = PubackProperties::parse(input)?; + Ok(Self { + packet_identifier, + reason, + properties, + }) + } + } +} From c2eefb33ec0dea91127414c918efaf4d10567825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 11:04:29 +0100 Subject: [PATCH 42/90] Implement MPubrel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packet/mod.rs | 1 + mqtt-format/src/v5/packet/pubrel.rs | 52 +++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 mqtt-format/src/v5/packet/pubrel.rs diff --git a/mqtt-format/src/v5/packet/mod.rs b/mqtt-format/src/v5/packet/mod.rs index 2cbf08e8..73eff85f 100644 --- a/mqtt-format/src/v5/packet/mod.rs +++ b/mqtt-format/src/v5/packet/mod.rs @@ -8,5 +8,6 @@ pub mod puback; pub mod pubcomp; pub mod publish; pub mod pubrec; +pub mod pubrel; pub mod suback; pub mod unsuback; diff --git a/mqtt-format/src/v5/packet/pubrel.rs b/mqtt-format/src/v5/packet/pubrel.rs new file mode 100644 index 00000000..5bcbc8be --- /dev/null +++ b/mqtt-format/src/v5/packet/pubrel.rs @@ -0,0 +1,52 @@ +use winnow::Bytes; + +use crate::v5::{ + fixed_header::PacketType, + properties::define_properties, + variable_header::{parse_packet_identifier, PacketIdentifier, ReasonString, UserProperties}, + MResult, +}; + +crate::v5::reason_code::make_combined_reason_code! { + pub enum PubrelReasonCode { + Success = crate::v5::reason_code::Success, + PacketIdentifierNotFound = crate::v5::reason_code::PacketIdentifierNotFound, + } +} + +define_properties!( + pub struct PubrelProperties<'i> { + reason_string: ReasonString<'i>, + user_properties: UserProperties<'i>, + } +); + +pub struct MPubrel<'i> { + packet_identifier: PacketIdentifier, + reason: PubrelReasonCode, + properties: PubrelProperties<'i>, +} + +impl<'i> MPubrel<'i> { + pub const PACKET_TYPE: PacketType = PacketType::Pubrel; + + pub fn parse(input: &mut &'i Bytes) -> MResult { + let packet_identifier = parse_packet_identifier(input)?; + + if input.is_empty() { + Ok(Self { + packet_identifier, + reason: PubrelReasonCode::Success, + properties: PubrelProperties::new(), + }) + } else { + let reason = PubrelReasonCode::parse(input)?; + let properties = PubrelProperties::parse(input)?; + Ok(Self { + packet_identifier, + reason, + properties, + }) + } + } +} From 015e112539d3e729449beb1d3e108d5c8b51689b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 11:39:46 +0100 Subject: [PATCH 43/90] Implement MSubscribe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packet/mod.rs | 1 + mqtt-format/src/v5/packet/subscribe.rs | 116 +++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 mqtt-format/src/v5/packet/subscribe.rs diff --git a/mqtt-format/src/v5/packet/mod.rs b/mqtt-format/src/v5/packet/mod.rs index 73eff85f..0e566232 100644 --- a/mqtt-format/src/v5/packet/mod.rs +++ b/mqtt-format/src/v5/packet/mod.rs @@ -10,4 +10,5 @@ pub mod publish; pub mod pubrec; pub mod pubrel; pub mod suback; +pub mod subscribe; pub mod unsuback; diff --git a/mqtt-format/src/v5/packet/subscribe.rs b/mqtt-format/src/v5/packet/subscribe.rs new file mode 100644 index 00000000..0aab6b70 --- /dev/null +++ b/mqtt-format/src/v5/packet/subscribe.rs @@ -0,0 +1,116 @@ +use winnow::{ + binary::bits::bits, + combinator::repeat_till, + error::{ErrMode, InputError, ParserError}, + Bytes, Parser, +}; + +use crate::v5::{ + fixed_header::QualityOfService, + properties::define_properties, + strings::parse_string, + variable_header::{ + parse_packet_identifier, PacketIdentifier, SubscriptionIdentifier, UserProperties, + }, + MResult, +}; + +define_properties! { + pub struct SubscribeProperties<'i> { + subscription_identifier: SubscriptionIdentifier, + user_properties: UserProperties<'i>, + } +} + +#[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)] +#[repr(u8)] +pub enum RetainHandling { + SendRetainedMessagesAlways = 0, + SendRetainedMessagesOnNewSubscribe = 1, + DoNotSendRetainedMessages = 2, +} + +pub struct SubscriptionOptions { + pub quality_of_service: QualityOfService, + pub no_local: bool, + pub retain_as_published: bool, + pub retain_handling: RetainHandling, +} + +impl SubscriptionOptions { + fn parse<'i>(input: &mut &'i Bytes) -> MResult { + let (quality_of_service, no_local, retain_as_published, retain_handling) = + bits::<_, _, InputError<(_, usize)>, _, _>(( + winnow::binary::bits::take(2usize) + .try_map(>::try_from), + winnow::binary::bits::bool, + winnow::binary::bits::bool, + winnow::binary::bits::take(2usize) + .try_map(>::try_from), + )) + .parse_next(input) + .map_err(|_: ErrMode>| { + ErrMode::from_error_kind(input, winnow::error::ErrorKind::Slice) + })?; + + Ok(SubscriptionOptions { + quality_of_service, + no_local, + retain_as_published, + retain_handling, + }) + } +} + +pub struct Subscription<'i> { + pub topic_filter: &'i str, + pub options: SubscriptionOptions, +} + +impl<'i> Subscription<'i> { + fn parse(input: &mut &'i Bytes) -> MResult> { + let (topic_filter, options) = + (parse_string, SubscriptionOptions::parse).parse_next(input)?; + + Ok(Subscription { + topic_filter, + options, + }) + } +} + +pub struct Subscriptions<'i> { + start: &'i [u8], +} + +impl<'i> Subscriptions<'i> { + fn parse(input: &mut &'i Bytes) -> MResult> { + let start = + repeat_till::<_, _, (), _, _, _, _>(1.., Subscription::parse, winnow::combinator::eof) + .recognize() + .parse_next(input)?; + + Ok(Subscriptions { start }) + } +} + +pub struct MSubscribe<'i> { + pub packet_identifier: PacketIdentifier, + pub properties: SubscribeProperties<'i>, + pub subscriptions: Subscriptions<'i>, +} + +impl<'i> MSubscribe<'i> { + fn parse(input: &mut &'i Bytes) -> MResult> { + let (packet_identifier, properties) = + (parse_packet_identifier, SubscribeProperties::parse).parse_next(input)?; + + let subscriptions = Subscriptions::parse(input)?; + + Ok(MSubscribe { + packet_identifier, + properties, + subscriptions, + }) + } +} From 1c7fe84de5cb300a5998120aed206111066fd468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 11:53:02 +0100 Subject: [PATCH 44/90] Implement MUnsubscribe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packet/mod.rs | 1 + mqtt-format/src/v5/packet/unsubscribe.rs | 70 ++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 mqtt-format/src/v5/packet/unsubscribe.rs diff --git a/mqtt-format/src/v5/packet/mod.rs b/mqtt-format/src/v5/packet/mod.rs index 0e566232..5e999547 100644 --- a/mqtt-format/src/v5/packet/mod.rs +++ b/mqtt-format/src/v5/packet/mod.rs @@ -12,3 +12,4 @@ pub mod pubrel; pub mod suback; pub mod subscribe; pub mod unsuback; +pub mod unsubscribe; diff --git a/mqtt-format/src/v5/packet/unsubscribe.rs b/mqtt-format/src/v5/packet/unsubscribe.rs new file mode 100644 index 00000000..4376efb5 --- /dev/null +++ b/mqtt-format/src/v5/packet/unsubscribe.rs @@ -0,0 +1,70 @@ +use winnow::{combinator::repeat_till, Bytes, Parser}; + +use crate::v5::{ + properties::define_properties, + strings::parse_string, + variable_header::{ + parse_packet_identifier, PacketIdentifier, SubscriptionIdentifier, UserProperties, + }, + MResult, +}; + +define_properties! { + pub struct UnsubscribeProperties<'i> { + subscription_identifier: SubscriptionIdentifier, + user_properties: UserProperties<'i>, + } +} + +pub struct Unsubscriptions<'i> { + start: &'i [u8], +} + +impl<'i> Unsubscriptions<'i> { + fn parse(input: &mut &'i Bytes) -> MResult> { + let start = repeat_till::<_, _, (), _, _, _, _>( + 1.., + Unsubscription::parse, + winnow::combinator::eof, + ) + .recognize() + .parse_next(input)?; + + Ok(Unsubscriptions { start }) + } +} + +pub struct Unsubscription<'i> { + pub topic_filter: &'i str, +} + +impl<'i> Unsubscription<'i> { + fn parse(input: &mut &'i Bytes) -> MResult { + let topic_filter = parse_string(input)?; + + Ok(Unsubscription { topic_filter }) + } +} + +pub struct MUnsubscribe<'i> { + packet_identifier: PacketIdentifier, + properties: UnsubscribeProperties<'i>, + unsubscriptions: Unsubscriptions<'i>, +} + +impl<'i> MUnsubscribe<'i> { + fn parse(input: &mut &'i Bytes) -> MResult { + let (packet_identifier, properties, unsubscriptions) = ( + parse_packet_identifier, + UnsubscribeProperties::parse, + Unsubscriptions::parse, + ) + .parse_next(input)?; + + Ok(MUnsubscribe { + packet_identifier, + properties, + unsubscriptions, + }) + } +} From 80e402daec0874d3609e1cc723d2c04ff6af0b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 11:55:54 +0100 Subject: [PATCH 45/90] Implement MPingreq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packet/mod.rs | 1 + mqtt-format/src/v5/packet/pingreq.rs | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 mqtt-format/src/v5/packet/pingreq.rs diff --git a/mqtt-format/src/v5/packet/mod.rs b/mqtt-format/src/v5/packet/mod.rs index 5e999547..4e9daa2b 100644 --- a/mqtt-format/src/v5/packet/mod.rs +++ b/mqtt-format/src/v5/packet/mod.rs @@ -3,6 +3,7 @@ pub mod connack; pub mod connect; pub mod disconnect; pub mod payload; +pub mod pingreq; pub mod pingresp; pub mod puback; pub mod pubcomp; diff --git a/mqtt-format/src/v5/packet/pingreq.rs b/mqtt-format/src/v5/packet/pingreq.rs new file mode 100644 index 00000000..8ce25723 --- /dev/null +++ b/mqtt-format/src/v5/packet/pingreq.rs @@ -0,0 +1,11 @@ +use winnow::{Bytes, Parser}; + +use crate::v5::MResult; + +pub struct MPingreq; + +impl MPingreq { + fn parse<'i>(input: &mut &'i Bytes) -> MResult { + winnow::combinator::eof.map(|_| MPingreq).parse_next(input) + } +} From 02806d24be00082826d2108b6b59a490da7609d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 11:58:53 +0100 Subject: [PATCH 46/90] Implement MDisconnect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packet/disconnect.rs | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/mqtt-format/src/v5/packet/disconnect.rs b/mqtt-format/src/v5/packet/disconnect.rs index 15bea513..557e0442 100644 --- a/mqtt-format/src/v5/packet/disconnect.rs +++ b/mqtt-format/src/v5/packet/disconnect.rs @@ -1,3 +1,11 @@ +use winnow::{Bytes, Parser}; + +use crate::v5::{ + properties::define_properties, + variable_header::{ReasonString, ServerReference, SessionExpiryInterval, UserProperties}, + MResult, +}; + crate::v5::reason_code::make_combined_reason_code! { pub enum DisconnectReasonCode { AdministrativeAction = crate::v5::reason_code::AdministrativeAction, @@ -32,3 +40,29 @@ crate::v5::reason_code::make_combined_reason_code! { WildcardSubscriptionsNotSupported = crate::v5::reason_code::WildcardSubscriptionsNotSupported, } } + +define_properties! { + pub struct DisconnectProperties<'i> { + session_expiry_interval: SessionExpiryInterval, + reason_string: ReasonString<'i>, + user_properties: UserProperties<'i>, + server_reference: ServerReference<'i> + } +} + +pub struct MDisconnect<'i> { + reason_code: DisconnectReasonCode, + properties: DisconnectProperties<'i>, +} + +impl<'i> MDisconnect<'i> { + fn parse(input: &mut &'i Bytes) -> MResult> { + let (reason_code, properties) = + (DisconnectReasonCode::parse, DisconnectProperties::parse).parse_next(input)?; + + Ok(MDisconnect { + reason_code, + properties, + }) + } +} From 1f8ad8ce6841c13708241b5b7f41ec558e7b6cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 12:05:26 +0100 Subject: [PATCH 47/90] Rename parse_data to parse_binary_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/bytes.rs | 9 ++++++--- mqtt-format/src/v5/packet/connect.rs | 4 ++-- mqtt-format/src/v5/variable_header.rs | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/mqtt-format/src/v5/bytes.rs b/mqtt-format/src/v5/bytes.rs index 96413f1d..e4a34502 100644 --- a/mqtt-format/src/v5/bytes.rs +++ b/mqtt-format/src/v5/bytes.rs @@ -2,7 +2,7 @@ use winnow::{binary::length_take, Bytes, Parser}; use super::MResult; -pub fn parse_data<'i>(input: &mut &'i Bytes) -> MResult<&'i [u8]> { +pub fn parse_binary_data<'i>(input: &mut &'i Bytes) -> MResult<&'i [u8]> { length_take(super::integers::parse_u16).parse_next(input) } @@ -10,12 +10,15 @@ pub fn parse_data<'i>(input: &mut &'i Bytes) -> MResult<&'i [u8]> { mod tests { use winnow::Bytes; - use crate::v5::bytes::parse_data; + use crate::v5::bytes::parse_binary_data; #[test] fn check_binary_data() { let input = &[0x0, 0x2, 0x4, 0x2]; - assert_eq!(parse_data(&mut Bytes::new(input)).unwrap(), &[0x4, 0x2]); + assert_eq!( + parse_binary_data(&mut Bytes::new(input)).unwrap(), + &[0x4, 0x2] + ); } } diff --git a/mqtt-format/src/v5/packet/connect.rs b/mqtt-format/src/v5/packet/connect.rs index 0a1b250e..5320c8e7 100644 --- a/mqtt-format/src/v5/packet/connect.rs +++ b/mqtt-format/src/v5/packet/connect.rs @@ -4,7 +4,7 @@ use winnow::{ }; use crate::v5::{ - bytes::parse_data, + bytes::parse_binary_data, fixed_header::{PacketType, QualityOfService}, integers::{parse_u16, parse_u32, parse_variable_u32}, level::ProtocolLevel, @@ -91,7 +91,7 @@ impl<'i> MConnect<'i> { .transpose()?; let username = user_name_flag.then(|| parse_string(input)).transpose()?; - let password = password_flag.then(|| parse_data(input)).transpose()?; + let password = password_flag.then(|| parse_binary_data(input)).transpose()?; Ok(Self { client_identifier, diff --git a/mqtt-format/src/v5/variable_header.rs b/mqtt-format/src/v5/variable_header.rs index 7b184f2e..a0e56bb1 100644 --- a/mqtt-format/src/v5/variable_header.rs +++ b/mqtt-format/src/v5/variable_header.rs @@ -80,13 +80,13 @@ define_properties! {[ MessageExpiryInterval as 0x02 => parse with parse_u32 as u32, ContentType<'i> as 0x03 => parse with super::strings::parse_string as &'i str, ResponseTopic<'i> as 0x08 => parse with super::strings::parse_string as &'i str, - CorrelationData<'i> as 0x09 => parse with super::bytes::parse_data as &'i [u8], + CorrelationData<'i> as 0x09 => parse with super::bytes::parse_binary_data as &'i [u8], SubscriptionIdentifier as 0x0B => parse with parse_u32 as u32, SessionExpiryInterval as 0x11 => parse with parse_u32 as u32, AssignedClientIdentifier<'i> as 0x12 => parse with super::strings::parse_string as &'i str, ServerKeepAlive as 0x13 => parse with parse_u32 as u32, AuthenticationMethod<'i> as 0x15 => parse with super::strings::parse_string as &'i str, - AuthenticationData<'i> as 0x16 => parse with super::bytes::parse_data as &'i [u8], + AuthenticationData<'i> as 0x16 => parse with super::bytes::parse_binary_data as &'i [u8], RequestProblemInformation as 0x17 => parse with winnow::binary::u8 as u8, WillDelayInterval as 0x18 => parse with parse_u32 as u32, RequestResponseInformation as 0x19 => parse with winnow::binary::u8 as u8, From eaa40150f8ed8868cca3c40dd92cda966ca63871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 12:05:40 +0100 Subject: [PATCH 48/90] Remove ApplicationMessagePayload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packet/connect.rs | 6 ++---- mqtt-format/src/v5/packet/mod.rs | 1 - mqtt-format/src/v5/packet/payload.rs | 13 ------------- 3 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 mqtt-format/src/v5/packet/payload.rs diff --git a/mqtt-format/src/v5/packet/connect.rs b/mqtt-format/src/v5/packet/connect.rs index 5320c8e7..6216504c 100644 --- a/mqtt-format/src/v5/packet/connect.rs +++ b/mqtt-format/src/v5/packet/connect.rs @@ -18,8 +18,6 @@ use crate::v5::{ MResult, }; -use super::payload::ApplicationMessagePayload; - pub struct MConnect<'i> { client_identifier: &'i str, username: Option<&'i str>, @@ -80,7 +78,7 @@ impl<'i> MConnect<'i> { .then(|| { let properties = ConnectWillProperties::parse(input)?; let topic = parse_string(input)?; - let payload = ApplicationMessagePayload::parse(input)?; + let payload = crate::v5::bytes::parse_binary_data(input)?; Ok(Will { properties, @@ -107,7 +105,7 @@ impl<'i> MConnect<'i> { pub struct Will<'i> { properties: ConnectWillProperties<'i>, topic: &'i str, - payload: ApplicationMessagePayload<'i>, + payload: &'i [u8], } crate::v5::properties::define_properties! { diff --git a/mqtt-format/src/v5/packet/mod.rs b/mqtt-format/src/v5/packet/mod.rs index 4e9daa2b..7ded7148 100644 --- a/mqtt-format/src/v5/packet/mod.rs +++ b/mqtt-format/src/v5/packet/mod.rs @@ -2,7 +2,6 @@ pub mod auth; pub mod connack; pub mod connect; pub mod disconnect; -pub mod payload; pub mod pingreq; pub mod pingresp; pub mod puback; diff --git a/mqtt-format/src/v5/packet/payload.rs b/mqtt-format/src/v5/packet/payload.rs deleted file mode 100644 index fba89284..00000000 --- a/mqtt-format/src/v5/packet/payload.rs +++ /dev/null @@ -1,13 +0,0 @@ -use winnow::Bytes; - -use crate::v5::MResult; - -pub struct ApplicationMessagePayload<'i> { - payload: &'i [u8], -} - -impl<'i> ApplicationMessagePayload<'i> { - pub fn parse(input: &mut &'i Bytes) -> MResult { - crate::v5::bytes::parse_data(input).map(|payload| Self { payload }) - } -} From 8f47364a6ff01665a86f474c0a73dee319b48998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 12:11:22 +0100 Subject: [PATCH 49/90] Replace manual bit checking with parser in MConnect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packet/connect.rs | 32 +++++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/mqtt-format/src/v5/packet/connect.rs b/mqtt-format/src/v5/packet/connect.rs index 6216504c..a62b30b4 100644 --- a/mqtt-format/src/v5/packet/connect.rs +++ b/mqtt-format/src/v5/packet/connect.rs @@ -1,6 +1,6 @@ use winnow::{ - error::{ErrMode, FromExternalError}, - Bytes, + error::{ErrMode, FromExternalError, InputError, ParserError}, + Bytes, Parser, }; use crate::v5::{ @@ -48,17 +48,21 @@ impl<'i> MConnect<'i> { // parse header let protocol_name = crate::v5::strings::parse_string(input)?; let protocol_level = ProtocolLevel::parse(input)?; - let connect_flags = winnow::binary::u8(input)?; - - let user_name_flag = 0b1000_0000 & connect_flags != 0; - let password_flag = 0b0100_0000 & connect_flags != 0; - let will_retain = 0b0010_0000 & connect_flags != 0; - let will_qos = - QualityOfService::try_from((0b0001_1000 & connect_flags) >> 3).map_err(|e| { - ErrMode::from_external_error(input, winnow::error::ErrorKind::Verify, e) + let (_, clean_start, will_flag, will_qos, will_retain, password_flag, user_name_flag) = + winnow::binary::bits::bits::<_, _, InputError<(_, usize)>, _, _>(( + winnow::binary::bits::pattern(0x0, 1usize), + winnow::binary::bits::bool, + winnow::binary::bits::bool, + winnow::binary::bits::take(2usize) + .try_map(>::try_from), + winnow::binary::bits::bool, + winnow::binary::bits::bool, + winnow::binary::bits::bool, + )) + .parse_next(input) + .map_err(|_: ErrMode>| { + ErrMode::from_error_kind(input, winnow::error::ErrorKind::Slice) })?; - let will_flag = 0b0000_0100 & connect_flags != 0; - let clean_start = 0b0000_0001 & connect_flags != 0; let keep_alive = parse_u16(input)?; @@ -89,7 +93,9 @@ impl<'i> MConnect<'i> { .transpose()?; let username = user_name_flag.then(|| parse_string(input)).transpose()?; - let password = password_flag.then(|| parse_binary_data(input)).transpose()?; + let password = password_flag + .then(|| parse_binary_data(input)) + .transpose()?; Ok(Self { client_identifier, From bd75274c81e2723fc70995453498d2607dd7c919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 12:40:17 +0100 Subject: [PATCH 50/90] Remove reference for &Bytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/variable_header.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mqtt-format/src/v5/variable_header.rs b/mqtt-format/src/v5/variable_header.rs index a0e56bb1..5a1e2e73 100644 --- a/mqtt-format/src/v5/variable_header.rs +++ b/mqtt-format/src/v5/variable_header.rs @@ -135,10 +135,7 @@ impl<'i> UserProperties<'i> { // This means that the iterator first needs to consume that property before searching for // the next! UserPropertyIterator { - // This is amazing. - // - // Bytes is unsized, so we can create it like this - current: &Bytes::new(&self.0), + current: Bytes::new(&self.0), first_prop: true, } } From f50413592a62eaecfd9b45d5ce1329cdec01a93d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 13:29:40 +0100 Subject: [PATCH 51/90] Move packet identifier parsing to struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packet/puback.rs | 4 ++-- mqtt-format/src/v5/packet/pubcomp.rs | 4 ++-- mqtt-format/src/v5/packet/publish.rs | 2 +- mqtt-format/src/v5/packet/pubrec.rs | 4 ++-- mqtt-format/src/v5/packet/pubrel.rs | 4 ++-- mqtt-format/src/v5/packet/suback.rs | 4 ++-- mqtt-format/src/v5/packet/subscribe.rs | 4 ++-- mqtt-format/src/v5/packet/unsuback.rs | 4 ++-- mqtt-format/src/v5/packet/unsubscribe.rs | 6 ++---- mqtt-format/src/v5/variable_header.rs | 6 ++++-- 10 files changed, 21 insertions(+), 21 deletions(-) diff --git a/mqtt-format/src/v5/packet/puback.rs b/mqtt-format/src/v5/packet/puback.rs index c478a86f..bf1db389 100644 --- a/mqtt-format/src/v5/packet/puback.rs +++ b/mqtt-format/src/v5/packet/puback.rs @@ -3,7 +3,7 @@ use winnow::Bytes; use crate::v5::{ fixed_header::PacketType, properties::define_properties, - variable_header::{parse_packet_identifier, PacketIdentifier, ReasonString, UserProperties}, + variable_header::{PacketIdentifier, ReasonString, UserProperties}, MResult, }; @@ -38,7 +38,7 @@ impl<'i> MPuback<'i> { pub const PACKET_TYPE: PacketType = PacketType::Puback; pub fn parse(input: &mut &'i Bytes) -> MResult { - let packet_identifier = parse_packet_identifier(input)?; + let packet_identifier = PacketIdentifier::parse(input)?; if input.is_empty() { Ok(Self { diff --git a/mqtt-format/src/v5/packet/pubcomp.rs b/mqtt-format/src/v5/packet/pubcomp.rs index f67d3482..031377a0 100644 --- a/mqtt-format/src/v5/packet/pubcomp.rs +++ b/mqtt-format/src/v5/packet/pubcomp.rs @@ -1,7 +1,7 @@ use winnow::Bytes; use crate::v5::{ - variable_header::{parse_packet_identifier, PacketIdentifier, ReasonString, UserProperties}, + variable_header::{PacketIdentifier, ReasonString, UserProperties}, MResult, }; @@ -27,7 +27,7 @@ pub struct MPubcomp<'i> { impl<'i> MPubcomp<'i> { pub fn parse(input: &mut &'i Bytes) -> MResult { - let packet_identifier = parse_packet_identifier(input)?; + let packet_identifier = PacketIdentifier::parse(input)?; let reason = PubcompReasonCode::parse(input)?; let properties = PubcompProperties::parse(input)?; Ok(Self { diff --git a/mqtt-format/src/v5/packet/publish.rs b/mqtt-format/src/v5/packet/publish.rs index f2f0deec..fb87adbb 100644 --- a/mqtt-format/src/v5/packet/publish.rs +++ b/mqtt-format/src/v5/packet/publish.rs @@ -42,7 +42,7 @@ impl<'i> MPublish<'i> { )); } - let packet_identifier = crate::v5::variable_header::parse_packet_identifier(input)?; + let packet_identifier = crate::v5::variable_header::PacketIdentifier::parse(input)?; let properties = PublishProperties::parse(input)?; let payload = input.finish(); diff --git a/mqtt-format/src/v5/packet/pubrec.rs b/mqtt-format/src/v5/packet/pubrec.rs index d588fb76..01627cf9 100644 --- a/mqtt-format/src/v5/packet/pubrec.rs +++ b/mqtt-format/src/v5/packet/pubrec.rs @@ -2,7 +2,7 @@ use winnow::Bytes; use crate::v5::{ fixed_header::PacketType, - variable_header::{parse_packet_identifier, PacketIdentifier, ReasonString, UserProperties}, + variable_header::{PacketIdentifier, ReasonString, UserProperties}, MResult, }; @@ -38,7 +38,7 @@ impl<'i> MPubrec<'i> { pub const PACKET_TYPE: PacketType = PacketType::Pubrec; pub fn parse(input: &mut &'i Bytes) -> MResult { - let packet_identifier = parse_packet_identifier(input)?; + let packet_identifier = PacketIdentifier::parse(input)?; let reason = PubrecReasonCode::parse(input)?; let properties = PubrecProperties::parse(input)?; Ok(Self { diff --git a/mqtt-format/src/v5/packet/pubrel.rs b/mqtt-format/src/v5/packet/pubrel.rs index 5bcbc8be..c02f7d3b 100644 --- a/mqtt-format/src/v5/packet/pubrel.rs +++ b/mqtt-format/src/v5/packet/pubrel.rs @@ -3,7 +3,7 @@ use winnow::Bytes; use crate::v5::{ fixed_header::PacketType, properties::define_properties, - variable_header::{parse_packet_identifier, PacketIdentifier, ReasonString, UserProperties}, + variable_header::{PacketIdentifier, ReasonString, UserProperties}, MResult, }; @@ -31,7 +31,7 @@ impl<'i> MPubrel<'i> { pub const PACKET_TYPE: PacketType = PacketType::Pubrel; pub fn parse(input: &mut &'i Bytes) -> MResult { - let packet_identifier = parse_packet_identifier(input)?; + let packet_identifier = PacketIdentifier::parse(input)?; if input.is_empty() { Ok(Self { diff --git a/mqtt-format/src/v5/packet/suback.rs b/mqtt-format/src/v5/packet/suback.rs index ce8ade24..bb720415 100644 --- a/mqtt-format/src/v5/packet/suback.rs +++ b/mqtt-format/src/v5/packet/suback.rs @@ -1,7 +1,7 @@ use winnow::{Bytes, Parser}; use crate::v5::{ - variable_header::{parse_packet_identifier, PacketIdentifier, ReasonString, UserProperties}, + variable_header::{PacketIdentifier, ReasonString, UserProperties}, MResult, }; @@ -37,7 +37,7 @@ pub struct MSuback<'i> { impl<'i> MSuback<'i> { pub fn parse(input: &mut &'i Bytes) -> MResult { - let packet_identifier = parse_packet_identifier(input)?; + let packet_identifier = PacketIdentifier::parse(input)?; let properties = SubackProperties::parse(input)?; // Verify that the payload only contains valid reason codes diff --git a/mqtt-format/src/v5/packet/subscribe.rs b/mqtt-format/src/v5/packet/subscribe.rs index 0aab6b70..4b65a0ec 100644 --- a/mqtt-format/src/v5/packet/subscribe.rs +++ b/mqtt-format/src/v5/packet/subscribe.rs @@ -10,7 +10,7 @@ use crate::v5::{ properties::define_properties, strings::parse_string, variable_header::{ - parse_packet_identifier, PacketIdentifier, SubscriptionIdentifier, UserProperties, + PacketIdentifier, SubscriptionIdentifier, UserProperties, }, MResult, }; @@ -103,7 +103,7 @@ pub struct MSubscribe<'i> { impl<'i> MSubscribe<'i> { fn parse(input: &mut &'i Bytes) -> MResult> { let (packet_identifier, properties) = - (parse_packet_identifier, SubscribeProperties::parse).parse_next(input)?; + (PacketIdentifier::parse, SubscribeProperties::parse).parse_next(input)?; let subscriptions = Subscriptions::parse(input)?; diff --git a/mqtt-format/src/v5/packet/unsuback.rs b/mqtt-format/src/v5/packet/unsuback.rs index 61fa654d..80aab928 100644 --- a/mqtt-format/src/v5/packet/unsuback.rs +++ b/mqtt-format/src/v5/packet/unsuback.rs @@ -2,7 +2,7 @@ use winnow::Bytes; use winnow::Parser; use crate::v5::{ - variable_header::{parse_packet_identifier, PacketIdentifier, ReasonString, UserProperties}, + variable_header::{PacketIdentifier, ReasonString, UserProperties}, MResult, }; @@ -33,7 +33,7 @@ pub struct MUnsuback<'i> { impl<'i> MUnsuback<'i> { pub fn parse(input: &mut &'i Bytes) -> MResult { - let packet_identifier = parse_packet_identifier(input)?; + let packet_identifier = PacketIdentifier::parse(input)?; let properties = UnsubackProperties::parse(input)?; // Verify that the payload only contains valid reason codes diff --git a/mqtt-format/src/v5/packet/unsubscribe.rs b/mqtt-format/src/v5/packet/unsubscribe.rs index 4376efb5..b3a06e81 100644 --- a/mqtt-format/src/v5/packet/unsubscribe.rs +++ b/mqtt-format/src/v5/packet/unsubscribe.rs @@ -3,9 +3,7 @@ use winnow::{combinator::repeat_till, Bytes, Parser}; use crate::v5::{ properties::define_properties, strings::parse_string, - variable_header::{ - parse_packet_identifier, PacketIdentifier, SubscriptionIdentifier, UserProperties, - }, + variable_header::{PacketIdentifier, SubscriptionIdentifier, UserProperties}, MResult, }; @@ -55,7 +53,7 @@ pub struct MUnsubscribe<'i> { impl<'i> MUnsubscribe<'i> { fn parse(input: &mut &'i Bytes) -> MResult { let (packet_identifier, properties, unsubscriptions) = ( - parse_packet_identifier, + PacketIdentifier::parse, UnsubscribeProperties::parse, Unsubscriptions::parse, ) diff --git a/mqtt-format/src/v5/variable_header.rs b/mqtt-format/src/v5/variable_header.rs index 5a1e2e73..6680013e 100644 --- a/mqtt-format/src/v5/variable_header.rs +++ b/mqtt-format/src/v5/variable_header.rs @@ -4,8 +4,10 @@ use super::{integers::parse_u16, integers::parse_u32, MResult}; pub struct PacketIdentifier(pub u16); -pub fn parse_packet_identifier<'i>(input: &mut &'i Bytes) -> MResult { - parse_u16(input).map(PacketIdentifier) +impl PacketIdentifier { + pub fn parse<'i>(input: &mut &'i Bytes) -> MResult { + parse_u16(input).map(PacketIdentifier) + } } pub trait MqttProperties<'lt>: Sized { From 2a136ab06d867756daf6d44b60f7283cfe89ceeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 13:31:34 +0100 Subject: [PATCH 52/90] Simplify code with clippy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/fixed_header.rs | 2 +- mqtt-format/src/v5/integers.rs | 6 +++--- mqtt-format/src/v5/level.rs | 2 +- mqtt-format/src/v5/packet/connack.rs | 2 +- mqtt-format/src/v5/packet/connect.rs | 6 +++--- mqtt-format/src/v5/packet/pingreq.rs | 2 +- mqtt-format/src/v5/packet/publish.rs | 2 +- mqtt-format/src/v5/packet/subscribe.rs | 2 +- mqtt-format/src/v5/variable_header.rs | 2 +- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/mqtt-format/src/v5/fixed_header.rs b/mqtt-format/src/v5/fixed_header.rs index dc266dba..4d35bbf3 100644 --- a/mqtt-format/src/v5/fixed_header.rs +++ b/mqtt-format/src/v5/fixed_header.rs @@ -44,7 +44,7 @@ pub struct MFixedHeader { remaining_length: u32, } -pub fn parse_fixed_header<'i>(input: &mut &'i Bytes) -> MResult { +pub fn parse_fixed_header(input: &mut &Bytes) -> MResult { let (packet_type, packet_flags): (u8, u8) = bits::<_, _, InputError<(_, usize)>, _, _>(( winnow::binary::bits::take(4usize), winnow::binary::bits::take(4usize), diff --git a/mqtt-format/src/v5/integers.rs b/mqtt-format/src/v5/integers.rs index 4d3e63ba..809efa2f 100644 --- a/mqtt-format/src/v5/integers.rs +++ b/mqtt-format/src/v5/integers.rs @@ -2,7 +2,7 @@ use winnow::{combinator::trace, token::take_while, Bytes, Parser}; use super::MResult; -pub fn parse_u16<'i>(input: &mut &'i Bytes) -> MResult { +pub fn parse_u16(input: &mut &Bytes) -> MResult { trace( "parse_u16", winnow::binary::u16(winnow::binary::Endianness::Big), @@ -10,7 +10,7 @@ pub fn parse_u16<'i>(input: &mut &'i Bytes) -> MResult { .parse_next(input) } -pub fn parse_u32<'i>(input: &mut &'i Bytes) -> MResult { +pub fn parse_u32(input: &mut &Bytes) -> MResult { trace( "parse_u32", winnow::binary::u32(winnow::binary::Endianness::Big), @@ -18,7 +18,7 @@ pub fn parse_u32<'i>(input: &mut &'i Bytes) -> MResult { .parse_next(input) } -pub fn parse_variable_u32<'i>(input: &mut &'i Bytes) -> MResult { +pub fn parse_variable_u32(input: &mut &Bytes) -> MResult { trace("parse_variable_u32", |input: &mut &Bytes| { let var_bytes = ( take_while(0..=3, |b| b & 0b1000_0000 != 0), diff --git a/mqtt-format/src/v5/level.rs b/mqtt-format/src/v5/level.rs index 52c62589..00dd60e3 100644 --- a/mqtt-format/src/v5/level.rs +++ b/mqtt-format/src/v5/level.rs @@ -10,7 +10,7 @@ pub enum ProtocolLevel { } impl ProtocolLevel { - pub fn parse<'i>(input: &mut &'i Bytes) -> MResult { + pub fn parse(input: &mut &Bytes) -> MResult { match winnow::binary::u8(input)? { 3 => Ok(Self::V3), 5 => Ok(Self::V5), diff --git a/mqtt-format/src/v5/packet/connack.rs b/mqtt-format/src/v5/packet/connack.rs index bd5c79b6..c8be0a20 100644 --- a/mqtt-format/src/v5/packet/connack.rs +++ b/mqtt-format/src/v5/packet/connack.rs @@ -77,7 +77,7 @@ impl<'i> MConnack<'i> { let (session_present, _) = winnow::binary::bits::bits::<_, _, InputError<(_, usize)>, _, _>(( winnow::binary::bits::take(1usize).map(|b: u8| b == 1), - winnow::binary::bits::pattern(0b0000_000, 7usize), + winnow::binary::bits::pattern(0b000_0000, 7usize), )) .parse_next(input) .map_err(|_: ErrMode>| { diff --git a/mqtt-format/src/v5/packet/connect.rs b/mqtt-format/src/v5/packet/connect.rs index a62b30b4..09f6c85e 100644 --- a/mqtt-format/src/v5/packet/connect.rs +++ b/mqtt-format/src/v5/packet/connect.rs @@ -1,12 +1,12 @@ use winnow::{ - error::{ErrMode, FromExternalError, InputError, ParserError}, + error::{ErrMode, InputError, ParserError}, Bytes, Parser, }; use crate::v5::{ bytes::parse_binary_data, fixed_header::{PacketType, QualityOfService}, - integers::{parse_u16, parse_u32, parse_variable_u32}, + integers::{parse_u16}, level::ProtocolLevel, strings::parse_string, variable_header::{ @@ -72,7 +72,7 @@ impl<'i> MConnect<'i> { let client_identifier = { let client_identifier = parse_string(input)?; - if client_identifier.len() == 0 { + if client_identifier.is_empty() { // Generate client ID? } client_identifier diff --git a/mqtt-format/src/v5/packet/pingreq.rs b/mqtt-format/src/v5/packet/pingreq.rs index 8ce25723..2c5a064a 100644 --- a/mqtt-format/src/v5/packet/pingreq.rs +++ b/mqtt-format/src/v5/packet/pingreq.rs @@ -5,7 +5,7 @@ use crate::v5::MResult; pub struct MPingreq; impl MPingreq { - fn parse<'i>(input: &mut &'i Bytes) -> MResult { + fn parse(input: &mut &Bytes) -> MResult { winnow::combinator::eof.map(|_| MPingreq).parse_next(input) } } diff --git a/mqtt-format/src/v5/packet/publish.rs b/mqtt-format/src/v5/packet/publish.rs index fb87adbb..c0ec09f8 100644 --- a/mqtt-format/src/v5/packet/publish.rs +++ b/mqtt-format/src/v5/packet/publish.rs @@ -35,7 +35,7 @@ crate::v5::properties::define_properties! { impl<'i> MPublish<'i> { pub fn parse(input: &mut &'i Bytes) -> MResult { let topic_name = crate::v5::strings::parse_string(input)?; - if !sanity_check_topic_name(&topic_name) { + if !sanity_check_topic_name(topic_name) { return Err(ErrMode::from_error_kind( input, winnow::error::ErrorKind::Verify, diff --git a/mqtt-format/src/v5/packet/subscribe.rs b/mqtt-format/src/v5/packet/subscribe.rs index 4b65a0ec..05b6a231 100644 --- a/mqtt-format/src/v5/packet/subscribe.rs +++ b/mqtt-format/src/v5/packet/subscribe.rs @@ -38,7 +38,7 @@ pub struct SubscriptionOptions { } impl SubscriptionOptions { - fn parse<'i>(input: &mut &'i Bytes) -> MResult { + fn parse(input: &mut &Bytes) -> MResult { let (quality_of_service, no_local, retain_as_published, retain_handling) = bits::<_, _, InputError<(_, usize)>, _, _>(( winnow::binary::bits::take(2usize) diff --git a/mqtt-format/src/v5/variable_header.rs b/mqtt-format/src/v5/variable_header.rs index 6680013e..808ec77a 100644 --- a/mqtt-format/src/v5/variable_header.rs +++ b/mqtt-format/src/v5/variable_header.rs @@ -5,7 +5,7 @@ use super::{integers::parse_u16, integers::parse_u32, MResult}; pub struct PacketIdentifier(pub u16); impl PacketIdentifier { - pub fn parse<'i>(input: &mut &'i Bytes) -> MResult { + pub fn parse(input: &mut &Bytes) -> MResult { parse_u16(input).map(PacketIdentifier) } } From 05fffb79e740e352018b3f98e58f1118639a66b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 13:32:22 +0100 Subject: [PATCH 53/90] Rename packet module to plural MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/mod.rs | 2 +- mqtt-format/src/v5/{packet => packets}/auth.rs | 0 mqtt-format/src/v5/{packet => packets}/connack.rs | 0 mqtt-format/src/v5/{packet => packets}/connect.rs | 0 mqtt-format/src/v5/{packet => packets}/disconnect.rs | 0 mqtt-format/src/v5/{packet => packets}/mod.rs | 0 mqtt-format/src/v5/{packet => packets}/pingreq.rs | 0 mqtt-format/src/v5/{packet => packets}/pingresp.rs | 0 mqtt-format/src/v5/{packet => packets}/puback.rs | 0 mqtt-format/src/v5/{packet => packets}/pubcomp.rs | 0 mqtt-format/src/v5/{packet => packets}/publish.rs | 0 mqtt-format/src/v5/{packet => packets}/pubrec.rs | 0 mqtt-format/src/v5/{packet => packets}/pubrel.rs | 0 mqtt-format/src/v5/{packet => packets}/suback.rs | 0 mqtt-format/src/v5/{packet => packets}/subscribe.rs | 0 mqtt-format/src/v5/{packet => packets}/unsuback.rs | 0 mqtt-format/src/v5/{packet => packets}/unsubscribe.rs | 0 17 files changed, 1 insertion(+), 1 deletion(-) rename mqtt-format/src/v5/{packet => packets}/auth.rs (100%) rename mqtt-format/src/v5/{packet => packets}/connack.rs (100%) rename mqtt-format/src/v5/{packet => packets}/connect.rs (100%) rename mqtt-format/src/v5/{packet => packets}/disconnect.rs (100%) rename mqtt-format/src/v5/{packet => packets}/mod.rs (100%) rename mqtt-format/src/v5/{packet => packets}/pingreq.rs (100%) rename mqtt-format/src/v5/{packet => packets}/pingresp.rs (100%) rename mqtt-format/src/v5/{packet => packets}/puback.rs (100%) rename mqtt-format/src/v5/{packet => packets}/pubcomp.rs (100%) rename mqtt-format/src/v5/{packet => packets}/publish.rs (100%) rename mqtt-format/src/v5/{packet => packets}/pubrec.rs (100%) rename mqtt-format/src/v5/{packet => packets}/pubrel.rs (100%) rename mqtt-format/src/v5/{packet => packets}/suback.rs (100%) rename mqtt-format/src/v5/{packet => packets}/subscribe.rs (100%) rename mqtt-format/src/v5/{packet => packets}/unsuback.rs (100%) rename mqtt-format/src/v5/{packet => packets}/unsubscribe.rs (100%) diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index f0233dee..96865099 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -2,7 +2,7 @@ pub mod bytes; pub mod fixed_header; pub mod integers; pub mod level; -pub mod packet; +pub mod packets; pub mod properties; pub mod reason_code; pub mod strings; diff --git a/mqtt-format/src/v5/packet/auth.rs b/mqtt-format/src/v5/packets/auth.rs similarity index 100% rename from mqtt-format/src/v5/packet/auth.rs rename to mqtt-format/src/v5/packets/auth.rs diff --git a/mqtt-format/src/v5/packet/connack.rs b/mqtt-format/src/v5/packets/connack.rs similarity index 100% rename from mqtt-format/src/v5/packet/connack.rs rename to mqtt-format/src/v5/packets/connack.rs diff --git a/mqtt-format/src/v5/packet/connect.rs b/mqtt-format/src/v5/packets/connect.rs similarity index 100% rename from mqtt-format/src/v5/packet/connect.rs rename to mqtt-format/src/v5/packets/connect.rs diff --git a/mqtt-format/src/v5/packet/disconnect.rs b/mqtt-format/src/v5/packets/disconnect.rs similarity index 100% rename from mqtt-format/src/v5/packet/disconnect.rs rename to mqtt-format/src/v5/packets/disconnect.rs diff --git a/mqtt-format/src/v5/packet/mod.rs b/mqtt-format/src/v5/packets/mod.rs similarity index 100% rename from mqtt-format/src/v5/packet/mod.rs rename to mqtt-format/src/v5/packets/mod.rs diff --git a/mqtt-format/src/v5/packet/pingreq.rs b/mqtt-format/src/v5/packets/pingreq.rs similarity index 100% rename from mqtt-format/src/v5/packet/pingreq.rs rename to mqtt-format/src/v5/packets/pingreq.rs diff --git a/mqtt-format/src/v5/packet/pingresp.rs b/mqtt-format/src/v5/packets/pingresp.rs similarity index 100% rename from mqtt-format/src/v5/packet/pingresp.rs rename to mqtt-format/src/v5/packets/pingresp.rs diff --git a/mqtt-format/src/v5/packet/puback.rs b/mqtt-format/src/v5/packets/puback.rs similarity index 100% rename from mqtt-format/src/v5/packet/puback.rs rename to mqtt-format/src/v5/packets/puback.rs diff --git a/mqtt-format/src/v5/packet/pubcomp.rs b/mqtt-format/src/v5/packets/pubcomp.rs similarity index 100% rename from mqtt-format/src/v5/packet/pubcomp.rs rename to mqtt-format/src/v5/packets/pubcomp.rs diff --git a/mqtt-format/src/v5/packet/publish.rs b/mqtt-format/src/v5/packets/publish.rs similarity index 100% rename from mqtt-format/src/v5/packet/publish.rs rename to mqtt-format/src/v5/packets/publish.rs diff --git a/mqtt-format/src/v5/packet/pubrec.rs b/mqtt-format/src/v5/packets/pubrec.rs similarity index 100% rename from mqtt-format/src/v5/packet/pubrec.rs rename to mqtt-format/src/v5/packets/pubrec.rs diff --git a/mqtt-format/src/v5/packet/pubrel.rs b/mqtt-format/src/v5/packets/pubrel.rs similarity index 100% rename from mqtt-format/src/v5/packet/pubrel.rs rename to mqtt-format/src/v5/packets/pubrel.rs diff --git a/mqtt-format/src/v5/packet/suback.rs b/mqtt-format/src/v5/packets/suback.rs similarity index 100% rename from mqtt-format/src/v5/packet/suback.rs rename to mqtt-format/src/v5/packets/suback.rs diff --git a/mqtt-format/src/v5/packet/subscribe.rs b/mqtt-format/src/v5/packets/subscribe.rs similarity index 100% rename from mqtt-format/src/v5/packet/subscribe.rs rename to mqtt-format/src/v5/packets/subscribe.rs diff --git a/mqtt-format/src/v5/packet/unsuback.rs b/mqtt-format/src/v5/packets/unsuback.rs similarity index 100% rename from mqtt-format/src/v5/packet/unsuback.rs rename to mqtt-format/src/v5/packets/unsuback.rs diff --git a/mqtt-format/src/v5/packet/unsubscribe.rs b/mqtt-format/src/v5/packets/unsubscribe.rs similarity index 100% rename from mqtt-format/src/v5/packet/unsubscribe.rs rename to mqtt-format/src/v5/packets/unsubscribe.rs From 6498766c8aad995764339aa90514b615f6ecc97d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 13:59:10 +0100 Subject: [PATCH 54/90] Do not include the remaining length in the fixed header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/fixed_header.rs | 109 ++++++++++++++--------------- 1 file changed, 52 insertions(+), 57 deletions(-) diff --git a/mqtt-format/src/v5/fixed_header.rs b/mqtt-format/src/v5/fixed_header.rs index 4d35bbf3..d5fb5def 100644 --- a/mqtt-format/src/v5/fixed_header.rs +++ b/mqtt-format/src/v5/fixed_header.rs @@ -4,7 +4,7 @@ use winnow::{ Bytes, Parser, }; -use super::{integers::parse_variable_u32, MResult}; +use super::MResult; #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)] #[repr(u8)] @@ -40,83 +40,78 @@ pub enum PacketType { #[derive(Debug, PartialEq)] pub struct MFixedHeader { - packet_type: PacketType, - remaining_length: u32, + pub packet_type: PacketType, } -pub fn parse_fixed_header(input: &mut &Bytes) -> MResult { - let (packet_type, packet_flags): (u8, u8) = bits::<_, _, InputError<(_, usize)>, _, _>(( - winnow::binary::bits::take(4usize), - winnow::binary::bits::take(4usize), - )) - .parse_next(input) - .map_err(|_: ErrMode>| { - ErrMode::from_error_kind(input, winnow::error::ErrorKind::Slice) - })?; +impl MFixedHeader { + pub fn parse(input: &mut &Bytes) -> MResult { + let (packet_type, packet_flags): (u8, u8) = bits::<_, _, InputError<(_, usize)>, _, _>(( + winnow::binary::bits::take(4usize), + winnow::binary::bits::take(4usize), + )) + .parse_next(input) + .map_err(|_: ErrMode>| { + ErrMode::from_error_kind(input, winnow::error::ErrorKind::Slice) + })?; - let packet_type = match (packet_type, packet_flags) { - (0, _) => { - return Err(ErrMode::from_error_kind( - input, - winnow::error::ErrorKind::Verify, - )) - } - (1, 0) => PacketType::Connect, - (2, 0) => PacketType::Connect, - (3, flags) => PacketType::Publish { - dup: (0b1000 & flags) != 0, - qos: QualityOfService::try_from((flags & 0b0110) >> 1).map_err(|e| { - ErrMode::from_external_error(input, winnow::error::ErrorKind::Verify, e) - })?, - retain: (0b0001 & flags) != 0, - }, - (4, 0) => PacketType::Puback, - (5, 0) => PacketType::Pubrec, - (6, 0b0010) => PacketType::Pubrel, - (7, 0) => PacketType::Pubcomp, - (8, 0b0010) => PacketType::Subscribe, - (9, 0) => PacketType::Suback, - (10, 0b0010) => PacketType::Unsubscribe, - (11, 0) => PacketType::Unsuback, - (12, 0) => PacketType::Pingreq, - (13, 0) => PacketType::Pingresp, - (14, 0) => PacketType::Disconnect, - (15, 0) => PacketType::Auth, - _ => { - return Err(ErrMode::from_error_kind( - input, - winnow::error::ErrorKind::Verify, - )) - } - }; - - let remaining_length = parse_variable_u32(input)?; + let packet_type = match (packet_type, packet_flags) { + (0, _) => { + return Err(ErrMode::from_error_kind( + input, + winnow::error::ErrorKind::Verify, + )) + } + (1, 0) => PacketType::Connect, + (2, 0) => PacketType::Connect, + (3, flags) => PacketType::Publish { + dup: (0b1000 & flags) != 0, + qos: QualityOfService::try_from((flags & 0b0110) >> 1).map_err(|e| { + ErrMode::from_external_error(input, winnow::error::ErrorKind::Verify, e) + })?, + retain: (0b0001 & flags) != 0, + }, + (4, 0) => PacketType::Puback, + (5, 0) => PacketType::Pubrec, + (6, 0b0010) => PacketType::Pubrel, + (7, 0) => PacketType::Pubcomp, + (8, 0b0010) => PacketType::Subscribe, + (9, 0) => PacketType::Suback, + (10, 0b0010) => PacketType::Unsubscribe, + (11, 0) => PacketType::Unsuback, + (12, 0) => PacketType::Pingreq, + (13, 0) => PacketType::Pingresp, + (14, 0) => PacketType::Disconnect, + (15, 0) => PacketType::Auth, + _ => { + return Err(ErrMode::from_error_kind( + input, + winnow::error::ErrorKind::Verify, + )) + } + }; - Ok(MFixedHeader { - packet_type, - remaining_length, - }) + Ok(MFixedHeader { packet_type }) + } } #[cfg(test)] mod tests { use winnow::Bytes; - use crate::v5::fixed_header::{parse_fixed_header, MFixedHeader}; + use crate::v5::fixed_header::MFixedHeader; #[test] fn check_fixed_header() { - let input = &[0b0011_1010, 0xA]; + let input = &[0b0011_1010]; assert_eq!( - parse_fixed_header(&mut Bytes::new(&input)).unwrap(), + MFixedHeader::parse(&mut Bytes::new(&input)).unwrap(), MFixedHeader { packet_type: crate::v5::fixed_header::PacketType::Publish { dup: true, qos: crate::v5::fixed_header::QualityOfService::AtLeastOnce, retain: false }, - remaining_length: 10, } ) } From 417b0bd8f53becc867e3a314500fac3d5606395d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 13:59:31 +0100 Subject: [PATCH 55/90] Add global MqttPacket type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packets/mod.rs | 96 +++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/mqtt-format/src/v5/packets/mod.rs b/mqtt-format/src/v5/packets/mod.rs index 7ded7148..c5c164ce 100644 --- a/mqtt-format/src/v5/packets/mod.rs +++ b/mqtt-format/src/v5/packets/mod.rs @@ -1,3 +1,17 @@ +use self::{ + auth::MAuth, connect::MConnect, disconnect::MDisconnect, pingreq::MPingreq, + pingresp::MPingresp, puback::MPuback, pubcomp::MPubcomp, publish::MPublish, pubrec::MPubrec, + pubrel::MPubrel, suback::MSuback, subscribe::MSubscribe, unsuback::MUnsuback, + unsubscribe::MUnsubscribe, +}; +use crate::v5::fixed_header::MFixedHeader; +use crate::v5::packets::connack::MConnack; +use crate::v5::MResult; +use winnow::Bytes; +use winnow::Parser; + +use super::fixed_header::PacketType; + pub mod auth; pub mod connack; pub mod connect; @@ -13,3 +27,85 @@ pub mod suback; pub mod subscribe; pub mod unsuback; pub mod unsubscribe; + +pub enum MqttPacket<'i> { + Auth(MAuth<'i>), + Connack(MConnack<'i>), + Connect(MConnect<'i>), + Disconnect(MDisconnect<'i>), + Pingreq(MPingreq), + Pingresp(MPingresp), + Puback(MPuback<'i>), + Pubcomp(MPubcomp<'i>), + Publish(MPublish<'i>), + Pubrec(MPubrec<'i>), + Pubrel(MPubrel<'i>), + Suback(MSuback<'i>), + Subscribe(MSubscribe<'i>), + Unsuback(MUnsuback<'i>), + Unsubscribe(MUnsubscribe<'i>), +} + +impl<'i> MqttPacket<'i> { + pub fn parse(input: &mut &'i Bytes) -> MResult { + let fixed_header = MFixedHeader::parse(input)?; + + let parse_packet = |input: &mut &'i Bytes| match fixed_header.packet_type { + PacketType::Connect => MConnect::parse(input).map(MqttPacket::from), + PacketType::Connack => MConnack::parse(input).map(MqttPacket::from), + PacketType::Publish { + dup: _, + qos: _, + retain: _, + } => MPublish::parse(input).map(MqttPacket::from), + PacketType::Puback => MPuback::parse(input).map(MqttPacket::from), + PacketType::Pubrec => MPubrec::parse(input).map(MqttPacket::from), + PacketType::Pubrel => MPubrel::parse(input).map(MqttPacket::from), + PacketType::Pubcomp => MPubcomp::parse(input).map(MqttPacket::from), + PacketType::Subscribe => MSubscribe::parse(input).map(MqttPacket::from), + PacketType::Suback => MSuback::parse(input).map(MqttPacket::from), + PacketType::Unsubscribe => MUnsubscribe::parse(input).map(MqttPacket::from), + PacketType::Unsuback => MUnsuback::parse(input).map(MqttPacket::from), + PacketType::Pingreq => MPingreq::parse(input).map(MqttPacket::from), + PacketType::Pingresp => MPingresp::parse(input).map(MqttPacket::from), + PacketType::Disconnect => MDisconnect::parse(input).map(MqttPacket::from), + PacketType::Auth => MAuth::parse(input).map(MqttPacket::from), + }; + + let packet = + winnow::binary::length_and_then(crate::v5::integers::parse_variable_u32, parse_packet) + .parse_next(input)?; + + Ok(packet) + } +} + +macro_rules! impl_try_from_packet { + ($($kind:ty => $name:ident),*) => { + $( + impl<'i> From<$kind> for MqttPacket<'i> { + fn from(from: $kind) -> Self { + MqttPacket::$name(from) + } + } + )* + }; +} + +impl_try_from_packet!( + MAuth<'i> => Auth, + MConnack<'i> => Connack, + MConnect<'i> => Connect, + MDisconnect<'i> => Disconnect, + MPingreq => Pingreq, + MPingresp => Pingresp, + MPuback<'i> => Puback, + MPubcomp<'i> => Pubcomp, + MPublish<'i> => Publish, + MPubrec<'i> => Pubrec, + MPubrel<'i> => Pubrel, + MSuback<'i> => Suback, + MSubscribe<'i> => Subscribe, + MUnsuback<'i> => Unsuback, + MUnsubscribe<'i> => Unsubscribe +); From fcf97aab2f53b2b9f36f15ae382b1c231a6bcc70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:03:04 +0100 Subject: [PATCH 56/90] Make fixed header types copy and clone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/fixed_header.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mqtt-format/src/v5/fixed_header.rs b/mqtt-format/src/v5/fixed_header.rs index d5fb5def..1ca78699 100644 --- a/mqtt-format/src/v5/fixed_header.rs +++ b/mqtt-format/src/v5/fixed_header.rs @@ -8,14 +8,14 @@ use super::MResult; #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)] #[repr(u8)] -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone, Copy)] pub enum QualityOfService { AtMostOnce = 0, AtLeastOnce = 1, ExactlyOnce = 2, } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone, Copy)] pub enum PacketType { Connect, Connack, From 900238a90ab24385d9e1d9a1f7d4743242f3733f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:03:32 +0100 Subject: [PATCH 57/90] Make all parse methods on packets public MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packets/disconnect.rs | 2 +- mqtt-format/src/v5/packets/pingreq.rs | 2 +- mqtt-format/src/v5/packets/subscribe.rs | 2 +- mqtt-format/src/v5/packets/unsubscribe.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mqtt-format/src/v5/packets/disconnect.rs b/mqtt-format/src/v5/packets/disconnect.rs index 557e0442..b3426faf 100644 --- a/mqtt-format/src/v5/packets/disconnect.rs +++ b/mqtt-format/src/v5/packets/disconnect.rs @@ -56,7 +56,7 @@ pub struct MDisconnect<'i> { } impl<'i> MDisconnect<'i> { - fn parse(input: &mut &'i Bytes) -> MResult> { + pub fn parse(input: &mut &'i Bytes) -> MResult> { let (reason_code, properties) = (DisconnectReasonCode::parse, DisconnectProperties::parse).parse_next(input)?; diff --git a/mqtt-format/src/v5/packets/pingreq.rs b/mqtt-format/src/v5/packets/pingreq.rs index 2c5a064a..75b2cc19 100644 --- a/mqtt-format/src/v5/packets/pingreq.rs +++ b/mqtt-format/src/v5/packets/pingreq.rs @@ -5,7 +5,7 @@ use crate::v5::MResult; pub struct MPingreq; impl MPingreq { - fn parse(input: &mut &Bytes) -> MResult { + pub fn parse(input: &mut &Bytes) -> MResult { winnow::combinator::eof.map(|_| MPingreq).parse_next(input) } } diff --git a/mqtt-format/src/v5/packets/subscribe.rs b/mqtt-format/src/v5/packets/subscribe.rs index 05b6a231..93ef6006 100644 --- a/mqtt-format/src/v5/packets/subscribe.rs +++ b/mqtt-format/src/v5/packets/subscribe.rs @@ -101,7 +101,7 @@ pub struct MSubscribe<'i> { } impl<'i> MSubscribe<'i> { - fn parse(input: &mut &'i Bytes) -> MResult> { + pub fn parse(input: &mut &'i Bytes) -> MResult> { let (packet_identifier, properties) = (PacketIdentifier::parse, SubscribeProperties::parse).parse_next(input)?; diff --git a/mqtt-format/src/v5/packets/unsubscribe.rs b/mqtt-format/src/v5/packets/unsubscribe.rs index b3a06e81..ed8b6bc8 100644 --- a/mqtt-format/src/v5/packets/unsubscribe.rs +++ b/mqtt-format/src/v5/packets/unsubscribe.rs @@ -51,7 +51,7 @@ pub struct MUnsubscribe<'i> { } impl<'i> MUnsubscribe<'i> { - fn parse(input: &mut &'i Bytes) -> MResult { + pub fn parse(input: &mut &'i Bytes) -> MResult { let (packet_identifier, properties, unsubscriptions) = ( PacketIdentifier::parse, UnsubscribeProperties::parse, From 257d27f6f578be5f8755760f8bcc130364235f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:05:55 +0100 Subject: [PATCH 58/90] Make all fields of packets public MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packets/auth.rs | 4 ++-- mqtt-format/src/v5/packets/connect.rs | 14 +++++++------- mqtt-format/src/v5/packets/disconnect.rs | 4 ++-- mqtt-format/src/v5/packets/puback.rs | 6 +++--- mqtt-format/src/v5/packets/pubcomp.rs | 6 +++--- mqtt-format/src/v5/packets/publish.rs | 8 ++++---- mqtt-format/src/v5/packets/pubrec.rs | 6 +++--- mqtt-format/src/v5/packets/pubrel.rs | 6 +++--- mqtt-format/src/v5/packets/suback.rs | 6 +++--- mqtt-format/src/v5/packets/unsuback.rs | 6 +++--- mqtt-format/src/v5/packets/unsubscribe.rs | 6 +++--- 11 files changed, 36 insertions(+), 36 deletions(-) diff --git a/mqtt-format/src/v5/packets/auth.rs b/mqtt-format/src/v5/packets/auth.rs index a35141c3..5984a265 100644 --- a/mqtt-format/src/v5/packets/auth.rs +++ b/mqtt-format/src/v5/packets/auth.rs @@ -23,8 +23,8 @@ crate::v5::properties::define_properties! { } pub struct MAuth<'i> { - reason: AuthReasonCode, - properties: AuthProperties<'i>, + pub reason: AuthReasonCode, + pub properties: AuthProperties<'i>, } impl<'i> MAuth<'i> { diff --git a/mqtt-format/src/v5/packets/connect.rs b/mqtt-format/src/v5/packets/connect.rs index 09f6c85e..6a681359 100644 --- a/mqtt-format/src/v5/packets/connect.rs +++ b/mqtt-format/src/v5/packets/connect.rs @@ -6,7 +6,7 @@ use winnow::{ use crate::v5::{ bytes::parse_binary_data, fixed_header::{PacketType, QualityOfService}, - integers::{parse_u16}, + integers::parse_u16, level::ProtocolLevel, strings::parse_string, variable_header::{ @@ -19,12 +19,12 @@ use crate::v5::{ }; pub struct MConnect<'i> { - client_identifier: &'i str, - username: Option<&'i str>, - password: Option<&'i [u8]>, - clean_start: bool, - will: Option>, - properties: ConnectProperties<'i>, + pub client_identifier: &'i str, + pub username: Option<&'i str>, + pub password: Option<&'i [u8]>, + pub clean_start: bool, + pub will: Option>, + pub properties: ConnectProperties<'i>, } crate::v5::properties::define_properties! { diff --git a/mqtt-format/src/v5/packets/disconnect.rs b/mqtt-format/src/v5/packets/disconnect.rs index b3426faf..d2223944 100644 --- a/mqtt-format/src/v5/packets/disconnect.rs +++ b/mqtt-format/src/v5/packets/disconnect.rs @@ -51,8 +51,8 @@ define_properties! { } pub struct MDisconnect<'i> { - reason_code: DisconnectReasonCode, - properties: DisconnectProperties<'i>, + pub reason_code: DisconnectReasonCode, + pub properties: DisconnectProperties<'i>, } impl<'i> MDisconnect<'i> { diff --git a/mqtt-format/src/v5/packets/puback.rs b/mqtt-format/src/v5/packets/puback.rs index bf1db389..adc3f66c 100644 --- a/mqtt-format/src/v5/packets/puback.rs +++ b/mqtt-format/src/v5/packets/puback.rs @@ -29,9 +29,9 @@ define_properties!( ); pub struct MPuback<'i> { - packet_identifier: PacketIdentifier, - reason: PubackReasonCode, - properties: PubackProperties<'i>, + pub packet_identifier: PacketIdentifier, + pub reason: PubackReasonCode, + pub properties: PubackProperties<'i>, } impl<'i> MPuback<'i> { diff --git a/mqtt-format/src/v5/packets/pubcomp.rs b/mqtt-format/src/v5/packets/pubcomp.rs index 031377a0..692adc97 100644 --- a/mqtt-format/src/v5/packets/pubcomp.rs +++ b/mqtt-format/src/v5/packets/pubcomp.rs @@ -20,9 +20,9 @@ crate::v5::properties::define_properties! { } pub struct MPubcomp<'i> { - packet_identifier: PacketIdentifier, - reason: PubcompReasonCode, - properties: PubcompProperties<'i>, + pub packet_identifier: PacketIdentifier, + pub reason: PubcompReasonCode, + pub properties: PubcompProperties<'i>, } impl<'i> MPubcomp<'i> { diff --git a/mqtt-format/src/v5/packets/publish.rs b/mqtt-format/src/v5/packets/publish.rs index c0ec09f8..fe6d50b1 100644 --- a/mqtt-format/src/v5/packets/publish.rs +++ b/mqtt-format/src/v5/packets/publish.rs @@ -13,10 +13,10 @@ use crate::v5::{ }; pub struct MPublish<'i> { - topic_name: &'i str, - packet_identifier: crate::v5::variable_header::PacketIdentifier, - properties: PublishProperties<'i>, - payload: &'i [u8], + pub topic_name: &'i str, + pub packet_identifier: crate::v5::variable_header::PacketIdentifier, + pub properties: PublishProperties<'i>, + pub payload: &'i [u8], } crate::v5::properties::define_properties! { diff --git a/mqtt-format/src/v5/packets/pubrec.rs b/mqtt-format/src/v5/packets/pubrec.rs index 01627cf9..2bff006f 100644 --- a/mqtt-format/src/v5/packets/pubrec.rs +++ b/mqtt-format/src/v5/packets/pubrec.rs @@ -29,9 +29,9 @@ crate::v5::properties::define_properties![ ]; pub struct MPubrec<'i> { - packet_identifier: PacketIdentifier, - reason: PubrecReasonCode, - properties: PubrecProperties<'i>, + pub packet_identifier: PacketIdentifier, + pub reason: PubrecReasonCode, + pub properties: PubrecProperties<'i>, } impl<'i> MPubrec<'i> { diff --git a/mqtt-format/src/v5/packets/pubrel.rs b/mqtt-format/src/v5/packets/pubrel.rs index c02f7d3b..ac655966 100644 --- a/mqtt-format/src/v5/packets/pubrel.rs +++ b/mqtt-format/src/v5/packets/pubrel.rs @@ -22,9 +22,9 @@ define_properties!( ); pub struct MPubrel<'i> { - packet_identifier: PacketIdentifier, - reason: PubrelReasonCode, - properties: PubrelProperties<'i>, + pub packet_identifier: PacketIdentifier, + pub reason: PubrelReasonCode, + pub properties: PubrelProperties<'i>, } impl<'i> MPubrel<'i> { diff --git a/mqtt-format/src/v5/packets/suback.rs b/mqtt-format/src/v5/packets/suback.rs index bb720415..b94c8c1f 100644 --- a/mqtt-format/src/v5/packets/suback.rs +++ b/mqtt-format/src/v5/packets/suback.rs @@ -30,9 +30,9 @@ crate::v5::properties::define_properties! { } pub struct MSuback<'i> { - packet_identifier: PacketIdentifier, - properties: SubackProperties<'i>, - reasons: &'i [SubackReasonCode], + pub packet_identifier: PacketIdentifier, + pub properties: SubackProperties<'i>, + pub reasons: &'i [SubackReasonCode], } impl<'i> MSuback<'i> { diff --git a/mqtt-format/src/v5/packets/unsuback.rs b/mqtt-format/src/v5/packets/unsuback.rs index 80aab928..42c4cda8 100644 --- a/mqtt-format/src/v5/packets/unsuback.rs +++ b/mqtt-format/src/v5/packets/unsuback.rs @@ -26,9 +26,9 @@ crate::v5::properties::define_properties! { } pub struct MUnsuback<'i> { - packet_identifier: PacketIdentifier, - properties: UnsubackProperties<'i>, - reasons: &'i [UnsubackReasonCode], + pub packet_identifier: PacketIdentifier, + pub properties: UnsubackProperties<'i>, + pub reasons: &'i [UnsubackReasonCode], } impl<'i> MUnsuback<'i> { diff --git a/mqtt-format/src/v5/packets/unsubscribe.rs b/mqtt-format/src/v5/packets/unsubscribe.rs index ed8b6bc8..52fa857d 100644 --- a/mqtt-format/src/v5/packets/unsubscribe.rs +++ b/mqtt-format/src/v5/packets/unsubscribe.rs @@ -45,9 +45,9 @@ impl<'i> Unsubscription<'i> { } pub struct MUnsubscribe<'i> { - packet_identifier: PacketIdentifier, - properties: UnsubscribeProperties<'i>, - unsubscriptions: Unsubscriptions<'i>, + pub packet_identifier: PacketIdentifier, + pub properties: UnsubscribeProperties<'i>, + pub unsubscriptions: Unsubscriptions<'i>, } impl<'i> MUnsubscribe<'i> { From ce44104f0ac08c321a2d1a0751529143d71e8480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:08:46 +0100 Subject: [PATCH 59/90] Add accessors to properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/properties.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mqtt-format/src/v5/properties.rs b/mqtt-format/src/v5/properties.rs index 8701e8df..aa1003e6 100644 --- a/mqtt-format/src/v5/properties.rs +++ b/mqtt-format/src/v5/properties.rs @@ -49,12 +49,19 @@ macro_rules! define_properties { } impl<$lt> $name <$lt> { + #[allow(dead_code)] pub(crate) fn new() -> Self { $name { $($prop_name: None),* } } + $( + pub fn $prop_name(&self) -> Option<& $prop> { + self.$prop_name.as_ref() + } + )* + pub fn parse(input: &mut & $lt winnow::Bytes) -> crate::v5::MResult<$name<$lt>> { use winnow::Parser; use winnow::error::ErrMode; From a20a2a591ff90966d7ef7cc78b06265dff24508e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:11:25 +0100 Subject: [PATCH 60/90] Add SubscriptionsIter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packets/subscribe.rs | 29 ++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/mqtt-format/src/v5/packets/subscribe.rs b/mqtt-format/src/v5/packets/subscribe.rs index 93ef6006..05211a92 100644 --- a/mqtt-format/src/v5/packets/subscribe.rs +++ b/mqtt-format/src/v5/packets/subscribe.rs @@ -9,9 +9,7 @@ use crate::v5::{ fixed_header::QualityOfService, properties::define_properties, strings::parse_string, - variable_header::{ - PacketIdentifier, SubscriptionIdentifier, UserProperties, - }, + variable_header::{PacketIdentifier, SubscriptionIdentifier, UserProperties}, MResult, }; @@ -92,6 +90,31 @@ impl<'i> Subscriptions<'i> { Ok(Subscriptions { start }) } + + pub fn iter(&self) -> SubscriptionsIter<'i> { + SubscriptionsIter { + current: Bytes::new(self.start), + } + } +} + +pub struct SubscriptionsIter<'i> { + current: &'i Bytes, +} + +impl<'i> Iterator for SubscriptionsIter<'i> { + type Item = Subscription<'i>; + + fn next(&mut self) -> Option { + if !self.current.is_empty() { + let sub = Subscription::parse(&mut self.current) + .expect("Already parsed subscriptions should be valid"); + + return Some(sub); + } + + None + } } pub struct MSubscribe<'i> { From 35629f277f10ea051f9317ef0d2321ba4d0fcd0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:15:14 +0100 Subject: [PATCH 61/90] Add UnsubscriptionIter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packets/unsubscribe.rs | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/mqtt-format/src/v5/packets/unsubscribe.rs b/mqtt-format/src/v5/packets/unsubscribe.rs index 52fa857d..027ead31 100644 --- a/mqtt-format/src/v5/packets/unsubscribe.rs +++ b/mqtt-format/src/v5/packets/unsubscribe.rs @@ -30,6 +30,31 @@ impl<'i> Unsubscriptions<'i> { Ok(Unsubscriptions { start }) } + + pub fn iter(&self) -> UnsubscriptionsIter<'i> { + UnsubscriptionsIter { + current: Bytes::new(self.start), + } + } +} + +pub struct UnsubscriptionsIter<'i> { + current: &'i Bytes, +} + +impl<'i> Iterator for UnsubscriptionsIter<'i> { + type Item = Unsubscription<'i>; + + fn next(&mut self) -> Option { + if !self.current.is_empty() { + let sub = Unsubscription::parse(&mut self.current) + .expect("Already parsed subscriptions should be valid"); + + return Some(sub); + } + + None + } } pub struct Unsubscription<'i> { From 5bfe2cae8614d6438e2783e0b3ee496c793b15cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:24:20 +0100 Subject: [PATCH 62/90] Fix wrong control packet type association MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/fixed_header.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mqtt-format/src/v5/fixed_header.rs b/mqtt-format/src/v5/fixed_header.rs index 1ca78699..1c7655ca 100644 --- a/mqtt-format/src/v5/fixed_header.rs +++ b/mqtt-format/src/v5/fixed_header.rs @@ -62,7 +62,7 @@ impl MFixedHeader { )) } (1, 0) => PacketType::Connect, - (2, 0) => PacketType::Connect, + (2, 0) => PacketType::Connack, (3, flags) => PacketType::Publish { dup: (0b1000 & flags) != 0, qos: QualityOfService::try_from((flags & 0b0110) >> 1).map_err(|e| { From 68ec5dcdc0bb8334286160843ca0eea7017cbdc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:24:41 +0100 Subject: [PATCH 63/90] Make fixed header types Eq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/fixed_header.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mqtt-format/src/v5/fixed_header.rs b/mqtt-format/src/v5/fixed_header.rs index 1c7655ca..ce33adb6 100644 --- a/mqtt-format/src/v5/fixed_header.rs +++ b/mqtt-format/src/v5/fixed_header.rs @@ -8,14 +8,14 @@ use super::MResult; #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)] #[repr(u8)] -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum QualityOfService { AtMostOnce = 0, AtLeastOnce = 1, ExactlyOnce = 2, } -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum PacketType { Connect, Connack, From 6e9bc761a26534fcb8d092f0a28e36ce8d46e6c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:25:14 +0100 Subject: [PATCH 64/90] Add missing flags to publish packet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packets/mod.rs | 8 +++----- mqtt-format/src/v5/packets/publish.rs | 14 +++++++++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/mqtt-format/src/v5/packets/mod.rs b/mqtt-format/src/v5/packets/mod.rs index c5c164ce..31e21021 100644 --- a/mqtt-format/src/v5/packets/mod.rs +++ b/mqtt-format/src/v5/packets/mod.rs @@ -53,11 +53,9 @@ impl<'i> MqttPacket<'i> { let parse_packet = |input: &mut &'i Bytes| match fixed_header.packet_type { PacketType::Connect => MConnect::parse(input).map(MqttPacket::from), PacketType::Connack => MConnack::parse(input).map(MqttPacket::from), - PacketType::Publish { - dup: _, - qos: _, - retain: _, - } => MPublish::parse(input).map(MqttPacket::from), + PacketType::Publish { dup, qos, retain } => { + MPublish::parse(dup, qos, retain, input).map(MqttPacket::from) + } PacketType::Puback => MPuback::parse(input).map(MqttPacket::from), PacketType::Pubrec => MPubrec::parse(input).map(MqttPacket::from), PacketType::Pubrel => MPubrel::parse(input).map(MqttPacket::from), diff --git a/mqtt-format/src/v5/packets/publish.rs b/mqtt-format/src/v5/packets/publish.rs index fe6d50b1..9975db63 100644 --- a/mqtt-format/src/v5/packets/publish.rs +++ b/mqtt-format/src/v5/packets/publish.rs @@ -5,6 +5,7 @@ use winnow::{ }; use crate::v5::{ + fixed_header::QualityOfService, variable_header::{ ContentType, CorrelationData, MessageExpiryInterval, PayloadFormatIndicator, ResponseTopic, SubscriptionIdentifier, TopicAlias, UserProperties, @@ -13,6 +14,9 @@ use crate::v5::{ }; pub struct MPublish<'i> { + pub duplicate: bool, + pub quality_of_service: QualityOfService, + pub retain: bool, pub topic_name: &'i str, pub packet_identifier: crate::v5::variable_header::PacketIdentifier, pub properties: PublishProperties<'i>, @@ -33,7 +37,12 @@ crate::v5::properties::define_properties! { } impl<'i> MPublish<'i> { - pub fn parse(input: &mut &'i Bytes) -> MResult { + pub fn parse( + duplicate: bool, + quality_of_service: QualityOfService, + retain: bool, + input: &mut &'i Bytes, + ) -> MResult { let topic_name = crate::v5::strings::parse_string(input)?; if !sanity_check_topic_name(topic_name) { return Err(ErrMode::from_error_kind( @@ -48,6 +57,9 @@ impl<'i> MPublish<'i> { let payload = input.finish(); Ok(Self { + duplicate, + quality_of_service, + retain, topic_name, packet_identifier, properties, From 91e94a213c2924b4e648ad0ed41c79d79cfc1eb8 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 13:56:31 +0100 Subject: [PATCH 65/90] Add possibility to ref upstream docs when defining properties Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/properties.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/mqtt-format/src/v5/properties.rs b/mqtt-format/src/v5/properties.rs index aa1003e6..b64885bf 100644 --- a/mqtt-format/src/v5/properties.rs +++ b/mqtt-format/src/v5/properties.rs @@ -41,11 +41,26 @@ impl MqttPropertySlot { } macro_rules! define_properties { - (pub struct $name:ident <$lt:lifetime> { - $($prop_name:ident : $prop:ty),* $(,)? + ( + $( packet_type: $packettypename:ident $(,)?)? + $( anker: $anker:literal $(,)?)? + pub struct $name:ident <$lt:lifetime> { + $( $((anker: $prop_anker:literal ))? $prop_name:ident : $prop:ty),* $(,)? }) => { + $( + #[doc = std::concat!("Properties helper type for the [", std::stringify!($packettypename), "] type.")] + #[doc = ""] // newline + )? + $( + #[doc = std::concat!("[Specification](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#", $anker, ")")] + )? pub struct $name < $lt > { - $($prop_name: Option<$prop>),* + $( + $( + #[doc = std::concat!("[Specification](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#", $prop_anker, ")")] + )? + $prop_name: Option<$prop> + ),* } impl<$lt> $name <$lt> { From d7f88c2b99b943b96c826d07afb411a28a2a0d32 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 13:58:54 +0100 Subject: [PATCH 66/90] Add docs for PublishProperties Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/publish.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/mqtt-format/src/v5/packets/publish.rs b/mqtt-format/src/v5/packets/publish.rs index 9975db63..ddb29fe8 100644 --- a/mqtt-format/src/v5/packets/publish.rs +++ b/mqtt-format/src/v5/packets/publish.rs @@ -24,14 +24,31 @@ pub struct MPublish<'i> { } crate::v5::properties::define_properties! { + packet_type: MPublish, + anker: "_Toc3901109", pub struct PublishProperties<'i> { + (anker: "_Toc3901111") payload_format_indicator: PayloadFormatIndicator, + + (anker: "_Toc3901112") message_expiry_interval: MessageExpiryInterval, + + (anker: "_Toc3901113") topic_alias: TopicAlias, + + (anker: "_Toc3901114") response_topic: ResponseTopic<'i>, + + (anker: "_Toc3901115") correlation_data: CorrelationData<'i>, + + (anker: "_Toc3901116") user_properties: UserProperties<'i>, + + (anker: "_Toc3901117") subscription_identifier: SubscriptionIdentifier, + + (anker: "_Toc3901118") content_type: ContentType<'i>, } } From 93582540db80dff4ee3cfb5896054a1315af3350 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 13:58:54 +0100 Subject: [PATCH 67/90] Add docs for AuthProperties Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/auth.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mqtt-format/src/v5/packets/auth.rs b/mqtt-format/src/v5/packets/auth.rs index 5984a265..f53025e9 100644 --- a/mqtt-format/src/v5/packets/auth.rs +++ b/mqtt-format/src/v5/packets/auth.rs @@ -14,10 +14,19 @@ crate::v5::reason_code::make_combined_reason_code! { } crate::v5::properties::define_properties! { + packet_type: MAuth, + anker: "_Toc3901221", pub struct AuthProperties<'i> { + (anker: "_Toc3901223") authentication_method: AuthenticationMethod<'i>, + + (anker: "_Toc3901224") authentication_data: AuthenticationData<'i>, + + (anker: "_Toc3901225") reason_string: ReasonString<'i>, + + (anker: "_Toc3901226") user_properties: UserProperties<'i>, } } From d5897fb0d32fc229f96d6a73458a77cd1af3f3d5 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 13:58:54 +0100 Subject: [PATCH 68/90] Add docs for ConnackProperties Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/connack.rs | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/mqtt-format/src/v5/packets/connack.rs b/mqtt-format/src/v5/packets/connack.rs index c8be0a20..ed1a340b 100644 --- a/mqtt-format/src/v5/packets/connack.rs +++ b/mqtt-format/src/v5/packets/connack.rs @@ -43,23 +43,58 @@ crate::v5::reason_code::make_combined_reason_code! { } define_properties![ + packet_type: MConnack, + anker: "_Toc3901080", pub struct ConnackProperties<'i> { + (anker: "_Toc3901082") session_expiry_interval: SessionExpiryInterval, + + (anker: "_Toc3901083") receive_maximum: ReceiveMaximum, + + (anker: "_Toc3901084") maximum_qos: MaximumQoS, + + (anker: "_Toc3901085") retain_available: RetainAvailable, + + (anker: "_Toc3901086") maximum_packet_size: MaximumPacketSize, + + (anker: "_Toc3901087") assigned_client_identifier: AssignedClientIdentifier<'i>, + + (anker: "_Toc3901088") topic_alias_maximum: TopicAliasMaximum, + + (anker: "_Toc3901089") reason_string: ReasonString<'i>, + + (anker: "_Toc3901090") user_properties: UserProperties<'i>, + + (anker: "_Toc3901091") wildcard_subscription_available: WildcardSubscriptionAvailable, + + (anker: "_Toc3901092") subscription_identifiers_available: SubscriptionIdentifiersAvailable, + + (anker: "_Toc3901093") shared_scubscription_available: SharedSubscriptionAvailable, + + (anker: "_Toc3901094") server_keep_alive: ServerKeepAlive, + + (anker: "_Toc3901095") response_information: ResponseInformation<'i>, + + (anker: "_Toc3901096") server_reference: ServerReference<'i>, + + (anker: "_Toc3901097") authentication_method: AuthenticationMethod<'i>, + + (anker: "_Toc3901098") authentication_data: AuthenticationData<'i>, } ]; From f753f551e3a4d8d3359d9c8e32e2d10b06c97e61 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 14:10:20 +0100 Subject: [PATCH 69/90] Add docs for ConnectProperties Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/connect.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/mqtt-format/src/v5/packets/connect.rs b/mqtt-format/src/v5/packets/connect.rs index 6a681359..d2e24802 100644 --- a/mqtt-format/src/v5/packets/connect.rs +++ b/mqtt-format/src/v5/packets/connect.rs @@ -28,15 +28,34 @@ pub struct MConnect<'i> { } crate::v5::properties::define_properties! { + packet_type: MConnect, + anker: "_Toc3901046", pub struct ConnectProperties<'i> { + (anker: "_Toc3901048") session_expiry_interval: SessionExpiryInterval, + + (anker: "_Toc3901049") receive_maximum: ReceiveMaximum, + + (anker: "_Toc3901050") maximum_packet_size: MaximumPacketSize, + + (anker: "_Toc3901051") topic_alias_maximum: TopicAliasMaximum, + + (anker: "_Toc3901052") request_response_information: RequestResponseInformation, + + (anker: "_Toc3901053") request_problem_information: RequestProblemInformation, + + (anker: "_Toc3901054") user_properties: UserProperties<'i>, + + (anker: "_Toc3901055") authentication_method: AuthenticationMethod<'i>, + + (anker: "_Toc3901056") authentication_data: AuthenticationData<'i>, } } From ecc36a42d25c79cd9ed1cd1738a03e243e3d3314 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 14:10:20 +0100 Subject: [PATCH 70/90] Add docs for DisconnectProperties Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/disconnect.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mqtt-format/src/v5/packets/disconnect.rs b/mqtt-format/src/v5/packets/disconnect.rs index d2223944..65cc024c 100644 --- a/mqtt-format/src/v5/packets/disconnect.rs +++ b/mqtt-format/src/v5/packets/disconnect.rs @@ -42,10 +42,19 @@ crate::v5::reason_code::make_combined_reason_code! { } define_properties! { + packet_type: MDisconnect, + anker: "_Toc3901209", pub struct DisconnectProperties<'i> { + (anker: "_Toc3901211") session_expiry_interval: SessionExpiryInterval, + + (anker: "_Toc3901212") reason_string: ReasonString<'i>, + + (anker: "_Toc3901213") user_properties: UserProperties<'i>, + + (anker: "_Toc3901214") server_reference: ServerReference<'i> } } From 36593c94b46f0180016d7d3df785b492feb8eec3 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 14:10:20 +0100 Subject: [PATCH 71/90] Add docs for PubackProperties Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/puback.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mqtt-format/src/v5/packets/puback.rs b/mqtt-format/src/v5/packets/puback.rs index adc3f66c..2a9a617e 100644 --- a/mqtt-format/src/v5/packets/puback.rs +++ b/mqtt-format/src/v5/packets/puback.rs @@ -22,8 +22,13 @@ crate::v5::reason_code::make_combined_reason_code! { } define_properties!( + packet_type: MPuback, + anker: "_Toc3901125", pub struct PubackProperties<'i> { + (anker: "_Toc3901127") reason_string: ReasonString<'i>, + + (anker: "_Toc3901128") user_properties: UserProperties<'i>, } ); From 6bc7e248657e3176a2df729801ab6b7f754badc4 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 14:10:20 +0100 Subject: [PATCH 72/90] Add docs for PubcompProperties Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/pubcomp.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mqtt-format/src/v5/packets/pubcomp.rs b/mqtt-format/src/v5/packets/pubcomp.rs index 692adc97..6c79df8b 100644 --- a/mqtt-format/src/v5/packets/pubcomp.rs +++ b/mqtt-format/src/v5/packets/pubcomp.rs @@ -13,8 +13,13 @@ crate::v5::reason_code::make_combined_reason_code! { } crate::v5::properties::define_properties! { + packet_type: MPubcomp, + anker: "_Toc3901153", pub struct PubcompProperties <'i> { + (anker: "_Toc3901154") reason_string: ReasonString<'i>, + + (anker: "_Toc3901155") user_properties: UserProperties<'i>, } } From 4695e65ccf1922b2bf299351db338f04e99c9db2 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 14:10:20 +0100 Subject: [PATCH 73/90] Add docs for PubrecProperties Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/pubrec.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mqtt-format/src/v5/packets/pubrec.rs b/mqtt-format/src/v5/packets/pubrec.rs index 2bff006f..bc599c1f 100644 --- a/mqtt-format/src/v5/packets/pubrec.rs +++ b/mqtt-format/src/v5/packets/pubrec.rs @@ -22,8 +22,13 @@ crate::v5::reason_code::make_combined_reason_code! { } crate::v5::properties::define_properties![ + packet_type: MPubrec, + anker: "_Toc3901135", pub struct PubrecProperties<'i> { + (anker: "_Toc3901137") reason_string: ReasonString<'i>, + + (anker: "_Toc3901138") user_properties: UserProperties<'i>, } ]; From 810324786393e87556c6ade5d3e3a2aa6d9907f7 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 14:10:20 +0100 Subject: [PATCH 74/90] Add docs for PubrelProperties Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/pubrel.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mqtt-format/src/v5/packets/pubrel.rs b/mqtt-format/src/v5/packets/pubrel.rs index ac655966..c8eaa463 100644 --- a/mqtt-format/src/v5/packets/pubrel.rs +++ b/mqtt-format/src/v5/packets/pubrel.rs @@ -15,8 +15,13 @@ crate::v5::reason_code::make_combined_reason_code! { } define_properties!( + packet_type: MPubrel, + anker: "_Toc3901145", pub struct PubrelProperties<'i> { + (anker: "_Toc3901147") reason_string: ReasonString<'i>, + + (anker: "_Toc3901148") user_properties: UserProperties<'i>, } ); From f00b5dd4caca86d566d6d1b86ad1fa67c186b81e Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 14:10:20 +0100 Subject: [PATCH 75/90] Add docs for SubackProperties Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/suback.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mqtt-format/src/v5/packets/suback.rs b/mqtt-format/src/v5/packets/suback.rs index b94c8c1f..0fab3cb9 100644 --- a/mqtt-format/src/v5/packets/suback.rs +++ b/mqtt-format/src/v5/packets/suback.rs @@ -23,8 +23,13 @@ crate::v5::reason_code::make_combined_reason_code! { } crate::v5::properties::define_properties! { + packet_type: MSuback, + anker: "_Toc3901174", pub struct SubackProperties<'i> { + (anker: "_Toc3901175") reason_string: ReasonString<'i>, + + (anker: "_Toc3901176") user_properties: UserProperties<'i>, } } From 33c9e158f907d85e0bbc271d2334dc1d35a6c07a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 14:10:20 +0100 Subject: [PATCH 76/90] Add docs for UnsubscribeProperties Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/unsubscribe.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mqtt-format/src/v5/packets/unsubscribe.rs b/mqtt-format/src/v5/packets/unsubscribe.rs index 027ead31..cd64d57a 100644 --- a/mqtt-format/src/v5/packets/unsubscribe.rs +++ b/mqtt-format/src/v5/packets/unsubscribe.rs @@ -8,8 +8,13 @@ use crate::v5::{ }; define_properties! { + packet_type: MUnsubscribe, + anker: "_Toc3901182", pub struct UnsubscribeProperties<'i> { + (anker: "_Toc3901183") subscription_identifier: SubscriptionIdentifier, + + (anker: "_Toc3901183") user_properties: UserProperties<'i>, } } From c3ad6385d74553f79783e579d3a1fb742d4f35f2 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 14:15:01 +0100 Subject: [PATCH 77/90] Outsource link generation to helper macro Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/mod.rs | 1 + mqtt-format/src/v5/properties.rs | 4 ++-- mqtt-format/src/v5/util.rs | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 mqtt-format/src/v5/util.rs diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index 96865099..a16e8190 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -6,6 +6,7 @@ pub mod packets; pub mod properties; pub mod reason_code; pub mod strings; +pub mod util; pub mod variable_header; pub type MResult = winnow::PResult; diff --git a/mqtt-format/src/v5/properties.rs b/mqtt-format/src/v5/properties.rs index b64885bf..1f054295 100644 --- a/mqtt-format/src/v5/properties.rs +++ b/mqtt-format/src/v5/properties.rs @@ -52,12 +52,12 @@ macro_rules! define_properties { #[doc = ""] // newline )? $( - #[doc = std::concat!("[Specification](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#", $anker, ")")] + #[doc = $crate::v5::util::md_speclink!($anker)] )? pub struct $name < $lt > { $( $( - #[doc = std::concat!("[Specification](https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#", $prop_anker, ")")] + #[doc = $crate::v5::util::md_speclink!($prop_anker)] )? $prop_name: Option<$prop> ),* diff --git a/mqtt-format/src/v5/util.rs b/mqtt-format/src/v5/util.rs new file mode 100644 index 00000000..75c03eb8 --- /dev/null +++ b/mqtt-format/src/v5/util.rs @@ -0,0 +1,16 @@ +macro_rules! speclink { + ($anker:literal) => { + std::concat!( + "https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#", + $anker + ) + }; +} +pub(crate) use speclink; + +macro_rules! md_speclink { + ($anker:literal) => { + std::concat!("[Specification](", $crate::v5::util::speclink!($anker), ")") + }; +} +pub(crate) use md_speclink; From 11bb6b70e40279711c2bbfe89a2408a4e5619cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:28:17 +0100 Subject: [PATCH 78/90] Make Will fields pub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packets/connect.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mqtt-format/src/v5/packets/connect.rs b/mqtt-format/src/v5/packets/connect.rs index d2e24802..695a856f 100644 --- a/mqtt-format/src/v5/packets/connect.rs +++ b/mqtt-format/src/v5/packets/connect.rs @@ -128,9 +128,9 @@ impl<'i> MConnect<'i> { } pub struct Will<'i> { - properties: ConnectWillProperties<'i>, - topic: &'i str, - payload: &'i [u8], + pub properties: ConnectWillProperties<'i>, + pub topic: &'i str, + pub payload: &'i [u8], } crate::v5::properties::define_properties! { From 5a1d83fbac5c66ed2b2901281d71e200bb1a8ebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:29:47 +0100 Subject: [PATCH 79/90] Remove PACKET_TYPE const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It was unused and is actually not compatible with how we wanted to use it Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packets/connack.rs | 3 --- mqtt-format/src/v5/packets/connect.rs | 4 +--- mqtt-format/src/v5/packets/puback.rs | 3 --- mqtt-format/src/v5/packets/pubrec.rs | 3 --- mqtt-format/src/v5/packets/pubrel.rs | 3 --- 5 files changed, 1 insertion(+), 15 deletions(-) diff --git a/mqtt-format/src/v5/packets/connack.rs b/mqtt-format/src/v5/packets/connack.rs index ed1a340b..a50b0ca5 100644 --- a/mqtt-format/src/v5/packets/connack.rs +++ b/mqtt-format/src/v5/packets/connack.rs @@ -4,7 +4,6 @@ use winnow::{ }; use crate::v5::{ - fixed_header::PacketType, properties::define_properties, variable_header::{ AssignedClientIdentifier, AuthenticationData, AuthenticationMethod, MaximumPacketSize, @@ -106,8 +105,6 @@ pub struct MConnack<'i> { } impl<'i> MConnack<'i> { - pub const PACKET_TYPE: PacketType = PacketType::Connack; - pub fn parse(input: &mut &'i Bytes) -> MResult> { let (session_present, _) = winnow::binary::bits::bits::<_, _, InputError<(_, usize)>, _, _>(( diff --git a/mqtt-format/src/v5/packets/connect.rs b/mqtt-format/src/v5/packets/connect.rs index 695a856f..66e54175 100644 --- a/mqtt-format/src/v5/packets/connect.rs +++ b/mqtt-format/src/v5/packets/connect.rs @@ -5,7 +5,7 @@ use winnow::{ use crate::v5::{ bytes::parse_binary_data, - fixed_header::{PacketType, QualityOfService}, + fixed_header::QualityOfService, integers::parse_u16, level::ProtocolLevel, strings::parse_string, @@ -61,8 +61,6 @@ crate::v5::properties::define_properties! { } impl<'i> MConnect<'i> { - const PACKET_TYPE: PacketType = PacketType::Connect; - pub fn parse(input: &mut &'i Bytes) -> MResult { // parse header let protocol_name = crate::v5::strings::parse_string(input)?; diff --git a/mqtt-format/src/v5/packets/puback.rs b/mqtt-format/src/v5/packets/puback.rs index 2a9a617e..2c2b8e44 100644 --- a/mqtt-format/src/v5/packets/puback.rs +++ b/mqtt-format/src/v5/packets/puback.rs @@ -1,7 +1,6 @@ use winnow::Bytes; use crate::v5::{ - fixed_header::PacketType, properties::define_properties, variable_header::{PacketIdentifier, ReasonString, UserProperties}, MResult, @@ -40,8 +39,6 @@ pub struct MPuback<'i> { } impl<'i> MPuback<'i> { - pub const PACKET_TYPE: PacketType = PacketType::Puback; - pub fn parse(input: &mut &'i Bytes) -> MResult { let packet_identifier = PacketIdentifier::parse(input)?; diff --git a/mqtt-format/src/v5/packets/pubrec.rs b/mqtt-format/src/v5/packets/pubrec.rs index bc599c1f..ee07107b 100644 --- a/mqtt-format/src/v5/packets/pubrec.rs +++ b/mqtt-format/src/v5/packets/pubrec.rs @@ -1,7 +1,6 @@ use winnow::Bytes; use crate::v5::{ - fixed_header::PacketType, variable_header::{PacketIdentifier, ReasonString, UserProperties}, MResult, }; @@ -40,8 +39,6 @@ pub struct MPubrec<'i> { } impl<'i> MPubrec<'i> { - pub const PACKET_TYPE: PacketType = PacketType::Pubrec; - pub fn parse(input: &mut &'i Bytes) -> MResult { let packet_identifier = PacketIdentifier::parse(input)?; let reason = PubrecReasonCode::parse(input)?; diff --git a/mqtt-format/src/v5/packets/pubrel.rs b/mqtt-format/src/v5/packets/pubrel.rs index c8eaa463..109cc00f 100644 --- a/mqtt-format/src/v5/packets/pubrel.rs +++ b/mqtt-format/src/v5/packets/pubrel.rs @@ -1,7 +1,6 @@ use winnow::Bytes; use crate::v5::{ - fixed_header::PacketType, properties::define_properties, variable_header::{PacketIdentifier, ReasonString, UserProperties}, MResult, @@ -33,8 +32,6 @@ pub struct MPubrel<'i> { } impl<'i> MPubrel<'i> { - pub const PACKET_TYPE: PacketType = PacketType::Pubrel; - pub fn parse(input: &mut &'i Bytes) -> MResult { let packet_identifier = PacketIdentifier::parse(input)?; From 07bd2b65ca8da2b469298bb943df5cec1f1f5c43 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 14:32:24 +0100 Subject: [PATCH 80/90] Add links to specification for packet types Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/auth.rs | 1 + mqtt-format/src/v5/packets/connack.rs | 1 + mqtt-format/src/v5/packets/connect.rs | 1 + mqtt-format/src/v5/packets/disconnect.rs | 1 + mqtt-format/src/v5/packets/pingreq.rs | 1 + mqtt-format/src/v5/packets/pingresp.rs | 1 + mqtt-format/src/v5/packets/puback.rs | 1 + mqtt-format/src/v5/packets/pubcomp.rs | 1 + mqtt-format/src/v5/packets/publish.rs | 1 + mqtt-format/src/v5/packets/pubrec.rs | 1 + mqtt-format/src/v5/packets/pubrel.rs | 1 + mqtt-format/src/v5/packets/suback.rs | 1 + mqtt-format/src/v5/packets/subscribe.rs | 1 + mqtt-format/src/v5/packets/unsuback.rs | 1 + mqtt-format/src/v5/packets/unsubscribe.rs | 1 + 15 files changed, 15 insertions(+) diff --git a/mqtt-format/src/v5/packets/auth.rs b/mqtt-format/src/v5/packets/auth.rs index f53025e9..a7831518 100644 --- a/mqtt-format/src/v5/packets/auth.rs +++ b/mqtt-format/src/v5/packets/auth.rs @@ -31,6 +31,7 @@ crate::v5::properties::define_properties! { } } +#[doc = crate::v5::util::md_speclink!("_Toc3901217")] pub struct MAuth<'i> { pub reason: AuthReasonCode, pub properties: AuthProperties<'i>, diff --git a/mqtt-format/src/v5/packets/connack.rs b/mqtt-format/src/v5/packets/connack.rs index a50b0ca5..6c1fedea 100644 --- a/mqtt-format/src/v5/packets/connack.rs +++ b/mqtt-format/src/v5/packets/connack.rs @@ -98,6 +98,7 @@ define_properties![ } ]; +#[doc = crate::v5::util::md_speclink!("_Toc3901074")] pub struct MConnack<'i> { pub session_present: bool, pub reason_code: ConnectReasonCode, diff --git a/mqtt-format/src/v5/packets/connect.rs b/mqtt-format/src/v5/packets/connect.rs index 66e54175..7758e26c 100644 --- a/mqtt-format/src/v5/packets/connect.rs +++ b/mqtt-format/src/v5/packets/connect.rs @@ -60,6 +60,7 @@ crate::v5::properties::define_properties! { } } +#[doc = crate::v5::util::md_speclink!("_Toc3901033")] impl<'i> MConnect<'i> { pub fn parse(input: &mut &'i Bytes) -> MResult { // parse header diff --git a/mqtt-format/src/v5/packets/disconnect.rs b/mqtt-format/src/v5/packets/disconnect.rs index 65cc024c..71fc16f4 100644 --- a/mqtt-format/src/v5/packets/disconnect.rs +++ b/mqtt-format/src/v5/packets/disconnect.rs @@ -59,6 +59,7 @@ define_properties! { } } +#[doc = crate::v5::util::md_speclink!("_Toc3901205")] pub struct MDisconnect<'i> { pub reason_code: DisconnectReasonCode, pub properties: DisconnectProperties<'i>, diff --git a/mqtt-format/src/v5/packets/pingreq.rs b/mqtt-format/src/v5/packets/pingreq.rs index 75b2cc19..13a6adb8 100644 --- a/mqtt-format/src/v5/packets/pingreq.rs +++ b/mqtt-format/src/v5/packets/pingreq.rs @@ -2,6 +2,7 @@ use winnow::{Bytes, Parser}; use crate::v5::MResult; +#[doc = crate::v5::util::md_speclink!("_Toc3901195")] pub struct MPingreq; impl MPingreq { diff --git a/mqtt-format/src/v5/packets/pingresp.rs b/mqtt-format/src/v5/packets/pingresp.rs index 0cef50ae..b17c08ed 100644 --- a/mqtt-format/src/v5/packets/pingresp.rs +++ b/mqtt-format/src/v5/packets/pingresp.rs @@ -2,6 +2,7 @@ use winnow::Bytes; use crate::v5::MResult; +#[doc = crate::v5::util::md_speclink!("_Toc3901200")] pub struct MPingresp; impl MPingresp { diff --git a/mqtt-format/src/v5/packets/puback.rs b/mqtt-format/src/v5/packets/puback.rs index 2c2b8e44..1ecb74f1 100644 --- a/mqtt-format/src/v5/packets/puback.rs +++ b/mqtt-format/src/v5/packets/puback.rs @@ -32,6 +32,7 @@ define_properties!( } ); +#[doc = crate::v5::util::md_speclink!("_Toc3901121")] pub struct MPuback<'i> { pub packet_identifier: PacketIdentifier, pub reason: PubackReasonCode, diff --git a/mqtt-format/src/v5/packets/pubcomp.rs b/mqtt-format/src/v5/packets/pubcomp.rs index 6c79df8b..745dbebe 100644 --- a/mqtt-format/src/v5/packets/pubcomp.rs +++ b/mqtt-format/src/v5/packets/pubcomp.rs @@ -24,6 +24,7 @@ crate::v5::properties::define_properties! { } } +#[doc = crate::v5::util::md_speclink!("_Toc3901151")] pub struct MPubcomp<'i> { pub packet_identifier: PacketIdentifier, pub reason: PubcompReasonCode, diff --git a/mqtt-format/src/v5/packets/publish.rs b/mqtt-format/src/v5/packets/publish.rs index ddb29fe8..20fe68ec 100644 --- a/mqtt-format/src/v5/packets/publish.rs +++ b/mqtt-format/src/v5/packets/publish.rs @@ -13,6 +13,7 @@ use crate::v5::{ MResult, }; +#[doc = crate::v5::util::md_speclink!("_Toc3901100")] pub struct MPublish<'i> { pub duplicate: bool, pub quality_of_service: QualityOfService, diff --git a/mqtt-format/src/v5/packets/pubrec.rs b/mqtt-format/src/v5/packets/pubrec.rs index ee07107b..05147fe1 100644 --- a/mqtt-format/src/v5/packets/pubrec.rs +++ b/mqtt-format/src/v5/packets/pubrec.rs @@ -32,6 +32,7 @@ crate::v5::properties::define_properties![ } ]; +#[doc = crate::v5::util::md_speclink!("_Toc3901131")] pub struct MPubrec<'i> { pub packet_identifier: PacketIdentifier, pub reason: PubrecReasonCode, diff --git a/mqtt-format/src/v5/packets/pubrel.rs b/mqtt-format/src/v5/packets/pubrel.rs index 109cc00f..5c2d0574 100644 --- a/mqtt-format/src/v5/packets/pubrel.rs +++ b/mqtt-format/src/v5/packets/pubrel.rs @@ -25,6 +25,7 @@ define_properties!( } ); +#[doc = crate::v5::util::md_speclink!("_Toc3901141")] pub struct MPubrel<'i> { pub packet_identifier: PacketIdentifier, pub reason: PubrelReasonCode, diff --git a/mqtt-format/src/v5/packets/suback.rs b/mqtt-format/src/v5/packets/suback.rs index 0fab3cb9..ae47eb0d 100644 --- a/mqtt-format/src/v5/packets/suback.rs +++ b/mqtt-format/src/v5/packets/suback.rs @@ -34,6 +34,7 @@ crate::v5::properties::define_properties! { } } +#[doc = crate::v5::util::md_speclink!("_Toc3901171")] pub struct MSuback<'i> { pub packet_identifier: PacketIdentifier, pub properties: SubackProperties<'i>, diff --git a/mqtt-format/src/v5/packets/subscribe.rs b/mqtt-format/src/v5/packets/subscribe.rs index 05211a92..d2ab8254 100644 --- a/mqtt-format/src/v5/packets/subscribe.rs +++ b/mqtt-format/src/v5/packets/subscribe.rs @@ -60,6 +60,7 @@ impl SubscriptionOptions { } } +#[doc = crate::v5::util::md_speclink!("_Toc3901161")] pub struct Subscription<'i> { pub topic_filter: &'i str, pub options: SubscriptionOptions, diff --git a/mqtt-format/src/v5/packets/unsuback.rs b/mqtt-format/src/v5/packets/unsuback.rs index 42c4cda8..259e12ad 100644 --- a/mqtt-format/src/v5/packets/unsuback.rs +++ b/mqtt-format/src/v5/packets/unsuback.rs @@ -25,6 +25,7 @@ crate::v5::properties::define_properties! { } } +#[doc = crate::v5::util::md_speclink!("_Toc3901187")] pub struct MUnsuback<'i> { pub packet_identifier: PacketIdentifier, pub properties: UnsubackProperties<'i>, diff --git a/mqtt-format/src/v5/packets/unsubscribe.rs b/mqtt-format/src/v5/packets/unsubscribe.rs index cd64d57a..4a83f842 100644 --- a/mqtt-format/src/v5/packets/unsubscribe.rs +++ b/mqtt-format/src/v5/packets/unsubscribe.rs @@ -74,6 +74,7 @@ impl<'i> Unsubscription<'i> { } } +#[doc = crate::v5::util::md_speclink!("_Toc3901179")] pub struct MUnsubscribe<'i> { pub packet_identifier: PacketIdentifier, pub properties: UnsubscribeProperties<'i>, From 10ef3f90513017493f32046e8d9056fcc3bbe552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:34:37 +0100 Subject: [PATCH 81/90] Add book emoji to specification links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/util.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mqtt-format/src/v5/util.rs b/mqtt-format/src/v5/util.rs index 75c03eb8..233df896 100644 --- a/mqtt-format/src/v5/util.rs +++ b/mqtt-format/src/v5/util.rs @@ -10,7 +10,11 @@ pub(crate) use speclink; macro_rules! md_speclink { ($anker:literal) => { - std::concat!("[Specification](", $crate::v5::util::speclink!($anker), ")") + std::concat!( + "[📖 Specification](", + $crate::v5::util::speclink!($anker), + ")" + ) }; } pub(crate) use md_speclink; From 7a1e037c3930637e9e856f04764507e359491975 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 14:41:49 +0100 Subject: [PATCH 82/90] Fix: Implement protocol name/level verification Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/connect.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/mqtt-format/src/v5/packets/connect.rs b/mqtt-format/src/v5/packets/connect.rs index 7758e26c..615df7fe 100644 --- a/mqtt-format/src/v5/packets/connect.rs +++ b/mqtt-format/src/v5/packets/connect.rs @@ -64,8 +64,17 @@ crate::v5::properties::define_properties! { impl<'i> MConnect<'i> { pub fn parse(input: &mut &'i Bytes) -> MResult { // parse header - let protocol_name = crate::v5::strings::parse_string(input)?; - let protocol_level = ProtocolLevel::parse(input)?; + + // verify the protocol name + let _ = crate::v5::strings::parse_string + .verify(|s: &str| s == "MQTT") + .parse_next(input)?; + + // just for verification + let _ = ProtocolLevel::parse + .verify(|lvl: &ProtocolLevel| *lvl == ProtocolLevel::V5) + .parse_next(input)?; + let (_, clean_start, will_flag, will_qos, will_retain, password_flag, user_name_flag) = winnow::binary::bits::bits::<_, _, InputError<(_, usize)>, _, _>(( winnow::binary::bits::pattern(0x0, 1usize), From 85743740cd2193ede71051ec0f7e35701e11355d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:43:31 +0100 Subject: [PATCH 83/90] Add missing debug/copy impls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/level.rs | 2 +- mqtt-format/src/v5/mod.rs | 2 ++ mqtt-format/src/v5/packets/auth.rs | 1 + mqtt-format/src/v5/packets/connack.rs | 1 + mqtt-format/src/v5/packets/connect.rs | 2 ++ mqtt-format/src/v5/packets/disconnect.rs | 1 + mqtt-format/src/v5/packets/mod.rs | 1 + mqtt-format/src/v5/packets/pingreq.rs | 1 + mqtt-format/src/v5/packets/pingresp.rs | 1 + mqtt-format/src/v5/packets/puback.rs | 1 + mqtt-format/src/v5/packets/pubcomp.rs | 1 + mqtt-format/src/v5/packets/publish.rs | 1 + mqtt-format/src/v5/packets/pubrec.rs | 1 + mqtt-format/src/v5/packets/pubrel.rs | 1 + mqtt-format/src/v5/packets/suback.rs | 1 + mqtt-format/src/v5/packets/subscribe.rs | 12 +++++++++++- mqtt-format/src/v5/packets/unsuback.rs | 1 + mqtt-format/src/v5/packets/unsubscribe.rs | 9 +++++++++ mqtt-format/src/v5/properties.rs | 3 ++- mqtt-format/src/v5/reason_code.rs | 2 ++ mqtt-format/src/v5/variable_header.rs | 10 ++++++++++ 21 files changed, 52 insertions(+), 3 deletions(-) diff --git a/mqtt-format/src/v5/level.rs b/mqtt-format/src/v5/level.rs index 00dd60e3..55a28945 100644 --- a/mqtt-format/src/v5/level.rs +++ b/mqtt-format/src/v5/level.rs @@ -3,7 +3,7 @@ use winnow::Bytes; use super::MResult; -#[derive(PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq)] pub enum ProtocolLevel { V3, V5, diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index a16e8190..c3b7fe7c 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -1,3 +1,5 @@ +#![deny(missing_debug_implementations)] + pub mod bytes; pub mod fixed_header; pub mod integers; diff --git a/mqtt-format/src/v5/packets/auth.rs b/mqtt-format/src/v5/packets/auth.rs index a7831518..c2ba9932 100644 --- a/mqtt-format/src/v5/packets/auth.rs +++ b/mqtt-format/src/v5/packets/auth.rs @@ -31,6 +31,7 @@ crate::v5::properties::define_properties! { } } +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901217")] pub struct MAuth<'i> { pub reason: AuthReasonCode, diff --git a/mqtt-format/src/v5/packets/connack.rs b/mqtt-format/src/v5/packets/connack.rs index 6c1fedea..40142974 100644 --- a/mqtt-format/src/v5/packets/connack.rs +++ b/mqtt-format/src/v5/packets/connack.rs @@ -98,6 +98,7 @@ define_properties![ } ]; +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901074")] pub struct MConnack<'i> { pub session_present: bool, diff --git a/mqtt-format/src/v5/packets/connect.rs b/mqtt-format/src/v5/packets/connect.rs index 615df7fe..84349bc5 100644 --- a/mqtt-format/src/v5/packets/connect.rs +++ b/mqtt-format/src/v5/packets/connect.rs @@ -18,6 +18,7 @@ use crate::v5::{ MResult, }; +#[derive(Debug)] pub struct MConnect<'i> { pub client_identifier: &'i str, pub username: Option<&'i str>, @@ -135,6 +136,7 @@ impl<'i> MConnect<'i> { } } +#[derive(Debug)] pub struct Will<'i> { pub properties: ConnectWillProperties<'i>, pub topic: &'i str, diff --git a/mqtt-format/src/v5/packets/disconnect.rs b/mqtt-format/src/v5/packets/disconnect.rs index 71fc16f4..96b9d15b 100644 --- a/mqtt-format/src/v5/packets/disconnect.rs +++ b/mqtt-format/src/v5/packets/disconnect.rs @@ -59,6 +59,7 @@ define_properties! { } } +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901205")] pub struct MDisconnect<'i> { pub reason_code: DisconnectReasonCode, diff --git a/mqtt-format/src/v5/packets/mod.rs b/mqtt-format/src/v5/packets/mod.rs index 31e21021..c3138a89 100644 --- a/mqtt-format/src/v5/packets/mod.rs +++ b/mqtt-format/src/v5/packets/mod.rs @@ -28,6 +28,7 @@ pub mod subscribe; pub mod unsuback; pub mod unsubscribe; +#[derive(Debug)] pub enum MqttPacket<'i> { Auth(MAuth<'i>), Connack(MConnack<'i>), diff --git a/mqtt-format/src/v5/packets/pingreq.rs b/mqtt-format/src/v5/packets/pingreq.rs index 13a6adb8..ae87c192 100644 --- a/mqtt-format/src/v5/packets/pingreq.rs +++ b/mqtt-format/src/v5/packets/pingreq.rs @@ -2,6 +2,7 @@ use winnow::{Bytes, Parser}; use crate::v5::MResult; +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901195")] pub struct MPingreq; diff --git a/mqtt-format/src/v5/packets/pingresp.rs b/mqtt-format/src/v5/packets/pingresp.rs index b17c08ed..6d1fbc7a 100644 --- a/mqtt-format/src/v5/packets/pingresp.rs +++ b/mqtt-format/src/v5/packets/pingresp.rs @@ -2,6 +2,7 @@ use winnow::Bytes; use crate::v5::MResult; +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901200")] pub struct MPingresp; diff --git a/mqtt-format/src/v5/packets/puback.rs b/mqtt-format/src/v5/packets/puback.rs index 1ecb74f1..85393e0c 100644 --- a/mqtt-format/src/v5/packets/puback.rs +++ b/mqtt-format/src/v5/packets/puback.rs @@ -32,6 +32,7 @@ define_properties!( } ); +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901121")] pub struct MPuback<'i> { pub packet_identifier: PacketIdentifier, diff --git a/mqtt-format/src/v5/packets/pubcomp.rs b/mqtt-format/src/v5/packets/pubcomp.rs index 745dbebe..4fc63eb3 100644 --- a/mqtt-format/src/v5/packets/pubcomp.rs +++ b/mqtt-format/src/v5/packets/pubcomp.rs @@ -24,6 +24,7 @@ crate::v5::properties::define_properties! { } } +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901151")] pub struct MPubcomp<'i> { pub packet_identifier: PacketIdentifier, diff --git a/mqtt-format/src/v5/packets/publish.rs b/mqtt-format/src/v5/packets/publish.rs index 20fe68ec..d33b80f9 100644 --- a/mqtt-format/src/v5/packets/publish.rs +++ b/mqtt-format/src/v5/packets/publish.rs @@ -13,6 +13,7 @@ use crate::v5::{ MResult, }; +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901100")] pub struct MPublish<'i> { pub duplicate: bool, diff --git a/mqtt-format/src/v5/packets/pubrec.rs b/mqtt-format/src/v5/packets/pubrec.rs index 05147fe1..57fb949e 100644 --- a/mqtt-format/src/v5/packets/pubrec.rs +++ b/mqtt-format/src/v5/packets/pubrec.rs @@ -32,6 +32,7 @@ crate::v5::properties::define_properties![ } ]; +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901131")] pub struct MPubrec<'i> { pub packet_identifier: PacketIdentifier, diff --git a/mqtt-format/src/v5/packets/pubrel.rs b/mqtt-format/src/v5/packets/pubrel.rs index 5c2d0574..55bb4f55 100644 --- a/mqtt-format/src/v5/packets/pubrel.rs +++ b/mqtt-format/src/v5/packets/pubrel.rs @@ -25,6 +25,7 @@ define_properties!( } ); +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901141")] pub struct MPubrel<'i> { pub packet_identifier: PacketIdentifier, diff --git a/mqtt-format/src/v5/packets/suback.rs b/mqtt-format/src/v5/packets/suback.rs index ae47eb0d..d1a5f5f9 100644 --- a/mqtt-format/src/v5/packets/suback.rs +++ b/mqtt-format/src/v5/packets/suback.rs @@ -34,6 +34,7 @@ crate::v5::properties::define_properties! { } } +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901171")] pub struct MSuback<'i> { pub packet_identifier: PacketIdentifier, diff --git a/mqtt-format/src/v5/packets/subscribe.rs b/mqtt-format/src/v5/packets/subscribe.rs index d2ab8254..cb0d3432 100644 --- a/mqtt-format/src/v5/packets/subscribe.rs +++ b/mqtt-format/src/v5/packets/subscribe.rs @@ -20,7 +20,7 @@ define_properties! { } } -#[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)] +#[derive(Debug, num_enum::TryFromPrimitive, num_enum::IntoPrimitive)] #[repr(u8)] pub enum RetainHandling { SendRetainedMessagesAlways = 0, @@ -28,6 +28,7 @@ pub enum RetainHandling { DoNotSendRetainedMessages = 2, } +#[derive(Debug)] pub struct SubscriptionOptions { pub quality_of_service: QualityOfService, pub no_local: bool, @@ -60,6 +61,7 @@ impl SubscriptionOptions { } } +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901161")] pub struct Subscription<'i> { pub topic_filter: &'i str, @@ -82,6 +84,12 @@ pub struct Subscriptions<'i> { start: &'i [u8], } +impl<'i> std::fmt::Debug for Subscriptions<'i> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Subscriptions").finish() + } +} + impl<'i> Subscriptions<'i> { fn parse(input: &mut &'i Bytes) -> MResult> { let start = @@ -99,6 +107,7 @@ impl<'i> Subscriptions<'i> { } } +#[allow(missing_debug_implementations)] pub struct SubscriptionsIter<'i> { current: &'i Bytes, } @@ -118,6 +127,7 @@ impl<'i> Iterator for SubscriptionsIter<'i> { } } +#[derive(Debug)] pub struct MSubscribe<'i> { pub packet_identifier: PacketIdentifier, pub properties: SubscribeProperties<'i>, diff --git a/mqtt-format/src/v5/packets/unsuback.rs b/mqtt-format/src/v5/packets/unsuback.rs index 259e12ad..a5439966 100644 --- a/mqtt-format/src/v5/packets/unsuback.rs +++ b/mqtt-format/src/v5/packets/unsuback.rs @@ -25,6 +25,7 @@ crate::v5::properties::define_properties! { } } +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901187")] pub struct MUnsuback<'i> { pub packet_identifier: PacketIdentifier, diff --git a/mqtt-format/src/v5/packets/unsubscribe.rs b/mqtt-format/src/v5/packets/unsubscribe.rs index 4a83f842..cfee0cfc 100644 --- a/mqtt-format/src/v5/packets/unsubscribe.rs +++ b/mqtt-format/src/v5/packets/unsubscribe.rs @@ -23,6 +23,12 @@ pub struct Unsubscriptions<'i> { start: &'i [u8], } +impl<'i> std::fmt::Debug for Unsubscriptions<'i> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Unsubscriptions").finish() + } +} + impl<'i> Unsubscriptions<'i> { fn parse(input: &mut &'i Bytes) -> MResult> { let start = repeat_till::<_, _, (), _, _, _, _>( @@ -43,6 +49,7 @@ impl<'i> Unsubscriptions<'i> { } } +#[allow(missing_debug_implementations)] pub struct UnsubscriptionsIter<'i> { current: &'i Bytes, } @@ -62,6 +69,7 @@ impl<'i> Iterator for UnsubscriptionsIter<'i> { } } +#[derive(Debug)] pub struct Unsubscription<'i> { pub topic_filter: &'i str, } @@ -74,6 +82,7 @@ impl<'i> Unsubscription<'i> { } } +#[derive(Debug)] #[doc = crate::v5::util::md_speclink!("_Toc3901179")] pub struct MUnsubscribe<'i> { pub packet_identifier: PacketIdentifier, diff --git a/mqtt-format/src/v5/properties.rs b/mqtt-format/src/v5/properties.rs index 1f054295..42eaa0f3 100644 --- a/mqtt-format/src/v5/properties.rs +++ b/mqtt-format/src/v5/properties.rs @@ -5,7 +5,7 @@ use winnow::{ use super::MResult; -pub struct MqttPropertySlot { +pub(crate) struct MqttPropertySlot { allow_repeat: bool, slot: Option, } @@ -54,6 +54,7 @@ macro_rules! define_properties { $( #[doc = $crate::v5::util::md_speclink!($anker)] )? + #[derive(Debug)] pub struct $name < $lt > { $( $( diff --git a/mqtt-format/src/v5/reason_code.rs b/mqtt-format/src/v5/reason_code.rs index 934884a3..795eebd5 100644 --- a/mqtt-format/src/v5/reason_code.rs +++ b/mqtt-format/src/v5/reason_code.rs @@ -4,6 +4,7 @@ macro_rules! make_combined_reason_code { }) => { #[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)] #[repr(u8)] + #[derive(Debug, Copy, Clone)] pub enum $name { $( $reason_code_name = <$reason_code_type>::CODE ),* } @@ -22,6 +23,7 @@ pub(crate) use make_combined_reason_code; macro_rules! define_reason_code { ($name:ident => $code:literal) => { + #[derive(Debug, Copy, Clone)] pub struct $name; impl $name { pub const CODE: u8 = $code; diff --git a/mqtt-format/src/v5/variable_header.rs b/mqtt-format/src/v5/variable_header.rs index 808ec77a..2933dd1b 100644 --- a/mqtt-format/src/v5/variable_header.rs +++ b/mqtt-format/src/v5/variable_header.rs @@ -2,6 +2,7 @@ use winnow::{Bytes, Parser}; use super::{integers::parse_u16, integers::parse_u32, MResult}; +#[derive(Debug, Clone, Copy)] pub struct PacketIdentifier(pub u16); impl PacketIdentifier { @@ -27,6 +28,7 @@ macro_rules! define_properties { $(,)? ]) => { $( + #[derive(Debug)] pub struct $name < $($tylt)? >(pub $(& $lt)? $kind); impl<'lt $(, $tylt)?> MqttProperties<'lt> for $name < $($tylt)? > @@ -54,6 +56,7 @@ macro_rules! define_properties { } )* + #[derive(Debug)] pub enum Property<'i> { $( $name ( $name $(< $tylt >)? ), @@ -108,6 +111,12 @@ define_properties! {[ pub struct UserProperties<'i>(pub &'i [u8]); +impl<'i> std::fmt::Debug for UserProperties<'i> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("UserProperties").finish() + } +} + impl<'i> MqttProperties<'i> for UserProperties<'i> { const IDENTIFIER: u32 = 0x26; const ALLOW_REPEATING: bool = true; @@ -157,6 +166,7 @@ impl<'i> UserProperty<'i> { } } +#[allow(missing_debug_implementations)] pub struct UserPropertyIterator<'i> { current: &'i Bytes, first_prop: bool, From 666d45031343c0e9c411496c488b24892c97ce38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:51:01 +0100 Subject: [PATCH 84/90] Clarify that the ignored value is a reserved MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/v5/packets/connect.rs | 36 ++++++++++++++++----------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/mqtt-format/src/v5/packets/connect.rs b/mqtt-format/src/v5/packets/connect.rs index 84349bc5..70a329b0 100644 --- a/mqtt-format/src/v5/packets/connect.rs +++ b/mqtt-format/src/v5/packets/connect.rs @@ -76,21 +76,27 @@ impl<'i> MConnect<'i> { .verify(|lvl: &ProtocolLevel| *lvl == ProtocolLevel::V5) .parse_next(input)?; - let (_, clean_start, will_flag, will_qos, will_retain, password_flag, user_name_flag) = - winnow::binary::bits::bits::<_, _, InputError<(_, usize)>, _, _>(( - winnow::binary::bits::pattern(0x0, 1usize), - winnow::binary::bits::bool, - winnow::binary::bits::bool, - winnow::binary::bits::take(2usize) - .try_map(>::try_from), - winnow::binary::bits::bool, - winnow::binary::bits::bool, - winnow::binary::bits::bool, - )) - .parse_next(input) - .map_err(|_: ErrMode>| { - ErrMode::from_error_kind(input, winnow::error::ErrorKind::Slice) - })?; + let ( + _reserved, + clean_start, + will_flag, + will_qos, + will_retain, + password_flag, + user_name_flag, + ) = winnow::binary::bits::bits::<_, _, InputError<(_, usize)>, _, _>(( + winnow::binary::bits::pattern(0x0, 1usize), + winnow::binary::bits::bool, + winnow::binary::bits::bool, + winnow::binary::bits::take(2usize).try_map(>::try_from), + winnow::binary::bits::bool, + winnow::binary::bits::bool, + winnow::binary::bits::bool, + )) + .parse_next(input) + .map_err(|_: ErrMode>| { + ErrMode::from_error_kind(input, winnow::error::ErrorKind::Slice) + })?; let keep_alive = parse_u16(input)?; From 0dc7bd926dd8779bfc0029db0bc0d2b0a652c5b6 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 14:51:51 +0100 Subject: [PATCH 85/90] Fix: Store parsed data in Will/MConnect Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/packets/connect.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mqtt-format/src/v5/packets/connect.rs b/mqtt-format/src/v5/packets/connect.rs index 70a329b0..ce93142a 100644 --- a/mqtt-format/src/v5/packets/connect.rs +++ b/mqtt-format/src/v5/packets/connect.rs @@ -26,6 +26,7 @@ pub struct MConnect<'i> { pub clean_start: bool, pub will: Option>, pub properties: ConnectProperties<'i>, + pub keep_alive: u16, } crate::v5::properties::define_properties! { @@ -122,6 +123,8 @@ impl<'i> MConnect<'i> { properties, topic, payload, + will_qos, + will_retain, }) }) .transpose()?; @@ -138,6 +141,7 @@ impl<'i> MConnect<'i> { will, clean_start, properties, + keep_alive, }) } } @@ -147,6 +151,8 @@ pub struct Will<'i> { pub properties: ConnectWillProperties<'i>, pub topic: &'i str, pub payload: &'i [u8], + pub will_qos: QualityOfService, + pub will_retain: bool, } crate::v5::properties::define_properties! { From f3b2a0f8fe8b75c762d802951eb9aa37eda1a162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:57:10 +0100 Subject: [PATCH 86/90] Add correct feature flags to modules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mqtt-format/src/lib.rs b/mqtt-format/src/lib.rs index c82d7c33..db654dfd 100644 --- a/mqtt-format/src/lib.rs +++ b/mqtt-format/src/lib.rs @@ -7,6 +7,7 @@ #![deny(clippy::disallowed_methods)] #![deny(clippy::disallowed_types)] -#[cfg(mqttv3)] +#[cfg(feature = "mqttv3")] pub mod v3; +#[cfg(feature = "mqttv5")] pub mod v5; From 1c1aebaaf90c57a66e47682530fcf52db249a14b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 14:57:20 +0100 Subject: [PATCH 87/90] Feature gate dependencies behind resp. features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/Cargo.toml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mqtt-format/Cargo.toml b/mqtt-format/Cargo.toml index cc31638d..d174d723 100644 --- a/mqtt-format/Cargo.toml +++ b/mqtt-format/Cargo.toml @@ -12,16 +12,19 @@ categories = ["embedded", "parsing"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] +default = ["mqttv5"] yoke = ["dep:yoke"] debug = ["winnow/debug"] +mqttv3 = ["dep:futures", "dep:nom", "dep:nom-supreme"] +mqttv5 = ["dep:winnow"] [dependencies] -futures = "0.3.28" -nom = "7.1.3" -nom-supreme = "0.8.0" +futures = { version = "0.3.28", optional = true } +nom = { version = "7.1.3", optional = true } +nom-supreme = { version = "0.8.0", optional = true } num_enum = "0.7.2" thiserror = "1.0.40" -winnow = "0.6.5" +winnow = { version = "0.6.5", optional = true } yoke = { version = "0.7.0", features = ["derive"], optional = true } [dev-dependencies] From b505e2d0d3d7b96fe5cb0a9492ddf1e53fc07511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 15:00:56 +0100 Subject: [PATCH 88/90] Do not disallow Result::expect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- mqtt-format/clippy.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/mqtt-format/clippy.toml b/mqtt-format/clippy.toml index 12f26d4f..59c091e3 100644 --- a/mqtt-format/clippy.toml +++ b/mqtt-format/clippy.toml @@ -1,6 +1,5 @@ disallowed-methods = [ "std::result::Result::unwrap", - "std::result::Result::expect", "std::option::Option::unwrap", "std::option::Option::expect", ] From b4ea00c022eeeee935458acb16b0283b4bbb0412 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Wed, 20 Mar 2024 15:04:15 +0100 Subject: [PATCH 89/90] Add missing license headers Signed-off-by: Matthias Beyer --- mqtt-format/src/v5/bytes.rs | 6 ++++++ mqtt-format/src/v5/fixed_header.rs | 6 ++++++ mqtt-format/src/v5/integers.rs | 6 ++++++ mqtt-format/src/v5/level.rs | 6 ++++++ mqtt-format/src/v5/mod.rs | 6 ++++++ mqtt-format/src/v5/packets/auth.rs | 6 ++++++ mqtt-format/src/v5/packets/connack.rs | 6 ++++++ mqtt-format/src/v5/packets/connect.rs | 6 ++++++ mqtt-format/src/v5/packets/disconnect.rs | 6 ++++++ mqtt-format/src/v5/packets/mod.rs | 6 ++++++ mqtt-format/src/v5/packets/pingreq.rs | 6 ++++++ mqtt-format/src/v5/packets/pingresp.rs | 6 ++++++ mqtt-format/src/v5/packets/puback.rs | 6 ++++++ mqtt-format/src/v5/packets/pubcomp.rs | 6 ++++++ mqtt-format/src/v5/packets/publish.rs | 6 ++++++ mqtt-format/src/v5/packets/pubrec.rs | 6 ++++++ mqtt-format/src/v5/packets/pubrel.rs | 6 ++++++ mqtt-format/src/v5/packets/suback.rs | 6 ++++++ mqtt-format/src/v5/packets/subscribe.rs | 6 ++++++ mqtt-format/src/v5/packets/unsuback.rs | 6 ++++++ mqtt-format/src/v5/packets/unsubscribe.rs | 6 ++++++ mqtt-format/src/v5/properties.rs | 6 ++++++ mqtt-format/src/v5/reason_code.rs | 6 ++++++ mqtt-format/src/v5/strings.rs | 6 ++++++ mqtt-format/src/v5/util.rs | 6 ++++++ mqtt-format/src/v5/variable_header.rs | 6 ++++++ 26 files changed, 156 insertions(+) diff --git a/mqtt-format/src/v5/bytes.rs b/mqtt-format/src/v5/bytes.rs index e4a34502..51fb3523 100644 --- a/mqtt-format/src/v5/bytes.rs +++ b/mqtt-format/src/v5/bytes.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{binary::length_take, Bytes, Parser}; use super::MResult; diff --git a/mqtt-format/src/v5/fixed_header.rs b/mqtt-format/src/v5/fixed_header.rs index ce33adb6..2d959f52 100644 --- a/mqtt-format/src/v5/fixed_header.rs +++ b/mqtt-format/src/v5/fixed_header.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{ binary::bits::bits, error::{ErrMode, FromExternalError, InputError, ParserError}, diff --git a/mqtt-format/src/v5/integers.rs b/mqtt-format/src/v5/integers.rs index 809efa2f..dd3a8890 100644 --- a/mqtt-format/src/v5/integers.rs +++ b/mqtt-format/src/v5/integers.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{combinator::trace, token::take_while, Bytes, Parser}; use super::MResult; diff --git a/mqtt-format/src/v5/level.rs b/mqtt-format/src/v5/level.rs index 55a28945..d12f6643 100644 --- a/mqtt-format/src/v5/level.rs +++ b/mqtt-format/src/v5/level.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::error::{ErrMode, ParserError}; use winnow::Bytes; diff --git a/mqtt-format/src/v5/mod.rs b/mqtt-format/src/v5/mod.rs index c3b7fe7c..c6877fbc 100644 --- a/mqtt-format/src/v5/mod.rs +++ b/mqtt-format/src/v5/mod.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + #![deny(missing_debug_implementations)] pub mod bytes; diff --git a/mqtt-format/src/v5/packets/auth.rs b/mqtt-format/src/v5/packets/auth.rs index c2ba9932..60cef190 100644 --- a/mqtt-format/src/v5/packets/auth.rs +++ b/mqtt-format/src/v5/packets/auth.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::Bytes; use crate::v5::{ diff --git a/mqtt-format/src/v5/packets/connack.rs b/mqtt-format/src/v5/packets/connack.rs index 40142974..3f1d468f 100644 --- a/mqtt-format/src/v5/packets/connack.rs +++ b/mqtt-format/src/v5/packets/connack.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{ error::{ErrMode, InputError, ParserError}, Bytes, Parser, diff --git a/mqtt-format/src/v5/packets/connect.rs b/mqtt-format/src/v5/packets/connect.rs index ce93142a..a73344eb 100644 --- a/mqtt-format/src/v5/packets/connect.rs +++ b/mqtt-format/src/v5/packets/connect.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{ error::{ErrMode, InputError, ParserError}, Bytes, Parser, diff --git a/mqtt-format/src/v5/packets/disconnect.rs b/mqtt-format/src/v5/packets/disconnect.rs index 96b9d15b..068a1dde 100644 --- a/mqtt-format/src/v5/packets/disconnect.rs +++ b/mqtt-format/src/v5/packets/disconnect.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{Bytes, Parser}; use crate::v5::{ diff --git a/mqtt-format/src/v5/packets/mod.rs b/mqtt-format/src/v5/packets/mod.rs index c3138a89..2e862090 100644 --- a/mqtt-format/src/v5/packets/mod.rs +++ b/mqtt-format/src/v5/packets/mod.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use self::{ auth::MAuth, connect::MConnect, disconnect::MDisconnect, pingreq::MPingreq, pingresp::MPingresp, puback::MPuback, pubcomp::MPubcomp, publish::MPublish, pubrec::MPubrec, diff --git a/mqtt-format/src/v5/packets/pingreq.rs b/mqtt-format/src/v5/packets/pingreq.rs index ae87c192..417ed514 100644 --- a/mqtt-format/src/v5/packets/pingreq.rs +++ b/mqtt-format/src/v5/packets/pingreq.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{Bytes, Parser}; use crate::v5::MResult; diff --git a/mqtt-format/src/v5/packets/pingresp.rs b/mqtt-format/src/v5/packets/pingresp.rs index 6d1fbc7a..712bf2e7 100644 --- a/mqtt-format/src/v5/packets/pingresp.rs +++ b/mqtt-format/src/v5/packets/pingresp.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::Bytes; use crate::v5::MResult; diff --git a/mqtt-format/src/v5/packets/puback.rs b/mqtt-format/src/v5/packets/puback.rs index 85393e0c..11c82ddb 100644 --- a/mqtt-format/src/v5/packets/puback.rs +++ b/mqtt-format/src/v5/packets/puback.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::Bytes; use crate::v5::{ diff --git a/mqtt-format/src/v5/packets/pubcomp.rs b/mqtt-format/src/v5/packets/pubcomp.rs index 4fc63eb3..dcc4e67d 100644 --- a/mqtt-format/src/v5/packets/pubcomp.rs +++ b/mqtt-format/src/v5/packets/pubcomp.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::Bytes; use crate::v5::{ diff --git a/mqtt-format/src/v5/packets/publish.rs b/mqtt-format/src/v5/packets/publish.rs index d33b80f9..f43d7b27 100644 --- a/mqtt-format/src/v5/packets/publish.rs +++ b/mqtt-format/src/v5/packets/publish.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{ error::{ErrMode, ParserError}, stream::Stream, diff --git a/mqtt-format/src/v5/packets/pubrec.rs b/mqtt-format/src/v5/packets/pubrec.rs index 57fb949e..7a42b3fa 100644 --- a/mqtt-format/src/v5/packets/pubrec.rs +++ b/mqtt-format/src/v5/packets/pubrec.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::Bytes; use crate::v5::{ diff --git a/mqtt-format/src/v5/packets/pubrel.rs b/mqtt-format/src/v5/packets/pubrel.rs index 55bb4f55..9c5abc81 100644 --- a/mqtt-format/src/v5/packets/pubrel.rs +++ b/mqtt-format/src/v5/packets/pubrel.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::Bytes; use crate::v5::{ diff --git a/mqtt-format/src/v5/packets/suback.rs b/mqtt-format/src/v5/packets/suback.rs index d1a5f5f9..120b59d3 100644 --- a/mqtt-format/src/v5/packets/suback.rs +++ b/mqtt-format/src/v5/packets/suback.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{Bytes, Parser}; use crate::v5::{ diff --git a/mqtt-format/src/v5/packets/subscribe.rs b/mqtt-format/src/v5/packets/subscribe.rs index cb0d3432..bdf74bce 100644 --- a/mqtt-format/src/v5/packets/subscribe.rs +++ b/mqtt-format/src/v5/packets/subscribe.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{ binary::bits::bits, combinator::repeat_till, diff --git a/mqtt-format/src/v5/packets/unsuback.rs b/mqtt-format/src/v5/packets/unsuback.rs index a5439966..297f30ac 100644 --- a/mqtt-format/src/v5/packets/unsuback.rs +++ b/mqtt-format/src/v5/packets/unsuback.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::Bytes; use winnow::Parser; diff --git a/mqtt-format/src/v5/packets/unsubscribe.rs b/mqtt-format/src/v5/packets/unsubscribe.rs index cfee0cfc..4e783f47 100644 --- a/mqtt-format/src/v5/packets/unsubscribe.rs +++ b/mqtt-format/src/v5/packets/unsubscribe.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{combinator::repeat_till, Bytes, Parser}; use crate::v5::{ diff --git a/mqtt-format/src/v5/properties.rs b/mqtt-format/src/v5/properties.rs index 42eaa0f3..5ea4ac9e 100644 --- a/mqtt-format/src/v5/properties.rs +++ b/mqtt-format/src/v5/properties.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{ error::{ErrMode, ParserError}, Bytes, diff --git a/mqtt-format/src/v5/reason_code.rs b/mqtt-format/src/v5/reason_code.rs index 795eebd5..17a0fdc5 100644 --- a/mqtt-format/src/v5/reason_code.rs +++ b/mqtt-format/src/v5/reason_code.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + macro_rules! make_combined_reason_code { (pub enum $name:ident { $($reason_code_name:ident = $reason_code_type:ty),* $(,)? diff --git a/mqtt-format/src/v5/strings.rs b/mqtt-format/src/v5/strings.rs index fc5d6d91..46f82b0e 100644 --- a/mqtt-format/src/v5/strings.rs +++ b/mqtt-format/src/v5/strings.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{ binary::length_take, error::{ErrMode, FromExternalError}, diff --git a/mqtt-format/src/v5/util.rs b/mqtt-format/src/v5/util.rs index 233df896..f0375eba 100644 --- a/mqtt-format/src/v5/util.rs +++ b/mqtt-format/src/v5/util.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + macro_rules! speclink { ($anker:literal) => { std::concat!( diff --git a/mqtt-format/src/v5/variable_header.rs b/mqtt-format/src/v5/variable_header.rs index 2933dd1b..a5188c05 100644 --- a/mqtt-format/src/v5/variable_header.rs +++ b/mqtt-format/src/v5/variable_header.rs @@ -1,3 +1,9 @@ +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// + use winnow::{Bytes, Parser}; use super::{integers::parse_u16, integers::parse_u32, MResult}; From 52f32087bb76343e64b9e7796afa7e3d39f2a7bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Wed, 20 Mar 2024 15:07:58 +0100 Subject: [PATCH 90/90] Make cloudmqtt binaries use the mqttv3 feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index eff51d55..2a256b6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ bytes = "1.4.0" clap = { version = "4.2.1", optional = true, features = ["derive"] } dashmap = "5.4.0" futures = "0.3.28" -mqtt-format = { version = "0.5.0", path = "mqtt-format", features = ["yoke"] } +mqtt-format = { version = "0.5.0", path = "mqtt-format", features = ["yoke", "mqttv3"] } nom = { version = "7.1.3" } thiserror = "1.0.40" tokio = { version = "1.27.0", default-features = false, features = [