1use crate::arena;
11use std::fmt;
12
13pub struct SeqString {
21 ptr: *const u8,
22 len: usize,
23 capacity: usize, global: bool,
25}
26
27impl PartialEq for SeqString {
29 fn eq(&self, other: &Self) -> bool {
30 self.as_str() == other.as_str()
31 }
32}
33
34impl Eq for SeqString {}
35
36unsafe impl Send for SeqString {}
41
42impl SeqString {
43 pub fn as_str(&self) -> &str {
48 unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(self.ptr, self.len)) }
49 }
50
51 #[allow(dead_code)]
53 pub fn is_global(&self) -> bool {
54 self.global
55 }
56
57 pub fn len(&self) -> usize {
59 self.len
60 }
61
62 #[allow(dead_code)]
64 pub fn is_empty(&self) -> bool {
65 self.len == 0
66 }
67}
68
69impl Clone for SeqString {
70 fn clone(&self) -> Self {
76 let s = self.as_str().to_string();
77 global_string(s)
78 }
79}
80
81impl Drop for SeqString {
82 fn drop(&mut self) {
83 if self.global {
84 unsafe {
88 let _s = String::from_raw_parts(
89 self.ptr as *mut u8,
90 self.len,
91 self.capacity, );
93 }
95 }
96 }
98}
99
100impl fmt::Debug for SeqString {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 write!(f, "SeqString({:?}, global={})", self.as_str(), self.global)
103 }
104}
105
106impl fmt::Display for SeqString {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 write!(f, "{}", self.as_str())
109 }
110}
111
112pub fn arena_string(s: &str) -> SeqString {
120 arena::with_arena(|arena| {
121 let arena_str = arena.alloc_str(s);
122 SeqString {
123 ptr: arena_str.as_ptr(),
124 len: arena_str.len(),
125 capacity: 0, global: false,
127 }
128 })
129}
130
131pub fn global_string(s: String) -> SeqString {
139 let len = s.len();
140 let capacity = s.capacity();
141 let ptr = s.as_ptr();
142 std::mem::forget(s); SeqString {
145 ptr,
146 len,
147 capacity, global: true,
149 }
150}
151
152impl From<&str> for SeqString {
154 fn from(s: &str) -> Self {
155 arena_string(s)
156 }
157}
158
159impl From<String> for SeqString {
161 fn from(s: String) -> Self {
162 global_string(s)
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn test_arena_string() {
172 let s = arena_string("Hello, arena!");
173 assert_eq!(s.as_str(), "Hello, arena!");
174 assert_eq!(s.len(), 13);
175 assert!(!s.is_global());
176 }
177
178 #[test]
179 fn test_global_string() {
180 let s = global_string("Hello, global!".to_string());
181 assert_eq!(s.as_str(), "Hello, global!");
182 assert_eq!(s.len(), 14);
183 assert!(s.is_global());
184 }
185
186 #[test]
187 fn test_clone_creates_global() {
188 let s1 = arena_string("test");
190 let s2 = s1.clone();
191
192 assert_eq!(s1.as_str(), s2.as_str());
193 assert!(!s1.is_global());
194 assert!(s2.is_global()); }
196
197 #[test]
198 fn test_clone_global() {
199 let s1 = global_string("test".to_string());
200 let s2 = s1.clone();
201
202 assert_eq!(s1.as_str(), s2.as_str());
203 assert!(s1.is_global());
204 assert!(s2.is_global());
205 }
206
207 #[test]
208 fn test_drop_global() {
209 {
211 let s = global_string("Will be dropped".to_string());
212 assert_eq!(s.as_str(), "Will be dropped");
213 }
214 }
216
217 #[test]
218 fn test_drop_arena() {
219 {
221 let s = arena_string("Will be dropped (no-op)");
222 assert_eq!(s.as_str(), "Will be dropped (no-op)");
223 }
224 }
226
227 #[test]
228 fn test_equality() {
229 let s1 = arena_string("test");
230 let s2 = arena_string("test");
231 let s3 = global_string("test".to_string());
232 let s4 = arena_string("different");
233
234 assert_eq!(s1, s2); assert_eq!(s1, s3); assert_ne!(s1, s4); }
238
239 #[test]
240 fn test_from_str() {
241 let s: SeqString = "test".into();
242 assert_eq!(s.as_str(), "test");
243 assert!(!s.is_global()); }
245
246 #[test]
247 fn test_from_string() {
248 let s: SeqString = "test".to_string().into();
249 assert_eq!(s.as_str(), "test");
250 assert!(s.is_global()); }
252
253 #[test]
254 fn test_debug_format() {
255 let s = arena_string("debug");
256 let debug_str = format!("{:?}", s);
257 assert!(debug_str.contains("debug"));
258 assert!(debug_str.contains("global=false"));
259 }
260
261 #[test]
262 fn test_display_format() {
263 let s = global_string("display".to_string());
264 let display_str = format!("{}", s);
265 assert_eq!(display_str, "display");
266 }
267
268 #[test]
269 fn test_empty_string() {
270 let s = arena_string("");
271 assert_eq!(s.len(), 0);
272 assert!(s.is_empty());
273 assert_eq!(s.as_str(), "");
274 }
275
276 #[test]
277 fn test_unicode() {
278 let s = arena_string("Hello, δΈη! π¦");
279 assert_eq!(s.as_str(), "Hello, δΈη! π¦");
280 assert!(s.len() > 10); }
282
283 #[test]
284 fn test_global_string_preserves_capacity() {
285 let mut s = String::with_capacity(100);
287 s.push_str("hi");
288
289 assert_eq!(s.len(), 2);
290 assert_eq!(s.capacity(), 100);
291
292 let cem = global_string(s);
293
294 assert_eq!(cem.len(), 2);
296 assert_eq!(cem.capacity, 100); assert_eq!(cem.as_str(), "hi");
298 assert!(cem.is_global());
299
300 drop(cem);
302
303 }
305
306 #[test]
307 fn test_arena_string_capacity_zero() {
308 let s = arena_string("test");
310 assert_eq!(s.capacity, 0); assert!(!s.is_global());
312 }
313}