#[cfg(any(test, doc, feature = "alloc"))]
use alloc::string::String;
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, rc::Rc, sync::Arc};
#[cfg(any(test, feature = "alloc"))]
use core::convert::Infallible;
use core::ops::Deref;
#[cfg(feature = "arrayvec")]
use arrayvec::{ArrayString, CapacityError};
pub trait Stringy: Default + Deref<Target = str> + AsRef<str> {
type Error;
fn new() -> Self {
Default::default()
}
fn reserve_back(&mut self, additional: usize);
unsafe fn reserve_front(&mut self, additional: usize) -> Result<&mut [u8], Self::Error>;
fn truncate_back(&mut self, len: usize);
fn remove_front(&mut self, len: usize);
fn push_back(&mut self, s: &str) -> Result<(), Self::Error>;
fn push_front(&mut self, s: &str) -> Result<(), Self::Error>;
fn push_back_many(&mut self, s: &[&str]) -> Result<(), Self::Error> {
self.reserve_back(s.iter().copied().map(str::len).sum());
s.iter().try_for_each(|s| self.push_back(s))
}
fn push_front_many(&mut self, s: &[&str]) -> Result<(), Self::Error> {
unsafe {
let mut bytes = self.reserve_front(s.iter().copied().map(str::len).sum())?;
for &s in s.iter() {
let (lo, hi) = bytes.split_at_mut_unchecked(s.len());
lo.copy_from_slice(s.as_bytes());
bytes = hi;
}
Ok(())
}
}
}
#[cfg(any(test, feature = "alloc"))]
impl Stringy for String {
type Error = Infallible;
#[inline]
fn reserve_back(&mut self, additional: usize) {
self.reserve(additional);
}
#[inline]
unsafe fn reserve_front(&mut self, additional: usize) -> Result<&mut [u8], Infallible> {
self.reserve(additional);
unsafe {
let vec = self.as_mut_vec();
let orig_len = vec.len();
vec.set_len(vec.len() + additional);
vec.copy_within(0..orig_len, additional);
Ok(&mut vec[..additional])
}
}
#[inline]
fn truncate_back(&mut self, len: usize) {
assert!(self.is_char_boundary(len));
self.truncate(len);
}
#[inline]
fn remove_front(&mut self, len: usize) {
self.drain(..len);
}
#[inline]
fn push_back(&mut self, s: &str) -> Result<(), Infallible> {
self.push_str(s);
Ok(())
}
#[inline]
fn push_front(&mut self, s: &str) -> Result<(), Infallible> {
self.insert_str(0, s);
Ok(())
}
}
#[cfg(feature = "arrayvec")]
impl<const N: usize> Stringy for ArrayString<N> {
type Error = CapacityError;
#[inline]
fn reserve_back(&mut self, _: usize) {}
#[inline]
unsafe fn reserve_front(&mut self, additional: usize) -> Result<&mut [u8], CapacityError> {
if additional > self.remaining_capacity() {
return Err(CapacityError::new(()));
}
unsafe {
self.set_len(self.len() + additional);
let bytes = self.as_bytes_mut();
bytes.copy_within(0.., additional);
Ok(&mut bytes[..additional])
}
}
#[inline]
fn truncate_back(&mut self, len: usize) {
assert!(self.is_char_boundary(len));
self.truncate(len);
}
#[inline]
fn remove_front(&mut self, len: usize) {
assert!(self.is_char_boundary(len));
unsafe {
self.as_bytes_mut().copy_within(len.., 0);
self.set_len(self.len() - len);
}
}
#[inline]
fn push_back(&mut self, s: &str) -> Result<(), CapacityError> {
self.try_push_str(s).map_err(CapacityError::simplify)
}
#[inline]
fn push_front(&mut self, s: &str) -> Result<(), CapacityError> {
unsafe {
self.reserve_front(s.len())?.copy_from_slice(s.as_bytes());
}
Ok(())
}
}
pub trait Stringable: From<Self::Builder> + Deref<Target = str> + AsRef<str> {
type Builder: Stringy;
fn from_str(s: &str) -> Result<Self, <Self::Builder as Stringy>::Error> {
let mut string = Self::Builder::new();
string.push_back(s)?;
Ok(string.into())
}
fn from_many(s: &[&str]) -> Result<Self, <Self::Builder as Stringy>::Error> {
let mut string = Self::Builder::new();
string.push_back_many(s)?;
Ok(string.into())
}
}
impl<T: Stringy> Stringable for T {
type Builder = T;
}
#[cfg(feature = "alloc")]
impl Stringable for Box<str> {
type Builder = String;
}
#[cfg(feature = "alloc")]
impl Stringable for Rc<str> {
type Builder = String;
}
#[cfg(feature = "alloc")]
impl Stringable for Arc<str> {
type Builder = String;
}