objects/object/
identifiers.rs1use std::{fmt, hash::Hash};
12
13use serde::{Deserialize, Serialize};
14
15macro_rules! string_newtype {
16 ($(#[$meta:meta])* $name:ident) => {
17 $(#[$meta])*
18 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
19 #[serde(transparent)]
20 pub struct $name(pub String);
21
22 impl $name {
23 pub fn new(s: impl Into<String>) -> Self {
24 Self(s.into())
25 }
26
27 pub fn as_str(&self) -> &str {
28 &self.0
29 }
30
31 pub fn into_string(self) -> String {
32 self.0
33 }
34 }
35
36 impl fmt::Display for $name {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 f.write_str(&self.0)
39 }
40 }
41
42 impl AsRef<str> for $name {
43 fn as_ref(&self) -> &str {
44 &self.0
45 }
46 }
47
48 impl std::ops::Deref for $name {
49 type Target = str;
50 fn deref(&self) -> &str {
51 &self.0
52 }
53 }
54
55 impl From<String> for $name {
56 fn from(s: String) -> Self {
57 Self(s)
58 }
59 }
60
61 impl From<&str> for $name {
62 fn from(s: &str) -> Self {
63 Self(s.to_string())
64 }
65 }
66
67 impl From<$name> for String {
68 fn from(n: $name) -> String {
69 n.0
70 }
71 }
72
73 impl PartialEq<str> for $name {
74 fn eq(&self, other: &str) -> bool {
75 self.0 == other
76 }
77 }
78
79 impl PartialEq<&str> for $name {
80 fn eq(&self, other: &&str) -> bool {
81 self.0 == *other
82 }
83 }
84
85 impl PartialEq<String> for $name {
86 fn eq(&self, other: &String) -> bool {
87 self.0 == *other
88 }
89 }
90
91 impl std::borrow::Borrow<str> for $name {
92 fn borrow(&self) -> &str {
93 &self.0
94 }
95 }
96 };
97}
98
99string_newtype!(
100 ThreadName
102);
103
104string_newtype!(
105 MarkerName
107);
108
109string_newtype!(
110 Scope
112);
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn thread_name_display() {
120 let t = ThreadName::new("main");
121 assert_eq!(t.0, "main");
122 assert_eq!(t.0, "main");
123 assert_eq!(&*t, "main");
124 }
125
126 #[test]
127 fn serde_transparent_roundtrip() {
128 let t = ThreadName::new("feature/foo");
129 let json = serde_json::to_string(&t).unwrap();
130 assert_eq!(json, "\"feature/foo\"");
131 let back: ThreadName = serde_json::from_str(&json).unwrap();
132 assert_eq!(back, t);
133 }
134
135 #[test]
136 fn marker_name_distinct_from_thread_name() {
137 let _t: ThreadName = "main".into();
138 let _m: MarkerName = "v1.0".into();
139 }
141
142 #[test]
143 #[allow(clippy::cmp_owned)] fn comparison_with_str() {
145 let t = ThreadName::from("main");
146 assert!(t == "main");
147 assert!(t == *"main");
148 assert!(t == String::from("main"));
149 }
150
151 #[test]
152 fn borrow_for_hashmap_lookup() {
153 use std::collections::HashMap;
154 let mut map = HashMap::new();
155 map.insert(ThreadName::new("main"), 1);
156 assert_eq!(map.get("main"), Some(&1));
157 }
158}