#![allow(unused_imports)]
#[doc(hidden)]
extern crate alloc;
use alloc::borrow::Cow;
use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::str;
use alloc::str::from_boxed_utf8_unchecked;
use alloc::string::String;
use alloc::vec::Vec;
#[cfg(all(feature = "unstable", not(feature = "std")))]
use core::error::Error;
use core::fmt;
use core::fmt::Write;
use core::ops::{self, Add, AddAssign};
use core::str::{FromStr, Utf8Error};
use core::{hash, slice};
#[cfg(feature = "std")]
use std::error::Error;
use smallvec::SmallVec;
pub use smallvec::CollectionAllocErr;
#[macro_export]
macro_rules! format_smallstr {
($($tt:tt)*) => {{
use ::core::fmt::Write;
let mut s = $crate::SmallStr::new();
s.write_fmt(format_args!($($tt)*)).expect("a formatting trait implementation returned an error");
s
}};
}
#[cfg(target_pointer_width = "64")]
const _: () = assert!(core::mem::size_of::<SmallStr>() == core::mem::size_of::<String>());
pub type SmallString = SmallStr<16>;
#[derive(PartialEq, PartialOrd, Eq, Ord)]
#[repr(transparent)]
pub struct SmallStr<const N: usize = 16> {
vec: SmallVec<u8, N>,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct FromUtf8Error<const N: usize> {
bytes: SmallVec<u8, N>,
error: Utf8Error,
}
#[derive(Debug)]
pub struct FromUtf16Error(());
impl<const N: usize> SmallStr<N> {
#[inline]
pub fn new() -> SmallStr<N> {
Self {
vec: SmallVec::new(),
}
}
#[inline]
pub fn with_capacity(capacity: usize) -> SmallStr<N> {
SmallStr {
vec: SmallVec::with_capacity(capacity),
}
}
#[inline]
pub fn force_heap(&mut self) {
self.vec.reserve(N + 1);
}
#[inline]
pub fn is_inlined(&self) -> bool {
!self.vec.spilled()
}
#[inline]
pub fn inline_size(&self) -> usize {
N
}
#[inline]
pub fn from_utf8(vec: SmallVec<u8, N>) -> Result<SmallStr<N>, FromUtf8Error<N>> {
match str::from_utf8(&vec) {
Ok(..) => Ok(SmallStr { vec }),
Err(e) => Err(FromUtf8Error {
bytes: vec,
error: e,
}),
}
}
pub fn from_utf16(v: &[u16]) -> Result<SmallStr<N>, FromUtf16Error> {
let mut ret = SmallStr::with_capacity(v.len());
for c in char::decode_utf16(v.iter().cloned()) {
if let Ok(c) = c {
ret.push(c);
} else {
return Err(FromUtf16Error(()));
}
}
Ok(ret)
}
#[inline]
pub fn from_utf16_lossy(v: &[u16]) -> SmallStr<N> {
char::decode_utf16(v.iter().cloned())
.map(|r| r.unwrap_or(char::REPLACEMENT_CHARACTER))
.collect()
}
#[inline]
pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> SmallStr<N> {
unsafe {
SmallStr {
vec: SmallVec::from_raw_parts(buf, length, capacity),
}
}
}
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.vec.as_mut_ptr()
}
#[inline]
pub unsafe fn from_utf8_unchecked(bytes: SmallVec<u8, N>) -> SmallStr<N> {
SmallStr { vec: bytes }
}
#[inline]
pub fn into_bytes(self) -> SmallVec<u8, N> {
self.vec
}
#[inline]
pub fn as_str(&self) -> &str {
self
}
#[inline]
pub fn as_mut_str(&mut self) -> &mut str {
self
}
pub fn push_str(&mut self, string: &str) {
self.vec.extend_from_slice(string.as_bytes())
}
#[inline]
pub fn capacity(&self) -> usize {
self.vec.capacity()
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.vec.reserve(additional)
}
#[inline]
pub fn reserve_exact(&mut self, additional: usize) {
self.vec.reserve_exact(additional)
}
pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
self.vec.try_reserve(additional)
}
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
self.vec.try_reserve_exact(additional)
}
#[inline]
pub fn shrink_to_fit(&mut self) {
self.vec.shrink_to_fit()
}
#[inline]
pub fn push(&mut self, ch: char) {
match ch.len_utf8() {
1 => self.vec.push(ch as u8),
_ => self
.vec
.extend_from_slice(ch.encode_utf8(&mut [0; 4]).as_bytes()),
}
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.vec
}
#[inline]
pub fn truncate(&mut self, new_len: usize) {
if new_len <= self.len() {
assert!(self.is_char_boundary(new_len));
self.vec.truncate(new_len)
}
}
#[inline]
pub fn pop(&mut self) -> Option<char> {
let ch = self.chars().next_back()?;
let newlen = self.len() - ch.len_utf8();
unsafe {
self.vec.set_len(newlen);
}
Some(ch)
}
#[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();
self.vec.drain(idx..next);
ch
}
#[inline]
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(char) -> bool,
{
struct SetLenOnDrop<'a, const N: usize> {
s: &'a mut SmallStr<N>,
idx: usize,
del_bytes: usize,
}
impl<'a, const N: usize> Drop for SetLenOnDrop<'a, N> {
fn drop(&mut self) {
let new_len = self.idx - self.del_bytes;
debug_assert!(new_len <= self.s.len());
unsafe { self.s.vec.set_len(new_len) };
}
}
let len = self.len();
let mut guard = SetLenOnDrop {
s: self,
idx: 0,
del_bytes: 0,
};
while guard.idx < len {
let ch =
unsafe { guard.s.get_unchecked(guard.idx..len).chars().next().unwrap_unchecked() };
let ch_len = ch.len_utf8();
if !f(ch) {
guard.del_bytes += ch_len;
} else if guard.del_bytes > 0 {
ch.encode_utf8(unsafe {
slice::from_raw_parts_mut(
guard.s.as_mut_ptr().add(guard.idx - guard.del_bytes),
ch.len_utf8(),
)
});
}
guard.idx += ch_len;
}
drop(guard);
}
#[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();
self.vec.insert_from_slice(idx, bits);
}
#[inline]
pub fn insert_str(&mut self, idx: usize, string: &str) {
assert!(self.is_char_boundary(idx));
self.vec.insert_from_slice(idx, string.as_bytes());
}
#[inline]
pub unsafe fn as_mut_vec(&mut self) -> &mut SmallVec<u8, N> {
&mut self.vec
}
#[inline]
pub fn as_vec(&self) -> &SmallVec<u8, N> {
&self.vec
}
#[inline]
pub fn len(&self) -> usize {
self.vec.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
#[must_use = "use `.truncate()` if you don't need the other half"]
pub fn split_off(&mut self, at: usize) -> SmallStr<N> {
assert!(self.is_char_boundary(at));
let other = self.vec.split_off(at);
unsafe { SmallStr::from_utf8_unchecked(other) }
}
#[inline]
pub fn clear(&mut self) {
self.vec.clear()
}
#[inline]
pub fn into_boxed_str(self) -> Box<str> {
let slice = self.vec.into_boxed_slice();
unsafe { from_boxed_utf8_unchecked(slice) }
}
#[inline]
pub fn leak<'a>(self) -> &'a mut str {
Box::leak(self.into_boxed_str())
}
}
impl<const N: usize> FromUtf8Error<N> {
pub fn as_bytes(&self) -> &[u8] {
&self.bytes[..]
}
pub fn into_bytes(self) -> SmallVec<u8, N> {
self.bytes
}
pub fn utf8_error(&self) -> Utf8Error {
self.error
}
}
impl<const N: usize> fmt::Display for FromUtf8Error<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.error, f)
}
}
impl fmt::Display for FromUtf16Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt("invalid utf-16: lone surrogate found", f)
}
}
#[cfg(any(feature = "unstable", feature = "std"))]
impl<const N: usize> Error for FromUtf8Error<N> {
#[allow(deprecated)]
fn description(&self) -> &str {
"invalid utf-8"
}
}
#[cfg(any(feature = "unstable", feature = "std"))]
impl Error for FromUtf16Error {
#[allow(deprecated)]
fn description(&self) -> &str {
"invalid utf-16"
}
}
impl<const N: usize> Clone for SmallStr<N> {
#[inline]
fn clone(&self) -> Self {
SmallStr {
vec: self.vec.clone(),
}
}
#[inline]
fn clone_from(&mut self, source: &Self) {
self.vec.clone_from(&source.vec);
}
}
impl<const N: usize> FromIterator<char> for SmallStr<N> {
fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> SmallStr<N> {
let mut buf = SmallStr::new();
buf.extend(iter);
buf
}
}
impl<'a, const N: usize> FromIterator<&'a char> for SmallStr<N> {
fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> SmallStr<N> {
let mut buf = SmallStr::new();
buf.extend(iter);
buf
}
}
impl<'a, const N: usize> FromIterator<&'a str> for SmallStr<N> {
fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> SmallStr<N> {
let mut buf = SmallStr::new();
buf.extend(iter);
buf
}
}
impl<const N: usize> FromIterator<SmallStr<N>> for SmallStr<N> {
fn from_iter<I: IntoIterator<Item = SmallStr<N>>>(iter: I) -> SmallStr<N> {
let mut iterator = iter.into_iter();
match iterator.next() {
None => SmallStr::new(),
Some(mut buf) => {
buf.extend(iterator);
buf
}
}
}
}
impl<const N: usize> FromIterator<Box<str>> for SmallStr<N> {
fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> SmallStr<N> {
let mut buf = SmallStr::new();
buf.extend(iter);
buf
}
}
impl<'a, const N: usize> FromIterator<Cow<'a, str>> for SmallStr<N> {
fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> SmallStr<N> {
let mut s = SmallStr::new();
s.extend(iter);
s
}
}
impl<const N: usize> Extend<char> for SmallStr<N> {
fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
let iterator = iter.into_iter();
let (lower_bound, _) = iterator.size_hint();
self.reserve(lower_bound);
iterator.for_each(move |c| self.push(c));
}
#[inline]
#[cfg(feature = "unstable")]
fn extend_one(&mut self, c: char) {
self.push(c);
}
#[inline]
#[cfg(feature = "unstable")]
fn extend_reserve(&mut self, additional: usize) {
self.reserve(additional);
}
}
impl<'a, const N: usize> Extend<&'a char> for SmallStr<N> {
fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
self.extend(iter.into_iter().cloned());
}
#[inline]
#[cfg(feature = "unstable")]
fn extend_one(&mut self, &c: &'a char) {
self.push(c);
}
#[inline]
#[cfg(feature = "unstable")]
fn extend_reserve(&mut self, additional: usize) {
self.reserve(additional);
}
}
impl<'a, const N: usize> Extend<&'a str> for SmallStr<N> {
fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
iter.into_iter().for_each(move |s| self.push_str(s));
}
#[inline]
#[cfg(feature = "unstable")]
fn extend_one(&mut self, s: &'a str) {
self.push_str(s);
}
}
impl<const N: usize> Extend<Box<str>> for SmallStr<N> {
fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
iter.into_iter().for_each(move |s| self.push_str(&s));
}
}
impl<const N: usize> Extend<SmallStr<N>> for SmallStr<N> {
fn extend<I: IntoIterator<Item = SmallStr<N>>>(&mut self, iter: I) {
iter.into_iter().for_each(move |s| self.push_str(&s));
}
#[inline]
#[cfg(feature = "unstable")]
fn extend_one(&mut self, s: SmallStr<N>) {
self.push_str(&s);
}
}
impl<'a, const N: usize> Extend<Cow<'a, str>> for SmallStr<N> {
fn extend<I: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: I) {
iter.into_iter().for_each(move |s| self.push_str(&s));
}
#[inline]
#[cfg(feature = "unstable")]
fn extend_one(&mut self, s: Cow<'a, str>) {
self.push_str(&s);
}
}
impl<const N: usize> PartialEq<str> for SmallStr<N> {
#[inline]
fn eq(&self, other: &str) -> bool {
PartialEq::eq(self.as_str(), other)
}
}
impl<const N: usize> PartialEq<SmallStr<N>> for str {
#[inline]
fn eq(&self, other: &SmallStr<N>) -> bool {
PartialEq::eq(self, other.as_str())
}
}
impl<'a, const N: usize> PartialEq<&'a str> for SmallStr<N> {
#[inline]
fn eq(&self, other: &&'a str) -> bool {
PartialEq::eq(self.as_str(), &other[..])
}
}
impl<'a, const N: usize> PartialEq<SmallStr<N>> for &'a str {
#[inline]
fn eq(&self, other: &SmallStr<N>) -> bool {
PartialEq::eq(&self[..], other.as_str())
}
}
impl<'a, const N: usize> PartialEq<SmallStr<N>> for Cow<'a, str> {
#[inline]
fn eq(&self, other: &SmallStr<N>) -> bool {
PartialEq::eq(&self[..], other.as_str())
}
}
impl<'a, const N: usize> PartialEq<Cow<'a, str>> for SmallStr<N> {
#[inline]
fn eq(&self, other: &Cow<'a, str>) -> bool {
PartialEq::eq(self.as_str(), &other[..])
}
}
impl<const N: usize> PartialEq<SmallStr<N>> for String {
#[inline]
fn eq(&self, other: &SmallStr<N>) -> bool {
PartialEq::eq(&self[..], other.as_str())
}
}
impl<const N: usize> PartialEq<String> for SmallStr<N> {
#[inline]
fn eq(&self, other: &String) -> bool {
PartialEq::eq(self.as_str(), &other[..])
}
}
impl Default for SmallStr<16> {
#[inline]
fn default() -> SmallStr {
SmallStr::new()
}
}
impl<const N: usize> fmt::Display for SmallStr<N> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl<const N: usize> fmt::Debug for SmallStr<N> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<const N: usize> hash::Hash for SmallStr<N> {
#[inline]
fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
(**self).hash(hasher)
}
}
impl<const N: usize> Add<&str> for SmallStr<N> {
type Output = SmallStr<N>;
#[inline]
fn add(mut self, other: &str) -> SmallStr<N> {
self.push_str(other);
self
}
}
impl<const N: usize> AddAssign<&str> for SmallStr<N> {
#[inline]
fn add_assign(&mut self, other: &str) {
self.push_str(other);
}
}
impl<const N: usize, I> ops::Index<I> for SmallStr<N>
where
I: slice::SliceIndex<str>,
{
type Output = I::Output;
#[inline]
fn index(&self, index: I) -> &I::Output {
&self.as_str()[index]
}
}
impl<const N: usize, I> ops::IndexMut<I> for SmallStr<N>
where
I: slice::SliceIndex<str>,
{
#[inline]
fn index_mut(&mut self, index: I) -> &mut I::Output {
&mut self.as_mut_str()[index]
}
}
impl<const N: usize> ops::Deref for SmallStr<N> {
type Target = str;
#[inline]
fn deref(&self) -> &str {
unsafe { str::from_utf8_unchecked(&self.vec) }
}
}
impl<const N: usize> ops::DerefMut for SmallStr<N> {
#[inline]
fn deref_mut(&mut self) -> &mut str {
unsafe { str::from_utf8_unchecked_mut(&mut self.vec) }
}
}
impl<const N: usize> FromStr for SmallStr<N> {
type Err = core::convert::Infallible;
#[inline]
fn from_str(s: &str) -> Result<SmallStr<N>, Self::Err> {
Ok(SmallStr::from(s))
}
}
impl<const N: usize> AsRef<str> for SmallStr<N> {
#[inline]
fn as_ref(&self) -> &str {
self
}
}
impl<const N: usize> AsMut<str> for SmallStr<N> {
#[inline]
fn as_mut(&mut self) -> &mut str {
self
}
}
impl<const N: usize> AsRef<[u8]> for SmallStr<N> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl<const N: usize> From<&str> for SmallStr<N> {
#[inline]
fn from(s: &str) -> Self {
SmallStr {
vec: SmallVec::from_slice(s.as_bytes()),
}
}
}
impl<const N: usize> From<&mut str> for SmallStr<N> {
#[inline]
fn from(s: &mut str) -> SmallStr<N> {
SmallStr::from(&*s)
}
}
impl<const N: usize, const N2: usize> From<&SmallStr<N>> for SmallStr<N2> {
#[inline]
fn from(s: &SmallStr<N>) -> SmallStr<N2> {
SmallStr {
vec: SmallVec::from_slice(&s.vec),
}
}
}
impl<const N: usize> From<Box<str>> for SmallStr<N> {
fn from(s: Box<str>) -> SmallStr<N> {
SmallStr::from(s.as_ref())
}
}
impl<const N: usize> From<SmallStr<N>> for Box<str> {
fn from(s: SmallStr<N>) -> Box<str> {
s.into_boxed_str()
}
}
impl<'a, const N: usize> From<Cow<'a, str>> for SmallStr<N> {
fn from(s: Cow<'a, str>) -> SmallStr<N> {
match s {
Cow::Borrowed(s) => SmallStr::from(s),
Cow::Owned(owned) => SmallStr::from(owned),
}
}
}
impl<'a, const N: usize> From<SmallStr<N>> for Cow<'a, str> {
#[inline]
fn from(s: SmallStr<N>) -> Cow<'a, str> {
Cow::Owned(String::from(s))
}
}
impl<'a, const N: usize> From<&'a SmallStr<N>> for Cow<'a, str> {
#[inline]
fn from(s: &'a SmallStr<N>) -> Cow<'a, str> {
Cow::Borrowed(s.as_str())
}
}
impl<const N: usize> From<String> for SmallStr<N> {
fn from(value: String) -> Self {
SmallStr {
vec: SmallVec::from_vec(value.into_bytes()),
}
}
}
impl<'a, const N: usize> From<&'a String> for SmallStr<N> {
fn from(value: &'a String) -> Self {
SmallStr::from(&**value)
}
}
impl<const N: usize> From<SmallStr<N>> for String {
fn from(value: SmallStr<N>) -> Self {
unsafe { String::from_utf8_unchecked(value.vec.into_vec()) }
}
}
impl<'a, const N: usize> From<&'a SmallStr<N>> for String {
fn from(value: &'a SmallStr<N>) -> Self {
value.as_str().to_owned()
}
}
impl<const N: usize> From<char> for SmallStr<N> {
#[inline]
fn from(c: char) -> Self {
let mut s = SmallStr::with_capacity(c.len_utf8());
s.push(c);
s
}
}
impl<const N: usize> Write for SmallStr<N> {
#[inline]
fn write_str(&mut self, s: &str) -> fmt::Result {
self.push_str(s);
Ok(())
}
fn write_char(&mut self, c: char) -> fmt::Result {
self.push(c);
Ok(())
}
}
pub trait ToSmallStr {
#[allow(dead_code)]
fn to_smallstr<const N: usize>(&self) -> SmallStr<N>;
}
impl<T: fmt::Display + ?Sized> ToSmallStr for T {
fn to_smallstr<const N: usize>(&self) -> SmallStr<N> {
let mut buf = SmallStr::new();
buf.write_fmt(format_args!("{}", self))
.expect("a Display implementation returned an error unexpectedly");
buf
}
}
#[cfg(feature = "serde")]
use serde::de::{Error as SerdeError, Unexpected, Visitor};
#[cfg(feature = "serde")]
impl<const N: usize> serde::Serialize for SmallStr<N> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.as_str().serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, const N: usize> serde::Deserialize<'de> for SmallStr<N> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct SmallStrVisitor<const N: usize>;
impl<'a, const N: usize> Visitor<'a> for SmallStrVisitor<N> {
type Value = SmallStr<N>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: SerdeError,
{
Ok(SmallStr::from(v))
}
fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E>
where
E: SerdeError,
{
Ok(SmallStr::from(v))
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: SerdeError,
{
Ok(SmallStr::from(v))
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: SerdeError,
{
match core::str::from_utf8(v) {
Ok(s) => Ok(SmallStr::from(s)),
Err(_) => Err(SerdeError::invalid_value(Unexpected::Bytes(v), &self)),
}
}
fn visit_borrowed_bytes<E>(self, v: &'a [u8]) -> Result<Self::Value, E>
where
E: SerdeError,
{
match core::str::from_utf8(v) {
Ok(s) => Ok(SmallStr::from(s)),
Err(_) => Err(SerdeError::invalid_value(Unexpected::Bytes(v), &self)),
}
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
where
E: SerdeError,
{
match String::from_utf8(v) {
Ok(s) => Ok(SmallStr::from(s)),
Err(e) => Err(SerdeError::invalid_value(
Unexpected::Bytes(&e.into_bytes()),
&self,
)),
}
}
}
deserializer.deserialize_str(SmallStrVisitor)
}
}