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