#![allow(unused_variables)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(unused_parens)]
#![allow(unused_assignments)]
#![allow(unused_mut)]
#![allow(dead_code)]
#[cfg(feature = "std")]
use crate::fstr;
use crate::tstr;
use core::cmp::{min, Ordering};
use core::ops::Add;
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct zstr<const N: usize> {
chrs: [u8; N],
} impl<const N: usize> zstr<N> {
pub fn make(s: &str) -> zstr<N> {
let mut chars = [0u8; N];
let bytes = s.as_bytes(); let mut i = 0;
let limit = min(N - 1, bytes.len());
chars[..limit].clone_from_slice(&bytes[..limit]);
zstr { chrs: chars }
}
pub fn create(s: &str) -> zstr<N> {
Self::make(s)
}
pub fn try_make(s: &str) -> Result<zstr<N>, &str> {
if s.len() > N - 1 {
Err(s)
} else {
Ok(zstr::make(s))
}
}
pub fn new() -> zstr<N> {
zstr::make("")
}
pub fn from_raw(s: &[u8]) -> zstr<N> {
let mut z = zstr { chrs: [0; N] };
let mut i = 0;
while i < N - 1 && i < s.len() && s[i] != 0 {
z.chrs[i] = s[i];
i += 1;
}
z
}
#[inline(always)]
pub fn len(&self) -> usize {
self.blen()
}
pub fn linear_len(&self) -> usize {
let mut i = 0;
while self.chrs[i] != 0 {
i += 1;
}
return i;
}
#[inline(always)]
pub fn capacity(&self) -> usize {
N - 1
}
fn blen(&self) -> usize {
let (mut min, mut max) = (0, N);
let mut mid = 0;
while min < max {
mid = (min + max) / 2;
if self.chrs[mid] == 0 {
max = mid;
} else {
min = mid + 1;
}
} min
}
pub fn to_string(&self) -> alloc::string::String {
alloc::string::String::from(self.as_str())
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.chrs[..self.blen() + 1]
}
pub fn to_str(&self) -> &str {
unsafe { core::str::from_utf8_unchecked(&self.chrs[0..self.blen()]) }
}
pub fn as_str(&self) -> &str {
core::str::from_utf8(&self.chrs[0..self.blen()]).unwrap()
}
pub fn set(&mut self, i: usize, c: char) -> bool {
let ref mut cbuf = [0u8; 4];
c.encode_utf8(cbuf);
let clen = c.len_utf8();
if let Some((bi, rc)) = self.as_str().char_indices().nth(i) {
if clen == rc.len_utf8() {
self.chrs[bi..bi + clen].clone_from_slice(&cbuf[..clen]);
return true;
}
}
return false;
} #[inline]
pub fn push<'t>(&mut self, s: &'t str) -> &'t str {
self.push_str(s)
}
pub fn push_str<'t>(&mut self, src: &'t str) -> &'t str {
let srclen = src.len();
let slen = self.blen();
let bytes = &src.as_bytes();
let length = core::cmp::min(slen + srclen, N - 1);
let remain = if N - 1 >= (slen + srclen) {
0
} else {
(srclen + slen) - N + 1
};
let mut i = 0;
while i < srclen && i + slen + 1 < N {
self.chrs[slen + i] = bytes[i];
i += 1;
} &src[srclen - remain..]
}
pub fn push_char(&mut self, c: char) -> bool {
let clen = c.len_utf8();
let slen = self.len();
if slen + clen >= N {
return false;
}
let mut buf = [0u8; 4]; c.encode_utf8(&mut buf);
for i in 0..clen {
self.chrs[slen + i] = buf[i];
}
self.chrs[slen + clen] = 0;
true
}
pub fn pop_char(&mut self) -> Option<char> {
if self.chrs[0] == 0 {
return None;
} let (ci, lastchar) = self.char_indices().last().unwrap();
let mut cm = ci;
while cm < N && self.chrs[cm] != 0 {
self.chrs[cm] = 0;
cm += 1;
}
Some(lastchar)
}
pub fn charlen(&self) -> usize {
self.as_str().chars().count()
}
pub fn nth(&self, n: usize) -> Option<char> {
self.as_str().chars().nth(n)
}
pub fn nth_bytechar(&self, n: usize) -> char {
self.chrs[n] as char
}
pub fn nth_ascii(&self, n: usize) -> char {
self.chrs[n] as char
}
pub fn is_ascii(&self) -> bool {
self.as_str().is_ascii()
}
pub fn truncate(&mut self, n: usize) {
if let Some((bi, c)) = self.as_str().char_indices().nth(n) {
let mut bm = bi;
while bm < N && self.chrs[bm] != 0 {
self.chrs[bm] = 0;
bm += 1;
}
}
}
pub fn truncate_bytes(&mut self, n: usize) {
if n < N {
assert!(self.is_char_boundary(n));
let mut m = n;
while m < N && self.chrs[m] != 0 {
self.chrs[m] = 0;
m += 1;
}
}
}
pub fn right_ascii_trim(&mut self) {
let mut n = self.blen();
while n > 0 && (self.chrs[n - 1] as char).is_ascii_whitespace() {
self.chrs[n - 1] = 0;
n -= 1;
}
assert!(self.is_char_boundary(n));
}
pub fn reverse_bytes(&mut self) {
let n = self.blen();
let m = n / 2;
let mut i = 0;
while i < m {
self.chrs.swap(i, n - i - 1);
i += 1;
}
}
pub fn swap_bytes(&mut self, i: usize, k: usize) -> bool {
if i != k && i < N && k < N && self.chrs[i] != 0 && self.chrs[k] != 0 {
self.chrs.swap(i, k);
true
} else {
false
}
}
pub fn clear(&mut self) {
self.chrs = [0; N];
}
pub fn make_ascii_lowercase(&mut self) {
assert!(self.is_ascii());
for b in &mut self.chrs {
if *b == 0 {
break;
} else if *b >= 65 && *b <= 90 {
*b += 32;
}
}
}
pub fn make_ascii_uppercase(&mut self) {
assert!(self.is_ascii());
for b in &mut self.chrs {
if *b == 0 {
break;
} else if *b >= 97 && *b <= 122 {
*b -= 32;
}
}
}
pub fn to_ascii_upper(&self) -> Self {
let mut cp = self.clone();
cp.make_ascii_uppercase();
cp
}
pub fn to_ascii_lower(&self) -> Self {
let mut cp = *self;
cp.make_ascii_lowercase();
cp
}
}
impl<const N: usize> core::ops::Deref for zstr<N> {
type Target = str;
fn deref(&self) -> &Self::Target {
self.to_str()
}
}
impl<const N: usize> core::convert::AsRef<str> for zstr<N> {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<const N: usize> core::convert::AsMut<str> for zstr<N> {
fn as_mut(&mut self) -> &mut str {
let blen = self.blen();
unsafe { core::str::from_utf8_unchecked_mut(&mut self.chrs[0..blen]) }
}
}
impl<T: AsRef<str> + ?Sized, const N: usize> core::convert::From<&T> for zstr<N> {
fn from(s: &T) -> zstr<N> {
zstr::make(s.as_ref())
}
}
impl<T: AsMut<str> + ?Sized, const N: usize> core::convert::From<&mut T> for zstr<N> {
fn from(s: &mut T) -> zstr<N> {
zstr::make(s.as_mut())
}
}
#[cfg(feature = "std")]
impl<const N: usize> std::convert::From<std::string::String> for zstr<N> {
fn from(s: std::string::String) -> zstr<N> {
zstr::<N>::make(&s[..])
}
}
#[cfg(feature = "std")]
impl<const N: usize, const M: usize> std::convert::From<fstr<M>> for zstr<N> {
fn from(s: fstr<M>) -> zstr<N> {
zstr::<N>::make(s.to_str())
}
}
impl<const N: usize, const M: usize> core::convert::From<tstr<M>> for zstr<N> {
fn from(s: tstr<M>) -> zstr<N> {
zstr::<N>::make(s.to_str())
}
}
impl<const N: usize> core::cmp::PartialOrd for zstr<N> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<const N: usize> core::cmp::Ord for zstr<N> {
fn cmp(&self, other: &Self) -> Ordering {
self.chrs[0..self.blen()].cmp(&other.chrs[0..other.blen()])
}
}
impl<const M: usize> zstr<M> {
pub fn resize<const N: usize>(&self) -> zstr<N> {
let slen = self.blen();
let length = if (slen < N - 1) { slen } else { N - 1 };
let mut chars = [0u8; N];
chars[..length].clone_from_slice(&self.chrs[..length]);
zstr { chrs: chars }
}
pub fn reallocate<const N: usize>(&self) -> Option<zstr<N>> {
if self.len() < N {
Some(self.resize())
} else {
None
}
}
}
impl<const N: usize> core::fmt::Display for zstr<N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl<const N: usize> PartialEq<&str> for zstr<N> {
fn eq(&self, other: &&str) -> bool {
self.as_str() == *other } }
impl<const N: usize> PartialEq<&str> for &zstr<N> {
fn eq(&self, other: &&str) -> bool {
&self.as_str() == other
} }
impl<'t, const N: usize> PartialEq<zstr<N>> for &'t str {
fn eq(&self, other: &zstr<N>) -> bool {
&other.as_str() == self
}
}
impl<'t, const N: usize> PartialEq<&zstr<N>> for &'t str {
fn eq(&self, other: &&zstr<N>) -> bool {
&other.as_str() == self
}
}
impl<const N: usize> Default for zstr<N> {
fn default() -> Self {
zstr::<N>::make("")
}
}
#[cfg(feature = "std")]
impl<const N: usize, const M: usize> PartialEq<zstr<N>> for fstr<M> {
fn eq(&self, other: &zstr<N>) -> bool {
other.as_str() == self.to_str()
}
}
#[cfg(feature = "std")]
impl<const N: usize, const M: usize> PartialEq<fstr<N>> for zstr<M> {
fn eq(&self, other: &fstr<N>) -> bool {
other.to_str() == self.as_str()
}
}
#[cfg(feature = "std")]
impl<const N: usize, const M: usize> PartialEq<&fstr<N>> for zstr<M> {
fn eq(&self, other: &&fstr<N>) -> bool {
other.to_str() == self.as_str()
}
}
impl<const N: usize> core::fmt::Debug for zstr<N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.pad(&self.to_str())
}
}
impl<const N: usize> zstr<N> {
pub fn substr(&self, start: usize, end: usize) -> zstr<N> {
let mut chars = [0u8; N];
let mut inds = self.char_indices();
let len = self.len();
let blen = self.blen();
if start >= len || end <= start {
return zstr { chrs: chars };
}
let (si, _) = inds.nth(start).unwrap();
let last = if (end >= len) {
blen
} else {
match inds.nth(end - start - 1) {
Some((ei, _)) => ei,
None => blen,
} }; chars[..last - si].clone_from_slice(&self.chrs[si..last]);
zstr { chrs: chars }
} }
pub type ztr8 = zstr<8>;
pub type ztr16 = zstr<16>;
pub type ztr32 = zstr<32>;
pub type ztr64 = zstr<64>;
pub type ztr128 = zstr<128>;
impl<const N: usize> core::fmt::Write for zstr<N> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
if s.len() + self.len() > N - 1 {
return Err(core::fmt::Error::default());
}
self.push(s);
Ok(())
} }
#[cfg(feature = "std")]
mod special_index {
extern crate std;
use super::*;
use std::ops::{Range, RangeFrom, RangeFull, RangeTo};
use std::ops::{RangeInclusive, RangeToInclusive};
impl<const N: usize> core::ops::Index<usize> for zstr<N> {
type Output = u8;
fn index(&self, index: usize) -> &Self::Output {
&self.chrs[index]
}
} impl<const N: usize> core::ops::IndexMut<usize> for zstr<N> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let ln = self.blen();
if index >= ln {
panic!("index {} out of range ({})", index, ln);
}
&mut self.chrs[index]
}
}
impl<const N: usize> core::ops::Index<Range<usize>> for zstr<N> {
type Output = str;
fn index(&self, index: Range<usize>) -> &Self::Output {
&self.as_str()[index]
}
} impl<const N: usize> core::ops::Index<RangeTo<usize>> for zstr<N> {
type Output = str;
fn index(&self, index: RangeTo<usize>) -> &Self::Output {
&self.as_str()[index]
}
} impl<const N: usize> core::ops::Index<RangeFrom<usize>> for zstr<N> {
type Output = str;
fn index(&self, index: RangeFrom<usize>) -> &Self::Output {
&self.as_str()[index]
}
} impl<const N: usize> core::ops::Index<RangeInclusive<usize>> for zstr<N> {
type Output = str;
fn index(&self, index: RangeInclusive<usize>) -> &Self::Output {
&self.as_str()[index]
}
} impl<const N: usize> core::ops::Index<RangeToInclusive<usize>> for zstr<N> {
type Output = str;
fn index(&self, index: RangeToInclusive<usize>) -> &Self::Output {
&self.as_str()[index]
}
} impl<const N: usize> core::ops::Index<RangeFull> for zstr<N> {
type Output = str;
fn index(&self, index: RangeFull) -> &Self::Output {
&self.as_str()[index]
}
} }
impl<const N: usize> Add<&str> for zstr<N> {
type Output = zstr<N>;
fn add(self, other: &str) -> zstr<N> {
let mut a2 = self;
a2.push(other);
a2
}
}
impl<const N: usize> Add<&zstr<N>> for &str {
type Output = zstr<N>;
fn add(self, other: &zstr<N>) -> zstr<N> {
let mut a2 = zstr::from(self);
a2.push(other);
a2
}
}
impl<const N: usize> Add<zstr<N>> for &str {
type Output = zstr<N>;
fn add(self, other: zstr<N>) -> zstr<N> {
let mut a2 = zstr::from(self);
a2.push(&other);
a2
}
}