Skip to content

Commit

Permalink
Merge pull request #260 from matthiasbeyer/specialize-property-types
Browse files Browse the repository at this point in the history
Specialize property types
  • Loading branch information
TheNeikos authored Mar 28, 2024
2 parents d43a8d3 + ad0c0a4 commit feba470
Show file tree
Hide file tree
Showing 14 changed files with 154 additions and 44 deletions.
27 changes: 27 additions & 0 deletions mqtt-format/src/v5/boolean.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// 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::ParserError;
use winnow::Bytes;

use super::write::WResult;
use super::write::WriteMqttPacket;
use super::MResult;

pub fn parse_bool(input: &mut &Bytes) -> MResult<bool> {
winnow::binary::u8(input).and_then(|byte| match byte {
0 => Ok(false),
1 => Ok(true),
_ => Err({
winnow::error::ErrMode::from_error_kind(input, winnow::error::ErrorKind::Verify)
}),
})
}

#[inline]
pub fn write_bool<W: WriteMqttPacket>(buffer: &mut W, b: bool) -> WResult<W> {
buffer.write_byte(b as u8)
}
19 changes: 5 additions & 14 deletions mqtt-format/src/v5/fixed_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,13 @@ use super::write::WResult;
use super::write::WriteMqttPacket;
use super::MResult;

