fundamentum_sdk_mqtt/
publish_options.rs

1use std::collections::HashMap;
2
3use rumqttc::v5::mqttbytes::QoS;
4
5/// Configuration options to publish data.
6#[derive(Default, Debug, Clone, PartialEq, Eq)]
7pub struct PublishOptions {
8    /// Quality field of services is an agreement between the message sender and
9    /// receiver that defines the level of delivery guarantee for a specific message.
10    pub qos: Option<QoS>,
11    /// Retain make the broker store the last message and each
12    /// client that subscribe will receive this last message immediately after
13    /// they subscribe.
14    pub retain: Option<bool>,
15    /// User-defined key-value pairs metadata to send with the MQTT message.
16    pub user_properties: Option<HashMap<String, String>>,
17    /// String that describes the content of the application message.
18    pub content_type: Option<String>,
19}
20
21/// Fully resolved configuration options to publish data.
22///
23/// See [`PublishOptions`] for the unresolved version of this type.
24#[cfg_attr(test, derive(Eq, PartialEq, Debug))]
25pub struct PublishOptionsResolved {
26    /// Quality field of services is an agreement between the message sender and
27    /// receiver that defines the level of delivery guarantee for a specific message.
28    pub qos: QoS,
29    /// Retain make the broker store the last message and each
30    /// client that subscribe will receive this last message immediately after
31    /// they subscribe.
32    pub retain: bool,
33    /// User-defined key-value pairs metadata to send with the MQTT message.
34    pub user_properties: HashMap<String, String>,
35    /// String that describes the content of the application message.
36    pub content_type: Option<String>,
37}
38
39impl PublishOptionsResolved {
40    /// Override the options of `self` from `other` if no options were initially
41    /// provided. (RHS wins)
42    #[must_use]
43    pub fn override_with(&self, other: &PublishOptions) -> Self {
44        Self {
45            qos: other.qos.unwrap_or(self.qos),
46            retain: other.retain.unwrap_or(self.retain),
47            user_properties: other.user_properties.as_ref().map_or_else(
48                || self.user_properties.clone(),
49                |other| {
50                    let mut merged = self.user_properties.clone();
51                    merged.extend(other.clone());
52                    merged
53                },
54            ),
55            content_type: other.content_type.clone(),
56        }
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn given_fallback_config_when_override_with_then_new_config() {
66        let fallback = PublishOptionsResolved {
67            qos: QoS::ExactlyOnce,
68            retain: false,
69            user_properties: HashMap::from([
70                ("key".to_owned(), "value".to_owned()),
71                ("hello".to_owned(), "world".to_owned()),
72            ]),
73            content_type: None,
74        };
75
76        let options = fallback.override_with(&PublishOptions {
77            qos: None,
78            retain: Some(true),
79            user_properties: Some(HashMap::from([
80                ("some".to_owned(), "header".to_owned()),
81                ("hello".to_owned(), "universe".to_owned()),
82            ])),
83            content_type: Some("application/json".to_owned()),
84        });
85
86        assert_eq!(
87            PublishOptionsResolved {
88                qos: QoS::ExactlyOnce,
89                retain: true,
90                user_properties: HashMap::from([
91                    ("key".to_owned(), "value".to_owned()),
92                    ("some".to_owned(), "header".to_owned()),
93                    ("hello".to_owned(), "universe".to_owned())
94                ]),
95                content_type: Some("application/json".to_owned()),
96            },
97            options
98        );
99    }
100}