use core::str::Utf8Error;
use std::mem::MaybeUninit;
use generic_vec::{
raw::{AllocResult, Storage, StorageWithCapacity},
ArrayVec, GenericVec,
};
#[cfg(feature = "alloc")]
use std::alloc::{Allocator, Global};
use crate::{string_base::StringBase, OwnedString};
#[cfg(feature = "alloc")]
pub type String<A = Global> = OwnedString<u8, Box<[MaybeUninit<u8>], A>>;
pub type ArrayString<const N: usize> = OwnedString<u8, [MaybeUninit<u8>; N]>;
#[cfg(feature = "alloc")]
impl String {
#[inline]
pub fn new() -> Self {
Self::with_storage(Box::default())
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self::new_with_capacity(capacity)
}
}
#[cfg(feature = "alloc")]
impl<A: Allocator> String<A> {
pub fn with_alloc(alloc: A) -> Self {
Self::with_storage(Box::new_uninit_slice_in(0, alloc))
}
}
impl<const N: usize> ArrayString<N> {
#[inline]
pub fn new() -> Self {
Self {
storage: ArrayVec::new(),
}
}
}
#[derive(PartialEq, Eq)]
pub struct FromUtf8Error<S: Storage<Item = u8>> {
bytes: GenericVec<u8, S>,
error: Utf8Error,
}
use core::fmt;
impl<S: Storage<Item = u8>> fmt::Debug for FromUtf8Error<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("FromUtf8Error")
.field("bytes", &self.bytes)
.field("error", &self.error)
.finish()
}
}
impl<S: ?Sized + Storage<Item = u8>> OwnedString<u8, S> {
#[inline]
pub fn from_utf8(vec: GenericVec<S::Item, S>) -> Result<Self, FromUtf8Error<S>>
where
S: Sized,
{
match core::str::from_utf8(&vec) {
Ok(..) => Ok(Self { storage: vec }),
Err(e) => Err(FromUtf8Error {
bytes: vec,
error: e,
}),
}
}
#[inline]
pub unsafe fn from_utf8_unchecked(vec: GenericVec<S::Item, S>) -> Self
where
S: Sized,
{
Self { storage: vec }
}
#[inline]
pub fn into_bytes(self) -> GenericVec<S::Item, S>
where
S: Sized,
{
self.storage
}
#[inline]
pub fn as_str(&self) -> &crate::str {
self
}
#[inline]
pub fn as_mut_str(&mut self) -> &mut crate::str {
self
}
#[inline]
pub fn push_str(&mut self, string: &crate::str) {
self.storage.extend_from_slice(&string.storage)
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.storage.reserve(additional)
}
pub fn try_reserve(&mut self, additional: usize) -> AllocResult {
self.storage.try_reserve(additional)
}
#[inline]
pub fn push(&mut self, ch: char) {
match ch.len_utf8() {
1 => {
self.storage.push(ch as u8);
}
_ => self
.storage
.extend_from_slice(ch.encode_utf8(&mut [0; 4]).as_bytes()),
}
}
#[inline]
pub fn pop(&mut self) -> Option<char> {
let ch = self.chars().rev().next()?;
let newlen = self.len() - ch.len_utf8();
unsafe {
self.storage.set_len_unchecked(newlen);
}
Some(ch)
}
#[inline]
pub fn truncate(&mut self, new_len: usize) {
if new_len <= self.len() {
assert!(self.is_char_boundary(new_len));
self.storage.truncate(new_len)
}
}
#[inline]
pub fn remove(&mut self, idx: usize) -> char {
let ch = match self[idx..].chars().next() {
Some(ch) => ch,
None => panic!("cannot remove a char from the end of a string"),
};
let next = idx + ch.len_utf8();
let len = self.len();
unsafe {
core::ptr::copy(
self.storage.as_ptr().add(next),
self.storage.as_mut_ptr().add(idx),
len - next,
);
self.storage.set_len_unchecked(len - (next - idx));
}
ch
}
#[inline]
pub fn insert(&mut self, idx: usize, ch: char) {
assert!(self.is_char_boundary(idx));
let mut bits = [0; 4];
let bits = ch.encode_utf8(&mut bits).as_bytes();
unsafe {
self.insert_bytes(idx, bits);
}
}
unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
let len = self.len();
let amt = bytes.len();
self.storage.reserve(amt);
core::ptr::copy(
self.storage.as_ptr().add(idx),
self.storage.as_mut_ptr().add(idx + amt),
len - idx,
);
core::ptr::copy(bytes.as_ptr(), self.storage.as_mut_ptr().add(idx), amt);
self.storage.set_len_unchecked(len + amt);
}
#[inline]
pub fn insert_str(&mut self, idx: usize, string: &str) {
assert!(self.is_char_boundary(idx));
unsafe {
self.insert_bytes(idx, string.as_bytes());
}
}
#[inline]
pub unsafe fn as_mut_vec(&mut self) -> &mut GenericVec<S::Item, S> {
&mut self.storage
}
#[inline]
#[must_use = "use `.truncate()` if you don't need the other half"]
pub fn split_off<B: ?Sized + StorageWithCapacity<Item = u8>>(
&mut self,
at: usize,
) -> StringBase<GenericVec<S::Item, B>> {
assert!(self.is_char_boundary(at));
let other = self.storage.split_off(at);
unsafe { StringBase::from_utf8_unchecked(other) }
}
#[inline]
pub fn clear(&mut self) {
self.storage.clear()
}
#[inline]
pub fn capacity(&self) -> usize {
self.storage.capacity()
}
}