#![allow(unused_variables)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(unused_parens)]
#![allow(unused_assignments)]
#![allow(unused_mut)]
#![allow(unused_imports)]
#![allow(dead_code)]
use core::cmp::{min, Ordering, PartialOrd};
#[cfg(not(feature = "no-alloc"))]
extern crate alloc;
use core::ops::Add;
#[derive(Copy, Clone)]
pub struct cstr<const N: usize = 32> {
chrs: [u8; N],
front: u16,
len: u16,
}
impl<const N: usize> cstr<N> {
pub fn make(src: &str) -> cstr<N> {
if N < 1 || N > 65535 {
panic!("cstr strings are limited to a capacity between 1 and 65535");
}
let mut m = cstr::<N>::new();
let length = core::cmp::min(N, src.len());
m.chrs[..length].copy_from_slice(&src.as_bytes()[..length]);
m.len = length as u16;
m
}
pub fn from_ascii(src: &str) -> cstr<N> {
if N < 1 || N > 65535 {
panic!("cstr strings are limited to a maximum capacity of 65535");
}
if !src.is_ascii() {
panic!("cstr string is not ascii");
}
let mut m = cstr::<N>::new();
let length = core::cmp::min(N, src.len());
m.chrs[..length].copy_from_slice(&src.as_bytes()[..length]);
m.len = length as u16;
m
}
pub fn try_make(src: &str) -> Result<cstr<N>, &str> {
let length = src.len();
if length > N || N > 65535 || N < 1 {
return Err(src);
}
let mut m = cstr::new();
m.chrs[..].copy_from_slice(&src.as_bytes()[..length]);
m.len = length as u16;
Ok(m)
}
pub fn try_make_ascii(src: &str) -> Option<cstr<N>> {
let length = src.len();
if length > N || N > 65535 || N < 1 || !src.is_ascii() {
return None;
}
let mut m = cstr::new();
m.chrs[..].copy_from_slice(&src.as_bytes()[..length]);
m.len = length as u16;
Some(m)
}
pub fn make_remainder(src: &str) -> (cstr<N>, &str) {
if N > 65535 || N < 1 {
panic!("cstr strings are limited to a capacity between 1 and 65535");
}
let mut m = cstr::new();
let length = core::cmp::min(N, src.len());
m.chrs[..].copy_from_slice(&src.as_bytes()[..length]);
m.len = length as u16;
(m, &src[length..])
}
pub fn from_pair(left: &str, right: &str) -> Option<cstr<N>> {
let (llen, rlen) = (left.len(), right.len());
if llen + rlen > N || N > 65535 || N < 1 {
return None;
}
let mut m = cstr::new();
m.len = (llen + rlen) as u16;
m.chrs[..llen].copy_from_slice(&left.as_bytes()[..llen]);
m.chrs[llen..].copy_from_slice(&right.as_bytes()[llen..]);
Some(m)
}
pub const fn const_make(src: &str) -> cstr<N> {
let mut m = cstr::<N>::new();
let mut len = src.len();
if len>N {len=N;}
let bytes = src.as_bytes();
let mut i = 0;
while i<len {
m.chrs[i] = bytes[i];
i += 1;
}
m.len = len as u16;
m
}
pub const fn const_try_make(s:&str) -> Result<cstr<N>, &str> {
if s.len()>N || N<1 || N>65535 {Err(s)}
else { Ok(cstr::const_make(s)) }
}
#[inline(always)]
pub fn is_contiguous(&self) -> bool {
(self.front as usize + self.len as usize) <= N
}
pub fn reset(&mut self) {
if self.front == 0 {
return;
}
let mut mhrs = [0; N];
for i in 0..self.len as usize {
mhrs[i] = self.chrs[self.index(i)];
}
self.chrs = mhrs;
self.front = 0;
}
pub fn clear(&mut self) {
self.len = 0;
}
pub fn zero(&mut self) {
self.chrs = [0; N];
self.front = 0;
self.len = 0;
}
pub fn make_contiguous(&mut self) {
if !self.is_contiguous() {
self.reset();
}
}
pub fn nth(&self, n: usize) -> Option<char> {
if n < self.len as usize {
Some(self.chrs[self.index(n)] as char)
} else {
None
}
}
#[inline]
pub const fn nth_bytechar(&self, n: usize) -> char {
self.chrs[self.index(n)] as char
}
pub fn set(&mut self, n: usize, c: char) -> bool {
if c.len_utf8() > 1 || n >= self.len as usize {
false
} else {
self.chrs[self.index(n)] = c as u8;
true
}
}
pub fn push_str<'t>(&mut self, src: &'t str) -> &'t str {
let srclen = src.len();
let slen = self.len as usize;
let bytes = &src.as_bytes();
let length = core::cmp::min(slen + srclen, N);
let remain = if N > (slen + srclen) {
0
} else {
(srclen + slen) - N
};
let mut i = 0;
while i < srclen && i + slen < N {
self.chrs[self.index(slen + i)] = bytes[i];
i += 1;
} self.len += i as u16;
&src[srclen - remain..]
}
pub fn push_front<'t>(&mut self, src: &'t str) -> &'t str {
let srclen = src.len();
let slen = self.len as usize;
let bytes = &src.as_bytes();
let length = core::cmp::min(slen + srclen, N);
let remain = if N >= (slen + srclen) {
0
} else {
(srclen + slen) - N
};
let mut i = 0;
while i < srclen && i + slen < N {
self.front = ((self.front as usize + N - 1) % N) as u16;
self.chrs[self.front as usize] = bytes[srclen - 1 - i];
i += 1;
} self.len += i as u16;
&src[..remain]
}
pub fn push_str_front<'t>(&mut self, src: &'t str) -> &'t str {
self.push_front(src)
}
pub fn push_char(&mut self, c: char) -> bool {
let clen = c.len_utf8();
if clen > 1 || self.len as usize + clen > N {
return false;
}
let mut buf = [0u8; 4]; let bstr = c.encode_utf8(&mut buf);
self.push_str(bstr);
true
}
pub fn push_char_front(&mut self, c: char) -> bool {
let clen = c.len_utf8();
if clen > 1 || self.len as usize + clen > N {
return false;
}
let newfront = (self.front as usize + N - 1) % N;
self.chrs[newfront] = c as u8;
self.front = newfront as u16;
self.len += 1;
true
}
pub fn pop_char(&mut self) -> Option<char> {
if self.len() == 0 {
return None;
}
let lasti = ((self.front + self.len - 1) as usize) % N;
let firstchar = self.chrs[lasti] as char;
self.len -= 1;
Some(firstchar)
}
pub fn pop_char_front(&mut self) -> Option<char> {
if self.len() == 0 {
return None;
}
let firstchar = self.chrs[self.front as usize] as char;
self.front = self.index16(1);
self.len -= 1;
Some(firstchar)
}
pub fn truncate_right(&mut self, n: usize) {
if (n < self.len as usize) {
self.len = n as u16;
}
}
#[inline]
pub fn truncate(&mut self, n: usize) {
self.truncate_right(n);
}
pub fn truncate_left(&mut self, n: usize) {
if (n > 0 && n <= self.len as usize) {
self.front = self.index16(n as u16);
self.len -= n as u16;
}
}
pub fn truncate_front(&mut self, n: usize) {
self.truncate_left(n);
}
pub fn find<P>(&self, predicate: P) -> Option<usize>
where
P: Fn(char) -> bool,
{
let (a, b) = self.to_strs();
if let Some(pos) = a.find(|x: char| predicate(x)) {
Some(pos)
} else if let Some(pos) = b.find(|x: char| predicate(x)) {
Some(a.len() + pos)
} else {
None
}
}
pub fn rfind<P>(&self, predicate: P) -> Option<usize>
where
P: Fn(char) -> bool,
{
let (a, b) = self.to_strs();
if let Some(pos) = b.find(|x: char| predicate(x)) {
Some(a.len() + pos)
} else if let Some(pos) = a.find(|x: char| predicate(x)) {
Some(pos)
} else {
None
}
}
pub fn find_substr(&self, s: &str) -> Option<usize> {
let (a, b) = self.to_strs();
if let Some(pos) = a.find(s) {
return Some(pos);
}
if s.len() > 1 {
for i in 0..s.len() - 1 {
let mid = s.len() - i - 1;
if a.ends_with(&s[..mid]) && b.starts_with(&s[mid..]) {
return Some(a.len() - mid);
}
} }
if let Some(pos) = b.find(s) {
return Some(a.len() + pos);
} else {
None
}
}
pub fn rfind_substr(&self, s: &str) -> Option<usize> {
let (a, b) = self.to_strs();
if let Some(pos) = b.find(s) {
return Some(a.len() + pos);
}
if s.len() > 1 {
for i in 0..s.len() - 1 {
let mid = s.len() - i - 1;
if b.starts_with(&s[mid..]) && a.ends_with(&s[..mid]) {
return Some(a.len() - mid);
}
} }
if let Some(pos) = a.find(s) {
Some(pos)
} else {
None
}
}
pub fn trim_left(&mut self) {
let (a, b) = self.to_strs();
let offset;
if let Some(i) = a.find(|c: char| !c.is_whitespace()) {
offset = i as u16;
} else if let Some(k) = b.find(|c: char| !c.is_whitespace()) {
offset = (a.len() + k) as u16;
} else {
offset = (a.len() + b.len()) as u16;
}
self.front = self.index16(offset); self.len -= offset;
}
pub fn trim_right(&mut self) {
let (a, b) = self.to_strs();
let offset;
if b.len() == 0 {
if let Some(k) = a.rfind(|c: char| !c.is_whitespace()) {
offset = a.len() - k - 1;
} else {
offset = a.len();
}
}
else if let Some(i) = b.rfind(|c: char| !c.is_whitespace()) {
offset = b.len() - i - 1;
} else if let Some(k) = a.rfind(|c: char| !c.is_whitespace()) {
offset = b.len() + (a.len() - k - 1)
} else {
offset = a.len() + b.len();
}
self.len -= offset as u16;
}
pub fn trim_whitespaces(&mut self) {
self.trim_left();
self.trim_right();
}
#[inline(always)]
const fn endi(&self) -> usize {
(self.front as usize + self.len as usize) % N
}
#[inline(always)]
const fn index(&self, i: usize) -> usize {
(self.front as usize + i) % N
}
#[inline(always)]
pub const fn len(&self) -> usize {
self.len as usize
}
#[inline(always)]
pub const fn new() -> Self {
cstr {
chrs: [0; N],
front: 0,
len: 0,
}
}
pub fn to_strs(&self) -> (&str, &str) {
let answer;
if self.len() == 0 {
answer = ("", "");
} else if self.is_contiguous() {
let front = self.front as usize;
answer = (
core::str::from_utf8(&self.chrs[front..front + (self.len as usize)]).unwrap(),
"",
)
} else {
answer = (
core::str::from_utf8(&self.chrs[self.front as usize..]).unwrap(),
core::str::from_utf8(&self.chrs[..self.endi()]).unwrap(),
)
}
answer
}
pub fn chars<'a>(&'a self) -> CircCharIter<'a> {
let contig = self.is_contiguous();
CircCharIter {
first: if contig {
&self.chrs[self.front as usize..(self.front + self.len) as usize]
} else {
&self.chrs[self.front as usize..]
},
second: if contig {
&[]
} else {
&self.chrs[..self.endi()]
},
index: 0,
}
}
pub fn iter<'a>(&'a self) -> CircCharIter<'a> {
self.chars()
}
pub fn to_contiguous(&self) -> cstr<N> {
let mut c = *self;
if !c.is_contiguous() {
c.reset();
}
c
}
pub fn force_str(&self) -> &str {
let (a, b) = self.to_strs();
if b.len() > 0 {
panic!("cstr cannot be transformed into a single str slice without calling reset()");
}
a
}
#[cfg(not(feature = "no-alloc"))]
pub fn to_string(&self) -> alloc::string::String {
let (a, b) = self.to_strs();
let mut s = alloc::string::String::from(a);
if b.len() > 0 {
s.push_str(b);
}
s
}
pub fn substr(&self, start: usize, end: usize) -> cstr<N> {
let mut s = cstr::<N>::default();
if (end <= start || start as u16 > self.len - 1 || end > self.len as usize) {
return s;
}
for i in start..end {
s.chrs[i - start] = self.chrs[self.index(i)];
}
s.len = (end - start) as u16;
s
}
pub fn make_ascii_lowercase(&mut self) {
for i in 0..self.len as usize {
let b = &mut self.chrs[self.index(i)];
if *b >= 65 && *b <= 90 {
*b |= 32;
}
}
}
pub fn make_ascii_uppercase(&mut self) {
for i in 0..self.len as usize {
let b = &mut self.chrs[self.index(i)];
if *b >= 97 && *b <= 122 {
*b -= 32;
}
}
}
pub fn case_insensitive_eq<TA>(&self, other: TA) -> bool
where
TA: AsRef<str>,
{
if self.len() != other.as_ref().len() {
return false;
}
let obytes = other.as_ref().as_bytes();
for i in 0..self.len() {
let mut c = self.chrs[(self.front as usize + i) % N];
if (c > 64 && c < 91) {
c = c | 32;
} let mut d = obytes[i];
if (d > 64 && d < 91) {
d = d | 32;
} if c != d {
return false;
}
} true
}
pub fn from_utf16(v: &[u16]) -> Result<Self, Self> {
let mut s = Self::new();
for c in char::decode_utf16(v.iter().cloned()) {
if let Ok(c1) = c {
if !s.push_char(c1) {
return Err(s);
}
} else {
return Err(s);
}
}
Ok(s)
}
#[inline(always)]
fn index16(&self, i: u16) -> u16 {
(self.front + i) % (N as u16)
}
}
impl<const M: usize> cstr<M> {
pub fn resize<const N: usize>(&self) -> cstr<N> {
let slen = self.len();
let length = if (slen < N) { slen } else { N };
let mut s = cstr::<N>::default();
let (a, b) = self.to_strs();
s.chrs[..a.len()].copy_from_slice(a.as_bytes());
if b.len() > 0 {
s.chrs[a.len()..].copy_from_slice(b.as_bytes());
}
s.len = self.len;
s
}
pub fn reallocate<const N: usize>(&self) -> Option<cstr<N>> {
if self.len() < N {
Some(self.resize())
} else {
None
}
}
}
impl<const N: usize> Default for cstr<N> {
fn default() -> Self {
cstr {
chrs: [0; N],
front: 0,
len: 0,
}
}
}
impl<const N: usize> core::fmt::Debug for cstr<N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let (a, b) = self.to_strs();
f.pad(a)?;
f.pad(b)
}
}
impl<const N: usize> core::fmt::Display for cstr<N> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let (a, b) = self.to_strs();
f.pad(a)?;
f.pad(b)
}
}
impl<const N: usize> PartialEq<&str> for cstr<N> {
fn eq(&self, other: &&str) -> bool {
&self == other
} }
impl<const N: usize> PartialEq<&str> for &cstr<N> {
fn eq(&self, other: &&str) -> bool {
let (a, b) = self.to_strs();
let (alen, blen) = (a.len(), b.len());
alen + blen == other.len() && a == &other[..alen] && (blen == 0 || b == &other[alen..])
} }
impl<const N: usize> PartialEq<cstr<N>> for &str {
fn eq(&self, other: &cstr<N>) -> bool {
let (a, b) = other.to_strs();
let (alen, blen) = (a.len(), b.len());
alen + blen == self.len() && a == &self[..alen] && (blen == 0 || b == &self[alen..])
} }
impl<const N: usize> PartialEq<&cstr<N>> for &str {
fn eq(&self, other: &&cstr<N>) -> bool {
let (a, b) = other.to_strs();
let (alen, blen) = (a.len(), b.len());
alen + blen == self.len() && a == &self[..alen] && (blen == 0 || b == &self[alen..])
} }
pub struct CircCharIter<'a> {
first: &'a [u8],
second: &'a [u8],
index: usize,
}
impl<'a> Iterator for CircCharIter<'a> {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.first.len() {
self.index += 1;
Some(self.first[self.index - 1] as char)
} else if self.index - self.first.len() < self.second.len() {
self.index += 1;
Some(self.second[self.index - self.first.len() - 1] as char)
} else {
None
}
} }
impl<const N: usize, const M: usize> PartialEq<cstr<M>> for cstr<N> {
fn eq(&self, other: &cstr<M>) -> bool {
if self.len != other.len {
return false;
}
for i in 0..self.len {
if self.chrs[(self.front + i) as usize % N]
!= other.chrs[(other.front + i) as usize % M]
{
return false;
}
} true
} } impl<const N: usize> Eq for cstr<N> {}
impl<const N: usize> Ord for cstr<N> {
fn cmp(&self, other: &Self) -> Ordering {
let mut schars = self.chars();
let mut ochars = other.chars();
let mut answer = Ordering::Equal;
loop {
match (schars.next(), ochars.next()) {
(Some(x), Some(y)) if x.cmp(&y) == Ordering::Equal => {}
(Some(x), Some(y)) => {
answer = x.cmp(&y);
break;
}
(None, None) => {
break;
}
(None, _) => {
answer = Ordering::Less;
break;
}
(_, None) => {
answer = Ordering::Greater;
break;
}
} } answer
} }
impl<const N: usize> PartialOrd for cstr<N> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
} }
impl<const N: usize> PartialOrd<&str> for cstr<N> {
fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
let mut schars = self.chars();
let mut ochars = other.chars();
let mut answer = Ordering::Equal;
loop {
match (schars.next(), ochars.next()) {
(Some(x), Some(y)) if x.cmp(&y) == Ordering::Equal => {}
(Some(x), Some(y)) => {
answer = x.cmp(&y);
break;
}
(None, None) => {
break;
}
(None, _) => {
answer = Ordering::Less;
break;
}
(_, None) => {
answer = Ordering::Greater;
break;
}
} } Some(answer)
} }
impl<const N: usize> PartialOrd<&str> for &cstr<N> {
fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
let mut schars = self.chars();
let mut ochars = other.chars();
let mut answer = Ordering::Equal;
loop {
match (schars.next(), ochars.next()) {
(Some(x), Some(y)) if x.cmp(&y) == Ordering::Equal => {}
(Some(x), Some(y)) => {
answer = x.cmp(&y);
break;
}
(None, None) => {
break;
}
(None, _) => {
answer = Ordering::Less;
break;
}
(_, None) => {
answer = Ordering::Greater;
break;
}
} } Some(answer)
} }
impl<const N: usize> core::hash::Hash for cstr<N> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
for i in (0..self.len as usize).rev() {
self.nth_bytechar(i).hash(state);
}
}
}
impl<T: AsRef<str> + ?Sized, const N: usize> core::convert::From<&T> for cstr<N> {
fn from(s: &T) -> cstr<N> {
cstr::make(s.as_ref())
}
}
impl<T: AsMut<str> + ?Sized, const N: usize> core::convert::From<&mut T> for cstr<N> {
fn from(s: &mut T) -> cstr<N> {
cstr::make(s.as_mut())
}
}
impl<const N: usize> core::fmt::Write for cstr<N> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
if s.len() + self.len() > N {
return Err(core::fmt::Error::default());
}
self.push_str(s);
Ok(())
} }
impl<const N: usize, TA: AsRef<str>> Add<TA> for cstr<N> {
type Output = cstr<N>;
fn add(self, other: TA) -> cstr<N> {
let mut a2 = self;
a2.push_str(other.as_ref());
a2
}
}
impl<const N: usize> Add<&cstr<N>> for &str {
type Output = cstr<N>;
fn add(self, other: &cstr<N>) -> cstr<N> {
let mut a2 = *other;
a2.push_front(self);
a2
}
}
impl<const N: usize> Add<cstr<N>> for &str {
type Output = cstr<N>;
fn add(self, mut other: cstr<N>) -> cstr<N> {
other.push_front(self);
other
}
}
impl<const N: usize> Add for &cstr<N> {
type Output = cstr<N>;
fn add(self, other: &cstr<N>) -> cstr<N> {
let mut a2 = *self;
let (l, r) = other.to_strs();
a2.push_str(l);
if r.len() > 0 {
a2.push_str(r);
}
a2
}
}
impl<const N: usize> Add for cstr<N> {
type Output = cstr<N>;
fn add(self, other: cstr<N>) -> cstr<N> {
let mut a2 = self;
let (l, r) = other.to_strs();
a2.push_str(l);
if r.len() > 0 {
a2.push_str(r);
}
a2
}
}
impl<const N: usize> core::str::FromStr for cstr<N> {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() <= N {
Ok(cstr::from(s))
} else {
Err("capacity exceeded")
}
}
}
pub type cstr1k = cstr<1024>;
pub type cstr8 = cstr<8>;
pub type cstr16 = cstr<16>;
pub type cstr32 = cstr<32>;
pub type cstr64 = cstr<64>;
pub type cstr128 = cstr<128>;
pub type cstr256 = cstr<256>;
pub type cstr512 = cstr<512>;