Path: blob/main/crates/core/src/alloc/string.rs
3073 views
use crate::{1alloc::{TryClone, str_ptr_from_raw_parts, try_realloc},2error::OutOfMemory,3};4use core::{fmt, mem, ops};5use std_alloc::{alloc::Layout, boxed::Box, string as inner};67/// A newtype wrapper around [`std::string::String`] that only exposes8/// fallible-allocation methods.9#[derive(Default)]10pub struct String {11inner: inner::String,12}1314impl TryClone for String {15fn try_clone(&self) -> Result<Self, OutOfMemory> {16let mut s = Self::new();17s.push_str(self)?;18Ok(s)19}20}2122impl fmt::Debug for String {23fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {24fmt::Debug::fmt(&self.inner, f)25}26}2728impl fmt::Display for String {29fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {30fmt::Display::fmt(&self.inner, f)31}32}3334impl ops::Deref for String {35type Target = str;3637#[inline]38fn deref(&self) -> &Self::Target {39&self.inner40}41}4243impl ops::DerefMut for String {44#[inline]45fn deref_mut(&mut self) -> &mut Self::Target {46&mut self.inner47}48}4950impl From<inner::String> for String {51#[inline]52fn from(inner: inner::String) -> Self {53Self { inner }54}55}5657impl String {58/// Same as [`std::string::String::new`].59#[inline]60pub fn new() -> Self {61Self {62inner: inner::String::new(),63}64}6566/// Same as [`std::string::String::with_capacity`] but returns an error on67/// allocation failure.68#[inline]69pub fn with_capacity(capacity: usize) -> Result<Self, OutOfMemory> {70let mut s = Self::new();71s.reserve(capacity)?;72Ok(s)73}7475/// Same as [`std::string::String::capacity`].76#[inline]77pub fn capacity(&self) -> usize {78self.inner.capacity()79}8081/// Same as [`std::string::String::reserve`] but returns an error on82/// allocation failure.83#[inline]84pub fn reserve(&mut self, additional: usize) -> Result<(), OutOfMemory> {85self.inner86.try_reserve(additional)87.map_err(|_| OutOfMemory::new(self.len().saturating_add(additional)))88}8990/// Same as [`std::string::String::reserve_exact`] but returns an error on91/// allocation failure.92#[inline]93pub fn reserve_exact(&mut self, additional: usize) -> Result<(), OutOfMemory> {94self.inner95.try_reserve_exact(additional)96.map_err(|_| OutOfMemory::new(self.len().saturating_add(additional)))97}9899/// Same as [`std::string::String::push`] but returns an error on allocation100/// failure.101#[inline]102pub fn push(&mut self, c: char) -> Result<(), OutOfMemory> {103self.reserve(c.len_utf8())?;104self.inner.push(c);105Ok(())106}107108/// Same as [`std::string::String::push_str`] but returns an error on109/// allocation failure.110#[inline]111pub fn push_str(&mut self, s: &str) -> Result<(), OutOfMemory> {112self.reserve(s.len())?;113self.inner.push_str(s);114Ok(())115}116117/// Same as [`std::string::String::into_raw_parts`].118pub fn into_raw_parts(mut self) -> (*mut u8, usize, usize) {119// NB: Can't use `String::into_raw_parts` until our MSRV is >= 1.93.120#[cfg(not(miri))]121{122let ptr = self.as_mut_ptr();123let len = self.len();124let cap = self.capacity();125mem::forget(self);126(ptr, len, cap)127}128// NB: Miri requires using `into_raw_parts`, but always run on nightly,129// so it's fine to use there.130#[cfg(miri)]131{132let _ = &mut self;133self.inner.into_raw_parts()134}135}136137/// Same as [`std::string::String::from_raw_parts`].138pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> Self {139Self {140// Safety: Same as our unsafe contract.141inner: unsafe { inner::String::from_raw_parts(buf, length, capacity) },142}143}144145/// Same as [`std::string::String::shrink_to_fit`] but returns an error on146/// allocation failure.147pub fn shrink_to_fit(&mut self) -> Result<(), OutOfMemory> {148// If our length is already equal to our capacity, then there is nothing149// to shrink.150if self.len() == self.capacity() {151return Ok(());152}153154// `realloc` requires a non-zero original layout as well as a non-zero155// destination layout, so this guard ensures that the sizes below are156// all nonzero. This handles a couple cases:157//158// * If `len == cap == 0` then no allocation has ever been made.159// * If `len == 0` and `cap != 0` then this function effectively frees160// the memory.161//162// In both of these cases delegate to the standard library's163// `shrink_to_fit` which is guaranteed to not perform a `realloc`.164if self.is_empty() {165self.inner.shrink_to_fit();166return Ok(());167}168169let (ptr, len, cap) = mem::take(self).into_raw_parts();170debug_assert!(!ptr.is_null());171debug_assert!(len > 0);172debug_assert!(cap > len);173let old_layout = Layout::array::<u8>(cap).unwrap();174debug_assert_eq!(old_layout.size(), cap);175let new_layout = Layout::array::<u8>(len).unwrap();176debug_assert_eq!(old_layout.align(), new_layout.align());177debug_assert_eq!(new_layout.size(), len);178179// SAFETY: `ptr` was previously allocated in the global allocator,180// `layout` has a nonzero size and matches the current allocation of181// `ptr`, `len` is nonzero, and `len` is a valid array size182// for `len` elements given its constructor.183let result = unsafe { try_realloc(ptr, old_layout, len) };184185match result {186Ok(ptr) => {187// SAFETY: `result` is allocated with the global allocator and188// has room for exactly `[u8; len]`.189*self = unsafe { Self::from_raw_parts(ptr.as_ptr(), len, len) };190Ok(())191}192Err(oom) => {193// SAFETY: If reallocation fails then it's guaranteed that the194// original allocation is not tampered with, so it's safe to195// reassemble the original vector.196*self = unsafe { Self::from_raw_parts(ptr, len, cap) };197Err(oom)198}199}200}201202/// Same as [`std::string::String::into_boxed_str`] but returns an error on203/// allocation failure.204pub fn into_boxed_str(mut self) -> Result<Box<str>, OutOfMemory> {205self.shrink_to_fit()?;206207let (ptr, len, cap) = self.into_raw_parts();208debug_assert_eq!(len, cap);209let ptr = str_ptr_from_raw_parts(ptr, len);210211// SAFETY: The `ptr` is allocated with the global allocator and points212// to a valid block of utf8.213let boxed = unsafe { Box::from_raw(ptr) };214215Ok(boxed)216}217}218219220