Skip to main content

orbit_core/fleet/
name.rs

1use std::fmt;
2use std::ops::Deref;
3use std::str::FromStr;
4use std::sync::Arc;
5
6/// Same-host fleet namespace, distinct from a process or application name.
7///
8/// One to eight ASCII letters, digits, hyphens or underscores, stored inline.
9#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub struct FleetName {
11    bytes: [u8; 8],
12    len: u8,
13}
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16pub struct InvalidFleetName;
17
18impl fmt::Display for InvalidFleetName {
19    fn fmt(
20        &self,
21        f: &mut fmt::Formatter<'_>,
22    ) -> fmt::Result {
23        f.write_str(
24            "fleet name must contain 1–8 ASCII letters, digits, '-' or '_'",
25        )
26    }
27}
28
29impl std::error::Error for InvalidFleetName {}
30
31impl FleetName {
32    /// Namespace API contract, independent of platform-specific SHM limits.
33    pub const MAX_LEN: usize = 8;
34
35    pub fn new(name: impl AsRef<str>) -> Self {
36        Self::try_new(name).expect("invalid fleet name")
37    }
38
39    pub fn try_new(name: impl AsRef<str>) -> Result<Self, InvalidFleetName> {
40        let name = name.as_ref();
41        if name.is_empty()
42            || name.len() > Self::MAX_LEN
43            || !name
44                .bytes()
45                .all(|b| b.is_ascii_alphanumeric() || b == b'-' || b == b'_')
46        {
47            return Err(InvalidFleetName);
48        }
49        let mut bytes = [0; 8];
50        bytes[..name.len()].copy_from_slice(name.as_bytes());
51        Ok(Self { bytes, len: name.len() as u8 })
52    }
53
54    pub fn as_str(&self) -> &str {
55        std::str::from_utf8(&self.bytes[..usize::from(self.len)])
56            .expect("fleet name contains validated ASCII")
57    }
58}
59
60impl FromStr for FleetName {
61    type Err = InvalidFleetName;
62
63    fn from_str(name: &str) -> Result<Self, Self::Err> {
64        Self::try_new(name)
65    }
66}
67
68impl From<&str> for FleetName {
69    fn from(name: &str) -> Self {
70        Self::new(name)
71    }
72}
73
74impl From<String> for FleetName {
75    fn from(name: String) -> Self {
76        Self::new(name)
77    }
78}
79
80impl From<Arc<str>> for FleetName {
81    fn from(name: Arc<str>) -> Self {
82        Self::new(name)
83    }
84}
85
86impl From<FleetName> for Arc<str> {
87    fn from(name: FleetName) -> Self {
88        Arc::from(name.as_str())
89    }
90}
91
92impl From<FleetName> for String {
93    fn from(name: FleetName) -> Self {
94        name.as_str().to_owned()
95    }
96}
97
98impl AsRef<str> for FleetName {
99    fn as_ref(&self) -> &str {
100        self.as_str()
101    }
102}
103
104impl Deref for FleetName {
105    type Target = str;
106
107    fn deref(&self) -> &str {
108        self.as_str()
109    }
110}
111
112impl fmt::Display for FleetName {
113    fn fmt(
114        &self,
115        f: &mut fmt::Formatter<'_>,
116    ) -> fmt::Result {
117        f.write_str(self.as_str())
118    }
119}