aws_iot_device_sdk_embedded_rust/
common.rs1pub const MQTT_TOPIC_LENGTH_MAX: usize = 65535;
3
4pub const THINGNAME_MAX_LENGTH: usize = 128;
5pub const SHADOW_NAME_LENGTH_MAX: usize = 64;
6pub const JOBID_MAX_LENGTH: usize = 64;
7
8pub const TUNNEL_TOPIC_MAX_LENGTH: usize = THINGNAME_MAX_LENGTH + 32;
9pub const DEFENDER_TOPIC_MAX_LENGTH: usize = THINGNAME_MAX_LENGTH + 32;
10pub const JOBS_TOPIC_MAX_LENGTH: usize = THINGNAME_MAX_LENGTH + JOBID_MAX_LENGTH + 32;
11pub const SHADOW_TOPIC_MAX_LENGTH: usize = THINGNAME_MAX_LENGTH + SHADOW_NAME_LENGTH_MAX + 32;
12
13pub const AWS_THINGS_PREFIX: &str = "$aws/things/";
14
15pub const SUFFIX_ACCEPTED: &str = "/accepted";
16pub const SUFFIX_REJECTED: &str = "/rejected";
17
18pub const ACCEPTED: &str = "accepted";
19pub const REJECTED: &str = "rejected";
20
21#[derive(Debug, PartialEq, Clone)]
22pub enum Error {
23 FAIL, MqttTopicFailed, ThingnameParseFailed, MessageTypeParseFailed, RootParseFailed, ShadownameParseFailed, JobsIdParseFailed, NoMatch, }
32
33fn is_valid_param(s: &str, max_len: usize) -> Result<(), Error> {
39 if !s.is_empty() && s.len() < max_len {
40 return Ok(());
41 }
42 Err(Error::FAIL)
43}
44
45pub fn is_valid_mqtt_topic(mqtt_topic: &str) -> Result<(), Error> {
51 is_valid_param(mqtt_topic, MQTT_TOPIC_LENGTH_MAX).map_err(|_| Error::MqttTopicFailed)
52}
53
54pub fn is_valid_prefix<'a>(s: &'a str, pre: &str) -> Result<&'a str, Error> {
60 s.strip_prefix(pre).ok_or(Error::NoMatch)
61}
62
63fn is_valid_name(name: &str, len: usize) -> Result<(), Error> {
69 is_valid_param(name, len)?;
70 for a in name.chars() {
71 match a {
72 '-' | '_' | '0'..='9' | 'A'..='Z' | 'a'..='z' | ':' => continue,
73 _ => return Err(Error::FAIL),
74 }
75 }
76 Ok(())
77}
78
79pub fn is_valid_thing_name(thing_name: &str) -> Result<(), Error> {
85 is_valid_name(thing_name, THINGNAME_MAX_LENGTH).map_err(|_| Error::ThingnameParseFailed)
86}
87
88pub fn is_valid_shadow_name(shadow_name: &str) -> Result<(), Error> {
94 is_valid_name(shadow_name, SHADOW_NAME_LENGTH_MAX).map_err(|_| Error::ShadownameParseFailed)
95}
96
97pub fn is_valid_bridge<'a>(s: &'a str, bridge: &str) -> Result<&'a str, Error> {
104 s.strip_prefix(bridge).ok_or(Error::RootParseFailed)
105}
106
107pub fn is_valid_job_id(job_id: &str) -> Result<(), Error> {
113 is_valid_param(job_id, JOBID_MAX_LENGTH)?;
115 for a in job_id.chars() {
116 match a {
117 '-' | '_' | '0'..='9' | 'A'..='Z' | 'a'..='z' => continue,
118 _ => return Err(Error::JobsIdParseFailed),
119 }
120 }
121 Ok(())
122}
123#[cfg(test)]
124mod tests {
125 use crate::common::*;
126 #[test]
127 fn valid_mqtt_topic() -> Result<(), Error> {
128 is_valid_mqtt_topic("hello/world")?;
129 Ok(())
130 }
131 #[test]
132 fn valid_prefix() -> Result<(), Error> {
133 is_valid_prefix("hello/world", "hello/")?;
134 Ok(())
135 }
136 #[test]
137 fn valid_thing_name() -> Result<(), Error> {
138 is_valid_thing_name("-_09AZaz:")?;
139 Ok(())
140 }
141 #[test]
142 fn valid_shadow_name() -> Result<(), Error> {
143 is_valid_shadow_name("common")?;
144 Ok(())
145 }
146 #[test]
147 fn valid_job_id() -> Result<(), Error> {
148 is_valid_job_id("_-09AZaz")?;
149 Ok(())
150 }
151}