Skip to main content

openthread/ot/types/
radio_region.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::prelude_internal::*;
6
7/// Represents a radio regulatory region/domain.
8///
9/// See [`crate::Radio::get_region()`] and [`crate::Radio::set_region()`].
10#[derive(Debug, Hash, Clone, Eq, Default, PartialEq, Copy)]
11pub struct RadioRegion(u16);
12
13impl RadioRegion {
14    /// Creates an instance of `RadioRegion` from an array of two bytes.
15    pub fn from_bytes(bytes: [u8; 2]) -> RadioRegion {
16        RadioRegion(((bytes[0] as u16) << 8) + bytes[1] as u16)
17    }
18
19    /// Returns the value of this `RadioRegion` as an array of two bytes.
20    pub fn bytes(&self) -> [u8; 2] {
21        [(self.0 >> 8) as u8, self.0 as u8]
22    }
23}
24
25impl From<u16> for RadioRegion {
26    fn from(x: u16) -> Self {
27        RadioRegion(x)
28    }
29}
30
31impl From<RadioRegion> for u16 {
32    fn from(x: RadioRegion) -> Self {
33        x.0
34    }
35}
36
37impl From<[u8; 2]> for RadioRegion {
38    fn from(x: [u8; 2]) -> Self {
39        RadioRegion::from_bytes(x)
40    }
41}
42
43impl From<RadioRegion> for [u8; 2] {
44    fn from(x: RadioRegion) -> Self {
45        x.bytes()
46    }
47}
48
49impl TryFrom<&str> for RadioRegion {
50    type Error = anyhow::Error;
51    fn try_from(region: &str) -> Result<Self, Self::Error> {
52        region.parse()
53    }
54}
55
56impl core::str::FromStr for RadioRegion {
57    type Err = anyhow::Error;
58
59    fn from_str(region: &str) -> Result<Self, Self::Err> {
60        if region.is_empty() {
61            return Ok(RadioRegion::default());
62        }
63        if region.len() == 2 {
64            #[allow(clippy::bytes_nth)]
65            let ret = RadioRegion::from_bytes([
66                region.bytes().nth(0).unwrap(),
67                region.bytes().nth(1).unwrap(),
68            ]);
69            return Ok(ret);
70        }
71        Err(anyhow::format_err!("Bad region string {:?}", region))
72    }
73}
74
75impl TryFrom<String> for RadioRegion {
76    type Error = anyhow::Error;
77    fn try_from(region: String) -> Result<Self, Self::Error> {
78        RadioRegion::try_from(region.as_str())
79    }
80}
81
82#[allow(clippy::to_string_trait_impl)]
83impl ToString for RadioRegion {
84    fn to_string(&self) -> String {
85        if self.0 == 0 {
86            return String::default();
87        }
88        core::str::from_utf8(&self.bytes()).unwrap_or("").to_string()
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    use assert_matches::assert_matches;
97
98    #[test]
99    fn test_region_code() {
100        assert_eq!(RadioRegion::from(0), RadioRegion::default());
101        assert_eq!(RadioRegion::from(0).to_string(), "".to_string());
102        assert_eq!(RadioRegion::from_bytes([0x34, 0x32]).to_string(), "42".to_string());
103        assert_eq!(RadioRegion::try_from("US").unwrap().to_string(), "US".to_string());
104        assert_eq!(RadioRegion::try_from("").unwrap(), RadioRegion::default());
105        assert_matches!(RadioRegion::try_from("1"), Err(_));
106        assert_matches!(RadioRegion::try_from("111"), Err(_));
107    }
108}