fixedstr/
zero_terminated.rs1#![allow(unused_variables)]
15#![allow(non_snake_case)]
16#![allow(non_camel_case_types)]
17#![allow(unused_parens)]
18#![allow(unused_assignments)]
19#![allow(unused_mut)]
20#![allow(dead_code)]
21
22#[cfg(feature = "std")]
23#[cfg(not(feature = "no-alloc"))]
24use crate::fstr;
25
26use crate::tstr;
27use core::cmp::{min, Ordering};
28use core::ops::Add;
29
30#[cfg(not(feature = "no-alloc"))]
31extern crate alloc;
32
33#[cfg(feature = "std")]
34#[cfg(not(feature = "no-alloc"))]
35extern crate std;
36
37#[derive(Copy, Clone, Eq)]
45pub struct zstr<const N: usize> {
46 chrs: [u8; N],
47} impl<const N: usize> zstr<N> {
49 pub fn make(s: &str) -> zstr<N> {
54 let mut chars = [0u8; N];
55 let bytes = s.as_bytes(); let mut i = 0;
57 let limit = if N == 0 { 0 } else { min(N - 1, bytes.len()) };
58 chars[..limit].clone_from_slice(&bytes[..limit]);
59 zstr { chrs: chars }
60 } #[inline]
64 pub fn create(s: &str) -> zstr<N> {
65 Self::make(s)
66 }
67
68 pub fn try_make(s: &str) -> Result<zstr<N>, &str> {
71 if s.len() + 1 > N {
72 Err(s)
73 } else {
74 Ok(zstr::make(s))
75 }
76 }
77
78 pub const fn new() -> zstr<N> {
81 zstr {
82 chrs: [0;N]
83 }
84 }
85
86pub const fn const_make(s:&str) -> zstr<N> {
91 let mut t = zstr::<N>::new();
92 let mut len = s.len();
93 if len>N-1 { len = N-1; } let bytes = s.as_bytes();
96 let mut i = 0;
97 while i<len {
98 t.chrs[i] = bytes[i];
99 i += 1;
100 }
101 t
102 }pub const fn const_try_make(s:&str) -> Option<zstr<N>> {
106 if s.len()+1>N {None}
107 else { Some(zstr::const_make(s)) }
108 }
109
110 pub fn from_raw(s: &[u8]) -> zstr<N> {
117 let mut z = zstr { chrs: [0; N] };
118 let mut i = 0;
119 while i + 1 < N && i < s.len() && s[i] != 0 {
120 z.chrs[i] = s[i];
121 i += 1;
122 }
123 z
124 } #[inline(always)]
130 pub const fn len(&self) -> usize {
131 self.blen()
132 }
133
134 pub fn linear_len(&self) -> usize {
140 let mut i = 0;
141 while self.chrs[i] != 0 {
142 i += 1;
143 }
144 return i;
145 } pub fn check_integrity(&self) -> bool {
151 let mut n = self.linear_len();
152 if n == N {
153 return false;
154 }
155 while n < N {
156 if self.chrs[n] != 0 {
157 return false;
158 }
159 n += 1;
160 } true
162 } pub fn clean(&mut self) {
167 let mut n = self.linear_len();
168 if n == N {
169 self.chrs[n - 1] = 0;
170 }
171 while n < N {
172 self.chrs[n] = 0;
173 n += 1;
174 } } #[inline(always)]
179 pub fn capacity(&self) -> usize {
180 if N == 0 {
181 return 0;
182 }
183 N - 1
184 }
185
186 const fn blen(&self) -> usize {
188 let (mut min, mut max) = (0, N);
189 let mut mid = 0;
190 while min < max {
191 mid = (min + max) / 2;
192 if self.chrs[mid] == 0 {
193 max = mid;
195 } else {
196 min = mid + 1;
198 }
199 } min
201 } #[cfg(not(feature = "no-alloc"))]
206 pub fn to_string(&self) -> alloc::string::String {
207 alloc::string::String::from(self.as_str())
208 }
209
210 #[inline]
212 pub fn as_bytes(&self) -> &[u8] {
213 &self.chrs[..self.blen() + 1]
214 }
215
216 pub fn to_str(&self) -> &str {
218 unsafe { core::str::from_utf8_unchecked(&self.chrs[0..self.blen()]) }
219 }
220 pub fn as_str(&self) -> &str {
222 core::str::from_utf8(&self.chrs[0..self.blen()]).unwrap()
223 }
224
225 pub fn set(&mut self, i: usize, c: char) -> bool {
230 let ref mut cbuf = [0u8; 4];
231 c.encode_utf8(cbuf);
232 let clen = c.len_utf8();
233 if let Some((bi, rc)) = self.as_str().char_indices().nth(i) {
234 if clen == rc.len_utf8() {
235 self.chrs[bi..bi + clen].clone_from_slice(&cbuf[..clen]);
236 return true;
237 }
238 }
239 return false;
240 } #[inline]
246 pub fn push<'t>(&mut self, s: &'t str) -> &'t str {
247 self.push_str(s)
248 } pub fn push_str<'t>(&mut self, src: &'t str) -> &'t str {
252 let srclen = src.len();
253 let slen = self.blen();
254 let bytes = &src.as_bytes();
255 let length = core::cmp::min(slen + srclen, N - 1);
256 let remain = if N - 1 >= (slen + srclen) {
257 0
258 } else {
259 (srclen + slen) - N + 1
260 };
261 let mut i = 0;
262 while i < srclen && i + slen + 1 < N {
263 self.chrs[slen + i] = bytes[i];
264 i += 1;
265 } &src[srclen - remain..]
267 } pub fn push_char(&mut self, c: char) -> bool {
272 let clen = c.len_utf8();
273 let slen = self.len();
274 if slen + clen >= N {
275 return false;
276 }
277 let mut buf = [0u8; 4]; c.encode_utf8(&mut buf);
279 for i in 0..clen {
280 self.chrs[slen + i] = buf[i];
281 }
282 self.chrs[slen + clen] = 0;
283 true
284 } pub fn pop_char(&mut self) -> Option<char> {
288 if self.chrs[0] == 0 {
289 return None;
290 } let (ci, lastchar) = self.char_indices().last().unwrap();
292 let mut cm = ci;
294 while cm < N && self.chrs[cm] != 0 {
295 self.chrs[cm] = 0;
296 cm += 1;
297 }
298 Some(lastchar)
299 } pub fn charlen(&self) -> usize {
305 self.to_str().chars().count()
306 }
307
308 pub fn nth(&self, n: usize) -> Option<char> {
310 self.to_str().chars().nth(n)
311 }
313
314 pub fn nth_bytechar(&self, n: usize) -> char {
320 self.chrs[n] as char
321 }
322 pub fn nth_ascii(&self, n: usize) -> char {
324 self.chrs[n] as char
325 }
326
327 pub fn is_ascii(&self) -> bool {
329 self.to_str().is_ascii()
330 }
331
332 pub fn truncate(&mut self, n: usize) {
339 if let Some((bi, c)) = self.as_str().char_indices().nth(n) {
340 let mut bm = bi;
341 while bm < N && self.chrs[bm] != 0 {
342 self.chrs[bm] = 0;
343 bm += 1;
344 }
345 }
347 }
348
349 pub fn truncate_bytes(&mut self, n: usize) {
356 if n < N {
357 assert!(self.is_char_boundary(n));
358 let mut m = n;
360 while m < N && self.chrs[m] != 0 {
361 self.chrs[m] = 0;
362 m += 1;
363 }
364 }
365 } pub fn right_ascii_trim(&mut self) {
371 let mut n = self.blen();
372 while n > 0 && (self.chrs[n - 1] as char).is_ascii_whitespace() {
373 self.chrs[n - 1] = 0;
374 n -= 1;
375 }
376 assert!(self.is_char_boundary(n));
377 } pub fn reverse_bytes(&mut self) {
384 let n = self.blen();
385 let m = n / 2;
386 let mut i = 0;
387 while i < m {
388 self.chrs.swap(i, n - i - 1);
389 i += 1;
390 }
391 } pub fn swap_bytes(&mut self, i: usize, k: usize) -> bool {
397 if i != k && i < N && k < N && self.chrs[i] != 0 && self.chrs[k] != 0 {
398 self.chrs.swap(i, k);
399 true
400 } else {
401 false
402 }
403 } pub fn clear(&mut self) {
407 self.chrs = [0; N];
408 }
410
411 pub fn make_ascii_lowercase(&mut self) {
414 assert!(self.is_ascii());
415 for b in &mut self.chrs {
416 if *b == 0 {
417 break;
418 } else if *b >= 65 && *b <= 90 {
419 *b += 32;
420 }
421 }
422 } pub fn make_ascii_uppercase(&mut self) {
427 assert!(self.is_ascii());
428 for b in &mut self.chrs {
429 if *b == 0 {
430 break;
431 } else if *b >= 97 && *b <= 122 {
432 *b -= 32;
433 }
434 }
435 }
436
437 pub fn to_ascii_upper(&self) -> Self {
441 let mut cp = self.clone();
442 cp.make_ascii_uppercase();
443 cp
444 }
445
446 pub fn to_ascii_lower(&self) -> Self {
450 let mut cp = *self;
451 cp.make_ascii_lowercase();
452 cp
453 }
454
455 pub fn case_insensitive_eq<TA>(&self, other: TA) -> bool
458 where
459 TA: AsRef<str>,
460 {
461 if self.len() != other.as_ref().len() {
462 return false;
463 }
464 let obytes = other.as_ref().as_bytes();
465 for i in 0..self.len() {
466 let mut c = self.chrs[i];
467 if (c > 64 && c < 91) {
468 c = c | 32;
469 } let mut d = obytes[i];
471 if (d > 64 && d < 91) {
472 d = d | 32;
473 } if c != d {
475 return false;
476 }
477 } true
479 } pub fn to_ptr(&self) -> *const u8 {
484 let ptr = &self.chrs[0] as *const u8;
485 ptr
486 }
488
489 pub fn to_ptr_mut(&mut self) -> *mut u8 {
494 &mut self.chrs[0] as *mut u8
495 }
496
497 pub unsafe fn from_ptr(mut ptr: *const u8) -> Self {
500 let mut z = zstr::new();
501 let mut i = 0;
502 while *ptr != 0 && i + 1 < N {
503 z.chrs[i] = *ptr;
504 ptr = (ptr as usize + 1) as *const u8;
505 i += 1;
506 } z.chrs[i] = 0;
508 z
509 } pub fn from_utf16(v: &[u16]) -> Result<Self, Self> {
515 let mut s = Self::new();
516 let mut len = 0; let mut buf = [0u8; 4];
518 for c in char::decode_utf16(v.iter().cloned()) {
519 if let Ok(c1) = c {
520 let cbytes = c1.encode_utf8(&mut buf);
521 let clen = c1.len_utf8();
522 len += clen;
523 if len + 1 > N {
524 s.chrs[len - clen] = 0;
525 return Err(s);
526 } else {
527 s.chrs[len - clen..len].copy_from_slice(&buf[..clen]);
528 }
529 } else {
530 s.chrs[len] = 0;
531 return Err(s);
532 }
533 }
534 s.chrs[len] = 0;
535 Ok(s)
536 } } impl<const N: usize> core::ops::Deref for zstr<N> {
540 type Target = str;
541 fn deref(&self) -> &Self::Target {
542 self.to_str()
543 }
544}
545
546impl<const N: usize> core::convert::AsRef<str> for zstr<N> {
547 fn as_ref(&self) -> &str {
548 self.to_str()
549 }
550}
551impl<const N: usize> core::convert::AsMut<str> for zstr<N> {
552 fn as_mut(&mut self) -> &mut str {
553 let blen = self.blen();
554 unsafe { core::str::from_utf8_unchecked_mut(&mut self.chrs[0..blen]) }
555 }
556}
557
558impl<T: AsRef<str> + ?Sized, const N: usize> core::convert::From<&T> for zstr<N> {
559 fn from(s: &T) -> zstr<N> {
560 zstr::make(s.as_ref())
561 }
562}
563impl<T: AsMut<str> + ?Sized, const N: usize> core::convert::From<&mut T> for zstr<N> {
564 fn from(s: &mut T) -> zstr<N> {
565 zstr::make(s.as_mut())
566 }
567}
568
569#[cfg(feature = "std")]
570#[cfg(not(feature = "no-alloc"))]
571impl<const N: usize> std::convert::From<std::string::String> for zstr<N> {
572 fn from(s: std::string::String) -> zstr<N> {
573 zstr::<N>::make(&s[..])
574 }
575}
576#[cfg(feature = "std")]
577#[cfg(not(feature = "no-alloc"))]
578impl<const N: usize, const M: usize> std::convert::From<fstr<M>> for zstr<N> {
579 fn from(s: fstr<M>) -> zstr<N> {
580 zstr::<N>::make(s.to_str())
581 }
582}
583
584impl<const N: usize, const M: usize> core::convert::From<tstr<M>> for zstr<N> {
585 fn from(s: tstr<M>) -> zstr<N> {
586 zstr::<N>::make(s.to_str())
587 }
588}
589
590impl<const N: usize> core::cmp::PartialOrd for zstr<N> {
591 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
592 Some(self.cmp(other))
594 }
595}
596
597impl<const N: usize> core::cmp::Ord for zstr<N> {
598 fn cmp(&self, other: &Self) -> Ordering {
599 self.chrs[0..self.blen()].cmp(&other.chrs[0..other.blen()])
600 }
601}
602
603impl<const M: usize> zstr<M> {
604 pub fn resize<const N: usize>(&self) -> zstr<N> {
613 let slen = self.blen();
614 let length = if slen + 1 < N {
615 slen
616 } else if N == 0 {
617 0
618 } else {
619 N - 1
620 };
621 let mut chars = [0u8; N];
622 chars[..length].clone_from_slice(&self.chrs[..length]);
623 zstr { chrs: chars }
624 } pub fn reallocate<const N: usize>(&self) -> Option<zstr<N>> {
628 if self.len() < N {
629 Some(self.resize())
630 } else {
631 None
632 }
633 }
634} impl<const N: usize> core::fmt::Display for zstr<N> {
637 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
638 f.pad(self.to_str())
640 }
641}
642
643impl<const N: usize> PartialEq<&str> for zstr<N> {
644 fn eq(&self, other: &&str) -> bool {
645 self.to_str() == *other } }
648impl<const N: usize> PartialEq<&str> for &zstr<N> {
649 fn eq(&self, other: &&str) -> bool {
650 &self.to_str() == other
651 } }
664impl<'t, const N: usize> PartialEq<zstr<N>> for &'t str {
665 fn eq(&self, other: &zstr<N>) -> bool {
666 &other.to_str() == self
667 }
668}
669impl<'t, const N: usize> PartialEq<&zstr<N>> for &'t str {
670 fn eq(&self, other: &&zstr<N>) -> bool {
671 &other.to_str() == self
672 }
673}
674
675impl<const N: usize> Default for zstr<N> {
677 fn default() -> Self {
678 zstr::<N>::make("")
679 }
680}
681#[cfg(feature = "std")]
682#[cfg(not(feature = "no-alloc"))]
683impl<const N: usize, const M: usize> PartialEq<zstr<N>> for fstr<M> {
684 fn eq(&self, other: &zstr<N>) -> bool {
685 other.to_str() == self.to_str()
686 }
687}
688
689#[cfg(feature = "std")]
690#[cfg(not(feature = "no-alloc"))]
691impl<const N: usize, const M: usize> PartialEq<fstr<N>> for zstr<M> {
692 fn eq(&self, other: &fstr<N>) -> bool {
693 other.to_str() == self.to_str()
694 }
695}
696
697#[cfg(feature = "std")]
698#[cfg(not(feature = "no-alloc"))]
699impl<const N: usize, const M: usize> PartialEq<&fstr<N>> for zstr<M> {
700 fn eq(&self, other: &&fstr<N>) -> bool {
701 other.to_str() == self.to_str()
702 }
703}
704
705impl<const N: usize> core::fmt::Debug for zstr<N> {
706 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
707 f.pad(&self.to_str())
708 }
709} impl<const N: usize> zstr<N> {
712 pub fn substr(&self, start: usize, end: usize) -> zstr<N> {
715 let mut chars = [0u8; N];
716 let mut inds = self.char_indices();
717 let len = self.len();
718 let blen = self.blen();
719 if start >= len || end <= start {
720 return zstr { chrs: chars };
721 }
722 let (si, _) = inds.nth(start).unwrap();
723 let last = if (end >= len) {
724 blen
725 } else {
726 match inds.nth(end - start - 1) {
727 Some((ei, _)) => ei,
728 None => blen,
729 } }; chars[..last - si].clone_from_slice(&self.chrs[si..last]);
732 zstr { chrs: chars }
733 } }
735
736pub type ztr8 = zstr<8>;
738pub type ztr16 = zstr<16>;
739pub type ztr32 = zstr<32>;
740pub type ztr64 = zstr<64>;
741pub type ztr128 = zstr<128>;
742
743impl<const N: usize> core::fmt::Write for zstr<N> {
754 fn write_str(&mut self, s: &str) -> core::fmt::Result {
756 if s.len() + self.len() > N - 1 {
757 return Err(core::fmt::Error::default());
758 }
759 self.push(s);
760 Ok(())
761 } } #[cfg(feature = "experimental")]
765mod special_index {
766 use super::*;
767 use core::ops::{Range, RangeFrom, RangeFull, RangeTo};
768 use core::ops::{RangeInclusive, RangeToInclusive};
769
770 impl<const N: usize> core::ops::Index<Range<usize>> for zstr<N> {
771 type Output = str;
772 fn index(&self, index: Range<usize>) -> &Self::Output {
773 &self.as_str()[index]
774 }
775 } impl<const N: usize> core::ops::Index<RangeTo<usize>> for zstr<N> {
777 type Output = str;
778 fn index(&self, index: RangeTo<usize>) -> &Self::Output {
779 &self.as_str()[index]
780 }
781 } impl<const N: usize> core::ops::Index<RangeFrom<usize>> for zstr<N> {
783 type Output = str;
784 fn index(&self, index: RangeFrom<usize>) -> &Self::Output {
785 &self.as_str()[index]
786 }
787 } impl<const N: usize> core::ops::Index<RangeInclusive<usize>> for zstr<N> {
789 type Output = str;
790 fn index(&self, index: RangeInclusive<usize>) -> &Self::Output {
791 &self.as_str()[index]
792 }
793 } impl<const N: usize> core::ops::Index<RangeToInclusive<usize>> for zstr<N> {
795 type Output = str;
796 fn index(&self, index: RangeToInclusive<usize>) -> &Self::Output {
797 &self.as_str()[index]
798 }
799 } impl<const N: usize> core::ops::Index<RangeFull> for zstr<N> {
801 type Output = str;
802 fn index(&self, index: RangeFull) -> &Self::Output {
803 &self.as_str()[index]
804 }
805 } impl<const N: usize> core::ops::Index<usize> for zstr<N> {
814 type Output = u8;
815 fn index(&self, index: usize) -> &Self::Output {
816 &self.chrs[index]
817 }
818 } impl<const N: usize> core::ops::IndexMut<usize> for zstr<N> {
827 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
828 let ln = self.blen();
829 if index >= ln {
830 panic!("index {} out of range ({})", index, ln);
831 }
832 &mut self.chrs[index]
833 }
834 } } impl<const N: usize, TA: AsRef<str>> Add<TA> for zstr<N> {
838 type Output = zstr<N>;
839 fn add(self, other: TA) -> zstr<N> {
840 let mut a2 = self;
841 a2.push(other.as_ref());
842 a2
843 }
844} impl<const N: usize> Add<&zstr<N>> for &str {
856 type Output = zstr<N>;
857 fn add(self, other: &zstr<N>) -> zstr<N> {
858 let mut a2 = zstr::from(self);
859 a2.push(other);
860 a2
861 }
862} impl<const N: usize> Add<zstr<N>> for &str {
865 type Output = zstr<N>;
866 fn add(self, other: zstr<N>) -> zstr<N> {
867 let mut a2 = zstr::from(self);
868 a2.push(&other);
869 a2
870 }
871} impl<const N: usize> core::hash::Hash for zstr<N> {
874 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
875 self.as_ref().hash(state);
876 }
877} impl<const N: usize> core::cmp::PartialEq for zstr<N> {
887 fn eq(&self, other: &Self) -> bool {
888 self.as_ref() == other.as_ref()
889 }
890}
891
892impl<const N: usize> core::str::FromStr for zstr<N> {
893 type Err = &'static str;
894 fn from_str(s: &str) -> Result<Self, Self::Err> {
895 if s.len() < N {
896 Ok(zstr::from(s))
897 } else {
898 Err("capacity exceeded")
899 }
900 }
901}