1use crate::keys::*;
2use crate::parser::*;
3
4#[cfg(feature = "with-to-string")]
5pub extern crate std;
6
7pub use hex::FromHexError;
8
9macro_rules! fixed_len_struct_impl_to_string_msb {
10 (
11 $type:ident,$size:expr;
12 ) => {
13 impl core::str::FromStr for $type {
14 type Err = FromHexError;
15
16 fn from_str(s: &str) -> Result<Self, Self::Err> {
17 let mut res = [0; $size];
18 hex::decode_to_slice(s.as_bytes(), &mut res)?;
19 Ok(Self::from(res))
20 }
21 }
22
23 #[cfg(feature = "with-to-string")]
24 impl core::fmt::Display for $type {
25 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
26 let mut res = std::string::String::with_capacity($size * 2);
27 res.extend(std::iter::repeat('-').take($size * 2));
28 let slice = unsafe { &mut res.as_bytes_mut() };
29 hex::encode_to_slice(self.as_ref(), slice).unwrap();
30 write!(f, "{}", res)
31 }
32 }
33 };
34 (
35 $type:ident[$size:expr];
36 ) => {
37 impl core::str::FromStr for $type<[u8; $size]> {
38 type Err = FromHexError;
39
40 fn from_str(s: &str) -> Result<Self, Self::Err> {
41 let mut res = [0; $size];
42 hex::decode_to_slice(s.as_bytes(), &mut res)?;
43 Ok(Self::from(res))
44 }
45 }
46
47 #[cfg(feature = "with-to-string")]
48 impl<T: AsRef<[u8]>> core::fmt::Display for $type<T> {
49 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
50 let mut res = std::string::String::with_capacity($size * 2);
52 res.extend(std::iter::repeat('-').take($size * 2));
53
54 let slice = unsafe { &mut res.as_bytes_mut() };
56 hex::encode_to_slice(self.as_ref(), slice).unwrap();
57 write!(f, "{}", res)
58 }
59 }
60 };
61}
62
63macro_rules! fixed_len_struct_impl_string_lsb {
64 (
65 $type:ident,$size:expr;
66 ) => {
67 impl core::str::FromStr for $type {
68 type Err = FromHexError;
69
70 fn from_str(s: &str) -> Result<Self, Self::Err> {
71 let mut res = [0; $size];
72 hex::decode_to_slice(s.as_bytes(), &mut res)?;
73 res.reverse();
74 Ok(Self::from(res))
75 }
76 }
77
78 #[cfg(feature = "with-to-string")]
79 impl core::fmt::Display for $type {
80 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
81 let mut res = std::string::String::with_capacity($size * 2);
82 res.extend(std::iter::repeat('0').take($size * 2));
83 let slice = unsafe { &mut res.as_bytes_mut() };
84 self.as_ref().iter().rev().enumerate().for_each(|(i, b)| {
85 hex::encode_to_slice(&[*b], &mut slice[i * 2..i * 2 + 2]).unwrap();
86 });
87 write!(f, "{}", res)
88 }
89 }
90 };
91}
92
93fixed_len_struct_impl_to_string_msb! {
94 EUI64[8];
95}
96
97fixed_len_struct_impl_to_string_msb! {
98 DevNonce[2];
99}
100
101fixed_len_struct_impl_to_string_msb! {
102 AppNonce[3];
103}
104
105fixed_len_struct_impl_to_string_msb! {
106 DevAddr[4];
107}
108
109fixed_len_struct_impl_to_string_msb! {
110 NwkAddr[3];
111}
112
113fixed_len_struct_impl_to_string_msb! {
114 AppKey, 16;
115}
116
117fixed_len_struct_impl_to_string_msb! {
118 NewSKey, 16;
119}
120
121fixed_len_struct_impl_to_string_msb! {
122 AppSKey, 16;
123}
124
125fixed_len_struct_impl_string_lsb! {
126 DevEui, 8;
127}
128
129fixed_len_struct_impl_string_lsb! {
130 AppEui, 8;
131}
132
133#[cfg(test)]
134mod test {
135 use super::*;
136 use crate::extra::std::string::ToString;
137 use core::str::FromStr;
138
139 #[test]
140 fn test_appskey_to_string() {
141 let appskey = AppSKey::from([
142 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfd, 0xb9, 0x75, 0x31, 0x24, 0x68,
143 0xac, 0xed,
144 ]);
145 assert_eq!(appskey.to_string(), "0123456789abcdeffdb975312468aced");
146 }
147
148 #[test]
149 fn test_appskey_from_str() {
150 let appskey = AppSKey::from_str("00112233445566778899aabbccddeeff").unwrap();
151 assert_eq!(
152 appskey,
153 AppSKey::from([
154 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD,
155 0xEE, 0xFF
156 ])
157 );
158 }
159
160 #[test]
161 fn test_deveui_to_string() {
162 let deveui = DevEui::from([0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12]);
163 assert_eq!(deveui.to_string(), "123456789abcdef0");
164 }
165
166 #[test]
167 fn test_deveui_from_str() {
168 let deveui = DevEui::from_str("123456789abcdef0").unwrap();
169 assert_eq!(deveui, DevEui::from([0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12]));
170 }
171
172 #[test]
173 fn test_deveui_from_small_str() {
174 let result = DevEui::from_str("123456789abcd");
175 assert_eq!(result, Err(FromHexError::OddLength));
176 }
177
178 #[test]
179 fn test_deveui_from_large_str() {
180 let result = DevEui::from_str("123456789abcdef000");
181 assert_eq!(result, Err(FromHexError::InvalidStringLength));
182 }
183}