#[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
#[repr(u8)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum QualityOfService {
AtMostOnce = 0,
AtLeastOnce = 1,
ExactlyOnce = 2,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PacketType {
Connect,
Connack,
Publish {
dup: bool,
qos: QualityOfService,
qos: crate::v5::qos::QualityOfService,
retain: bool,
},
Puback,
Expand Down Expand Up @@ -76,9 +67,9 @@ impl MFixedHeader {
(2, 0) => PacketType::Connack,
(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)
})?,
qos: crate::v5::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,
Expand Down Expand Up @@ -158,7 +149,7 @@ mod tests {
MFixedHeader {
packet_type: crate::v5::fixed_header::PacketType::Publish {
dup: true,
qos: crate::v5::fixed_header::QualityOfService::AtLeastOnce,
qos: crate::v5::qos::QualityOfService::AtLeastOnce,
retain: false
},
}
Expand Down
21 changes: 21 additions & 0 deletions mqtt-format/src/v5/integers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//! All integers in MQTT are big-endian

use winnow::combinator::trace;
use winnow::error::FromExternalError;
use winnow::token::take_while;
use winnow::Bytes;
use winnow::Parser;
Expand All @@ -33,6 +34,26 @@ pub fn write_u16<W: WriteMqttPacket>(buffer: &mut W, u: u16) -> WResult<W> {
Ok(())
}

pub fn parse_u16_nonzero(input: &mut &Bytes) -> MResult<core::num::NonZeroU16> {
let u: u16 = trace(
"mqtt_u16",
winnow::binary::u16(winnow::binary::Endianness::Big),
)
.parse_next(input)?;

core::num::NonZeroU16::try_from(u).map_err(|e| {
winnow::error::ErrMode::from_external_error(input, winnow::error::ErrorKind::Verify, e)
})
}

#[inline]
pub fn write_u16_nonzero<W: WriteMqttPacket>(
buffer: &mut W,
u: core::num::NonZeroU16,
) -> WResult<W> {
write_u16(buffer, u.get())
}

/// Parse a u32
///
/// MQTT expects their numbers in big-endian
Expand Down
2 changes: 2 additions & 0 deletions mqtt-format/src/v5/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@
//! }
//! ```

pub mod boolean;
pub mod bytes;
pub mod fixed_header;
pub mod integers;
pub mod packets;
pub mod properties;
pub mod qos;
pub mod reason_code;
pub mod strings;
mod util;
Expand Down
8 changes: 5 additions & 3 deletions mqtt-format/src/v5/packets/connack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,11 @@ mod test {
reason_code: ConnackReasonCode::Success,
properties: ConnackProperties {
session_expiry_interval: Some(SessionExpiryInterval(120)),
receive_maximum: Some(ReceiveMaximum(123)),
maximum_qos: Some(MaximumQoS(8)),
retain_available: Some(RetainAvailable(1)),
receive_maximum: Some(ReceiveMaximum(core::num::NonZeroU16::new(123).unwrap())),
maximum_qos: Some(MaximumQoS(
crate::v5::qos::MaximumQualityOfService::AtMostOnce
)),
retain_available: Some(RetainAvailable(true)),
maximum_packet_size: Some(MaximumPacketSize(1024)),
assigned_client_identifier: Some(AssignedClientIdentifier("foobar")),
topic_alias_maximum: Some(TopicAliasMaximum(1234)),
Expand Down
8 changes: 4 additions & 4 deletions mqtt-format/src/v5/packets/connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use winnow::Bytes;
use winnow::Parser;

use crate::v5::bytes::parse_binary_data;
use crate::v5::fixed_header::QualityOfService;
use crate::v5::integers::parse_u16;
use crate::v5::qos::QualityOfService;
use crate::v5::strings::parse_string;
use crate::v5::variable_header::AuthenticationData;
use crate::v5::variable_header::AuthenticationMethod;
Expand Down Expand Up @@ -356,7 +356,7 @@ mod test {
},
topic: "crazy topic",
payload: &[0xAB, 0xCD, 0xEF],
will_qos: crate::v5::fixed_header::QualityOfService::ExactlyOnce,
will_qos: crate::v5::qos::QualityOfService::ExactlyOnce,
will_retain: true,
}),
keep_alive: 321,
Expand Down Expand Up @@ -393,13 +393,13 @@ mod test {
},
topic: "crazy topic",
payload: &[0xAB, 0xCD, 0xEF],
will_qos: crate::v5::fixed_header::QualityOfService::ExactlyOnce,
will_qos: crate::v5::qos::QualityOfService::ExactlyOnce,
will_retain: true,
}),
keep_alive: 321,
properties: ConnectProperties {
session_expiry_interval: Some(SessionExpiryInterval(123)),
receive_maximum: Some(ReceiveMaximum(1024)),
receive_maximum: Some(ReceiveMaximum(core::num::NonZeroU16::new(1024).unwrap())),
maximum_packet_size: Some(MaximumPacketSize(1024)),
topic_alias_maximum: Some(TopicAliasMaximum(1203)),
request_response_information: Some(RequestResponseInformation(90)),
Expand Down
4 changes: 2 additions & 2 deletions mqtt-format/src/v5/packets/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use winnow::stream::Stream;
use winnow::Bytes;
use winnow::Parser;

use crate::v5::fixed_header::QualityOfService;
use crate::v5::qos::QualityOfService;
use crate::v5::strings::write_string;
use crate::v5::variable_header::ContentType;
use crate::v5::variable_header::CorrelationData;
Expand Down Expand Up @@ -123,9 +123,9 @@ fn sanity_check_topic_name(topic_name: &str) -> bool {

#[cfg(test)]
mod test {
use crate::v5::fixed_header::QualityOfService;
use crate::v5::packets::publish::MPublish;
use crate::v5::packets::publish::PublishProperties;
use crate::v5::qos::QualityOfService;
use crate::v5::variable_header::PacketIdentifier;

#[test]
Expand Down
4 changes: 2 additions & 2 deletions mqtt-format/src/v5/packets/subscribe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use winnow::error::ParserError;
use winnow::Bytes;
use winnow::Parser;

use crate::v5::fixed_header::QualityOfService;
use crate::v5::properties::define_properties;
use crate::v5::qos::QualityOfService;
use crate::v5::strings::parse_string;
use crate::v5::strings::write_string;
use crate::v5::variable_header::PacketIdentifier;
Expand Down Expand Up @@ -230,13 +230,13 @@ impl<'i> MSubscribe<'i> {

#[cfg(test)]
mod test {
use crate::v5::fixed_header::QualityOfService;
use crate::v5::packets::subscribe::MSubscribe;
use crate::v5::packets::subscribe::RetainHandling;
use crate::v5::packets::subscribe::SubscribeProperties;
use crate::v5::packets::subscribe::Subscription;
use crate::v5::packets::subscribe::SubscriptionOptions;
use crate::v5::packets::subscribe::Subscriptions;
use crate::v5::qos::QualityOfService;
use crate::v5::test::TestWriter;
use crate::v5::variable_header::PacketIdentifier;
use crate::v5::variable_header::SubscriptionIdentifier;
Expand Down
58 changes: 58 additions & 0 deletions mqtt-format/src/v5/qos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//
// 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::FromExternalError;
use winnow::Bytes;

use super::write::WResult;
use super::write::WriteMqttPacket;
use super::MResult;

#[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
#[repr(u8)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum QualityOfService {
AtMostOnce = 0,
AtLeastOnce = 1,
ExactlyOnce = 2,
}

pub fn parse_qos(input: &mut &Bytes) -> MResult<QualityOfService> {
winnow::binary::u8(input).and_then(|byte| {
QualityOfService::try_from(byte).map_err(|e| {
winnow::error::ErrMode::from_external_error(input, winnow::error::ErrorKind::Verify, e)
})
})
}

#[inline]
pub fn write_qos<W: WriteMqttPacket>(buffer: &mut W, qos: QualityOfService) -> WResult<W> {
crate::v5::variable_header::write_u8(buffer, qos.into())
}

#[derive(num_enum::TryFromPrimitive, num_enum::IntoPrimitive)]
#[repr(u8)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum MaximumQualityOfService {
AtMostOnce = 0,
AtLeastOnce = 1,
}

pub fn parse_maximum_quality_of_service(input: &mut &Bytes) -> MResult<MaximumQualityOfService> {
winnow::binary::u8(input).and_then(|byte| {
MaximumQualityOfService::try_from(byte).map_err(|e| {
winnow::error::ErrMode::from_external_error(input, winnow::error::ErrorKind::Verify, e)
})
})
}

#[inline]
pub fn write_maximum_quality_of_service<W: WriteMqttPacket>(
buffer: &mut W,
qos: MaximumQualityOfService,
) -> WResult<W> {
crate::v5::variable_header::write_u8(buffer, qos.into())
}
29 changes: 19 additions & 10 deletions mqtt-format/src/v5/variable_header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use winnow::Bytes;
use winnow::Parser;

use super::integers::parse_u16;
use super::integers::parse_u16_nonzero;
use super::integers::parse_u32;
use super::integers::write_variable_u32;
use super::write::WResult;
Expand Down Expand Up @@ -145,7 +146,7 @@ macro_rules! define_properties {
}

#[inline]
fn write_u8<W: WriteMqttPacket>(buffer: &mut W, u: u8) -> WResult<W> {
pub(crate) fn write_u8<W: WriteMqttPacket>(buffer: &mut W, u: u8) -> WResult<W> {
buffer.write_byte(u)
}

Expand Down Expand Up @@ -280,11 +281,16 @@ define_properties! {[
testvalues: ["fooobarbar"],

ReceiveMaximum as 0x21 =>
parse with parse_u16 as u16;
write with super::integers::write_u16;
parse with parse_u16_nonzero as core::num::NonZeroU16;
write with super::integers::write_u16_nonzero;
with size |_| 2;
testfnname: test_roundtrip_receivemaximum;
testvalues: [12, 14, 42, 1337],
testvalues: [
core::num::NonZeroU16::new(12).unwrap(),
core::num::NonZeroU16::new(14).unwrap(),
core::num::NonZeroU16::new(42).unwrap(),
core::num::NonZeroU16::new(1337).unwrap(),
],

TopicAliasMaximum as 0x22 =>
parse with parse_u16 as u16;
Expand All @@ -301,18 +307,21 @@ define_properties! {[
testvalues: [12, 14, 42, 1337],

MaximumQoS as 0x24 =>
parse with winnow::binary::u8 as u8;
write with write_u8;
parse with crate::v5::qos::parse_maximum_quality_of_service as crate::v5::qos::MaximumQualityOfService;
write with crate::v5::qos::write_maximum_quality_of_service;
with size |_| 1;
testfnname: test_roundtrip_maximumqos;
testvalues: [12, 14, 42, 137],
testvalues: [
crate::v5::qos::MaximumQualityOfService::AtMostOnce,
crate::v5::qos::MaximumQualityOfService::AtLeastOnce,
],

RetainAvailable as 0x25 =>
parse with winnow::binary::u8 as u8;
write with write_u8;
parse with crate::v5::boolean::parse_bool as bool;
write with crate::v5::boolean::write_bool;
with size |_| 1;
testfnname: test_roundtrip_retainavailable;
testvalues: [12, 14, 42, 137],
testvalues: [true, false],

MaximumPacketSize as 0x27 =>
parse with parse_u32 as u32;
Expand Down
2 changes: 1 addition & 1 deletion src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub struct MqttWill {
properties: crate::packets::connect::ConnectWillProperties,
topic: MqttString,
payload: MqttBytes,
qos: mqtt_format::v5::fixed_header::QualityOfService,
qos: mqtt_format::v5::qos::QualityOfService,
retain: bool,
}

Expand Down
6 changes: 3 additions & 3 deletions src/packets/connack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ crate::properties::define_properties! {
session_expiry_interval: SessionExpiryInterval with setter = u32,

(anker: "_Toc3901083")
receive_maximum: ReceiveMaximum with setter = u16,
receive_maximum: ReceiveMaximum with setter = core::num::NonZeroU16,

(anker: "_Toc3901084")
maximum_qos: MaximumQoS with setter = u8,
maximum_qos: MaximumQoS with setter = mqtt_format::v5::qos::MaximumQualityOfService,

(anker: "_Toc3901085")
retain_available: RetainAvailable with setter = u8,
retain_available: RetainAvailable with setter = bool,

(anker: "_Toc3901086")
maximum_packet_size: MaximumPacketSize with setter = u32,
Expand Down
2 changes: 1 addition & 1 deletion src/packets/connect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ crate::properties::define_properties! {
session_expiry_interval: SessionExpiryInterval with setter = u32,

(anker: "_Toc3901049")
receive_maximum: ReceiveMaximum with setter = u16,
receive_maximum: ReceiveMaximum with setter = core::num::NonZeroU16,

(anker: "_Toc3901050")
maximum_packet_size: MaximumPacketSize with setter = u32,
Expand Down
Loading

0 comments on commit feba470

Please sign in to comment.