10c673b70SNick Fitzgerald use crate::{
20c673b70SNick Fitzgerald     alloc::{TryClone, str_ptr_from_raw_parts, try_realloc},
30c673b70SNick Fitzgerald     error::OutOfMemory,
40c673b70SNick Fitzgerald };
5*cfd8a4d2SNick Fitzgerald use core::{borrow::Borrow, fmt, mem, ops};
60c673b70SNick Fitzgerald use std_alloc::{alloc::Layout, boxed::Box, string as inner};
7bf42bd4fSNick Fitzgerald 
8bf42bd4fSNick Fitzgerald /// A newtype wrapper around [`std::string::String`] that only exposes
9bf42bd4fSNick Fitzgerald /// fallible-allocation methods.
10285a6dc6SNick Fitzgerald #[derive(Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
11bf42bd4fSNick Fitzgerald pub struct String {
12bf42bd4fSNick Fitzgerald     inner: inner::String,
13bf42bd4fSNick Fitzgerald }
14bf42bd4fSNick Fitzgerald 
15bf42bd4fSNick Fitzgerald impl TryClone for String {
16bf42bd4fSNick Fitzgerald     fn try_clone(&self) -> Result<Self, OutOfMemory> {
17bf42bd4fSNick Fitzgerald         let mut s = Self::new();
18bf42bd4fSNick Fitzgerald         s.push_str(self)?;
19bf42bd4fSNick Fitzgerald         Ok(s)
20bf42bd4fSNick Fitzgerald     }
21bf42bd4fSNick Fitzgerald }
22bf42bd4fSNick Fitzgerald 
23bf42bd4fSNick Fitzgerald impl fmt::Debug for String {
24bf42bd4fSNick Fitzgerald     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25bf42bd4fSNick Fitzgerald         fmt::Debug::fmt(&self.inner, f)
26bf42bd4fSNick Fitzgerald     }
27bf42bd4fSNick Fitzgerald }
28bf42bd4fSNick Fitzgerald 
29bf42bd4fSNick Fitzgerald impl fmt::Display for String {
30bf42bd4fSNick Fitzgerald     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31bf42bd4fSNick Fitzgerald         fmt::Display::fmt(&self.inner, f)
32bf42bd4fSNick Fitzgerald     }
33bf42bd4fSNick Fitzgerald }
34bf42bd4fSNick Fitzgerald 
35bf42bd4fSNick Fitzgerald impl ops::Deref for String {
36bf42bd4fSNick Fitzgerald     type Target = str;
37bf42bd4fSNick Fitzgerald 
38bf42bd4fSNick Fitzgerald     #[inline]
39bf42bd4fSNick Fitzgerald     fn deref(&self) -> &Self::Target {
40bf42bd4fSNick Fitzgerald         &self.inner
41bf42bd4fSNick Fitzgerald     }
42bf42bd4fSNick Fitzgerald }
43bf42bd4fSNick Fitzgerald 
44bf42bd4fSNick Fitzgerald impl ops::DerefMut for String {
45bf42bd4fSNick Fitzgerald     #[inline]
46bf42bd4fSNick Fitzgerald     fn deref_mut(&mut self) -> &mut Self::Target {
47bf42bd4fSNick Fitzgerald         &mut self.inner
48bf42bd4fSNick Fitzgerald     }
49bf42bd4fSNick Fitzgerald }
50bf42bd4fSNick Fitzgerald 
51*cfd8a4d2SNick Fitzgerald impl AsRef<str> for String {
52*cfd8a4d2SNick Fitzgerald     fn as_ref(&self) -> &str {
53*cfd8a4d2SNick Fitzgerald         self
54*cfd8a4d2SNick Fitzgerald     }
55*cfd8a4d2SNick Fitzgerald }
56*cfd8a4d2SNick Fitzgerald 
57*cfd8a4d2SNick Fitzgerald impl Borrow<str> for String {
58*cfd8a4d2SNick Fitzgerald     fn borrow(&self) -> &str {
59*cfd8a4d2SNick Fitzgerald         self
60*cfd8a4d2SNick Fitzgerald     }
61*cfd8a4d2SNick Fitzgerald }
62*cfd8a4d2SNick Fitzgerald 
63bf42bd4fSNick Fitzgerald impl From<inner::String> for String {
64bf42bd4fSNick Fitzgerald     #[inline]
65bf42bd4fSNick Fitzgerald     fn from(inner: inner::String) -> Self {
66bf42bd4fSNick Fitzgerald         Self { inner }
67bf42bd4fSNick Fitzgerald     }
68bf42bd4fSNick Fitzgerald }
69bf42bd4fSNick Fitzgerald 
7033a3a2ddSNick Fitzgerald impl serde::ser::Serialize for String {
7133a3a2ddSNick Fitzgerald     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
7233a3a2ddSNick Fitzgerald     where
7333a3a2ddSNick Fitzgerald         S: serde::Serializer,
7433a3a2ddSNick Fitzgerald     {
7533a3a2ddSNick Fitzgerald         serializer.serialize_str(self)
7633a3a2ddSNick Fitzgerald     }
7733a3a2ddSNick Fitzgerald }
7833a3a2ddSNick Fitzgerald 
7933a3a2ddSNick Fitzgerald impl<'de> serde::de::Deserialize<'de> for String {
8033a3a2ddSNick Fitzgerald     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
8133a3a2ddSNick Fitzgerald     where
8233a3a2ddSNick Fitzgerald         D: serde::Deserializer<'de>,
8333a3a2ddSNick Fitzgerald     {
8433a3a2ddSNick Fitzgerald         struct Visitor;
8533a3a2ddSNick Fitzgerald 
8633a3a2ddSNick Fitzgerald         impl<'de> serde::de::Visitor<'de> for Visitor {
8733a3a2ddSNick Fitzgerald             type Value = String;
8833a3a2ddSNick Fitzgerald 
8933a3a2ddSNick Fitzgerald             fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
9033a3a2ddSNick Fitzgerald                 f.write_str("a `wasmtime_core::alloc::String` str")
9133a3a2ddSNick Fitzgerald             }
9233a3a2ddSNick Fitzgerald 
9333a3a2ddSNick Fitzgerald             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
9433a3a2ddSNick Fitzgerald             where
9533a3a2ddSNick Fitzgerald                 E: serde::de::Error,
9633a3a2ddSNick Fitzgerald             {
9733a3a2ddSNick Fitzgerald                 let mut s = String::new();
9833a3a2ddSNick Fitzgerald                 s.reserve_exact(v.len()).map_err(|oom| E::custom(oom))?;
9933a3a2ddSNick Fitzgerald                 s.push_str(v).expect("reserved capacity");
10033a3a2ddSNick Fitzgerald                 Ok(s)
10133a3a2ddSNick Fitzgerald             }
10233a3a2ddSNick Fitzgerald         }
10333a3a2ddSNick Fitzgerald 
10433a3a2ddSNick Fitzgerald         // NB: do not use `deserialize_string` as that eagerly allocates the
10533a3a2ddSNick Fitzgerald         // `String` and does not give us a chance to handle OOM. Instead, use
10633a3a2ddSNick Fitzgerald         // `deserialize_str` which passes the visitor the borrowed `str`, giving
10733a3a2ddSNick Fitzgerald         // us a chance to fallibly allocate space.
10833a3a2ddSNick Fitzgerald         deserializer.deserialize_str(Visitor)
10933a3a2ddSNick Fitzgerald     }
11033a3a2ddSNick Fitzgerald }
11133a3a2ddSNick Fitzgerald 
112bf42bd4fSNick Fitzgerald impl String {
113bf42bd4fSNick Fitzgerald     /// Same as [`std::string::String::new`].
114bf42bd4fSNick Fitzgerald     #[inline]
115bf42bd4fSNick Fitzgerald     pub fn new() -> Self {
116bf42bd4fSNick Fitzgerald         Self {
117bf42bd4fSNick Fitzgerald             inner: inner::String::new(),
118bf42bd4fSNick Fitzgerald         }
119bf42bd4fSNick Fitzgerald     }
120bf42bd4fSNick Fitzgerald 
121bf42bd4fSNick Fitzgerald     /// Same as [`std::string::String::with_capacity`] but returns an error on
122bf42bd4fSNick Fitzgerald     /// allocation failure.
123bf42bd4fSNick Fitzgerald     #[inline]
124bf42bd4fSNick Fitzgerald     pub fn with_capacity(capacity: usize) -> Result<Self, OutOfMemory> {
125bf42bd4fSNick Fitzgerald         let mut s = Self::new();
126bf42bd4fSNick Fitzgerald         s.reserve(capacity)?;
127bf42bd4fSNick Fitzgerald         Ok(s)
128bf42bd4fSNick Fitzgerald     }
129bf42bd4fSNick Fitzgerald 
1300c673b70SNick Fitzgerald     /// Same as [`std::string::String::capacity`].
1310c673b70SNick Fitzgerald     #[inline]
1320c673b70SNick Fitzgerald     pub fn capacity(&self) -> usize {
1330c673b70SNick Fitzgerald         self.inner.capacity()
1340c673b70SNick Fitzgerald     }
1350c673b70SNick Fitzgerald 
136285a6dc6SNick Fitzgerald     /// Same as [`std::string::String::as_str`].
137285a6dc6SNick Fitzgerald     #[inline]
138285a6dc6SNick Fitzgerald     pub const fn as_str(&self) -> &str {
139285a6dc6SNick Fitzgerald         self.inner.as_str()
140285a6dc6SNick Fitzgerald     }
141285a6dc6SNick Fitzgerald 
142bf42bd4fSNick Fitzgerald     /// Same as [`std::string::String::reserve`] but returns an error on
143bf42bd4fSNick Fitzgerald     /// allocation failure.
144bf42bd4fSNick Fitzgerald     #[inline]
145bf42bd4fSNick Fitzgerald     pub fn reserve(&mut self, additional: usize) -> Result<(), OutOfMemory> {
146bf42bd4fSNick Fitzgerald         self.inner
147bf42bd4fSNick Fitzgerald             .try_reserve(additional)
148bf42bd4fSNick Fitzgerald             .map_err(|_| OutOfMemory::new(self.len().saturating_add(additional)))
149bf42bd4fSNick Fitzgerald     }
150bf42bd4fSNick Fitzgerald 
151bf42bd4fSNick Fitzgerald     /// Same as [`std::string::String::reserve_exact`] but returns an error on
152bf42bd4fSNick Fitzgerald     /// allocation failure.
153bf42bd4fSNick Fitzgerald     #[inline]
154bf42bd4fSNick Fitzgerald     pub fn reserve_exact(&mut self, additional: usize) -> Result<(), OutOfMemory> {
155bf42bd4fSNick Fitzgerald         self.inner
156bf42bd4fSNick Fitzgerald             .try_reserve_exact(additional)
157bf42bd4fSNick Fitzgerald             .map_err(|_| OutOfMemory::new(self.len().saturating_add(additional)))
158bf42bd4fSNick Fitzgerald     }
159bf42bd4fSNick Fitzgerald 
160bf42bd4fSNick Fitzgerald     /// Same as [`std::string::String::push`] but returns an error on allocation
161bf42bd4fSNick Fitzgerald     /// failure.
162bf42bd4fSNick Fitzgerald     #[inline]
163bf42bd4fSNick Fitzgerald     pub fn push(&mut self, c: char) -> Result<(), OutOfMemory> {
164bf42bd4fSNick Fitzgerald         self.reserve(c.len_utf8())?;
165bf42bd4fSNick Fitzgerald         self.inner.push(c);
166bf42bd4fSNick Fitzgerald         Ok(())
167bf42bd4fSNick Fitzgerald     }
168bf42bd4fSNick Fitzgerald 
169bf42bd4fSNick Fitzgerald     /// Same as [`std::string::String::push_str`] but returns an error on
170bf42bd4fSNick Fitzgerald     /// allocation failure.
171bf42bd4fSNick Fitzgerald     #[inline]
172bf42bd4fSNick Fitzgerald     pub fn push_str(&mut self, s: &str) -> Result<(), OutOfMemory> {
173bf42bd4fSNick Fitzgerald         self.reserve(s.len())?;
174bf42bd4fSNick Fitzgerald         self.inner.push_str(s);
175bf42bd4fSNick Fitzgerald         Ok(())
176bf42bd4fSNick Fitzgerald     }
1770c673b70SNick Fitzgerald 
1780c673b70SNick Fitzgerald     /// Same as [`std::string::String::into_raw_parts`].
1790c673b70SNick Fitzgerald     pub fn into_raw_parts(mut self) -> (*mut u8, usize, usize) {
1800c673b70SNick Fitzgerald         // NB: Can't use `String::into_raw_parts` until our MSRV is >= 1.93.
1810c673b70SNick Fitzgerald         #[cfg(not(miri))]
1820c673b70SNick Fitzgerald         {
1830c673b70SNick Fitzgerald             let ptr = self.as_mut_ptr();
1840c673b70SNick Fitzgerald             let len = self.len();
1850c673b70SNick Fitzgerald             let cap = self.capacity();
1860c673b70SNick Fitzgerald             mem::forget(self);
1870c673b70SNick Fitzgerald             (ptr, len, cap)
1880c673b70SNick Fitzgerald         }
1890c673b70SNick Fitzgerald         // NB: Miri requires using `into_raw_parts`, but always run on nightly,
1900c673b70SNick Fitzgerald         // so it's fine to use there.
1910c673b70SNick Fitzgerald         #[cfg(miri)]
1920c673b70SNick Fitzgerald         {
1930c673b70SNick Fitzgerald             let _ = &mut self;
1940c673b70SNick Fitzgerald             self.inner.into_raw_parts()
1950c673b70SNick Fitzgerald         }
1960c673b70SNick Fitzgerald     }
1970c673b70SNick Fitzgerald 
1980c673b70SNick Fitzgerald     /// Same as [`std::string::String::from_raw_parts`].
1990c673b70SNick Fitzgerald     pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> Self {
2000c673b70SNick Fitzgerald         Self {
2010c673b70SNick Fitzgerald             // Safety: Same as our unsafe contract.
2020c673b70SNick Fitzgerald             inner: unsafe { inner::String::from_raw_parts(buf, length, capacity) },
2030c673b70SNick Fitzgerald         }
2040c673b70SNick Fitzgerald     }
2050c673b70SNick Fitzgerald 
2060c673b70SNick Fitzgerald     /// Same as [`std::string::String::shrink_to_fit`] but returns an error on
2070c673b70SNick Fitzgerald     /// allocation failure.
2080c673b70SNick Fitzgerald     pub fn shrink_to_fit(&mut self) -> Result<(), OutOfMemory> {
2090c673b70SNick Fitzgerald         // If our length is already equal to our capacity, then there is nothing
2100c673b70SNick Fitzgerald         // to shrink.
2110c673b70SNick Fitzgerald         if self.len() == self.capacity() {
2120c673b70SNick Fitzgerald             return Ok(());
2130c673b70SNick Fitzgerald         }
2140c673b70SNick Fitzgerald 
2150c673b70SNick Fitzgerald         // `realloc` requires a non-zero original layout as well as a non-zero
2160c673b70SNick Fitzgerald         // destination layout, so this guard ensures that the sizes below are
2170c673b70SNick Fitzgerald         // all nonzero. This handles a couple cases:
2180c673b70SNick Fitzgerald         //
2190c673b70SNick Fitzgerald         // * If `len == cap == 0` then no allocation has ever been made.
2200c673b70SNick Fitzgerald         // * If `len == 0` and `cap != 0` then this function effectively frees
2210c673b70SNick Fitzgerald         //   the memory.
2220c673b70SNick Fitzgerald         //
2230c673b70SNick Fitzgerald         // In both of these cases delegate to the standard library's
2240c673b70SNick Fitzgerald         // `shrink_to_fit` which is guaranteed to not perform a `realloc`.
2250c673b70SNick Fitzgerald         if self.is_empty() {
2260c673b70SNick Fitzgerald             self.inner.shrink_to_fit();
2270c673b70SNick Fitzgerald             return Ok(());
2280c673b70SNick Fitzgerald         }
2290c673b70SNick Fitzgerald 
2300c673b70SNick Fitzgerald         let (ptr, len, cap) = mem::take(self).into_raw_parts();
2310c673b70SNick Fitzgerald         debug_assert!(!ptr.is_null());
2320c673b70SNick Fitzgerald         debug_assert!(len > 0);
2330c673b70SNick Fitzgerald         debug_assert!(cap > len);
2340c673b70SNick Fitzgerald         let old_layout = Layout::array::<u8>(cap).unwrap();
2350c673b70SNick Fitzgerald         debug_assert_eq!(old_layout.size(), cap);
2360c673b70SNick Fitzgerald         let new_layout = Layout::array::<u8>(len).unwrap();
2370c673b70SNick Fitzgerald         debug_assert_eq!(old_layout.align(), new_layout.align());
2380c673b70SNick Fitzgerald         debug_assert_eq!(new_layout.size(), len);
2390c673b70SNick Fitzgerald 
2400c673b70SNick Fitzgerald         // SAFETY: `ptr` was previously allocated in the global allocator,
2410c673b70SNick Fitzgerald         // `layout` has a nonzero size and matches the current allocation of
2420c673b70SNick Fitzgerald         // `ptr`, `len` is nonzero, and `len` is a valid array size
2430c673b70SNick Fitzgerald         // for `len` elements given its constructor.
2440c673b70SNick Fitzgerald         let result = unsafe { try_realloc(ptr, old_layout, len) };
2450c673b70SNick Fitzgerald 
2460c673b70SNick Fitzgerald         match result {
2470c673b70SNick Fitzgerald             Ok(ptr) => {
2480c673b70SNick Fitzgerald                 // SAFETY: `result` is allocated with the global allocator and
2490c673b70SNick Fitzgerald                 // has room for exactly `[u8; len]`.
2500c673b70SNick Fitzgerald                 *self = unsafe { Self::from_raw_parts(ptr.as_ptr(), len, len) };
2510c673b70SNick Fitzgerald                 Ok(())
2520c673b70SNick Fitzgerald             }
2530c673b70SNick Fitzgerald             Err(oom) => {
2540c673b70SNick Fitzgerald                 // SAFETY: If reallocation fails then it's guaranteed that the
2550c673b70SNick Fitzgerald                 // original allocation is not tampered with, so it's safe to
2560c673b70SNick Fitzgerald                 // reassemble the original vector.
2570c673b70SNick Fitzgerald                 *self = unsafe { Self::from_raw_parts(ptr, len, cap) };
2580c673b70SNick Fitzgerald                 Err(oom)
2590c673b70SNick Fitzgerald             }
2600c673b70SNick Fitzgerald         }
2610c673b70SNick Fitzgerald     }
2620c673b70SNick Fitzgerald 
2630c673b70SNick Fitzgerald     /// Same as [`std::string::String::into_boxed_str`] but returns an error on
2640c673b70SNick Fitzgerald     /// allocation failure.
2650c673b70SNick Fitzgerald     pub fn into_boxed_str(mut self) -> Result<Box<str>, OutOfMemory> {
2660c673b70SNick Fitzgerald         self.shrink_to_fit()?;
2670c673b70SNick Fitzgerald 
2680c673b70SNick Fitzgerald         let (ptr, len, cap) = self.into_raw_parts();
2690c673b70SNick Fitzgerald         debug_assert_eq!(len, cap);
2700c673b70SNick Fitzgerald         let ptr = str_ptr_from_raw_parts(ptr, len);
2710c673b70SNick Fitzgerald 
2720c673b70SNick Fitzgerald         // SAFETY: The `ptr` is allocated with the global allocator and points
2730c673b70SNick Fitzgerald         // to a valid block of utf8.
2740c673b70SNick Fitzgerald         let boxed = unsafe { Box::from_raw(ptr) };
2750c673b70SNick Fitzgerald 
2760c673b70SNick Fitzgerald         Ok(boxed)
2770c673b70SNick Fitzgerald     }
278bf42bd4fSNick Fitzgerald }
279