string_alloc/
string.rs

1use alloc::vec::Vec;
2use core::borrow::Borrow;
3use core::fmt;
4use core::hash::{Hash, Hasher};
5use core::ops::Deref;
6use core::str;
7
8use ::alloc::alloc::{Allocator, Global};
9
10#[derive(Debug, Clone)]
11pub struct String<A: Allocator + Clone + Default = Global> {
12    vec: Vec<u8, A>,
13}
14
15impl<A: Allocator + Clone + Default> String<A> {
16    /// Creates a new empty `String` with the specified allocator.
17    ///
18    /// See [`std::string::String::new`] for more details.
19    pub fn new_in(alloc: A) -> Self {
20        Self {
21            vec: Vec::new_in(alloc),
22        }
23    }
24
25    /// Creates a new empty `String` with at least the specified capacity with the specified allocator.
26    ///
27    /// See [`std::string::String::with_capacity`] for more details.
28    pub fn with_capacity_in(cap: usize, alloc: A) -> Self {
29        Self {
30            vec: Vec::with_capacity_in(cap, alloc),
31        }
32    }
33
34    /// Creates a new `String` from a string slice with the specified allocator.
35    ///
36    /// See [`std::string::String::from_str`] for more details.
37    pub fn from_str_in(s: &str, alloc: A) -> Self {
38        let mut vec = Vec::with_capacity_in(s.len(), alloc);
39        vec.extend_from_slice(s.as_bytes());
40        Self { vec }
41    }
42
43    /// Converts a vector of bytes to a `String` with the specified allocator.
44    ///
45    /// See [`std::string::String::from_utf8`] for more details.
46    pub fn from_utf8_in(vec: Vec<u8, A>) -> Result<Self, core::str::Utf8Error> {
47        match str::from_utf8(&vec) {
48            Ok(_) => Ok(Self { vec }),
49            Err(e) => Err(e),
50        }
51    }
52
53    /// Converts a vector of bytes to a `String` with the specified allocator without checking that the string contains valid UTF-8.
54    ///
55    /// See [`std::string::String::from_utf8_unchecked`] for more details.
56    pub unsafe fn from_utf8_unchecked_in(vec: Vec<u8, A>) -> Self {
57        Self { vec }
58    }
59
60    /// Appends a given string slice onto the end of this `String`.
61    ///
62    /// See [`std::string::String::push_str`] for more details.
63    pub fn push_str(&mut self, s: &str) {
64        self.vec.extend_from_slice(s.as_bytes());
65    }
66
67    /// Appends the given char to the end of this `String`.
68    ///
69    /// See [`std::string::String::push`] for more details.
70    pub fn push(&mut self, ch: char) {
71        let mut buf = [0; 4];
72        self.push_str(ch.encode_utf8(&mut buf));
73    }
74
75    /// Removes the last character from the string buffer and returns it.
76    ///
77    /// See [`std::string::String::pop`] for more details.
78    pub fn pop(&mut self) -> Option<char> {
79        let s = self.deref();
80        let ch = s.chars().rev().next()?;
81        let new_len = s.len() - ch.len_utf8();
82        self.vec.truncate(new_len);
83        Some(ch)
84    }
85
86    /// Inserts a character into this `String` at a byte position.
87    ///
88    /// See [`std::string::String::insert`] for more details.
89    pub fn insert(&mut self, idx: usize, ch: char) {
90        let mut buf = [0; 4];
91        let bytes = ch.encode_utf8(&mut buf);
92        let byte_idx = {
93            let s = self.deref();
94            s.char_indices()
95                .nth(idx)
96                .map(|(i, _)| i)
97                .unwrap_or_else(|| panic!("insertion index (is {}) should be <= len (is {})", idx, s.len()))
98        };
99        self.vec.splice(byte_idx..byte_idx, bytes.as_bytes().iter().cloned());
100    }
101
102    /// Removes a char from this `String` at a byte position and returns it.
103    ///
104    /// See [`std::string::String::remove`] for more details.
105    pub fn remove(&mut self, idx: usize) -> char {
106        let (start, ch) = {
107            let s = self.deref();
108            s.char_indices()
109                .nth(idx)
110                .unwrap_or_else(|| panic!("removal index (is {}) should be < len (is {})", idx, s.chars().count()))
111        };
112        let end = start + ch.len_utf8();
113        self.vec.drain(start..end);
114        ch
115    }
116
117    /// Splits the string into two at the given byte index.
118    ///
119    /// See [`std::string::String::split_off`] for more details.
120    pub fn split_off(&mut self, at: usize) -> Self
121    where
122        A: Clone,
123    {
124        let byte_idx = {
125            let s = self.deref();
126            s.char_indices().nth(at).map(|(i, _)| i).unwrap_or_else(|| {
127                panic!(
128                    "split_off index (is {}) should be <= len (is {})",
129                    at,
130                    s.chars().count()
131                )
132            })
133        };
134        let vec = self.vec.split_off(byte_idx);
135        Self { vec }
136    }
137
138    /// Retains only the characters specified by the predicate.
139    ///
140    /// See [`std::string::String::retain`] for more details.
141    pub fn retain<F>(&mut self, mut f: F)
142    where
143        F: FnMut(char) -> bool,
144    {
145        let mut i = 0;
146        let mut len = self.len();
147        while i < len {
148            let ch = {
149                let s = self.deref();
150                match s[i..].chars().next() {
151                    Some(c) => c,
152                    None => break,
153                }
154            };
155            let ch_len = ch.len_utf8();
156            if !f(ch) {
157                self.vec.drain(i..i + ch_len);
158                len -= ch_len;
159            } else {
160                i += ch_len;
161            }
162        }
163    }
164
165    /// Ensures that this `String`'s capacity is at least `additional` bytes larger than its length.
166    ///
167    /// See [`std::string::String::reserve`] for more details.
168    pub fn reserve(&mut self, additional: usize) {
169        self.vec.reserve(additional);
170    }
171
172    /// Ensures that this `String`'s capacity is exactly `additional` bytes larger than its length.
173    ///
174    /// See [`std::string::String::reserve_exact`] for more details.
175    pub fn reserve_exact(&mut self, additional: usize) {
176        self.vec.reserve_exact(additional);
177    }
178
179    /// Shrinks the capacity of this `String` to match its length.
180    ///
181    /// See [`std::string::String::shrink_to_fit`] for more details.
182    pub fn shrink_to_fit(&mut self) {
183        self.vec.shrink_to_fit();
184    }
185
186    /// Truncates this `String`, removing all contents.
187    ///
188    /// See [`std::string::String::clear`] for more details.
189    pub fn clear(&mut self) {
190        self.vec.clear();
191    }
192
193    /// Shortens this `String` to the specified length.
194    ///
195    /// See [`std::string::String::truncate`] for more details.
196    pub fn truncate(&mut self, new_len: usize) {
197        let current_len = self.chars().count();
198        if new_len > current_len {
199            panic!("truncate index (is {}) should be <= len (is {})", new_len, current_len);
200        }
201        let byte_idx = self.char_indices().nth(new_len).map(|(i, _)| i).unwrap_or(self.len());
202        self.vec.truncate(byte_idx);
203    }
204
205    /// Returns the length of this `String`, in bytes.
206    ///
207    /// See [`std::string::String::len`] for more details.
208    pub fn len(&self) -> usize {
209        self.vec.len()
210    }
211
212    /// Returns the capacity of this `String`, in bytes.
213    ///
214    /// See [`std::string::String::capacity`] for more details.
215    pub fn capacity(&self) -> usize {
216        self.vec.capacity()
217    }
218
219    /// Converts the string into a new string with the specified allocator type.
220    ///
221    /// This method allows converting between different allocator types while preserving the string's contents.
222    pub fn to_string_in<B: Allocator + Clone + Default>(&self) -> String<B> {
223        String::from_str_in(self, B::default())
224    }
225}
226
227impl<A: Allocator + Clone + Default> Deref for String<A> {
228    type Target = str;
229    fn deref(&self) -> &Self::Target {
230        unsafe { str::from_utf8_unchecked(&self.vec) }
231    }
232}
233
234impl<A: Allocator + Clone + Default> fmt::Display for String<A> {
235    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236        write!(f, "{}", self.deref())
237    }
238}
239
240impl<A: Allocator + Clone + Default> PartialEq<str> for String<A> {
241    fn eq(&self, other: &str) -> bool {
242        self.deref() == other
243    }
244}
245
246impl<A: Allocator + Clone + Default> PartialEq for String<A> {
247    fn eq(&self, other: &Self) -> bool {
248        self.deref() == other.deref()
249    }
250}
251
252impl<A: Allocator + Clone + Default> Eq for String<A> {}
253
254impl<A: Allocator + Clone + Default> PartialOrd for String<A> {
255    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
256        self.deref().partial_cmp(other.deref())
257    }
258}
259
260impl<A: Allocator + Clone + Default> Ord for String<A> {
261    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
262        self.deref().cmp(other.deref())
263    }
264}
265
266impl<A: Allocator + Clone + Default> Hash for String<A> {
267    fn hash<H: Hasher>(&self, state: &mut H) {
268        self.deref().hash(state);
269    }
270}
271
272impl<A: Allocator + Clone + Default> AsRef<str> for String<A> {
273    fn as_ref(&self) -> &str {
274        self.deref()
275    }
276}
277
278impl<A: Allocator + Clone + Default> AsRef<[u8]> for String<A> {
279    fn as_ref(&self) -> &[u8] {
280        self.vec.as_ref()
281    }
282}
283
284impl<A: Allocator + Clone + Default> Borrow<str> for String<A> {
285    fn borrow(&self) -> &str {
286        self.deref()
287    }
288}
289
290impl<A: Allocator + Clone + Default> From<&str> for String<A> {
291    fn from(s: &str) -> Self {
292        Self::from_str_in(s, A::default())
293    }
294}
295
296impl<A: Allocator + Clone + Default> From<Vec<u8, A>> for String<A> {
297    fn from(vec: Vec<u8, A>) -> Self {
298        Self { vec }
299    }
300}
301
302impl<A: Allocator + Clone + Default> Into<Vec<u8, A>> for String<A> {
303    fn into(self) -> Vec<u8, A> {
304        self.vec
305    }
306}
307
308// Add format! macro support
309impl<A: Allocator + Clone + Default> fmt::Write for String<A> {
310    fn write_str(&mut self, s: &str) -> fmt::Result {
311        self.push_str(s);
312        Ok(())
313    }
314
315    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
316        // Pre-allocate capacity based on the format string length
317        let capacity = args.as_str().map_or(0, |s| s.len());
318        self.reserve(capacity);
319
320        // Use the standard library's write_fmt implementation
321        fmt::write(self, args)
322    }
323}
324
325/// Creates a new `String` with the specified allocator and formats the arguments into it.
326///
327/// This macro is similar to the standard library's `format!` macro but returns our allocator-aware `String`.
328///
329/// # Examples
330///
331/// ```
332/// #![feature(allocator_api)]
333/// use string_alloc::{String, format_in};
334/// use std::alloc::Global;
335///
336/// let name = "World";
337/// let s = format_in!(Global, "Hello, {}!", name);
338/// assert_eq!(&*s, "Hello, World!");
339/// ```
340#[macro_export]
341macro_rules! format_in {
342    ($alloc:expr, $($arg:tt)*) => {{
343        use std::fmt::Write;
344        let mut s = $crate::String::new_in($alloc);
345        write!(s, $($arg)*).unwrap();
346        s
347    }};
348}
349
350// Add conversions to/from std::string::String
351#[cfg(feature = "std")]
352impl<A: Allocator + Clone + Default> From<std::string::String> for String<A> {
353    fn from(s: std::string::String) -> Self {
354        Self::from_str_in(&s, A::default())
355    }
356}
357
358#[cfg(feature = "std")]
359impl<A: Allocator + Clone + Default> From<String<A>> for std::string::String {
360    fn from(s: String<A>) -> Self {
361        Self::from(&*s)
362    }
363}
364
365// Add serde support
366#[cfg(feature = "serde")]
367impl<A: Allocator + Clone + Default> serde::Serialize for String<A> {
368    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
369    where
370        S: serde::Serializer,
371    {
372        serializer.serialize_str(self)
373    }
374}
375
376#[cfg(feature = "serde")]
377impl<'de, A: Allocator + Clone + Default> serde::Deserialize<'de> for String<A> {
378    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
379    where
380        D: serde::Deserializer<'de>,
381    {
382        let s = <&str>::deserialize(deserializer)?;
383        Ok(Self::from_str_in(s, A::default()))
384    }
385}
386
387impl<A: Allocator + Clone + Default> core::ops::Add<&str> for String<A> {
388    type Output = Self;
389
390    fn add(mut self, other: &str) -> Self {
391        self.push_str(other);
392        self
393    }
394}