extern crate alloc;
use alloc::string::ToString as _;
use alloc::vec;
use core::{borrow, cmp, fmt, hash, mem, ops, panic, slice, str};
use crate::{StringPtr, TkStrError};
pub const PREFIX_LENGTH: usize = mem::size_of::<u64>() - mem::size_of::<u16>();
const PREFIX_LENGTH_ADD1: usize = PREFIX_LENGTH + 1;
pub const SMALL_DATA_LENGTH: usize = mem::size_of::<u64>();
pub const MAX_LENGTH_SMALL: usize = PREFIX_LENGTH + SMALL_DATA_LENGTH;
pub const MAX_LENGTH_SMALL_ADD1: usize = MAX_LENGTH_SMALL + 1;
pub const MAX_LENGTH: usize = u16::MAX as usize;
#[repr(C)]
pub struct TokenString {
pub(crate) len: u16,
pub(crate) prefix: [u8; PREFIX_LENGTH],
pub(crate) u: Data,
}
const _: () = assert!(
mem::align_of::<TokenString>() == mem::size_of::<u64>(),
"struct TokenString is not aligned to 64 bits!"
);
const _: () = assert!(
mem::size_of::<TokenString>() == 2 * mem::size_of::<u64>(),
"struct TokenString has size != 128 bits"
);
const _: () = assert!(
mem::align_of::<Data>() == mem::size_of::<u64>(),
"struct Data is not aligned to 64 bits!"
);
const _: () = assert!(
mem::size_of::<Data>() == mem::size_of::<u64>(),
"union Data has size != 64 bits"
);
#[repr(C)]
pub union Data {
pub(crate) small: [u8; SMALL_DATA_LENGTH],
pub(crate) ptr: mem::ManuallyDrop<StringPtr>,
}
pub const EMPTY: TokenString = TokenString {
len: 0,
prefix: [0_u8; PREFIX_LENGTH],
u: Data {
small: [0_u8; SMALL_DATA_LENGTH],
},
};
impl TryFrom<&str> for TokenString {
type Error = TkStrError;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let bytes = value.as_bytes();
match value.len() {
| 0 => Ok(Self {
len: 0,
prefix: [0_u8; PREFIX_LENGTH],
u: Data {
small: [0_u8; SMALL_DATA_LENGTH],
},
}),
| 1 ..= PREFIX_LENGTH => {
let s = value.len();
let mut prefix = [0_u8; PREFIX_LENGTH];
prefix[.. s].copy_from_slice(&bytes[.. s]);
Ok(Self {
#[expect(
clippy::cast_possible_truncation,
reason = "Length has been checked above"
)]
len: s as u16,
prefix,
u: Data {
small: [0_u8; SMALL_DATA_LENGTH],
},
})
}
| PREFIX_LENGTH_ADD1 ..= MAX_LENGTH_SMALL => {
let s = value.len();
let mut prefix = [0_u8; PREFIX_LENGTH];
prefix.copy_from_slice(&bytes[.. PREFIX_LENGTH]);
let mut small = [0_u8; SMALL_DATA_LENGTH];
small[.. s - PREFIX_LENGTH]
.copy_from_slice(&bytes[PREFIX_LENGTH .. s]);
Ok(Self {
#[expect(
clippy::cast_possible_truncation,
reason = "Length has been checked above"
)]
len: s as u16,
prefix,
u: Data { small },
})
}
| MAX_LENGTH_SMALL_ADD1 ..= MAX_LENGTH => {
let ptr = StringPtr::from(bytes);
let u = Data {
ptr: mem::ManuallyDrop::new(ptr),
};
let mut prefix = [0_u8; PREFIX_LENGTH];
prefix.copy_from_slice(&bytes[.. PREFIX_LENGTH]);
Ok(Self {
#[expect(
clippy::cast_possible_truncation,
reason = "Length has been checked above"
)]
len: value.len() as u16,
prefix,
u,
})
}
| _ => Err(TkStrError::TooBig(value.len())),
}
}
}
impl TryFrom<&[u8]> for TokenString {
type Error = TkStrError;
#[inline]
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
match str::from_utf8(value) {
| Ok(str) => Self::try_from(str),
| Err(utf_err) => Err(TkStrError::UnicodeError(utf_err)),
}
}
}
impl TryFrom<&[char]> for TokenString {
type Error = TkStrError;
#[inline]
fn try_from(value: &[char]) -> Result<Self, Self::Error> {
let i = value.iter();
Self::try_from(i.collect::<alloc::string::String>())
}
}
impl TryFrom<&alloc::string::String> for TokenString {
type Error = TkStrError;
#[inline]
fn try_from(value: &alloc::string::String) -> Result<Self, Self::Error> {
let str = value.as_str();
Self::try_from(str)
}
}
impl TryFrom<alloc::string::String> for TokenString {
type Error = TkStrError;
#[inline]
fn try_from(value: alloc::string::String) -> Result<Self, Self::Error> {
let str = value.as_str();
Self::try_from(str)
}
}
impl Drop for TokenString {
#[cfg_attr(test, mutants::skip)]
#[inline]
fn drop(&mut self) {
if usize::from(self.len) > MAX_LENGTH_SMALL {
let mut m_ptr = unsafe { mem::ManuallyDrop::take(&mut self.u.ptr) };
m_ptr.drop_manually(self.len.into());
}
}
}
impl Clone for TokenString {
#[inline]
fn clone(&self) -> Self {
let u = if self.len as usize > MAX_LENGTH_SMALL {
Data {
ptr: mem::ManuallyDrop::new(unsafe {
self.u.ptr.clone_manually(self.len.into())
}),
}
} else {
Data {
small: unsafe { self.u.small },
}
};
Self {
len: self.len,
prefix: self.prefix,
u,
}
}
}
impl Default for TokenString {
#[inline]
fn default() -> Self {
EMPTY
}
}
impl Eq for TokenString {}
impl PartialEq for TokenString {
#[inline]
fn eq(&self, other: &Self) -> bool {
if self.len != other.len || self.prefix != other.prefix {
return false;
}
if self.len as usize <= MAX_LENGTH_SMALL {
unsafe { self.u.small == other.u.small }
} else {
unsafe { self.u.ptr.eq_manually(&other.u.ptr, self.len.into()) }
}
}
}
impl PartialEq<[u8]> for TokenString {
fn eq(&self, other: &[u8]) -> bool {
if self.len as usize != other.len() {
return false;
}
let len = self.len as usize;
match len {
| 0 => true,
| 1 ..= PREFIX_LENGTH => self.prefix[.. len] == other[.. len],
| PREFIX_LENGTH_ADD1 ..= MAX_LENGTH_SMALL => {
let bytes =
unsafe { slice::from_raw_parts(self.prefix.as_ptr(), len) };
bytes == other
}
| MAX_LENGTH_SMALL_ADD1 ..= MAX_LENGTH => unsafe {
self.u.ptr.as_slice_manually(len) == other
},
| _ => panic!("The TokenString is bigger than MAX_LENGTH!"),
}
}
}
impl PartialEq<str> for TokenString {
#[inline]
fn eq(&self, other: &str) -> bool {
self == other.as_bytes()
}
}
impl PartialEq<alloc::string::String> for TokenString {
#[inline]
fn eq(&self, other: &alloc::string::String) -> bool {
self == other.as_bytes()
}
}
impl Ord for TokenString {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
let pref_ord = self.prefix.cmp(&other.prefix);
if pref_ord != cmp::Ordering::Equal {
return pref_ord;
}
self.suffix().cmp(other.suffix())
}
}
impl PartialOrd for TokenString {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl fmt::Display for TokenString {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl fmt::Debug for TokenString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.len as usize > MAX_LENGTH_SMALL {
let string =
unsafe { self.u.ptr.as_string_manually(self.len.into()) };
let ptr = unsafe { &self.u.ptr };
f.debug_struct("TokenString")
.field("len", &self.len)
.field("prefix", &self.prefix_str())
.field("ptr", ptr)
.field("string", &string)
.finish()
} else {
unsafe {
f.debug_struct("TokenString")
.field("len", &self.len)
.field("prefix", &self.prefix_str())
.field("small", &self.small_str())
.field("string", &self.as_str())
.finish()
}
}
}
}
impl<Idx> ops::Index<Idx> for TokenString
where
Idx: slice::SliceIndex<str>,
{
type Output = Idx::Output;
#[inline]
fn index(&self, index: Idx) -> &Self::Output {
self.as_str().index(index)
}
}
impl borrow::Borrow<str> for TokenString {
#[inline]
fn borrow(&self) -> &str {
self.as_str()
}
}
impl AsRef<str> for TokenString {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl hash::Hash for TokenString {
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.as_str().hash(state);
}
}
unsafe impl Send for TokenString {}
unsafe impl Sync for TokenString {}
impl TokenString {
fn prefix_str(&self) -> &[u8] {
let l = cmp::min(self.len as usize, PREFIX_LENGTH);
&self.prefix[.. l]
}
unsafe fn small_str(&self) -> &[u8] {
let l = if self.len as usize > PREFIX_LENGTH {
self.len as usize - PREFIX_LENGTH
} else {
0
};
unsafe { &self.u.small[.. l] }
}
#[must_use]
#[inline]
pub const fn len(&self) -> usize {
self.len as usize
}
#[must_use]
#[inline]
pub const fn is_small(&self) -> bool {
self.len as usize <= MAX_LENGTH_SMALL
}
#[must_use]
#[inline]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
#[must_use]
pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> Self {
match bytes.len() {
| 0 => Self {
len: 0,
prefix: [0_u8; PREFIX_LENGTH],
u: Data {
small: [0_u8; SMALL_DATA_LENGTH],
},
},
| 1 ..= PREFIX_LENGTH => {
let s = bytes.len();
let mut prefix = [0_u8; PREFIX_LENGTH];
prefix[.. s].copy_from_slice(&bytes[.. s]);
Self {
#[expect(
clippy::cast_possible_truncation,
reason = "Length has been checked above"
)]
len: s as u16,
prefix,
u: Data {
small: [0_u8; SMALL_DATA_LENGTH],
},
}
}
| PREFIX_LENGTH_ADD1 ..= MAX_LENGTH_SMALL => {
let s = bytes.len();
let mut prefix = [0_u8; PREFIX_LENGTH];
prefix.copy_from_slice(&bytes[.. PREFIX_LENGTH]);
let mut small = [0_u8; SMALL_DATA_LENGTH];
small[.. s - PREFIX_LENGTH]
.copy_from_slice(&bytes[PREFIX_LENGTH .. s]);
Self {
#[expect(
clippy::cast_possible_truncation,
reason = "Length has been checked above"
)]
len: s as u16,
prefix,
u: Data { small },
}
}
| MAX_LENGTH_SMALL_ADD1 ..= MAX_LENGTH => {
let ptr = StringPtr::from(bytes);
let u = Data {
ptr: mem::ManuallyDrop::new(ptr),
};
let mut prefix = [0_u8; PREFIX_LENGTH];
prefix.copy_from_slice(&bytes[.. PREFIX_LENGTH]);
Self {
#[expect(
clippy::cast_possible_truncation,
reason = "Length has been checked above"
)]
len: bytes.len() as u16,
prefix,
u,
}
}
| _ => panic!(
"This byte slice is too big for a TokenString, {} > \
{MAX_LENGTH}",
bytes.len()
),
}
}
#[must_use]
#[inline]
pub fn from_str_unchecked(s: &str) -> Self {
unsafe { Self::from_bytes_unchecked(s.as_bytes()) }
}
#[must_use]
#[inline]
pub fn from_string_unchecked(s: &alloc::string::String) -> Self {
unsafe { Self::from_bytes_unchecked(s.as_bytes()) }
}
#[must_use]
#[inline]
pub fn as_str(&self) -> &str {
if self.len == 0 {
""
} else if self.len as usize > MAX_LENGTH_SMALL {
unsafe { self.u.ptr.as_string_manually(self.len.into()) }
} else {
let bytes = unsafe {
slice::from_raw_parts(self.prefix.as_ptr(), self.len.into())
};
unsafe { str::from_utf8_unchecked(bytes) }
}
}
#[must_use]
#[inline]
pub fn as_bytes(&self) -> &[u8] {
if self.len == 0 {
Default::default()
} else if self.len as usize > MAX_LENGTH_SMALL {
unsafe { self.u.ptr.as_slice_manually(self.len.into()) }
} else {
unsafe {
slice::from_raw_parts(self.prefix.as_ptr(), self.len.into())
}
}
}
#[must_use]
#[inline]
pub fn as_string(&self) -> alloc::string::String {
self.to_string()
}
#[must_use]
#[inline]
pub fn as_chars(&self) -> vec::Vec<char> {
self.as_str().chars().collect()
}
fn suffix(&self) -> &[u8] {
match self.len as usize {
| 0 ..= PREFIX_LENGTH => Default::default(),
| PREFIX_LENGTH_ADD1 ..= MAX_LENGTH_SMALL =>
unsafe { &self.u.small },
| MAX_LENGTH_SMALL_ADD1 ..= MAX_LENGTH =>
unsafe {
&self.u.ptr.as_slice_manually(self.len.into())[PREFIX_LENGTH ..]
},
| _ => panic!(
"Error: this TokenString is bigger than \
TokenString::MAX_LENGTH!"
),
}
}
#[inline]
pub fn get(&self, idx: u16) -> Result<u8, TkStrError> {
if idx >= self.len {
return Err(TkStrError::OutOfBounds(idx as usize));
}
unsafe { Ok(*self.as_bytes().get_unchecked(idx as usize)) }
}
#[must_use]
#[inline]
pub fn get_unchecked(&self, idx: u16) -> u8 {
assert!((idx < self.len), "index {idx} out of bounds");
unsafe { *self.as_bytes().get_unchecked(idx as usize) }
}
#[inline]
pub fn chars(&self) -> str::Chars {
self.as_str().chars()
}
#[must_use]
#[inline]
pub fn iter(&self) -> TokenStringIter<'_> {
<&Self as IntoIterator>::into_iter(self)
}
#[must_use]
#[inline]
pub const fn starts_ascii_uppercase(&self) -> bool {
self.prefix[0].is_ascii_uppercase()
}
#[must_use]
#[inline]
pub const fn starts_ascii_lowercase(&self) -> bool {
self.prefix[0].is_ascii_lowercase()
}
#[must_use]
#[inline]
pub fn is_ascii(&self) -> bool {
self.as_bytes().is_ascii()
}
#[must_use]
#[inline]
pub fn starts_with(&self, needle: &Self) -> bool {
self.as_bytes().starts_with(needle.as_bytes())
}
#[must_use]
#[inline]
pub fn starts_with_bytes(&self, needle: &[u8]) -> bool {
self.as_bytes().starts_with(needle)
}
#[must_use]
#[inline]
pub fn starts_with_str(&self, needle: &str) -> bool {
self.as_str().starts_with(needle)
}
#[must_use]
#[inline]
pub fn ends_with(&self, needle: &Self) -> bool {
self.as_bytes().ends_with(needle.as_bytes())
}
#[must_use]
#[inline]
pub fn ends_with_bytes(&self, needle: &[u8]) -> bool {
self.as_bytes().ends_with(needle)
}
#[must_use]
#[inline]
pub fn ends_with_str(&self, needle: &str) -> bool {
self.as_str().ends_with(needle)
}
fn map_bytes_mut(&mut self, f: fn(&mut [u8]) -> ()) {
if self.len as usize > MAX_LENGTH_SMALL {
unsafe {
f((*self.u.ptr).as_slice_manually_mut(self.len as usize));
}
} else {
unsafe {
f(slice::from_raw_parts_mut(
self.prefix.as_mut_ptr(),
self.len as usize,
));
}
}
}
#[must_use]
#[inline]
pub fn to_ascii_lowercase(&self) -> Self {
let mut ret_val = self.clone();
ret_val.map_bytes_mut(<[u8]>::make_ascii_lowercase);
ret_val
}
#[must_use]
#[inline]
pub fn to_ascii_uppercase(&self) -> Self {
let mut ret_val = self.clone();
ret_val.map_bytes_mut(<[u8]>::make_ascii_uppercase);
ret_val
}
#[must_use]
#[inline]
pub fn trim_ascii(&self) -> Self {
unsafe { Self::from_bytes_unchecked(self.as_bytes().trim_ascii()) }
}
#[must_use]
#[inline]
pub fn trim_ascii_start(&self) -> Self {
unsafe {
Self::from_bytes_unchecked(self.as_bytes().trim_ascii_start())
}
}
#[must_use]
#[inline]
pub fn trim_ascii_end(&self) -> Self {
unsafe { Self::from_bytes_unchecked(self.as_bytes().trim_ascii_end()) }
}
#[cfg(feature = "pattern")]
#[doc(cfg(pattern))]
#[inline]
pub fn strip_prefix<P: str::pattern::Pattern>(
&self,
prefix: P,
) -> Option<Self> {
self.as_str()
.strip_prefix(prefix)
.map(Self::from_str_unchecked)
}
#[cfg(feature = "pattern")]
#[doc(cfg(pattern))]
#[inline]
pub fn strip_suffix<P>(&self, suffix: P) -> Option<Self>
where
P: str::pattern::Pattern,
for<'a> P::Searcher<'a>: str::pattern::ReverseSearcher<'a>,
{
self.as_str()
.strip_suffix(suffix)
.map(Self::from_str_unchecked)
}
#[cfg(feature = "pattern")]
#[doc(cfg(pattern))]
#[inline]
pub fn contains<P: str::pattern::Pattern>(&self, pat: P) -> bool {
self.as_str().contains(pat)
}
}
pub struct TokenStringIter<'a> {
string: &'a TokenString,
idx: usize,
}
impl<'a> TokenStringIter<'a> {
#[must_use]
#[inline]
pub const fn new(s: &'a TokenString) -> Self {
TokenStringIter { string: s, idx: 0 }
}
}
impl Iterator for TokenStringIter<'_> {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
debug_assert!(
self.idx <= self.string.len.into(),
"The iterator index '{0}' is greater than the string length '{1}'!",
self.idx,
self.string.len
);
if self.idx == self.string.len.into() {
None
} else if self.string.len as usize > MAX_LENGTH_SMALL {
self.idx += 1;
Some(self.string.as_bytes()[self.idx - 1])
} else {
self.idx += 1;
Some(
unsafe {
slice::from_raw_parts(
self.string.prefix.as_ptr(),
self.string.len as usize,
)
}[self.idx - 1],
)
}
}
}
impl<'a> IntoIterator for &'a TokenString {
type IntoIter = TokenStringIter<'a>;
type Item = u8;
#[inline]
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter::new(self)
}
}
pub struct TokenStringIterOwn {
string: TokenString,
idx: usize,
}
impl TokenStringIterOwn {
#[must_use]
#[inline]
pub const fn new(s: TokenString) -> Self {
Self { string: s, idx: 0 }
}
}
impl Iterator for TokenStringIterOwn {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
debug_assert!(
self.idx <= self.string.len.into(),
"The iterator index '{0}' is greater than the string length '{1}'!",
self.idx,
self.string.len
);
if self.idx == self.string.len.into() {
None
} else if self.string.len as usize > MAX_LENGTH_SMALL {
self.idx += 1;
Some(self.string.as_bytes()[self.idx - 1])
} else {
self.idx += 1;
Some(
unsafe {
slice::from_raw_parts(
self.string.prefix.as_ptr(),
self.string.len as usize,
)
}[self.idx - 1],
)
}
}
}
impl IntoIterator for TokenString {
type IntoIter = TokenStringIterOwn;
type Item = u8;
#[inline]
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter::new(self)
}
}
#[cfg(test)]
mod prefix {
extern crate std;
use assert2::{check, let_assert};
use crate::TokenString;
#[test]
fn empty_is_empty() {
let_assert!(Ok(res) = TokenString::try_from(""));
check!(res.prefix[0] == 0);
check!(res.len == 0);
check!(res.is_small() == true);
}
#[test]
fn clone_empty() {
let_assert!(Ok(s1) = TokenString::try_from(""));
#[expect(
clippy::redundant_clone,
reason = "this clone isn't redundant?!"
)]
let res = s1.clone();
check!(res.prefix[0] == s1.prefix[0]);
check!(res.len == s1.len);
check!(res.is_small() == true);
}
#[test]
fn try_from_str() {
let_assert!(Ok(res) = TokenString::try_from("123456"));
check!(&res.prefix[0 .. 6] == b"123456");
check!(res.len == 6);
check!(res.is_small() == true);
}
#[test]
fn clone() {
let_assert!(Ok(s1) = TokenString::try_from("123456"));
#[expect(
clippy::redundant_clone,
reason = "this clone isn't redundant?!"
)]
let res = s1.clone();
check!(&res.prefix[0 .. 6] == &s1.prefix[0 .. 6]);
check!(res.len == s1.len);
check!(res.is_small() == true);
}
#[test]
fn try_from_bytes() {
let s1: &[u8] = b"123456";
let_assert!(Ok(res) = TokenString::try_from(s1));
check!(&res.prefix[0 .. 6] == b"123456");
check!(res.len == 6);
check!(res.is_small() == true);
}
#[test]
fn try_from_chars() {
#[expect(
clippy::std_instead_of_alloc,
reason = "We are testing, this needs std"
)]
let s1: std::vec::Vec<char> = "123456".chars().collect();
let_assert!(Ok(res) = TokenString::try_from(s1.as_slice()));
check!(&res.prefix[0 .. 6] == b"123456");
check!(res.len == 6);
check!(res.is_small() == true);
}
#[test]
fn try_from_string() {
#[expect(
clippy::std_instead_of_alloc,
reason = "We are testing, this needs std"
)]
let s1: std::string::String = "123456".into();
let_assert!(Ok(res) = TokenString::try_from(s1));
check!(&res.prefix[0 .. 6] == b"123456");
check!(res.len == 6);
check!(res.is_small() == true);
}
#[test]
fn try_from_stringref() {
#[expect(
clippy::std_instead_of_alloc,
reason = "We are testing, this needs std"
)]
let s1: std::string::String = "123456".into();
let_assert!(Ok(res) = TokenString::try_from(&s1));
check!(&res.prefix[0 .. 6] == b"123456");
check!(res.len == 6);
check!(res.is_small() == true);
}
#[test]
fn from_str_unchecked() {
let res = TokenString::from_str_unchecked("123456");
check!(&res.prefix[0 .. 6] == b"123456");
check!(res.len == 6);
}
#[test]
fn from_bytes_unchecked() {
let s1: &[u8] = b"123456";
let res = unsafe { TokenString::from_bytes_unchecked(s1) };
check!(&res.prefix[0 .. 6] == b"123456");
check!(res.len == 6);
check!(res.is_small() == true);
}
#[test]
fn from_stringref_unchecked() {
#[expect(
clippy::std_instead_of_alloc,
reason = "We are testing, this needs std"
)]
let s1: std::string::String = "123456".into();
let res = TokenString::from_string_unchecked(&s1);
check!(&res.prefix[0 .. 6] == b"123456");
check!(res.len == 6);
check!(res.is_small() == true);
}
}
#[cfg(test)]
mod small {
extern crate std;
use assert2::{check, let_assert};
use crate::TokenString;
#[test]
fn try_from_str() {
let_assert!(Ok(res) = TokenString::try_from("1234567"));
check!(&res.prefix[0 .. 6] == b"123456");
check!(unsafe { res.u.small[0] } == b'7');
check!(res.len == 7);
check!(res.is_small() == true);
}
#[test]
fn clone() {
let_assert!(Ok(s1) = TokenString::try_from("1234567"));
#[expect(
clippy::redundant_clone,
reason = "this clone isn't redundant?!"
)]
let res = s1.clone();
check!(&res.prefix[0 .. 6] == &s1.prefix[0 .. 6]);
check!(unsafe { res.u.small[0] == s1.u.small[0] });
check!(res.len == s1.len);
check!(res.is_small() == true);
}
#[test]
fn try_from_bytes() {
let s1: &[u8] = b"1234567";
let_assert!(Ok(res) = TokenString::try_from(s1));
check!(&res.prefix[0 .. 6] == b"123456");
check!(unsafe { res.u.small[0] } == b'7');
check!(res.len == 7);
check!(res.is_small() == true);
}
#[test]
fn try_from_chars() {
#[expect(
clippy::std_instead_of_alloc,
reason = "We are testing, this needs std"
)]
let s1: std::vec::Vec<char> = "1234567".chars().collect();
let_assert!(Ok(res) = TokenString::try_from(s1.as_slice()));
check!(&res.prefix[0 .. 6] == b"123456");
check!(unsafe { res.u.small[0] } == b'7');
check!(res.len == 7);
check!(res.is_small() == true);
}
#[test]
fn try_from_string() {
#[expect(
clippy::std_instead_of_alloc,
reason = "We are testing, this needs std"
)]
let s1: std::string::String = "1234567".into();
let_assert!(Ok(res) = TokenString::try_from(s1));
check!(&res.prefix[0 .. 6] == b"123456");
check!(unsafe { res.u.small[0] } == b'7');
check!(res.len == 7);
check!(res.is_small() == true);
}
#[test]
fn try_from_stringref() {
#[expect(
clippy::std_instead_of_alloc,
reason = "We are testing, this needs std"
)]
let s1: std::string::String = "1234567".into();
let_assert!(Ok(res) = TokenString::try_from(&s1));
check!(&res.prefix[0 .. 6] == b"123456");
check!(unsafe { res.u.small[0] } == b'7');
check!(res.len == 7);
check!(res.is_small() == true);
}
#[test]
fn from_str_unchecked() {
let res = TokenString::from_str_unchecked("1234567");
check!(&res.prefix[0 .. 6] == b"123456");
check!(unsafe { res.u.small[0] } == b'7');
check!(res.len == 7);
check!(res.is_small() == true);
}
#[test]
fn from_bytes_unchecked() {
let s1: &[u8] = b"1234567";
let res = unsafe { TokenString::from_bytes_unchecked(s1) };
check!(&res.prefix[0 .. 6] == b"123456");
check!(unsafe { res.u.small[0] } == b'7');
check!(res.len == 7);
check!(res.is_small() == true);
}
#[test]
fn from_stringref_unchecked() {
#[expect(
clippy::std_instead_of_alloc,
reason = "We are testing, this needs std"
)]
let s1: std::string::String = "1234567".into();
let res = TokenString::from_string_unchecked(&s1);
check!(&res.prefix[0 .. 6] == b"123456");
check!(unsafe { res.u.small[0] } == b'7');
check!(res.len == 7);
check!(res.is_small() == true);
}
}
#[cfg(test)]
mod heap {
extern crate std;
use assert2::{check, let_assert};
use crate::TokenString;
#[test]
fn try_from_str() {
let_assert!(Ok(res) = TokenString::try_from("1234567890ABCDE"));
check!(&res.prefix[0 .. 6] == b"123456");
check!(
unsafe { &res.u.ptr.as_slice_manually(res.len as usize)[.. 15] }
== b"1234567890ABCDE"
);
check!(res.len == 15);
check!(res.is_small() == false);
}
#[test]
fn clone() {
let_assert!(Ok(s1) = TokenString::try_from("1234567890ABCDE"));
#[expect(
clippy::redundant_clone,
reason = "this clone isn't redundant?!"
)]
let res = s1.clone();
check!(&res.prefix[0 .. 6] == &s1.prefix[0 .. 6]);
check!(
unsafe {
res.u.ptr.as_slice_manually(res.len as usize)[.. 15]
== s1.u.ptr.as_slice_manually(res.len as usize)[.. 15]
}
);
check!(res.len == s1.len);
check!(res.is_small() == false);
}
#[test]
fn try_from_bytes() {
let s1: &[u8] = b"1234567890ABCDE";
let_assert!(Ok(res) = TokenString::try_from(s1));
check!(&res.prefix[0 .. 6] == b"123456");
check!(
unsafe { &res.u.ptr.as_slice_manually(res.len as usize)[.. 15] }
== b"1234567890ABCDE"
);
check!(res.len == 15);
check!(res.is_small() == false);
}
#[test]
fn try_from_chars() {
#[expect(
clippy::std_instead_of_alloc,
reason = "We are testing, this needs std"
)]
let s1: std::vec::Vec<char> = "1234567890ABCDE".chars().collect();
let_assert!(Ok(res) = TokenString::try_from(s1.as_slice()));
check!(&res.prefix[0 .. 6] == b"123456");
check!(
unsafe { &res.u.ptr.as_slice_manually(res.len as usize)[.. 15] }
== b"1234567890ABCDE"
);
check!(res.len == 15);
check!(res.is_small() == false);
}
#[test]
fn try_from_string() {
#[expect(
clippy::std_instead_of_alloc,
reason = "We are testing, this needs std"
)]
let s1: std::string::String = "1234567890ABCDE".into();
let_assert!(Ok(res) = TokenString::try_from(s1));
check!(&res.prefix[0 .. 6] == b"123456");
check!(
unsafe { &res.u.ptr.as_slice_manually(res.len as usize)[.. 15] }
== b"1234567890ABCDE"
);
check!(res.len == 15);
check!(res.is_small() == false);
}
#[test]
fn try_from_stringref() {
#[expect(
clippy::std_instead_of_alloc,
reason = "We are testing, this needs std"
)]
let s1: std::string::String = "1234567890ABCDE".into();
let_assert!(Ok(res) = TokenString::try_from(&s1));
check!(&res.prefix[0 .. 6] == b"123456");
check!(
unsafe { &res.u.ptr.as_slice_manually(res.len as usize)[.. 15] }
== b"1234567890ABCDE"
);
check!(res.len == 15);
check!(res.is_small() == false);
}
#[test]
fn from_str_unchecked() {
let res = TokenString::from_str_unchecked("1234567890ABCDE");
check!(&res.prefix[0 .. 6] == b"123456");
check!(
unsafe { &res.u.ptr.as_slice_manually(res.len as usize)[.. 15] }
== b"1234567890ABCDE"
);
check!(res.len == 15);
check!(res.is_small() == false);
}
#[test]
fn from_bytes_unchecked() {
let s1: &[u8] = b"1234567890ABCDE";
let res = unsafe { TokenString::from_bytes_unchecked(s1) };
check!(&res.prefix[0 .. 6] == b"123456");
check!(
unsafe { &res.u.ptr.as_slice_manually(res.len as usize)[.. 15] }
== b"1234567890ABCDE"
);
check!(res.len == 15);
check!(res.is_small() == false);
}
#[test]
fn from_stringref_unchecked() {
#[expect(
clippy::std_instead_of_alloc,
reason = "We are testing, this needs std"
)]
let s1: std::string::String = "1234567890ABCDE".into();
let res = TokenString::from_string_unchecked(&s1);
check!(&res.prefix[0 .. 6] == b"123456");
check!(
unsafe { &res.u.ptr.as_slice_manually(res.len as usize)[.. 15] }
== b"1234567890ABCDE"
);
check!(res.len == 15);
check!(res.is_small() == false);
}
}