1use crate::error::CoreError as Error;
13use core::{fmt::Display, str::FromStr};
14use serde::{Deserialize, Serialize};
15
16#[macro_export]
21macro_rules! name_fn {
22 ($vis:vis $fn_name:ident => $name:literal) => {
23 #[inline(always)]
24 $vis fn $fn_name() -> $crate::id::Name {
25 $crate::id::Name::new_unchecked($name)
26 }
27 };
28}
29#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
34pub struct Name(String);
35
36pub const RFHAM_URN_PREFIX: &str = "urn:rfham:";
37
38name_fn!(pub brand_name_baofeng => "baofeng");
43name_fn!(pub brand_name_chameleon => "chameleon");
44name_fn!(pub brand_name_elecraft => "elecraft");
45name_fn!(pub brand_name_gabil => "gabil");
46name_fn!(pub brand_name_icom => "icom");
47name_fn!(pub brand_name_kenwood => "kenwood");
48name_fn!(pub brand_name_yaesu => "yaesu");
49
50impl Display for Name {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 write!(f, "{}", self.0)
57 }
58}
59
60impl From<Name> for String {
61 fn from(value: Name) -> Self {
62 value.0
63 }
64}
65
66impl AsRef<str> for Name {
67 fn as_ref(&self) -> &str {
68 self.0.as_ref()
69 }
70}
71
72impl FromStr for Name {
73 type Err = Error;
74
75 fn from_str(s: &str) -> Result<Self, Self::Err> {
76 if Self::is_valid(s) {
77 Ok(Self(s.to_ascii_lowercase()))
78 } else {
79 Err(Error::InvalidValueFromStr(s.to_string(), "Name"))
80 }
81 }
82}
83
84impl Name {
85 pub fn new_unchecked<S: Into<String>>(name: S) -> Self {
86 Self(name.into())
87 }
88
89 pub const fn as_str(&self) -> &str {
90 self.0.as_str()
91 }
92
93 pub fn is_valid(s: &str) -> bool {
94 let mut chars = s.chars();
95 !s.is_empty()
96 && chars.next().unwrap().is_ascii_alphabetic()
97 && chars.all(|c| c.is_ascii_alphanumeric() || ['-', '_'].contains(&c))
98 }
99}