kaon/common/
immutable_string.rs1use std::{
2 fmt::{self, Display},
3 ops::{Add, AddAssign, Deref},
4 rc::Rc,
5};
6
7use super::Named;
8
9#[derive(Debug, Clone, Default, Hash, PartialOrd, Ord, Eq)]
36pub struct ImmutableString(Rc<String>);
37
38impl ImmutableString {
39 pub fn new() -> Self {
41 Self(Rc::new(String::new()))
42 }
43
44 pub fn is_empty(&self) -> bool {
46 self.0.is_empty()
47 }
48
49 pub fn length(&self) -> usize {
51 self.0.len()
52 }
53
54 pub fn make_mut(&mut self) -> &mut String {
56 Rc::make_mut(&mut self.0)
57 }
58
59 pub fn into_owned(mut self) -> String {
63 self.make_mut();
64
65 Rc::try_unwrap(self.0).unwrap_or_else(|v| v.as_ref().to_string())
66 }
67}
68
69impl From<String> for ImmutableString {
70 fn from(str: String) -> Self {
71 Self(Rc::new(str))
72 }
73}
74
75impl From<&String> for ImmutableString {
76 fn from(str: &String) -> Self {
77 Self(Rc::new(str.to_string()))
78 }
79}
80
81impl From<&str> for ImmutableString {
82 fn from(str: &str) -> Self {
83 Self(Rc::new(str.to_string()))
84 }
85}
86
87impl From<&mut str> for ImmutableString {
88 fn from(str: &mut str) -> Self {
89 Self(Rc::new(str.to_string()))
90 }
91}
92
93impl From<Box<str>> for ImmutableString {
94 fn from(str: Box<str>) -> Self {
95 Self(Rc::new(str.to_string()))
96 }
97}
98
99impl Add<&str> for ImmutableString {
100 type Output = Self;
101
102 fn add(mut self, rhs: &str) -> Self::Output {
103 if rhs.is_empty() {
104 self
105 } else if self.is_empty() {
106 Self::from(rhs)
107 } else {
108 self.make_mut().push_str(rhs);
109
110 self
111 }
112 }
113}
114
115impl Add<&ImmutableString> for ImmutableString {
116 type Output = Self;
117
118 fn add(mut self, rhs: &ImmutableString) -> Self::Output {
119 if rhs.is_empty() {
120 self
121 } else if self.is_empty() {
122 rhs.clone()
123 } else {
124 self.make_mut().push_str(rhs.0.as_str());
125
126 self
127 }
128 }
129}
130
131impl Add<ImmutableString> for ImmutableString {
132 type Output = Self;
133
134 fn add(mut self, rhs: Self) -> Self::Output {
135 if rhs.is_empty() {
136 self
137 } else if self.is_empty() {
138 rhs
139 } else {
140 self.make_mut().push_str(rhs.0.as_str());
141
142 self
143 }
144 }
145}
146
147impl AddAssign<&str> for ImmutableString {
148 fn add_assign(&mut self, rhs: &str) {
149 self.make_mut().push_str(rhs);
150 }
151}
152
153impl AddAssign<&ImmutableString> for ImmutableString {
154 fn add_assign(&mut self, rhs: &ImmutableString) {
155 self.make_mut().push_str(rhs);
156 }
157}
158
159impl PartialEq for ImmutableString {
160 fn eq(&self, other: &Self) -> bool {
161 self.0.len() == other.0.len() && self.0 == other.0
162 }
163}
164
165impl Deref for ImmutableString {
166 type Target = String;
167
168 fn deref(&self) -> &Self::Target {
169 self.0.as_ref()
170 }
171}
172
173impl Display for ImmutableString {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 f.write_fmt(format_args!("{}", self.0))
176 }
177}
178
179impl Named for ImmutableString {
180 const NAME: &'static str = "String";
181}
182
183#[cfg(test)]
184mod test {
185 use super::*;
186
187 #[test]
188 fn test_add() {
189 let str = ImmutableString::from("Hello, ");
190
191 assert_eq!(str + "World!", ImmutableString::from("Hello, World!"));
192 }
193
194 #[test]
195 fn test_add_assign() {
196 let mut str = ImmutableString::from("ab");
197 str += "c";
198
199 assert_eq!(*str, "abc");
200 }
201
202 #[test]
203 fn test_deref() {
204 let str = ImmutableString::from("Hello");
205
206 assert_eq!(*str, "Hello");
207 }
208
209 #[test]
210 fn test_immutable_str() {
211 let s1: ImmutableString = "Hello, World".into();
212
213 let s2 = s1.clone();
215 let s3 = s1.clone();
216
217 assert_eq!(s1, s2);
218
219 let mut s: String = s1.into_owned();
220
221 s.push_str("!");
222
223 assert_eq!(s3, s2);
224
225 assert_eq!(s, "Hello, World!");
226 }
227}