string_pool/
string.rs

1use crate::pool::{ GlobalPool, Pool, SlicesWrap };
2use ::std::ops::{ Add, AddAssign, Bound, Deref, RangeBounds };
3use ::std::string::{ self as std_string, String as StdString };
4use ::std::str as std_str;
5
6pub struct String<P: Pool = GlobalPool> {
7	raw: P::Raw,
8	pool: P
9}
10
11#[cfg(test)]
12#[path = "./tests/string.rs"]
13mod tests;
14
15// constructors with default pool
16impl String {
17	pub fn new() -> Self {
18		Self::new_in(GlobalPool)
19	}
20
21	pub fn from_utf8(vec: Vec<u8>) -> Result<Self, std_string::FromUtf8Error> {
22		Self::from_utf8_in(vec, GlobalPool)
23	}
24
25	pub fn from_utf8_slice(slice: &[u8]) -> Result<Self, std_str::Utf8Error> {
26		Self::from_utf8_slice_in(slice, GlobalPool)
27	}
28
29	pub fn from_utf8_lossy(v: &[u8]) -> Self {
30		Self::from_utf8_lossy_in(v, GlobalPool)
31	}
32
33	pub fn from_utf16(v: &[u16]) -> Result<Self, std_string::FromUtf16Error> {
34		Self::from_utf16_in(v, GlobalPool)
35	}
36
37	pub fn from_utf16_lossy(v: &[u16]) -> Self {
38		Self::from_utf16_lossy_in(v, GlobalPool)
39	}
40
41	// skipping (nightly, for now): from_utf16le
42	// skipping (nightly, for now): from_utf16le_lossy
43	// skipping (nightly, for now): from_utf16be
44	// skipping (nightly, for now): from_utf16be_lossy
45	// skipping (nightly): into_raw_parts
46	// skipping: from_raw_parts
47
48	pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> Self {
49		Self::from_utf8_unchecked_in(bytes, GlobalPool)
50	}
51
52	pub unsafe fn from_utf8_unchecked_slice(slice: &[u8]) -> Self {
53		Self::from_utf8_unchecked_slice_in(slice, GlobalPool)
54	}
55}
56
57// constructors with custom pool
58impl<P: Pool> String<P> {
59	pub fn new_in(pool: P) -> Self {
60		let raw = pool.raw_empty();
61		Self { raw, pool }
62	}
63
64	pub fn from_utf8_in(vec: Vec<u8>, pool: P) -> Result<Self, std_string::FromUtf8Error> {
65		// running it through std String because it gives us FromUtf8Error, for
66		// compat with std String's from_utf8 function, don't think there is
67		// any other way to get it than through this
68		let std_string = StdString::from_utf8(vec)?;
69		let vec = std_string.into_bytes();
70		let raw = unsafe { pool.raw_from_vec(vec) };
71		Ok(Self { raw, pool })
72	}
73
74	pub fn from_utf8_slice_in(slice: &[u8], pool: P) -> Result<Self, std_str::Utf8Error> {
75		let s = std_str::from_utf8(slice)?;
76		let raw = unsafe { pool.raw_from_slice(s.as_bytes()) };
77		Ok(Self { raw, pool })
78	}
79
80	pub fn from_utf8_lossy_in(v: &[u8], pool: P) -> Self {
81		let s = StdString::from_utf8_lossy(v);
82		let raw = unsafe { pool.raw_from_slice(s.as_bytes()) };
83		Self { raw, pool }
84	}
85
86	pub fn from_utf16_in(v: &[u16], pool: P) -> Result<Self, std_string::FromUtf16Error> {
87		let s = StdString::from_utf16(v)?;
88		let raw = unsafe { pool.raw_from_slice(s.as_bytes()) };
89		Ok(Self { raw, pool })
90	}
91
92	pub fn from_utf16_lossy_in(v: &[u16], pool: P) -> Self {
93		let s = StdString::from_utf16_lossy(v);
94		let raw = unsafe { pool.raw_from_slice(s.as_bytes()) };
95		Self { raw, pool }
96	}
97
98	pub unsafe fn from_utf8_unchecked_in(bytes: Vec<u8>, pool: P) -> Self {
99		let raw = pool.raw_from_vec(bytes);
100		Self { raw, pool }
101	}
102
103	pub unsafe fn from_utf8_unchecked_slice_in(slice: &[u8], pool: P) -> Self {
104		let raw = pool.raw_from_slice(slice);
105		Self { raw, pool }
106	}
107
108	pub fn to_other_pool<P2: Pool>(&self, pool: P2) -> String<P2> {
109		let slice = self.pool.raw_to_slice(&self.raw);
110		let raw = unsafe { pool.raw_from_slice(slice) };
111		String { raw, pool }
112	}
113
114	pub fn into_other_pool<P2: Pool>(self, pool: P2) -> String<P2> {
115		let vec = self.pool.raw_into_vec(self.raw);
116		let raw = unsafe { pool.raw_from_vec(vec) };
117		String { raw, pool }
118	}
119
120	pub fn clone_to<P2: Pool>(&self, pool: P2) -> String<P2> {
121		self.to_other_pool(pool)
122	}
123}
124
125// functions that take self
126impl<P: Pool> String<P> {
127	pub fn into_bytes(self) -> Vec<u8> {
128		self.pool.raw_into_vec(self.raw)
129	}
130
131	pub fn as_str(&self) -> &str {
132		unsafe { std_str::from_utf8_unchecked(self.as_bytes()) }
133	}
134
135	// skipping: as_mut_str
136
137	pub fn push_str(&mut self, string: &str) {
138		let new_raw = unsafe {
139			self.pool.raw_from_slices(SlicesWrap(&[
140				self.as_bytes(),
141				string.as_bytes()
142			]))
143		};
144
145		self.raw = new_raw;
146	}
147
148	// skipping (nightly, for now): extend_from_within
149	// skipping: capacity
150	// skipping: reserve
151	// skipping: reserve_exact
152	// skipping: try_reserve
153	// skipping: try_reserve_exact
154	// skipping: shrink_to_fit
155	// skipping: shrink_to
156
157	pub fn push(&mut self, ch: char) {
158		self.push_str(ch.encode_utf8(&mut [0u8; 4]));
159	}
160
161	pub fn as_bytes(&self) -> &[u8] {
162		self.pool.raw_to_slice(&self.raw)
163	}
164
165	pub fn truncate(&mut self, new_len: usize) {
166		if new_len > self.len() { return }
167
168		assert!(self.is_char_boundary(new_len));
169		let new_slice = &self.as_bytes()[..new_len];
170		let new_raw = unsafe { self.pool.raw_from_slice(new_slice) };
171
172		self.raw = new_raw;
173	}
174
175	pub fn pop(&mut self) -> Option<char> {
176		let ch = self.chars().next_back()?;
177		let new_len = self.len() - ch.len_utf8();
178
179		let new_slice = &self.as_bytes()[..new_len];
180		let new_raw = unsafe { self.pool.raw_from_slice(new_slice) };
181
182		self.raw = new_raw;
183		Some(ch)
184	}
185
186	pub fn remove(&mut self, i: usize) -> char {
187		// let slice =
188		let ch = self[i..].chars().next()
189			.expect("cannot remove a char from the end of a string");
190		let next = i + ch.len_utf8();
191
192		let slice = self.as_bytes();
193		let new_raw = unsafe {
194			self.pool.raw_from_slices(SlicesWrap(&[
195				&slice[..i],
196				&slice[next..]
197			]))
198		};
199
200		self.raw = new_raw;
201		ch
202	}
203
204	// skipping (nightly, for now): remove_matches
205
206	pub fn retain<F>(&mut self, mut f: F)
207	where
208		F: FnMut(char) -> bool
209	{
210		// reason for capacity:
211		// worst case is true, false, true, false, etc
212		// which is keeping half of 1 byte chars
213		// so if chars are longer or longer sequences of no switching, it'll be less
214		// +1 is for odd ones, like. true false true, len 3, (3 / 2) + 1 == 2, will fit
215		// i mean, worst case is worse performance, it doesn't lead to correctness
216		// issues, so its not the most critical :p
217		let mut retained = Vec::with_capacity((self.len() / 2) + 1);
218		let mut state = None;
219
220		for (i, char) in self.char_indices() {
221			match (f(char), state) {
222				// start new streak
223				(true, None) => {
224					state = Some(i);
225				}
226
227				// end streak
228				(false, Some(i_start)) => {
229					retained.push(self[i_start..i].as_bytes());
230					state = None;
231				}
232
233				// continue true streak
234				(true, Some(_)) => { /* noop */ }
235
236				// continue false streak
237				(false, None) => { /* noop */ }
238			}
239		}
240
241		if let Some(i_start) = state {
242			retained.push(self[i_start..].as_bytes());
243		}
244
245		let new_raw = unsafe { self.pool.raw_from_slices(SlicesWrap(&retained)) };
246		self.raw = new_raw;
247	}
248
249	pub fn insert(&mut self, i: usize, ch: char) {
250		self.insert_str(i, ch.encode_utf8(&mut [0u8; 4]));
251	}
252
253	pub fn insert_str(&mut self, i: usize, string: &str) {
254		assert!(self.is_char_boundary(i));
255		let slice = self.as_bytes();
256
257		let new_raw = unsafe {
258			self.pool.raw_from_slices(SlicesWrap(&[
259				&slice[..i],
260				string.as_bytes(),
261				&slice[i..]
262			]))
263		};
264
265		self.raw = new_raw;
266	}
267
268	// skipping: as_mut_vec
269
270	pub fn split_off(&mut self, at: usize) -> Self {
271		self.split_off_in(at, self.pool.clone())
272	}
273
274	pub fn split_off_in<P2: Pool>(&mut self, at: usize, pool: P2) -> String<P2> {
275		assert!(self.is_char_boundary(at));
276
277		let self_raw = unsafe { self.pool.raw_from_slice(self[..at].as_bytes()) };
278		let other_raw = unsafe { pool.raw_from_slice(self[at..].as_bytes()) };
279
280		self.raw = self_raw;
281		String { raw: other_raw, pool }
282	}
283
284	pub fn clear(&mut self) {
285		self.raw = self.pool.raw_empty();
286	}
287
288	// skipping (for now): drain
289	// skipping (for now): replace_range
290
291	pub fn into_boxed_str(self) -> Box<str> {
292		let boxed = self.pool.raw_into_boxed_slice(self.raw);
293		unsafe { std_str::from_boxed_utf8_unchecked(boxed) }
294	}
295
296	pub fn leak<'h>(self) -> &'h mut str {
297		let slice = self.pool.raw_into_vec(self.raw).leak();
298		unsafe { std_str::from_utf8_unchecked_mut(slice) }
299	}
300}
301
302impl<P: Pool> Add<&str> for String<P> {
303	type Output = Self;
304	fn add(mut self, rhs: &str) -> Self {
305		// delegates to AddAssign<&str> for String<P>
306		self += rhs;
307		self
308	}
309}
310
311impl<P: Pool> Add<&str> for &String<P> {
312	type Output = String<P>;
313	fn add(self, rhs: &str) -> String<P> {
314		let raw = unsafe {
315			self.pool.raw_from_slices(SlicesWrap(&[
316				self.as_bytes(),
317				rhs.as_bytes()
318			]))
319		};
320		let pool = self.pool.clone();
321
322		String { raw, pool }
323	}
324}
325
326impl<P: Pool, P2: Pool> Add<String<P2>> for String<P> {
327	type Output = Self;
328	fn add(self, rhs: String<P2>) -> Self {
329		// delegates to Add<&str> for String<P>
330		self + &*rhs
331	}
332}
333
334impl<P: Pool, P2: Pool> Add<String<P2>> for &String<P> {
335	type Output = String<P>;
336	fn add(self, rhs: String<P2>) -> String<P> {
337		// delegates to Add<&str> for &String<P>
338		self + &*rhs
339	}
340}
341
342impl<P: Pool, P2: Pool> Add<&String<P2>> for String<P> {
343	type Output = Self;
344	fn add(self, rhs: &String<P2>) -> Self {
345		// delegates to Add<&str> for String<P>
346		self + &**rhs
347	}
348}
349
350impl<P: Pool, P2: Pool> Add<&String<P2>> for &String<P> {
351	type Output = String<P>;
352	fn add(self, rhs: &String<P2>) -> String<P> {
353		// delegates to Add<&str> for &String<P>
354		self + &**rhs
355	}
356}
357
358
359impl<P: Pool> AddAssign<&str> for String<P> {
360	fn add_assign(&mut self, rhs: &str) {
361		self.push_str(rhs);
362	}
363}
364
365impl<P: Pool, P2: Pool> AddAssign<String<P2>> for String<P> {
366	fn add_assign(&mut self, rhs: String<P2>) {
367		// delegates to AddAssign<&str> for String<P>
368		*self += &*rhs
369	}
370}
371
372impl<P: Pool, P2: Pool> AddAssign<&String<P2>> for String<P> {
373	fn add_assign(&mut self, rhs: &String<P2>) {
374		// delegates to AddAssign<&str> for String<P>
375		*self += &**rhs
376	}
377}
378
379impl<P: Pool> Clone for String<P> {
380	fn clone(&self) -> Self {
381		let raw = self.pool.raw_clone(&self.raw);
382		let pool = self.pool.clone();
383		Self { raw, pool }
384	}
385}
386
387impl<P: Pool> Deref for String<P> {
388	type Target = str;
389	fn deref(&self) -> &str {
390		self.as_str()
391	}
392}
393
394impl From<&str> for String {
395	fn from(s: &str) -> Self {
396		Self::from((s, GlobalPool))
397	}
398}
399
400impl<P: Pool> From<(&str, P)> for String<P> {
401	fn from((s, pool): (&str, P)) -> Self {
402		let raw = unsafe { pool.raw_from_slice(s.as_bytes()) };
403		Self { raw, pool }
404	}
405}