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