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    pub fn new_in(alloc: A) -> Self {
17        Self {
18            vec: Vec::new_in(alloc),
19        }
20    }
21
22    pub fn with_capacity_in(cap: usize, alloc: A) -> Self {
23        Self {
24            vec: Vec::with_capacity_in(cap, alloc),
25        }
26    }
27
28    pub fn from_str_in(s: &str, alloc: A) -> Self {
29        let mut vec = Vec::with_capacity_in(s.len(), alloc);
30        vec.extend_from_slice(s.as_bytes());
31        Self { vec }
32    }
33
34    pub fn from_utf8_in(vec: Vec<u8, A>) -> Result<Self, core::str::Utf8Error> {
35        match str::from_utf8(&vec) {
36            Ok(_) => Ok(Self { vec }),
37            Err(e) => Err(e),
38        }
39    }
40
41    pub unsafe fn from_utf8_unchecked_in(vec: Vec<u8, A>) -> Self {
42        Self { vec }
43    }
44
45    pub fn push_str(&mut self, s: &str) {
46        self.vec.extend_from_slice(s.as_bytes());
47    }
48
49    pub fn push(&mut self, ch: char) {
50        let mut buf = [0; 4];
51        self.push_str(ch.encode_utf8(&mut buf));
52    }
53
54    pub fn pop(&mut self) -> Option<char> {
55        let s = self.deref();
56        let ch = s.chars().rev().next()?;
57        let new_len = s.len() - ch.len_utf8();
58        self.vec.truncate(new_len);
59        Some(ch)
60    }
61
62    pub fn insert(&mut self, idx: usize, ch: char) {
63        let mut buf = [0; 4];
64        let bytes = ch.encode_utf8(&mut buf);
65        let byte_idx = {
66            let s = self.deref();
67            s.char_indices()
68                .nth(idx)
69                .map(|(i, _)| i)
70                .unwrap_or_else(|| panic!("insertion index (is {}) should be <= len (is {})", idx, s.len()))
71        };
72        self.vec.splice(byte_idx..byte_idx, bytes.as_bytes().iter().cloned());
73    }
74
75    pub fn remove(&mut self, idx: usize) -> char {
76        let (start, ch) = {
77            let s = self.deref();
78            s.char_indices()
79                .nth(idx)
80                .unwrap_or_else(|| panic!("removal index (is {}) should be < len (is {})", idx, s.chars().count()))
81        };
82        let end = start + ch.len_utf8();
83        self.vec.drain(start..end);
84        ch
85    }
86
87    pub fn split_off(&mut self, at: usize) -> Self
88    where
89        A: Clone,
90    {
91        let byte_idx = {
92            let s = self.deref();
93            s.char_indices().nth(at).map(|(i, _)| i).unwrap_or_else(|| {
94                panic!(
95                    "split_off index (is {}) should be <= len (is {})",
96                    at,
97                    s.chars().count()
98                )
99            })
100        };
101        let vec = self.vec.split_off(byte_idx);
102        Self { vec }
103    }
104
105    pub fn retain<F>(&mut self, mut f: F)
106    where
107        F: FnMut(char) -> bool,
108    {
109        let mut i = 0;
110        let mut len = self.len();
111        while i < len {
112            let ch = {
113                let s = self.deref();
114                match s[i..].chars().next() {
115                    Some(c) => c,
116                    None => break,
117                }
118            };
119            let ch_len = ch.len_utf8();
120            if !f(ch) {
121                self.vec.drain(i..i + ch_len);
122                len -= ch_len;
123            } else {
124                i += ch_len;
125            }
126        }
127    }
128
129    pub fn reserve(&mut self, additional: usize) {
130        self.vec.reserve(additional);
131    }
132
133    pub fn reserve_exact(&mut self, additional: usize) {
134        self.vec.reserve_exact(additional);
135    }
136
137    pub fn shrink_to_fit(&mut self) {
138        self.vec.shrink_to_fit();
139    }
140
141    pub fn clear(&mut self) {
142        self.vec.clear();
143    }
144
145    pub fn truncate(&mut self, new_len: usize) {
146        let current_len = self.chars().count();
147        if new_len > current_len {
148            panic!("truncate index (is {}) should be <= len (is {})", new_len, current_len);
149        }
150        let byte_idx = self.char_indices().nth(new_len).map(|(i, _)| i).unwrap_or(self.len());
151        self.vec.truncate(byte_idx);
152    }
153
154    pub fn len(&self) -> usize {
155        self.vec.len()
156    }
157
158    pub fn capacity(&self) -> usize {
159        self.vec.capacity()
160    }
161}
162
163impl<A: Allocator + Clone + Default> Deref for String<A> {
164    type Target = str;
165    fn deref(&self) -> &Self::Target {
166        unsafe { str::from_utf8_unchecked(&self.vec) }
167    }
168}
169
170impl<A: Allocator + Clone + Default> fmt::Display for String<A> {
171    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172        write!(f, "{}", self.deref())
173    }
174}
175
176impl<A: Allocator + Clone + Default> PartialEq<str> for String<A> {
177    fn eq(&self, other: &str) -> bool {
178        self.deref() == other
179    }
180}
181
182impl<A: Allocator + Clone + Default> PartialEq for String<A> {
183    fn eq(&self, other: &Self) -> bool {
184        self.deref() == other.deref()
185    }
186}
187
188impl<A: Allocator + Clone + Default> Eq for String<A> {}
189
190impl<A: Allocator + Clone + Default> PartialOrd for String<A> {
191    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
192        self.deref().partial_cmp(other.deref())
193    }
194}
195
196impl<A: Allocator + Clone + Default> Ord for String<A> {
197    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
198        self.deref().cmp(other.deref())
199    }
200}
201
202impl<A: Allocator + Clone + Default> Hash for String<A> {
203    fn hash<H: Hasher>(&self, state: &mut H) {
204        self.deref().hash(state);
205    }
206}
207
208impl<A: Allocator + Clone + Default> AsRef<str> for String<A> {
209    fn as_ref(&self) -> &str {
210        self.deref()
211    }
212}
213
214impl<A: Allocator + Clone + Default> AsRef<[u8]> for String<A> {
215    fn as_ref(&self) -> &[u8] {
216        self.vec.as_ref()
217    }
218}
219
220impl<A: Allocator + Clone + Default> Borrow<str> for String<A> {
221    fn borrow(&self) -> &str {
222        self.deref()
223    }
224}
225
226impl<A: Allocator + Clone + Default> From<&str> for String<A> {
227    fn from(s: &str) -> Self {
228        Self::from_str_in(s, A::default())
229    }
230}
231
232impl<A: Allocator + Clone + Default> From<Vec<u8, A>> for String<A> {
233    fn from(vec: Vec<u8, A>) -> Self {
234        Self { vec }
235    }
236}
237
238impl<A: Allocator + Clone + Default> Into<Vec<u8, A>> for String<A> {
239    fn into(self) -> Vec<u8, A> {
240        self.vec
241    }
242}
243
244// Add format! macro support
245impl<A: Allocator + Clone + Default> fmt::Write for String<A> {
246    fn write_str(&mut self, s: &str) -> fmt::Result {
247        self.push_str(s);
248        Ok(())
249    }
250
251    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
252        // Pre-allocate capacity based on the format string length
253        let capacity = args.as_str().map_or(0, |s| s.len());
254        self.reserve(capacity);
255
256        // Use the standard library's write_fmt implementation
257        fmt::write(self, args)
258    }
259}
260
261/// Creates a new `String` with the specified allocator and formats the arguments into it.
262///
263/// This macro is similar to the standard library's `format!` macro but returns our allocator-aware `String`.
264///
265/// # Examples
266///
267/// ```
268/// #![feature(allocator_api)]
269/// use string_alloc::{String, format_in};
270/// use std::alloc::Global;
271///
272/// let name = "World";
273/// let s = format_in!(Global, "Hello, {}!", name);
274/// assert_eq!(&*s, "Hello, World!");
275/// ```
276#[macro_export]
277macro_rules! format_in {
278    ($alloc:expr, $($arg:tt)*) => {{
279        use std::fmt::Write;
280        let mut s = $crate::String::new_in($alloc);
281        write!(s, $($arg)*).unwrap();
282        s
283    }};
284}
285
286// Add conversions to/from std::string::String
287#[cfg(feature = "std")]
288impl<A: Allocator + Clone + Default> From<std::string::String> for String<A> {
289    fn from(s: std::string::String) -> Self {
290        Self::from_str_in(&s, A::default())
291    }
292}
293
294#[cfg(feature = "std")]
295impl<A: Allocator + Clone + Default> From<String<A>> for std::string::String {
296    fn from(s: String<A>) -> Self {
297        Self::from(&*s)
298    }
299}
300
301// Add serde support
302#[cfg(feature = "serde")]
303impl<A: Allocator + Clone + Default> serde::Serialize for String<A> {
304    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
305    where
306        S: serde::Serializer,
307    {
308        serializer.serialize_str(self)
309    }
310}
311
312#[cfg(feature = "serde")]
313impl<'de, A: Allocator + Clone + Default> serde::Deserialize<'de> for String<A> {
314    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
315    where
316        D: serde::Deserializer<'de>,
317    {
318        let s = <&str>::deserialize(deserializer)?;
319        Ok(Self::from_str_in(s, A::default()))
320    }
321}
322
323impl<A: Allocator + Clone + Default> core::ops::Add<&str> for String<A> {
324    type Output = Self;
325
326    fn add(mut self, other: &str) -> Self {
327        self.push_str(other);
328        self
329    }
330}