kb/
rcstr.rs

1use std::borrow;
2use std::cell::Ref;
3use std::cell::RefCell;
4use std::cmp;
5use std::fmt;
6use std::hash;
7use std::ops;
8use std::rc::Rc;
9
10/// str smarat pointer that also stashes chars as
11/// needed so that char access can be constant time
12#[derive(Clone)]
13pub struct RcStr(Rc<Str>);
14
15pub struct Str {
16    string: String,
17    chars: RefCell<Option<Chars>>,
18}
19
20enum Chars {
21    ASCII,
22    Chars(Vec<char>),
23}
24
25impl RcStr {
26    fn new(s: String) -> Self {
27        s.into()
28    }
29    unsafe fn new_ascii(string: String) -> Self {
30        Self(Rc::new(Str {
31            string,
32            chars: RefCell::new(Some(Chars::ASCII)),
33        }))
34    }
35    pub fn len(&self) -> usize {
36        self.0.string.len()
37    }
38    fn chars(&self) -> Ref<Chars> {
39        if self.0.chars.borrow().is_none() {
40            let mut opt_chars = self.0.chars.borrow_mut();
41            *opt_chars = Some(if self.0.string.is_ascii() {
42                Chars::ASCII
43            } else {
44                Chars::Chars(self.0.string.chars().collect())
45            });
46        }
47        Ref::map(self.0.chars.borrow(), |chars| chars.as_ref().unwrap())
48    }
49    pub fn charlen(&self) -> usize {
50        let chars = self.chars();
51        let chars: &Chars = &chars;
52        match chars {
53            Chars::ASCII => self.len(),
54            Chars::Chars(chars) => chars.len(),
55        }
56    }
57    pub fn charslice(&self, start: usize, end: usize) -> RcStr {
58        let chars = self.chars();
59        let chars: &Chars = &chars;
60        match chars {
61            Chars::ASCII => unsafe { Self::new_ascii(self.0.string[start..end].to_owned()) },
62            Chars::Chars(chars) => Self::new(chars[start..end].iter().collect()),
63        }
64    }
65    pub fn getchar(&self, index: usize) -> Option<char> {
66        let chars = self.chars();
67        let chars: &Chars = &chars;
68        match chars {
69            Chars::ASCII => self.0.string.as_bytes().get(index).map(|c| *c as char),
70            Chars::Chars(chars) => chars.get(index).cloned(),
71        }
72    }
73}
74
75impl fmt::Debug for RcStr {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        write!(f, "{:?}", self.0.string)
78    }
79}
80
81impl fmt::Display for RcStr {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        write!(f, "{}", self.0.string)
84    }
85}
86
87impl borrow::Borrow<str> for RcStr {
88    fn borrow(&self) -> &str {
89        self.0.string.borrow()
90    }
91}
92
93impl ops::Deref for RcStr {
94    type Target = str;
95
96    fn deref(&self) -> &str {
97        self.0.string.deref()
98    }
99}
100
101impl AsRef<str> for RcStr {
102    fn as_ref(&self) -> &str {
103        self.0.string.as_ref()
104    }
105}
106
107impl cmp::PartialOrd for RcStr {
108    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
109        self.0.string.partial_cmp(&other.0.string)
110    }
111}
112
113impl cmp::Ord for RcStr {
114    fn cmp(&self, other: &Self) -> cmp::Ordering {
115        self.0.string.cmp(&other.0.string)
116    }
117}
118
119impl cmp::PartialEq for RcStr {
120    fn eq(&self, other: &Self) -> bool {
121        self.0.string.eq(&other.0.string)
122    }
123}
124
125impl cmp::Eq for RcStr {}
126
127impl hash::Hash for RcStr {
128    fn hash<H: hash::Hasher>(&self, state: &mut H) {
129        self.0.string.hash(state)
130    }
131}
132
133impl ops::Index<ops::Range<usize>> for RcStr {
134    type Output = str;
135    fn index(&self, index: ops::Range<usize>) -> &str {
136        self.0.string.index(index)
137    }
138}
139
140impl ops::Index<ops::RangeTo<usize>> for RcStr {
141    type Output = str;
142    fn index(&self, index: ops::RangeTo<usize>) -> &str {
143        self.0.string.index(index)
144    }
145}
146
147impl ops::Index<ops::RangeFrom<usize>> for RcStr {
148    type Output = str;
149    fn index(&self, index: ops::RangeFrom<usize>) -> &str {
150        self.0.string.index(index)
151    }
152}
153
154impl ops::Index<ops::RangeFull> for RcStr {
155    type Output = str;
156    fn index(&self, index: ops::RangeFull) -> &str {
157        self.0.string.index(index)
158    }
159}
160
161impl From<String> for RcStr {
162    fn from(string: String) -> Self {
163        Self(Rc::new(Str {
164            string,
165            chars: RefCell::new(None),
166        }))
167    }
168}
169
170impl From<&String> for RcStr {
171    fn from(string: &String) -> Self {
172        string.clone().into()
173    }
174}
175
176impl From<&str> for RcStr {
177    fn from(s: &str) -> Self {
178        s.to_owned().into()
179    }
180}