Skip to main content

twine_codec/dataset/
network_name.rs

1// Copyright (c) 2025 Jake Swensen
2// SPDX-License-Identifier: MPL-2.0
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8use core::str::FromStr;
9
10use twine_rs_macros::Tlv;
11use twine_tlv::prelude::*;
12
13use crate::error::TwineCodecError;
14
15const NETWORK_NAME_MAX_SIZE: usize = 16;
16
17/// A human readable UTF-8 string to identify the Thread network.
18#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Tlv)]
19#[tlv(tlv_type = 0x03, derive_inner)]
20pub struct NetworkName([u8; NETWORK_NAME_MAX_SIZE + 1]);
21
22impl TlvLength for NetworkName {
23    fn tlv_len(&self) -> usize {
24        self.0
25            .iter()
26            .position(|b| *b == 0)
27            .unwrap_or(NETWORK_NAME_MAX_SIZE)
28    }
29}
30
31impl core::fmt::Display for NetworkName {
32    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
33        let mut length = 0;
34
35        for byte in self.0.iter() {
36            if *byte == 0 {
37                break;
38            }
39            length += 1;
40        }
41
42        let s = core::str::from_utf8(&self.0[..length]).map_err(|_| core::fmt::Error)?;
43        write!(f, "{}", s)
44    }
45}
46
47impl FromStr for NetworkName {
48    type Err = TwineCodecError;
49
50    fn from_str(s: &str) -> Result<Self, Self::Err> {
51        let raw = s.as_bytes();
52        let length = raw.len();
53
54        if length > NETWORK_NAME_MAX_SIZE {
55            return Err(TwineCodecError::BufferMaxLength(
56                NETWORK_NAME_MAX_SIZE,
57                length,
58            ));
59        }
60
61        let mut n = [0_u8; NETWORK_NAME_MAX_SIZE + 1];
62        raw.iter().enumerate().for_each(|(i, byte)| {
63            n[i] = *byte;
64        });
65
66        Ok(Self(n))
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use alloc::format;
73
74    use super::*;
75
76    const EXPECTED_NAME_STR: &str = "TestNetwork";
77
78    #[test]
79    fn success_display_network_name() {
80        let network_name = NetworkName::from_str(EXPECTED_NAME_STR).unwrap();
81        let name_str = format!("{}", network_name);
82        assert_eq!(name_str, EXPECTED_NAME_STR);
83    }
84
85    #[test]
86    fn success_tlv_len() {
87        let network_name = NetworkName::from_str(EXPECTED_NAME_STR).unwrap();
88        assert_eq!(network_name.tlv_len(), EXPECTED_NAME_STR.len());
89    }
90
91    #[test]
92    fn success_from_str() {
93        let network_name = NetworkName::from_str(EXPECTED_NAME_STR).unwrap();
94        let name_str = format!("{}", network_name);
95        assert_eq!(name_str, EXPECTED_NAME_STR);
96    }
97}