base/
string.rs

1/// Represents a growable UTF-8 encoded string.
2pub struct String<A: Allocator = GlobalAllocator> {
3   buffer: Array<u8, A>,
4}
5
6impl<A: Allocator> String<A> {
7   /// Initialises an empty String with the specified allocator `A`
8   ///
9   /// ```
10   /// use base::alloc::GlobalAllocator;
11   /// use base::string::String;
12   ///
13   /// fn main() {
14   ///   let s = String::new_with(GlobalAllocator);
15   /// }
16   /// ```
17   pub fn new_with(alloc: A) -> Self {
18      Self {
19         buffer: Array::new_with(alloc),
20      }
21   }
22
23   /// Initialises a `String` from a given `&str` using the specified allocator, `A`.
24   ///
25   ///
26   /// ```
27   /// use base::alloc::GlobalAllocator;
28   /// use base::string::String;
29   ///
30   /// fn main()
31   /// {
32   ///   let s = String::from_str_with("hello!", GlobalAllocator);
33   /// }
34   /// ```
35   pub fn from_str_with(s: &str, alloc: A) -> Self {
36      let slice = s.as_bytes();
37      let mut buf = Array::new_with(alloc);
38      buf.resize(slice.len(), 0);
39
40      unsafe {
41         ptr::copy_nonoverlapping(s.as_ptr(), buf.as_mut_ptr(), slice.len());
42      }
43
44      return Self { buffer: buf };
45   }
46
47   /// Dereferences to the base `&str`.
48   #[inline]
49   pub fn as_str(&self) -> &str {
50      self
51   }
52
53   /// Pushes a Unicode character point to the current instance of `String`.
54   pub fn push(&mut self, c: char) {
55      let mut bytes = [0u8; 4];
56      c.encode_utf8(&mut bytes);
57      self.buffer.extend(bytes[0..c.len_utf8()].iter());
58   }
59}
60
61impl<A: Allocator> TryFrom<Array<u8, A>> for String<A> {
62   type Error = core::str::Utf8Error;
63
64   fn try_from(array: Array<u8, A>) -> Result<Self, Self::Error> {
65      str::from_utf8(&array)?;
66      Ok(Self { buffer: array })
67   }
68}
69
70impl String<GlobalAllocator> {
71   /// Initialises an empty `String`.
72   ///
73   ///
74   /// ```
75   /// use base::string::String;
76   ///
77   /// fn main()
78   /// {
79   ///   let s = String::new();
80   /// }
81   /// ```
82   pub fn new() -> Self {
83      Self::new_with(GlobalAllocator)
84   }
85
86   /// Initialises a `String` from a given `&str`.
87   ///
88   ///
89   /// ```
90   /// use base::string::String;
91   ///
92   /// fn main()
93   /// {
94   ///    let s = String::from("hello!");
95   /// }
96   /// ```
97   pub fn from(s: &str) -> Self {
98      Self::from_str_with(s, GlobalAllocator)
99   }
100}
101
102impl<A: Allocator> AsRef<str> for String<A> {
103   /// References the current `String` as a `&str`.
104   #[inline]
105   fn as_ref(&self) -> &str {
106      self
107   }
108}
109
110impl<A: Allocator> Borrow<str> for String<A> {
111   /// Borrows the current `String` as `&str`.
112   #[inline]
113   fn borrow(&self) -> &str {
114      self
115   }
116}
117
118impl<A: Allocator> Deref for String<A> {
119   type Target = str;
120
121   /// Dereferences the current `String` into a `&str`.
122   ///
123   ///
124   /// ```no_compile
125   /// use base::string::String;
126   ///
127   /// fn main()
128   /// {
129   ///    let s = String::from("hello!");
130   ///    let s = s.deref();
131   /// }
132   /// ```
133   #[inline]
134   fn deref(&self) -> &Self::Target {
135      unsafe { str::from_utf8_unchecked(&self.buffer) }
136   }
137}
138
139unsafe impl Send for String<GlobalAllocator> {}
140unsafe impl Sync for String<GlobalAllocator> {}
141
142impl<A: Allocator> DerefMut for String<A> {
143   /// Dereferences the current `String` into a mutable `&str`.
144   #[inline]
145   fn deref_mut(&mut self) -> &mut str {
146      unsafe { str::from_utf8_unchecked_mut(&mut self.buffer) }
147   }
148}
149
150impl<A: Allocator> fmt::Display for String<A> {
151   // allows println!() to work
152   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153      fmt::Display::fmt(self.as_str(), f)
154   }
155}
156
157impl<A: Allocator> fmt::Debug for String<A> {
158   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159      fmt::Display::fmt(self.as_str(), f)
160   }
161}
162
163impl<A, T> PartialEq<T> for String<A>
164where
165   A: Allocator,
166   T: AsRef<str>,
167{
168   #[inline]
169   fn eq(&self, other: &T) -> bool {
170      PartialEq::eq(self.as_str(), other.as_ref())
171   }
172}
173
174impl<A: Allocator> Eq for String<A> {}
175
176impl<A: Allocator> Hash for String<A> {
177   fn hash<H: Hasher>(&self, h: &mut H) {
178      Hash::hash(self.as_str(), h);
179   }
180}
181
182//------------------------------------------------------------
183//StringWide: A growable UTF-16 string.
184
185/// Represents a growable, UTF-16-encoded String.
186pub struct StringWide<A: Allocator = GlobalAllocator> {
187   buf: Array<u16, A>,
188}
189
190impl<A: Allocator> StringWide<A> {
191   /// Initialises an empty `StringWide` with the specified allocator, `A`.
192   ///
193   ///
194   /// ```no_run
195   /// use base::alloc::GlobalAllocator;
196   /// use base::string::StringWide;
197   ///
198   /// fn main() {
199   ///   let s = StringWide::new();
200   /// }
201   /// ```
202   pub fn new_with(alloc: A) -> Self {
203      Self {
204         buf: Array::new_with(alloc),
205      }
206   }
207
208   /// Initialises a `StringWide` from the given `&str` using the specified allocator, `A`.
209   ///
210   ///
211   /// ```no_run
212   /// use base::alloc::GlobalAllocator;
213   /// use base::string::StringWide;
214   ///
215   /// fn main()
216   /// {
217   ///   let s = StringWide::from_str_with("hello!", GlobalAllocator);
218   /// }
219   /// ```
220   pub fn from_str_with(s: &str, alloc: A) -> Self {
221      let w_iter = s.encode_utf16();
222
223      let mut buf = Array::new_with(alloc);
224      buf.reserve(w_iter.size_hint().0);
225
226      for wchar in w_iter {
227         buf.push(wchar);
228      }
229
230      Self { buf }
231   }
232
233   /// See `String::push`.
234   #[inline]
235   pub fn push(&mut self, c: char) {
236      let len = c.len_utf16();
237      self.buf.resize(self.buf.len() + len, 0);
238
239      let start = self.buf.len() - len;
240      c.encode_utf16(&mut self.buf[start..]);
241   }
242}
243
244impl StringWide<GlobalAllocator> {
245   /// Initialises an empty `StringWide`.
246   ///
247   ///
248   /// ```
249   /// use base::string::StringWide;
250   ///
251   /// fn main() {
252   ///   let s = StringWide::new();
253   /// }
254   /// ```
255   pub fn new() -> Self {
256      Self::new_with(GlobalAllocator)
257   }
258
259   /// Initialises a `StringWide` from the given `&str`.
260   ///
261   ///
262   /// ```
263   /// use base::string::StringWide;
264   ///
265   /// fn main()
266   /// {
267   ///   let s = StringWide::from("hello!");
268   /// }
269   /// ```
270   pub fn from(s: &str) -> Self {
271      Self::from_str_with(s, GlobalAllocator)
272   }
273}
274
275impl<A: Allocator> AsRef<[u16]> for StringWide<A> {
276   #[inline]
277   fn as_ref(&self) -> &[u16] {
278      &self.buf
279   }
280}
281
282impl<A: Allocator> Deref for StringWide<A> {
283   type Target = [u16];
284
285   #[inline]
286   fn deref(&self) -> &[u16] {
287      &self.buf
288   }
289}
290
291impl<A: Allocator> DerefMut for StringWide<A> {
292   #[inline]
293   fn deref_mut(&mut self) -> &mut [u16] {
294      &mut self.buf
295   }
296}
297
298unsafe impl Send for StringWide<GlobalAllocator> {}
299unsafe impl Sync for StringWide<GlobalAllocator> {}
300
301// IMPORTS //
302
303use {
304   crate::{
305      alloc::{Allocator, GlobalAllocator},
306      array::Array,
307   },
308   core::{
309      borrow::Borrow,
310      cmp::{Eq, PartialEq},
311      fmt,
312      hash::{Hash, Hasher},
313      ops::{Deref, DerefMut},
314      ptr, str,
315   },
316};