use core::{fmt, mem};
use alloc::vec::Vec;
pub const STATIC_SIZE: usize = mem::size_of::<usize>() * 2;
#[derive(Clone)]
enum State<'a> {
Slice(&'a [u8]),
Static([u8; STATIC_SIZE]),
Heap(Vec<u8>),
}
const _: () = {
assert!(mem::size_of::<State>() == mem::size_of::<Vec<u8>>());
};
#[repr(transparent)]
#[derive(Clone)]
pub struct String<'a> {
state: State<'a>
}
impl<'a> String<'a> {
#[inline]
pub const fn try_new_c(string: &'a [u8]) -> Option<Self> {
if string[string.len() - 1] == 0 {
Some(Self {
state: State::Slice(string)
})
} else {
None
}
}
#[inline]
pub const fn new_c(string: &'a [u8]) -> Self {
if string[string.len() - 1] == 0 {
Self {
state: State::Slice(string)
}
} else {
panic!("string is not NULL terminated")
}
}
pub fn new(string: &'a [u8]) -> Self {
let state = if let Some(this) = Self::try_new_c(string) {
this.state
} else if string.len() < STATIC_SIZE {
let mut buffer = [0u8; STATIC_SIZE];
buffer[..string.len()].copy_from_slice(string);
buffer[string.len()] = 0;
State::Static(buffer)
} else {
let mut buffer = Vec::with_capacity(string.len().saturating_add(1));
buffer.extend_from_slice(string);
buffer.push(0);
State::Heap(buffer)
};
Self {
state
}
}
pub fn as_ptr(&self) -> *const u8 {
match &self.state {
State::Heap(buf) => buf.as_ptr(),
State::Static(buf) => buf.as_ptr() as _,
State::Slice(buf) => buf.as_ptr(),
}
}
pub fn as_bytes(&self) -> &[u8] {
match &self.state {
State::Heap(buf) => &buf[..buf.len()-1],
State::Static(buf) => {
let mut cursor = 0;
while cursor < STATIC_SIZE {
if buf[cursor] == 0 {
break;
}
cursor = cursor.saturating_add(1);
}
&buf[..cursor]
},
State::Slice(buf) => &buf[..buf.len()-1],
}
}
}
impl fmt::Debug for String<'_> {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.as_bytes(), fmt)
}
}
impl PartialEq<[u8]> for String<'_> {
#[inline(always)]
fn eq(&self, other: &[u8]) -> bool {
PartialEq::eq(self.as_bytes(), other)
}
}
impl PartialEq<&[u8]> for String<'_> {
#[inline(always)]
fn eq(&self, other: &&[u8]) -> bool {
PartialEq::eq(self.as_bytes(), *other)
}
}
impl PartialEq<str> for String<'_> {
#[inline(always)]
fn eq(&self, other: &str) -> bool {
PartialEq::eq(self.as_bytes(), other.as_bytes())
}
}
impl<'a> From<&'a [u8]> for String<'a> {
#[inline]
fn from(value: &'a [u8]) -> Self {
Self::new(value)
}
}
impl<'a> From<&'a str> for String<'a> {
#[inline]
fn from(value: &'a str) -> Self {
Self::new(value.as_bytes())
}
}