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