use crate::StackVec;
#[cfg(feature = "std")]
use std::borrow::Cow;
use std::borrow::{Borrow, BorrowMut};
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::ops::{Add, AddAssign, Deref, DerefMut};
use std::str::{FromStr, Utf8Error};
use std::{fmt, ptr, str};
#[cfg_attr(docsrs, doc(cfg(feature = "str")))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FromUtf8Error<const N: usize> {
bytes: StackVec<u8, N>,
error: Utf8Error,
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
impl<const N: usize> std::error::Error for FromUtf8Error<N> {}
impl<const N: usize> fmt::Display for FromUtf8Error<N> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.error, f)
}
}
impl<const N: usize> FromUtf8Error<N> {
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.bytes[..]
}
#[inline]
pub fn into_bytes(self) -> StackVec<u8, N> {
self.bytes
}
#[inline]
pub const fn utf8_error(&self) -> Utf8Error {
self.error
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "str")))]
pub struct StackStr<const N: usize> {
vec: StackVec<u8, N>,
}
impl<const N: usize> StackStr<N> {
#[inline]
pub const fn new() -> Self {
StackStr {
vec: StackVec::new(),
}
}
#[inline]
pub fn from_utf8(vec: StackVec<u8, N>) -> Result<Self, FromUtf8Error<N>> {
match str::from_utf8(&vec) {
Ok(..) => Ok(StackStr { vec }),
Err(e) => Err(FromUtf8Error {
bytes: vec,
error: e,
}),
}
}
#[inline]
pub const unsafe fn from_utf8_unchecked(bytes: StackVec<u8, N>) -> Self {
StackStr { vec: bytes }
}
#[inline]
pub fn into_bytes(self) -> StackVec<u8, N> {
self.vec
}
#[inline]
pub const fn len(&self) -> usize {
self.vec.len()
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub const fn is_full(&self) -> bool {
self.len() == self.capacity()
}
#[inline]
pub const fn capacity(&self) -> usize {
self.vec.capacity()
}
#[inline]
pub const fn remaining_capacity(&self) -> usize {
self.capacity() - self.len()
}
#[inline]
pub unsafe fn set_len(&mut self, length: usize) {
self.vec.set_len(length);
}
#[inline]
pub fn as_str(&self) -> &str {
self
}
#[inline]
pub fn as_mut_str(&mut self) -> &mut str {
self
}
#[inline(always)]
pub const fn as_ptr(&self) -> *const u8 {
self.vec.as_ptr() as _
}
#[inline(always)]
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.vec.as_mut_ptr() as _
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.vec
}
#[inline]
pub unsafe fn as_mut_vec(&mut self) -> &mut StackVec<u8, N> {
&mut self.vec
}
#[inline]
pub fn push_str(&mut self, string: &str) {
self.vec.copy_from_slice(string.as_bytes())
}
#[inline]
pub fn push(&mut self, ch: char) {
match ch.len_utf8() {
1 => self.vec.push(ch as u8),
_ => self
.vec
.copy_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 new_len = self.len() - ch.len_utf8();
unsafe {
self.vec.set_len(new_len);
}
Some(ch)
}
#[inline]
pub fn truncate(&mut self, new_len: usize) {
if new_len <= self.len() {
assert!(self.is_char_boundary(new_len));
unsafe { self.set_len(new_len) }
}
}
#[inline]
pub fn clear(&mut self) {
unsafe {
self.set_len(0);
}
}
#[inline]
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(char) -> bool,
{
let len = self.len();
let mut del_bytes = 0;
let mut idx = 0;
unsafe {
self.vec.set_len(0);
}
while idx < len {
let ch = unsafe { self.get_unchecked(idx..len).chars().next().unwrap() };
let ch_len = ch.len_utf8();
if !f(ch) {
del_bytes += ch_len;
} else if del_bytes > 0 {
unsafe {
ptr::copy(
self.vec.as_ptr().add(idx),
self.vec.as_mut_ptr().add(idx - del_bytes),
ch_len,
);
}
}
idx += ch_len;
}
unsafe {
self.vec.set_len(len - del_bytes);
}
}
#[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();
assert!(self.vec.remaining_capacity() >= amt);
ptr::copy(
self.vec.as_ptr().add(idx),
self.vec.as_mut_ptr().add(idx + amt),
len - idx,
);
ptr::copy(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt);
self.vec.set_len(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 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 StackStr"),
};
let next = idx + ch.len_utf8();
let len = self.len();
unsafe {
ptr::copy(
self.vec.as_ptr().add(next),
self.vec.as_mut_ptr().add(idx),
len - next,
);
self.vec.set_len(len - (next - idx));
}
ch
}
}
impl<const N: usize> Clone for StackStr<N> {
#[inline]
fn clone(&self) -> Self {
let mut vec = StackVec::new();
vec.copy_from_slice(&self.vec);
StackStr { vec }
}
#[inline]
fn clone_from(&mut self, source: &Self) {
self.clear();
self.vec.copy_from_slice(&source.vec);
}
}
impl<const N: usize> Deref for StackStr<N> {
type Target = str;
#[inline(always)]
fn deref(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(self.vec.as_slice()) }
}
}
impl<const N: usize> DerefMut for StackStr<N> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut str {
unsafe { std::str::from_utf8_unchecked_mut(self.vec.as_mut_slice()) }
}
}
impl<const N: usize> AsRef<str> for StackStr<N> {
#[inline(always)]
fn as_ref(&self) -> &str {
self
}
}
impl<const N: usize> AsMut<str> for StackStr<N> {
#[inline(always)]
fn as_mut(&mut self) -> &mut str {
self
}
}
impl<const N: usize> AsRef<[u8]> for StackStr<N> {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl<const N: usize> Borrow<str> for StackStr<N> {
#[inline(always)]
fn borrow(&self) -> &str {
self
}
}
impl<const N: usize> BorrowMut<str> for StackStr<N> {
#[inline(always)]
fn borrow_mut(&mut self) -> &mut str {
self
}
}
impl<const N: usize> Borrow<[u8]> for StackStr<N> {
#[inline(always)]
fn borrow(&self) -> &[u8] {
self.as_bytes()
}
}
impl<const N: usize> Default for StackStr<N> {
#[inline(always)]
fn default() -> StackStr<N> {
StackStr::new()
}
}
impl<const N: usize> fmt::Debug for StackStr<N> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt(f)
}
}
impl<const N: usize> fmt::Display for StackStr<N> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt(f)
}
}
impl<const N: usize> fmt::Write for StackStr<N> {
#[inline]
fn write_str(&mut self, s: &str) -> fmt::Result {
self.push_str(s);
Ok(())
}
}
impl<const N1: usize, const N2: usize> PartialEq<StackStr<N2>> for StackStr<N1> {
#[inline]
fn eq(&self, other: &StackStr<N2>) -> bool {
**self == **other
}
}
impl<const N: usize> PartialEq<str> for StackStr<N> {
#[inline]
fn eq(&self, other: &str) -> bool {
&**self == other
}
}
impl<const N: usize> PartialEq<StackStr<N>> for str {
#[inline]
fn eq(&self, other: &StackStr<N>) -> bool {
self == &**other
}
}
impl<const N: usize> PartialEq<&str> for StackStr<N> {
#[inline]
fn eq(&self, other: &&str) -> bool {
&**self == *other
}
}
impl<const N: usize> PartialEq<StackStr<N>> for &str {
#[inline]
fn eq(&self, other: &StackStr<N>) -> bool {
*self == &**other
}
}
impl<const N: usize> Eq for StackStr<N> {}
impl<const N1: usize, const N2: usize> PartialOrd<StackStr<N2>> for StackStr<N1> {
#[inline]
fn partial_cmp(&self, other: &StackStr<N2>) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
}
impl<const N: usize> PartialOrd<str> for StackStr<N> {
#[inline]
fn partial_cmp(&self, other: &str) -> Option<Ordering> {
(**self).partial_cmp(other)
}
}
impl<const N: usize> PartialOrd<StackStr<N>> for str {
#[inline]
fn partial_cmp(&self, other: &StackStr<N>) -> Option<Ordering> {
self.partial_cmp(&**other)
}
}
impl<const N: usize> PartialOrd<&str> for StackStr<N> {
#[inline]
fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
(**self).partial_cmp(*other)
}
}
impl<const N: usize> PartialOrd<StackStr<N>> for &str {
#[inline]
fn partial_cmp(&self, other: &StackStr<N>) -> Option<Ordering> {
(*self).partial_cmp(&**other)
}
}
impl<const N: usize> Ord for StackStr<N> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
(**self).cmp(&**other)
}
}
impl<const N: usize> Extend<char> for StackStr<N> {
#[inline]
fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
let iterator = iter.into_iter();
iterator.for_each(move |c| self.push(c));
}
}
impl<'a, const N: usize> Extend<&'a char> for StackStr<N> {
#[inline]
fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
self.extend(iter.into_iter().cloned());
}
}
impl<'a, const N: usize> Extend<&'a str> for StackStr<N> {
#[inline]
fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
iter.into_iter().for_each(move |s| self.push_str(s));
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
impl<const N: usize> Extend<Box<str>> for StackStr<N> {
#[inline]
fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
iter.into_iter().for_each(move |s| self.push_str(&s));
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
impl<const N: usize> Extend<String> for StackStr<N> {
#[inline]
fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
iter.into_iter().for_each(move |s| self.push_str(&s));
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
impl<'a, const N: usize> Extend<Cow<'a, str>> for StackStr<N> {
#[inline]
fn extend<I: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: I) {
iter.into_iter().for_each(move |s| self.push_str(&s));
}
}
impl<const N: usize> FromIterator<char> for StackStr<N> {
#[inline]
fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> Self {
let mut buf = StackStr::new();
buf.extend(iter);
buf
}
}
impl<'a, const N: usize> FromIterator<&'a char> for StackStr<N> {
#[inline]
fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> Self {
let mut buf = StackStr::new();
buf.extend(iter);
buf
}
}
impl<'a, const N: usize> FromIterator<&'a str> for StackStr<N> {
#[inline]
fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> Self {
let mut buf = StackStr::new();
buf.extend(iter);
buf
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
impl<const N: usize> FromIterator<String> for StackStr<N> {
#[inline]
fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
let mut buf = StackStr::new();
buf.extend(iter);
buf
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
impl<const N: usize> FromIterator<Box<str>> for StackStr<N> {
#[inline]
fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> Self {
let mut buf = StackStr::new();
buf.extend(iter);
buf
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
impl<'a, const N: usize> FromIterator<Cow<'a, str>> for StackStr<N> {
#[inline]
fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> Self {
let mut buf = StackStr::new();
buf.extend(iter);
buf
}
}
impl<const N: usize> From<&str> for StackStr<N> {
#[inline]
fn from(s: &str) -> Self {
let mut buf = StackStr::new();
buf.push_str(s);
buf
}
}
impl<const N: usize> From<&mut str> for StackStr<N> {
#[inline]
fn from(s: &mut str) -> Self {
let mut buf = StackStr::new();
buf.push_str(s);
buf
}
}
impl<const N1: usize, const N2: usize> From<&StackStr<N2>> for StackStr<N1> {
#[inline]
fn from(s: &StackStr<N2>) -> Self {
let mut buf = StackStr::new();
buf.push_str(&s);
buf
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
impl<const N: usize> From<Box<str>> for StackStr<N> {
#[inline]
fn from(s: Box<str>) -> Self {
let mut buf = StackStr::new();
buf.push_str(&s);
buf
}
}
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
impl<const N: usize> From<Cow<'_, str>> for StackStr<N> {
#[inline]
fn from(s: Cow<'_, str>) -> Self {
let mut buf = StackStr::new();
buf.push_str(&s);
buf
}
}
impl<const N: usize> Hash for StackStr<N> {
#[inline]
fn hash<H: Hasher>(&self, hasher: &mut H) {
(**self).hash(hasher)
}
}
impl<const N: usize> Add<&str> for StackStr<N> {
type Output = StackStr<N>;
#[inline]
fn add(mut self, other: &str) -> Self {
self.push_str(other);
self
}
}
impl<const N: usize> AddAssign<&str> for StackStr<N> {
#[inline]
fn add_assign(&mut self, other: &str) {
self.push_str(other);
}
}
impl<const N: usize> FromStr for StackStr<N> {
type Err = std::convert::Infallible;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(StackStr::from(s))
}
}
impl<const N: usize> From<StackStr<N>> for StackVec<u8, N> {
#[inline]
fn from(s: StackStr<N>) -> Self {
s.into_bytes()
}
}
#[cfg(feature = "serde")]
mod impl_serde {
use super::*;
use serde::de::{Error, Unexpected, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::marker::PhantomData;
#[cfg_attr(docsrs, doc(cfg(all(feature = "str", feature = "serde"))))]
impl<const N: usize> Serialize for StackStr<N> {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self)
}
}
#[cfg_attr(docsrs, doc(cfg(all(feature = "str", feature = "serde"))))]
impl<'de, const N: usize> Deserialize<'de> for StackStr<N> {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct StackStrVisitor<const N: usize>(PhantomData<([u8; N])>);
impl<'de, const N: usize> Visitor<'de> for StackStrVisitor<N> {
type Value = StackStr<N>;
#[inline]
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a string with no more than {} bytes", N)
}
#[inline]
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
Ok(StackStr::from(v))
}
#[inline]
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: Error,
{
let s = str::from_utf8(v)
.map_err(|_| E::invalid_value(Unexpected::Bytes(v), &self))?;
Ok(StackStr::from(s))
}
}
deserializer.deserialize_str(StackStrVisitor::<N>(PhantomData))
}
}
}