1 use crate::{
2     alloc::{TryClone, str_ptr_from_raw_parts, try_realloc},
3     error::OutOfMemory,
4 };
5 use core::{fmt, mem, ops};
6 use std_alloc::{alloc::Layout, boxed::Box, string as inner};
7 
8 /// A newtype wrapper around [`std::string::String`] that only exposes
9 /// fallible-allocation methods.
10 #[derive(Default)]
11 pub struct String {
12     inner: inner::String,
13 }
14 
15 impl TryClone for String {
16     fn try_clone(&self) -> Result<Self, OutOfMemory> {
17         let mut s = Self::new();
18         s.push_str(self)?;
19         Ok(s)
20     }
21 }
22 
23 impl fmt::Debug for String {
24     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25         fmt::Debug::fmt(&self.inner, f)
26     }
27 }
28 
29 impl fmt::Display for String {
30     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31         fmt::Display::fmt(&self.inner, f)
32     }
33 }
34 
35 impl ops::Deref for String {
36     type Target = str;
37 
38     #[inline]
39     fn deref(&self) -> &Self::Target {
40         &self.inner
41     }
42 }
43 
44 impl ops::DerefMut for String {
45     #[inline]
46     fn deref_mut(&mut self) -> &mut Self::Target {
47         &mut self.inner
48     }
49 }
50 
51 impl From<inner::String> for String {
52     #[inline]
53     fn from(inner: inner::String) -> Self {
54         Self { inner }
55     }
56 }
57 
58 impl String {
59     /// Same as [`std::string::String::new`].
60     #[inline]
61     pub fn new() -> Self {
62         Self {
63             inner: inner::String::new(),
64         }
65     }
66 
67     /// Same as [`std::string::String::with_capacity`] but returns an error on
68     /// allocation failure.
69     #[inline]
70     pub fn with_capacity(capacity: usize) -> Result<Self, OutOfMemory> {
71         let mut s = Self::new();
72         s.reserve(capacity)?;
73         Ok(s)
74     }
75 
76     /// Same as [`std::string::String::capacity`].
77     #[inline]
78     pub fn capacity(&self) -> usize {
79         self.inner.capacity()
80     }
81 
82     /// Same as [`std::string::String::reserve`] but returns an error on
83     /// allocation failure.
84     #[inline]
85     pub fn reserve(&mut self, additional: usize) -> Result<(), OutOfMemory> {
86         self.inner
87             .try_reserve(additional)
88             .map_err(|_| OutOfMemory::new(self.len().saturating_add(additional)))
89     }
90 
91     /// Same as [`std::string::String::reserve_exact`] but returns an error on
92     /// allocation failure.
93     #[inline]
94     pub fn reserve_exact(&mut self, additional: usize) -> Result<(), OutOfMemory> {
95         self.inner
96             .try_reserve_exact(additional)
97             .map_err(|_| OutOfMemory::new(self.len().saturating_add(additional)))
98     }
99 
100     /// Same as [`std::string::String::push`] but returns an error on allocation
101     /// failure.
102     #[inline]
103     pub fn push(&mut self, c: char) -> Result<(), OutOfMemory> {
104         self.reserve(c.len_utf8())?;
105         self.inner.push(c);
106         Ok(())
107     }
108 
109     /// Same as [`std::string::String::push_str`] but returns an error on
110     /// allocation failure.
111     #[inline]
112     pub fn push_str(&mut self, s: &str) -> Result<(), OutOfMemory> {
113         self.reserve(s.len())?;
114         self.inner.push_str(s);
115         Ok(())
116     }
117 
118     /// Same as [`std::string::String::into_raw_parts`].
119     pub fn into_raw_parts(mut self) -> (*mut u8, usize, usize) {
120         // NB: Can't use `String::into_raw_parts` until our MSRV is >= 1.93.
121         #[cfg(not(miri))]
122         {
123             let ptr = self.as_mut_ptr();
124             let len = self.len();
125             let cap = self.capacity();
126             mem::forget(self);
127             (ptr, len, cap)
128         }
129         // NB: Miri requires using `into_raw_parts`, but always run on nightly,
130         // so it's fine to use there.
131         #[cfg(miri)]
132         {
133             let _ = &mut self;
134             self.inner.into_raw_parts()
135         }
136     }
137 
138     /// Same as [`std::string::String::from_raw_parts`].
139     pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> Self {
140         Self {
141             // Safety: Same as our unsafe contract.
142             inner: unsafe { inner::String::from_raw_parts(buf, length, capacity) },
143         }
144     }
145 
146     /// Same as [`std::string::String::shrink_to_fit`] but returns an error on
147     /// allocation failure.
148     pub fn shrink_to_fit(&mut self) -> Result<(), OutOfMemory> {
149         // If our length is already equal to our capacity, then there is nothing
150         // to shrink.
151         if self.len() == self.capacity() {
152             return Ok(());
153         }
154 
155         // `realloc` requires a non-zero original layout as well as a non-zero
156         // destination layout, so this guard ensures that the sizes below are
157         // all nonzero. This handles a couple cases:
158         //
159         // * If `len == cap == 0` then no allocation has ever been made.
160         // * If `len == 0` and `cap != 0` then this function effectively frees
161         //   the memory.
162         //
163         // In both of these cases delegate to the standard library's
164         // `shrink_to_fit` which is guaranteed to not perform a `realloc`.
165         if self.is_empty() {
166             self.inner.shrink_to_fit();
167             return Ok(());
168         }
169 
170         let (ptr, len, cap) = mem::take(self).into_raw_parts();
171         debug_assert!(!ptr.is_null());
172         debug_assert!(len > 0);
173         debug_assert!(cap > len);
174         let old_layout = Layout::array::<u8>(cap).unwrap();
175         debug_assert_eq!(old_layout.size(), cap);
176         let new_layout = Layout::array::<u8>(len).unwrap();
177         debug_assert_eq!(old_layout.align(), new_layout.align());
178         debug_assert_eq!(new_layout.size(), len);
179 
180         // SAFETY: `ptr` was previously allocated in the global allocator,
181         // `layout` has a nonzero size and matches the current allocation of
182         // `ptr`, `len` is nonzero, and `len` is a valid array size
183         // for `len` elements given its constructor.
184         let result = unsafe { try_realloc(ptr, old_layout, len) };
185 
186         match result {
187             Ok(ptr) => {
188                 // SAFETY: `result` is allocated with the global allocator and
189                 // has room for exactly `[u8; len]`.
190                 *self = unsafe { Self::from_raw_parts(ptr.as_ptr(), len, len) };
191                 Ok(())
192             }
193             Err(oom) => {
194                 // SAFETY: If reallocation fails then it's guaranteed that the
195                 // original allocation is not tampered with, so it's safe to
196                 // reassemble the original vector.
197                 *self = unsafe { Self::from_raw_parts(ptr, len, cap) };
198                 Err(oom)
199             }
200         }
201     }
202 
203     /// Same as [`std::string::String::into_boxed_str`] but returns an error on
204     /// allocation failure.
205     pub fn into_boxed_str(mut self) -> Result<Box<str>, OutOfMemory> {
206         self.shrink_to_fit()?;
207 
208         let (ptr, len, cap) = self.into_raw_parts();
209         debug_assert_eq!(len, cap);
210         let ptr = str_ptr_from_raw_parts(ptr, len);
211 
212         // SAFETY: The `ptr` is allocated with the global allocator and points
213         // to a valid block of utf8.
214         let boxed = unsafe { Box::from_raw(ptr) };
215 
216         Ok(boxed)
217     }
218 }
219