use core::mem::MaybeUninit;
use core::str;
use nvec::NVec;
use nvec::n_string::{FromUtf8Error, NString};
use nvec::n_vec::TryReserveError;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
use alloc::string::String;
#[cfg(feature = "std")]
use std::ffi::OsStr;
#[cfg(feature = "std")]
use std::path::Path;
impl<const N: usize> NString<N> {
#[inline]
pub const fn try_from_str(s: &str) -> Result<Self, TryReserveError> {
if s.len() > N {
return Err(TryReserveError);
}
let new = unsafe { Self::from_str_unchecked(s) };
Ok(new)
}
#[inline]
#[must_use]
pub const unsafe fn from_str_unchecked(s: &str) -> Self {
let mut new = Self::new();
unsafe { new.as_mut_ptr().copy_from_nonoverlapping(s.as_ptr(), s.len()) };
unsafe { new.set_len(s.len()) };
new
}
pub const fn from_utf8(bytes: NVec<u8, N>) -> Result<Self, FromUtf8Error<N>> {
match str::from_utf8(bytes.as_slice()) {
Ok(..) => {
let s = unsafe { Self::from_utf8_unchecked(bytes) };
Ok(s)
}
Err(utf8_error) => {
let e = FromUtf8Error {
error: utf8_error,
bytes,
};
Err(e)
}
}
}
#[inline]
#[must_use]
pub const unsafe fn from_utf8_unchecked(bytes: NVec<u8, N>) -> Self {
debug_assert!(str::from_utf8(bytes.as_slice()).is_ok());
Self(bytes)
}
#[inline(always)]
#[must_use]
pub const unsafe fn from_raw_parts(data: [MaybeUninit<u8>; N], len: usize) -> Self {
let bytes = unsafe { NVec::from_raw_parts(data, len) };
unsafe { Self::from_utf8_unchecked(bytes) }
}
#[inline(always)]
#[must_use]
pub const fn as_mut_vec(&mut self) -> &mut NVec<u8, N> {
&mut self.0
}
#[inline]
#[must_use]
pub const fn as_str(&self) -> &str {
let bytes = self.as_bytes();
unsafe { str::from_utf8_unchecked(bytes) }
}
#[inline]
#[must_use]
pub const fn as_mut_str(&mut self) -> &mut str {
let bytes = unsafe { self.as_bytes_mut() };
unsafe { str::from_utf8_unchecked_mut(bytes) }
}
#[inline]
#[must_use]
pub const fn as_bytes(&self) -> &[u8] {
self.0.as_slice()
}
#[inline]
#[must_use]
pub const unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
self.0.as_mut_slice()
}
#[inline]
#[must_use]
pub const fn as_ptr(&self) -> *const u8 {
self.0.as_ptr()
}
#[inline]
#[must_use]
pub const fn as_mut_ptr(&mut self) -> *mut u8 {
self.0.as_mut_ptr()
}
#[inline]
#[must_use]
pub const fn to_bytes(&self) -> NVec<u8, N> {
self.0.copied()
}
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn to_string(&self) -> String {
let bytes = self.to_bytes().into_vec();
unsafe { String::from_utf8_unchecked(bytes) }
}
#[cfg(feature = "alloc")]
#[inline]
#[must_use]
pub fn to_boxed_str(&self) -> Box<str> {
self.to_string().into()
}
#[inline(always)]
#[must_use]
pub const fn to_raw_parts(&self) -> ([MaybeUninit<u8>; N], usize) {
self.to_bytes().into_raw_parts()
}
}
impl<const N: usize> AsMut<str> for NString<N> {
#[inline]
fn as_mut(&mut self) -> &mut str {
self
}
}
#[cfg(feature = "std")]
impl<const N: usize> AsRef<Path> for NString<N> {
#[inline]
fn as_ref(&self) -> &Path {
self.as_str().as_ref()
}
}
#[cfg(feature = "std")]
impl<const N: usize> AsRef<OsStr> for NString<N> {
#[inline]
fn as_ref(&self) -> &OsStr {
self.as_str().as_ref()
}
}
#[cfg(feature = "std")]
impl<const N: usize> AsRef<[u8]> for NString<N> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl<const N: usize> AsRef<str> for NString<N> {
#[inline]
fn as_ref(&self) -> &str {
self
}
}
impl<const N: usize> TryFrom<char> for NString<N> {
type Error = TryReserveError;
#[inline]
fn try_from(value: char) -> Result<Self, Self::Error> {
let mut buf = [0; 4];
value.encode_utf8(&mut buf).try_into()
}
}
impl<const N: usize> TryFrom<NVec<u8, N>> for NString<N> {
type Error = FromUtf8Error<N>;
#[inline]
fn try_from(value: NVec<u8, N>) -> Result<Self, Self::Error> {
Self::from_utf8(value)
}
}
impl<const N: usize> TryFrom<&str> for NString<N> {
type Error = TryReserveError;
#[inline]
fn try_from(value: &str) -> Result<Self, Self::Error> {
Self::try_from_str(value)
}
}
impl<const N: usize> TryFrom<&mut str> for NString<N> {
type Error = TryReserveError;
#[inline]
fn try_from(value: &mut str) -> Result<Self, Self::Error> {
Self::try_from_str(value)
}
}
#[cfg(feature = "alloc")]
impl<const N: usize> From<NString<N>> for Box<str> {
#[inline]
fn from(value: NString<N>) -> Self {
value.to_boxed_str()
}
}
#[cfg(feature = "alloc")]
impl<const N: usize> From<NString<N>> for String {
#[inline]
fn from(value: NString<N>) -> Self {
value.to_string()
}
}