use core::fmt;
#[cfg(feature = "std")]
use std::string::String;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(doc)]
use crate::BStr63;
#[cfg(doc)]
use crate::BStr127;
#[cfg(doc)]
use crate::BoundedStr;
#[cfg(doc)]
use crate::FStr8;
#[cfg(doc)]
use crate::FStr16;
#[cfg(doc)]
use crate::FStr24;
#[cfg(doc)]
use crate::FStr32;
#[cfg(doc)]
use crate::FStr64;
#[cfg(doc)]
use crate::FStr128;
use crate::ExceedsCapacity;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FixedStr<const N: usize, Alignment> {
data: [u8; N],
align: [Alignment; 0],
}
impl<const N: usize, Alignment> FixedStr<N, Alignment> {
#[inline]
pub const fn new() -> Self {
FixedStr {
data: [0; N],
align: [],
}
}
#[inline]
pub const unsafe fn from_bytes(data: [u8; N]) -> Self {
FixedStr { data, align: [] }
}
#[inline]
pub fn try_from(s: &str) -> Result<Self, ExceedsCapacity> {
let length = s.len();
if length > N {
return Err(ExceedsCapacity {
length,
capacity: N,
});
}
let mut data = [0u8; N];
let bytes = s.as_bytes();
data[0..length].copy_from_slice(bytes);
Ok(FixedStr { data, align: [] })
}
pub const fn const_from(s: &str) -> Self {
let length = s.len();
if length > N {
panic!("String length exceeds capacity");
}
let bytes = s.as_bytes();
let mut t = FixedStr {
data: [0; N],
align: [],
};
{
let (left, _) = t.data.split_at_mut(length);
left.copy_from_slice(bytes);
}
t
}
#[inline]
pub const fn const_try_from(s: &str) -> Option<Self> {
let length = s.len();
if length > N {
None
} else {
let bytes = s.as_bytes();
let mut t = FixedStr {
data: [0; N],
align: [],
};
{
let (left, _) = t.data.split_at_mut(length);
left.copy_from_slice(bytes);
}
Some(t)
}
}
#[inline]
pub fn as_bytes(&self) -> &[u8; N] {
&self.data
}
#[inline]
pub fn as_str(&self) -> &str {
unsafe { core::str::from_utf8_unchecked(&self.data) }
}
#[inline]
pub fn as_str_trimmed(&self) -> &str {
let length = self
.data
.iter()
.position(|&b| b == 0)
.unwrap_or(self.data.len());
unsafe { core::str::from_utf8_unchecked(&self.data[..length]) }
}
#[cfg(feature = "std")]
pub fn to_string_trimmed(&self) -> String {
String::from(self.as_str_trimmed())
}
}
impl<const N: usize, Alignment> Default for FixedStr<N, Alignment> {
fn default() -> Self {
FixedStr::new()
}
}
impl<const N: usize, Alignment> fmt::Display for FixedStr<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 FixedStr<N, Alignment> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str_trimmed())
}
}
impl<const N: usize, Alignment> From<&str> for FixedStr<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 FixedStr<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 FixedStr<N, Alignment> {
#[track_caller]
fn from(s: String) -> Self {
Self::try_from(&s).unwrap()
}
}
#[cfg(feature = "serde")]
impl<const N: usize, Alignment> Serialize for FixedStr<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 FixedStr<N, Alignment> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let v = String::deserialize(deserializer)?;
FixedStr::try_from(&v).map_err(serde::de::Error::custom)
}
}