1use std::borrow::{Borrow, Cow};
7use std::fmt::{Debug, Display, Formatter};
8use std::ops::Deref;
9
10#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
11pub struct Name(compact_str::CompactString);
12
13impl Name {
14 #[inline]
15 pub fn new(name: impl AsRef<str>) -> Self {
16 Self(compact_str::CompactString::new(name))
17 }
18
19 #[inline]
20 pub const fn new_static(name: &'static str) -> Self {
21 Self(compact_str::CompactString::const_new(name))
22 }
23
24 #[inline]
25 pub fn as_str(&self) -> &str {
26 self.0.as_str()
27 }
28}
29
30impl Debug for Name {
31 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
32 write!(f, "Name({:?})", self.as_str())
33 }
34}
35
36impl Display for Name {
37 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
38 f.write_str(self.as_str())
39 }
40}
41
42impl AsRef<str> for Name {
43 #[inline]
44 fn as_ref(&self) -> &str {
45 self.as_str()
46 }
47}
48
49impl Deref for Name {
50 type Target = str;
51
52 #[inline]
53 fn deref(&self) -> &Self::Target {
54 self.as_str()
55 }
56}
57
58impl Borrow<str> for Name {
59 #[inline]
60 fn borrow(&self) -> &str {
61 self.as_str()
62 }
63}
64
65impl From<&str> for Name {
66 #[inline]
67 fn from(value: &str) -> Self {
68 Self(value.into())
69 }
70}
71
72impl From<String> for Name {
73 #[inline]
74 fn from(value: String) -> Self {
75 Self(value.into())
76 }
77}
78
79impl From<&String> for Name {
80 #[inline]
81 fn from(value: &String) -> Self {
82 Self(value.into())
83 }
84}
85
86impl From<Box<str>> for Name {
87 #[inline]
88 fn from(value: Box<str>) -> Self {
89 Self(value.into())
90 }
91}
92
93impl From<Cow<'_, str>> for Name {
94 #[inline]
95 fn from(value: Cow<'_, str>) -> Self {
96 Self(value.into())
97 }
98}
99
100impl PartialEq<str> for Name {
101 #[inline]
102 fn eq(&self, other: &str) -> bool {
103 self.as_str() == other
104 }
105}
106
107impl PartialEq<Name> for str {
108 #[inline]
109 fn eq(&self, other: &Name) -> bool {
110 other == self
111 }
112}
113
114impl PartialEq<&str> for Name {
115 #[inline]
116 fn eq(&self, other: &&str) -> bool {
117 self.as_str() == *other
118 }
119}
120
121impl PartialEq<Name> for &str {
122 #[inline]
123 fn eq(&self, other: &Name) -> bool {
124 other == self
125 }
126}
127
128impl PartialEq<String> for Name {
129 #[inline]
130 fn eq(&self, other: &String) -> bool {
131 self.as_str() == other
132 }
133}
134
135impl PartialEq<Name> for String {
136 #[inline]
137 fn eq(&self, other: &Name) -> bool {
138 other == self
139 }
140}
141
142impl PartialEq<&String> for Name {
143 #[inline]
144 fn eq(&self, other: &&String) -> bool {
145 self.as_str() == *other
146 }
147}
148
149impl PartialEq<Name> for &String {
150 #[inline]
151 fn eq(&self, other: &Name) -> bool {
152 other == self
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::Name;
159 use std::collections::hash_map::DefaultHasher;
160 use std::hash::{Hash, Hasher};
161
162 #[test]
163 fn new_and_new_static_match() {
164 let dynamic = Name::new("alpha");
165 let static_name = Name::new_static("alpha");
166 assert_eq!(dynamic, static_name);
167 assert_eq!(dynamic.as_str(), "alpha");
168 }
169
170 #[test]
171 fn compares_against_str_and_string() {
172 let name = Name::new("HOME");
173 let string = String::from("HOME");
174
175 assert_eq!(name, "HOME");
176 assert_eq!("HOME", name);
177 assert_eq!(name, string);
178 assert_eq!(string, name);
179 }
180
181 #[test]
182 fn display_and_debug_are_stable() {
183 let name = Name::new("select_var");
184 assert_eq!(format!("{name}"), "select_var");
185 assert_eq!(format!("{name:?}"), "Name(\"select_var\")");
186 }
187
188 #[test]
189 fn ordering_and_hash_follow_string_contents() {
190 let smaller = Name::new("a");
191 let larger = Name::new("b");
192 assert!(smaller < larger);
193
194 let mut left = DefaultHasher::new();
195 smaller.hash(&mut left);
196 let mut right = DefaultHasher::new();
197 Name::new("a").hash(&mut right);
198 assert_eq!(left.finish(), right.finish());
199 }
200
201 #[test]
202 fn supports_short_and_long_inputs() {
203 let short = Name::new("fd");
204 let long = Name::new("this_identifier_is_long_enough_to_spill_past_inline_storage");
205
206 assert_eq!(short.as_str(), "fd");
207 assert_eq!(
208 long.as_str(),
209 "this_identifier_is_long_enough_to_spill_past_inline_storage"
210 );
211 }
212}