use core::fmt;
#[cfg(feature = "std")]
use std::string::String;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::alignment_resolver::{AlignmentForLength, AlignmentMarker, AlignmentType};
use crate::bitmap_resolver::{BitmapForLength, BitmapMarker, BitmapType};
use crate::errors::ExceedsCapacity;
use crate::str_vec::StrVec;
#[cfg(doc)]
use crate::BStr7;
#[cfg(doc)]
use crate::BStr15;
#[cfg(doc)]
use crate::BStr31;
#[cfg(doc)]
use crate::BStr63;
#[cfg(doc)]
use crate::BStr127;
#[cfg(doc)]
use crate::FStr64;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct BoundedStr<const N: usize, Alignment> {
length: u8,
data: [u8; N],
align: [Alignment; 0],
}
impl<const N: usize, Alignment> Default for BoundedStr<N, Alignment> {
fn default() -> Self {
Self::new()
}
}
impl<const N: usize, Alignment> BoundedStr<N, Alignment> {
#[inline]
pub const fn new() -> Self {
Self {
length: 0,
data: [0; N],
align: [],
}
}
pub const fn const_from(src: &str) -> Self {
let bytes = src.as_bytes();
let length = bytes.len();
if length > N {
panic!("String length exceeds capacity");
}
let mut data = [0u8; N];
{
let (left, _) = data.split_at_mut(length);
left.copy_from_slice(bytes);
}
BoundedStr {
length: length as u8,
data,
align: [],
}
}
#[inline]
pub const fn const_try_from(src: &str) -> Option<Self> {
let bytes = src.as_bytes();
let length = bytes.len();
if length > N {
None
} else {
let mut data = [0u8; N];
{
let (left, _) = data.split_at_mut(length);
left.copy_from_slice(bytes);
}
Some(BoundedStr {
length: length as u8,
data,
align: [],
})
}
}
#[inline]
pub fn try_from(s: &str) -> Result<Self, ExceedsCapacity> {
let bytes = s.as_bytes();
let length = bytes.len();
if length > N {
return Err(ExceedsCapacity {
length,
capacity: N,
});
}
let mut data = [0u8; N];
data[0..length].copy_from_slice(bytes);
Ok(BoundedStr {
length: length as u8,
data,
align: [],
})
}
#[inline]
pub fn len(&self) -> usize {
self.length as usize
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn push_str(&mut self, s: &str) -> Result<(), ExceedsCapacity> {
let bytes = s.as_bytes();
let length = self.length as usize;
let new_len = length + bytes.len();
if new_len > N {
return Err(ExceedsCapacity {
length: new_len,
capacity: N,
});
}
self.data[length..new_len].copy_from_slice(bytes);
self.length = new_len as u8;
Ok(())
}
#[inline]
pub fn push(&mut self, c: char) -> Result<(), ExceedsCapacity> {
let mut buf = [0u8; 4];
let s = c.encode_utf8(&mut buf);
self.push_str(s)
}
#[inline]
pub fn as_str(&self) -> &str {
unsafe { core::str::from_utf8_unchecked(&self.data[..self.length as usize]) }
}
pub fn split(&self, delimiter: &str) -> StrVec<BitmapType<N>, N, AlignmentType<N>>
where
BitmapMarker: BitmapForLength<N>,
AlignmentMarker: AlignmentForLength<N>,
{
let s = self.as_str();
let mut result = StrVec::new();
let mut start = 0;
let mut i = 0;
while i < self.length as usize {
if &self.data[i..i + delimiter.len()] == delimiter.as_bytes() {
result.push(&s[start..i]).unwrap();
start = i + delimiter.len();
i += delimiter.len();
} else {
i += 1;
}
}
if start <= self.length as usize {
result.push(&s[start..]).unwrap();
}
result
}
}
impl<const N: usize, Alignment> fmt::Display for BoundedStr<N, Alignment> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl<const N: usize, Alignment> fmt::Debug for BoundedStr<N, Alignment> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl<const N: usize, Alignment> From<&str> for BoundedStr<N, Alignment> {
#[track_caller]
fn from(s: &str) -> Self {
Self::try_from(s).unwrap()
}
}
#[cfg(feature = "std")]
impl<const N: usize, Alignment> From<&String> for BoundedStr<N, Alignment> {
#[track_caller]
fn from(s: &String) -> Self {
Self::try_from(s).unwrap()
}
}
#[cfg(feature = "std")]
impl<const N: usize, Alignment> From<String> for BoundedStr<N, Alignment> {
#[track_caller]
fn from(s: String) -> Self {
Self::try_from(&s).unwrap()
}
}
#[cfg(feature = "serde")]
impl<const N: usize, Alignment> Serialize for BoundedStr<N, Alignment> {
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, Alignment> Deserialize<'de> for BoundedStr<N, Alignment> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
BoundedStr::try_from(&s).map_err(serde::de::Error::custom)
}
}