use alloc::string::String;
use alloc::vec::Vec;
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt::{self, Debug, Formatter};
use core::hash::{Hash, Hasher};
use core::ops::Deref;
use crate::allocator::Global;
use crate::dynamic::{DynamicVec, InlineVec, LIMIT};
#[derive(Clone)]
pub struct EcoByteString(DynamicVec<'static>);
impl EcoByteString {
pub const INLINE_LIMIT: usize = LIMIT;
#[inline]
pub const fn new() -> Self {
Self(DynamicVec::new())
}
#[inline]
#[track_caller]
pub fn inline(bytes: &[u8]) -> Self {
let Ok(inline) = InlineVec::from_slice(bytes) else {
exceeded_inline_capacity();
};
Self(DynamicVec::from_inline(inline))
}
#[inline]
pub fn from_static(bytes: &'static [u8]) -> Self {
Self(DynamicVec::from_slice_in(bytes, Global))
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self(DynamicVec::with_capacity(capacity))
}
#[inline]
pub fn from_bytes(bytes: &[u8]) -> Self {
Self(DynamicVec::from_slice(bytes))
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
self.0.as_slice()
}
#[inline]
pub fn make_mut(&mut self) -> &mut [u8] {
self.0.make_mut(0)
}
#[inline]
pub fn push(&mut self, byte: u8) {
self.0.push(byte);
}
#[inline]
pub fn extend_from_slice(&mut self, bytes: &[u8]) {
self.0.extend_from_slice(bytes);
}
#[inline]
pub fn pop(&mut self) -> Option<u8> {
if self.is_empty() {
return None;
}
let last = self.0.as_slice()[self.len() - 1];
self.0.truncate(self.len() - 1);
Some(last)
}
#[inline]
pub fn clear(&mut self) {
self.0.clear();
}
#[inline]
pub fn truncate(&mut self, new_len: usize) {
if new_len <= self.len() {
self.0.truncate(new_len);
}
}
#[inline]
pub fn into_eco_string(self) -> Result<super::EcoString, Self> {
if core::str::from_utf8(self.as_bytes()).is_ok() {
Ok(super::EcoString::from_raw(self.0))
} else {
Err(self)
}
}
pub fn into_eco_string_lossy(self) -> super::EcoString {
match self.into_eco_string() {
Ok(s) => s,
Err(bytes) => {
let lossy = String::from_utf8_lossy(bytes.as_bytes());
super::EcoString::from(lossy.as_ref())
}
}
}
pub fn repeat(&self, n: usize) -> Self {
let slice = self.as_bytes();
let capacity = slice.len().saturating_mul(n);
let mut vec = DynamicVec::with_capacity(capacity);
for _ in 0..n {
vec.extend_from_slice(slice);
}
Self(vec)
}
}
impl Deref for EcoByteString {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.as_bytes()
}
}
impl Default for EcoByteString {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl Debug for EcoByteString {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Debug::fmt(self.as_bytes(), f)
}
}
impl Eq for EcoByteString {}
impl PartialEq for EcoByteString {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl PartialEq<[u8]> for EcoByteString {
#[inline]
fn eq(&self, other: &[u8]) -> bool {
self.as_bytes() == other
}
}
impl PartialEq<&[u8]> for EcoByteString {
#[inline]
fn eq(&self, other: &&[u8]) -> bool {
self.as_bytes() == *other
}
}
impl<const N: usize> PartialEq<[u8; N]> for EcoByteString {
#[inline]
fn eq(&self, other: &[u8; N]) -> bool {
self.as_bytes() == other.as_slice()
}
}
impl<const N: usize> PartialEq<&[u8; N]> for EcoByteString {
#[inline]
fn eq(&self, other: &&[u8; N]) -> bool {
self.as_bytes() == other.as_slice()
}
}
impl PartialEq<EcoByteString> for [u8] {
#[inline]
fn eq(&self, other: &EcoByteString) -> bool {
self == other.as_bytes()
}
}
impl PartialEq<EcoByteString> for &[u8] {
#[inline]
fn eq(&self, other: &EcoByteString) -> bool {
*self == other.as_bytes()
}
}
impl Ord for EcoByteString {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.as_bytes().cmp(other.as_bytes())
}
}
impl PartialOrd for EcoByteString {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Hash for EcoByteString {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_bytes().hash(state);
}
}
impl AsRef<[u8]> for EcoByteString {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl Borrow<[u8]> for EcoByteString {
#[inline]
fn borrow(&self) -> &[u8] {
self.as_bytes()
}
}
impl From<&[u8]> for EcoByteString {
#[inline]
fn from(bytes: &[u8]) -> Self {
Self::from_bytes(bytes)
}
}
impl<const N: usize> From<&[u8; N]> for EcoByteString {
#[inline]
fn from(bytes: &[u8; N]) -> Self {
Self::from_bytes(bytes.as_slice())
}
}
impl From<Vec<u8>> for EcoByteString {
#[inline]
fn from(v: Vec<u8>) -> Self {
Self::from_bytes(&v)
}
}
impl From<&Vec<u8>> for EcoByteString {
#[inline]
fn from(v: &Vec<u8>) -> Self {
Self::from_bytes(v.as_slice())
}
}
impl From<&EcoByteString> for EcoByteString {
#[inline]
fn from(s: &EcoByteString) -> Self {
s.clone()
}
}
impl From<super::EcoString> for EcoByteString {
#[inline]
fn from(s: super::EcoString) -> Self {
Self(s.into_raw())
}
}
impl From<&super::EcoString> for EcoByteString {
#[inline]
fn from(s: &super::EcoString) -> Self {
Self::from_bytes(s.as_bytes())
}
}
impl TryFrom<EcoByteString> for super::EcoString {
type Error = EcoByteString;
#[inline]
fn try_from(value: EcoByteString) -> Result<Self, Self::Error> {
value.into_eco_string()
}
}
impl FromIterator<u8> for EcoByteString {
#[inline]
fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
let mut s = Self::new();
for byte in iter {
s.push(byte);
}
s
}
}
impl FromIterator<Self> for EcoByteString {
#[inline]
fn from_iter<T: IntoIterator<Item = Self>>(iter: T) -> Self {
let mut s = Self::new();
for piece in iter {
s.extend_from_slice(&piece);
}
s
}
}
impl<'a> FromIterator<&'a [u8]> for EcoByteString {
#[inline]
fn from_iter<T: IntoIterator<Item = &'a [u8]>>(iter: T) -> Self {
let mut buf = Self::new();
buf.extend(iter);
buf
}
}
impl Extend<u8> for EcoByteString {
#[inline]
fn extend<T: IntoIterator<Item = u8>>(&mut self, iter: T) {
for byte in iter {
self.push(byte);
}
}
}
impl<'a> Extend<&'a [u8]> for EcoByteString {
#[inline]
fn extend<T: IntoIterator<Item = &'a [u8]>>(&mut self, iter: T) {
iter.into_iter().for_each(move |s| self.extend_from_slice(s));
}
}
impl From<EcoByteString> for Vec<u8> {
#[inline]
fn from(s: EcoByteString) -> Self {
s.as_bytes().to_vec()
}
}
impl From<&EcoByteString> for Vec<u8> {
#[inline]
fn from(s: &EcoByteString) -> Self {
s.as_bytes().to_vec()
}
}
#[cold]
#[track_caller]
fn exceeded_inline_capacity() -> ! {
panic!("exceeded inline capacity");
}
#[cfg(feature = "serde")]
mod serde {
use crate::EcoByteString;
use core::fmt;
use serde::de::{Deserializer, Visitor};
impl serde::Serialize for EcoByteString {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_bytes(self.as_bytes())
}
}
impl<'de> serde::Deserialize<'de> for EcoByteString {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct EcoByteStringVisitor;
impl Visitor<'_> for EcoByteStringVisitor {
type Value = EcoByteString;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a byte string")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(EcoByteString::from(v))
}
}
deserializer.deserialize_bytes(EcoByteStringVisitor)
}
}
}