use core::{cmp::Ordering, fmt, hash, iter, ops, str};
use crate::Vec;
#[cfg(feature = "alloc")]
type Inner<const N: usize> = alloc::string::String;
#[cfg(not(feature = "alloc"))]
type Inner<const N: usize> = heapless::String<N>;
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct String<const N: usize>(Inner<N>);
impl<const N: usize> String<N> {
#[inline]
pub fn new() -> Self {
#[cfg(feature = "alloc")]
{
Self(Inner::with_capacity(N))
}
#[cfg(not(feature = "alloc"))]
{
Self(Inner::new())
}
}
#[inline]
pub fn from_utf8(vec: Vec<u8, N>) -> crate::Result<Self> {
let res = Inner::from_utf8(vec.into_inner()).map(Self);
#[cfg(feature = "alloc")]
{
res.map_err(|e| e.utf8_error().into())
}
#[cfg(not(feature = "alloc"))]
{
res.map_err(|e| e.into())
}
}
#[inline]
pub unsafe fn from_utf8_unchecked(vec: Vec<u8, N>) -> Self {
Self(Inner::from_utf8_unchecked(vec.into_inner()))
}
#[inline]
pub fn into_bytes(self) -> crate::Vec<u8, N> {
crate::Vec::from(self.0.into_bytes())
}
#[inline]
pub fn as_str(&self) -> &str {
self.0.as_str()
}
#[inline]
pub fn as_mut_str(&mut self) -> &mut str {
self.0.as_mut_str()
}
#[inline]
pub unsafe fn as_mut_vec(&mut self) -> &mut crate::vec::Inner<u8, N> {
self.0.as_mut_vec()
}
#[inline]
pub fn push_str(&mut self, string: &str) -> crate::Result<()> {
#[cfg(feature = "alloc")]
{
self.0.push_str(string);
Ok(())
}
#[cfg(not(feature = "alloc"))]
{
self.0
.push_str(string)
.map_err(|_| crate::Error::BufferOverflow)
}
}
#[inline]
pub fn capacity(&self) -> usize {
self.0.capacity()
}
#[inline]
pub fn push(&mut self, c: char) -> crate::Result<()> {
#[cfg(feature = "alloc")]
{
self.0.push(c);
Ok(())
}
#[cfg(not(feature = "alloc"))]
{
self.0.push(c).map_err(|_| crate::Error::BufferOverflow)
}
}
#[inline]
pub fn truncate(&mut self, new_len: usize) {
self.0.truncate(new_len)
}
#[inline]
pub fn pop(&mut self) -> Option<char> {
self.0.pop()
}
#[inline]
pub fn remove(&mut self, index: usize) -> char {
self.0.remove(index)
}
#[inline]
pub fn clear(&mut self) {
self.0.clear()
}
}
impl<const N: usize> Default for String<N> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<'a, const N: usize> TryFrom<&'a str> for String<N> {
type Error = crate::Error;
#[inline]
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
<Self as core::str::FromStr>::from_str(s).map_err(|_| crate::Error::BufferOverflow)
}
}
impl<const N: usize> str::FromStr for String<N> {
type Err = crate::Error;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Inner::from_str(s)
.map(Self)
.map_err(|_| crate::Error::BufferOverflow)
}
}
impl<const N: usize> From<String<N>> for Vec<u8, N> {
#[inline]
fn from(s: String<N>) -> Self {
s.into_bytes()
}
}
impl<const N: usize> From<String<N>> for Inner<N> {
#[inline]
fn from(s: String<N>) -> Self {
s.0
}
}
impl<const N: usize> From<Inner<N>> for String<N> {
#[inline]
fn from(s: Inner<N>) -> Self {
Self(s)
}
}
impl<const N: usize> iter::FromIterator<char> for String<N> {
#[inline]
fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
Self(Inner::from_iter(iter))
}
}
impl<'a, const N: usize> iter::FromIterator<&'a char> for String<N> {
#[inline]
fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
Self(Inner::from_iter(iter))
}
}
impl<'a, const N: usize> iter::FromIterator<&'a str> for String<N> {
#[inline]
fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
Self(Inner::from_iter(iter))
}
}
impl<const N: usize> fmt::Display for String<N> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<const N: usize> hash::Hash for String<N> {
#[inline]
fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
self.0.hash(hasher)
}
}
impl<const N: usize> fmt::Write for String<N> {
#[inline]
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
self.0.write_str(s)
}
#[inline]
fn write_char(&mut self, c: char) -> Result<(), fmt::Error> {
self.0.write_char(c)
}
}
impl<const N: usize> ops::Deref for String<N> {
type Target = str;
#[inline]
fn deref(&self) -> &str {
self.as_str()
}
}
impl<const N: usize> ops::DerefMut for String<N> {
#[inline]
fn deref_mut(&mut self) -> &mut str {
self.as_mut_str()
}
}
impl<const N: usize> AsRef<str> for String<N> {
#[inline]
fn as_ref(&self) -> &str {
self
}
}
impl<const N: usize> AsRef<[u8]> for String<N> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl<const N1: usize, const N2: usize> PartialEq<String<N2>> for String<N1> {
#[inline]
fn eq(&self, rhs: &String<N2>) -> bool {
self.0.eq(&rhs.0)
}
}
impl<const N: usize> PartialEq<str> for String<N> {
#[inline]
fn eq(&self, other: &str) -> bool {
self.0.eq(other)
}
}
impl<const N: usize> PartialEq<&str> for String<N> {
#[inline]
fn eq(&self, other: &&str) -> bool {
self.0.eq(other)
}
}
impl<const N: usize> PartialEq<String<N>> for str {
#[inline]
fn eq(&self, other: &String<N>) -> bool {
self.eq(&other.0)
}
}
impl<const N: usize> PartialEq<String<N>> for &str {
#[inline]
fn eq(&self, other: &String<N>) -> bool {
self.eq(&other.0)
}
}
impl<const N: usize> Eq for String<N> {}
impl<const N1: usize, const N2: usize> PartialOrd<String<N2>> for String<N1> {
#[inline]
fn partial_cmp(&self, other: &String<N2>) -> Option<Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl<const N: usize> Ord for String<N> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.0.cmp(&other.0)
}
}
macro_rules! impl_try_from_num {
($num:ty, $size:expr) => {
impl<const N: usize> core::convert::TryFrom<$num> for String<N> {
type Error = crate::Error;
#[inline]
fn try_from(s: $num) -> Result<Self, Self::Error> {
#[cfg(feature = "alloc")]
{
Ok(Self(alloc::string::ToString::to_string(&s)))
}
#[cfg(not(feature = "alloc"))]
{
Inner::try_from(s)
.map(Self)
.map_err(|_| crate::Error::BufferOverflow)
}
}
}
};
}
impl_try_from_num!(i8, 4);
impl_try_from_num!(i16, 6);
impl_try_from_num!(i32, 11);
impl_try_from_num!(i64, 20);
impl_try_from_num!(u8, 3);
impl_try_from_num!(u16, 5);
impl_try_from_num!(u32, 10);
impl_try_from_num!(u64, 20);