fixedstr_ext/
full_fixed.rs1#![allow(unused_variables)]
3#![allow(non_snake_case)]
4#![allow(non_camel_case_types)]
5#![allow(unused_parens)]
6#![allow(unused_assignments)]
7#![allow(unused_mut)]
8#![allow(dead_code)]
9
10#[cfg(feature = "std")]
11extern crate std;
12use crate::tiny_internal::*;
13use crate::zero_terminated::*;
14use core::cmp::{min, Ordering};
15use core::ops::Add;
16use std::eprintln;
17use std::string::String;
18
19#[derive(Copy, Clone, Eq)]
23pub struct fstr<const N: usize> {
24 chrs: [u8; N],
25 len: usize, } impl<const N: usize> fstr<N> {
28 pub fn make(s: &str) -> fstr<N> {
31 let bytes = s.as_bytes(); let mut blen = bytes.len();
33 if (blen > N) {
34 eprintln!("!Fixedstr Warning in fstr::make: length of string literal \"{}\" exceeds the capacity of type fstr<{}>; string truncated",s,N);
35 blen = N;
36 }
37 let mut chars = [0u8; N];
38 let mut i = 0;
39 let limit = min(N, blen);
40 chars[..limit].clone_from_slice(&bytes[..limit]);
41 fstr {
48 chrs: chars,
49 len: blen, }
51 } pub fn create(s: &str) -> fstr<N> {
56 let bytes = s.as_bytes(); let mut blen = bytes.len();
58 if (blen > N) {
59 blen = N;
60 }
61 let mut chars = [0u8; N];
62 let mut i = 0;
63 let limit = min(N, blen);
64 chars[..limit].clone_from_slice(&bytes[..limit]);
65 fstr {
66 chrs: chars,
67 len: blen,
68 }
69 } pub fn try_make(s: &str) -> Result<fstr<N>, &str> {
74 if s.len() > N {
75 Err(s)
76 } else {
77 Ok(fstr::make(s))
78 }
79 }
80
81 pub const fn const_create(s: &str) -> fstr<N> {
86 let mut t = fstr::<N>::new();
87 let mut len = s.len();
88 if len > N {
89 len = N;
90 } t.len = len;
92 let bytes = s.as_bytes();
93 let mut i = 0;
94 while i < len {
95 t.chrs[i] = bytes[i];
96 i += 1;
97 }
98 t
99 } pub const fn const_create_from_str_slice(strs: &[&str]) -> fstr<N> {
104 let mut result = fstr::<N>::new();
105 let mut position = 0;
106 let mut remaining = strs;
107 while let [current, tail @ ..] = remaining {
108 let current_bytes = current.as_bytes();
109 let mut i = 0;
110 while i < current_bytes.len() && position < N {
111 result.chrs[position] = current_bytes[i];
112 position += 1;
113 i += 1;
114 }
115 if position >= N {
116 break;
117 }
118 remaining = tail;
119 }
120 result.len = position;
121 result
122 }
123
124 pub const fn const_try_create(s: &str) -> Result<fstr<N>, &str> {
126 if s.len() + 1 > N {
127 Err(s)
128 } else {
129 Ok(fstr::const_create(s))
130 }
131 }
132
133 #[inline]
136 pub const fn new() -> fstr<N> {
137 fstr {
138 chrs: [0; N],
139 len: 0,
140 }
141 } #[inline]
147 pub const fn len(&self) -> usize {
148 self.len
149 }
150
151 pub const fn capacity(&self) -> usize {
153 N
154 }
155
156 pub fn to_string(&self) -> String {
158 String::from(self.to_str())
160 }
162
163 pub const fn as_u8(&self) -> [u8; N] {
165 self.chrs
166 }
167
168 pub fn as_bytes(&self) -> &[u8] {
170 &self.chrs[0..self.len]
171 }
172
173 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
175 let n = self.len;
176 &mut self.chrs[0..n]
177 }
178
179 pub fn to_str(&self) -> &str {
183 unsafe { std::str::from_utf8_unchecked(&self.chrs[0..self.len]) }
184 }
185
186 pub const fn to_ptr(&'static self) -> *const u8 {
190 self.chrs.as_ptr()
191 }
192
193 pub fn as_str(&self) -> &str {
197 std::str::from_utf8(&self.chrs[0..self.len]).unwrap()
198 }
199
200 pub fn as_str_safe(&self) -> Result<&str, core::str::Utf8Error> {
202 core::str::from_utf8(&self.chrs[0..self.len])
203 }
204
205 pub fn set(&mut self, i: usize, c: char) -> bool {
210 let ref mut cbuf = [0u8; 4]; c.encode_utf8(cbuf);
212 let clen = c.len_utf8();
213 if let Some((bi, rc)) = self.to_str().char_indices().nth(i) {
214 if clen == rc.len_utf8() {
215 self.chrs[bi..bi + clen].clone_from_slice(&cbuf[..clen]);
216 return true;
218 }
219 }
220 return false;
221 }
222 pub fn push<'t>(&mut self, s: &'t str) -> &'t str {
227 self.push_str(s)
228 } pub fn push_str<'t>(&mut self, src: &'t str) -> &'t str {
260 let srclen = src.len();
261 let slen = self.len();
262 let bytes = &src.as_bytes();
263 let length = core::cmp::min(slen + srclen, N);
264 let remain = if N >= (slen + srclen) {
265 0
266 } else {
267 (srclen + slen) - N
268 };
269 let mut i = 0;
270 while i < srclen && i + slen < N {
271 self.chrs[slen + i] = bytes[i];
272 i += 1;
273 } self.len += i;
275 &src[srclen - remain..]
276 }
277
278 pub fn push_char(&mut self, c: char) -> bool {
281 let clen = c.len_utf8();
282 if self.len + clen > N {
283 return false;
284 }
285 let mut buf = [0u8; 4]; let bstr = c.encode_utf8(&mut buf);
287 self.push(bstr);
288 true
289 } pub fn pop_char(&mut self) -> Option<char> {
293 if self.len() == 0 {
294 return None;
295 }
296 let (ci, lastchar) = self.char_indices().last().unwrap();
297 self.len = ci;
298 Some(lastchar)
299 } pub fn charlen(&self) -> usize {
304 self.to_str().chars().count()
305 }
306
307 pub fn nth(&self, n: usize) -> Option<char> {
309 self.to_str().chars().nth(n)
310 }
311
312 pub const fn nth_bytechar(&self, n: usize) -> char {
318 self.chrs[n] as char
319 }
320 pub const fn nth_ascii(&self, n: usize) -> char {
322 self.chrs[n] as char
323 }
324
325 pub fn truncate(&mut self, n: usize) {
330 if let Some((bi, c)) = self.to_str().char_indices().nth(n) {
331 self.len = bi;
333 }
334 }
336
337 pub fn truncate_bytes(&mut self, n: usize) {
340 if (n < self.len) {
341 assert!(self.is_char_boundary(n));
342 self.len = n
343 }
344 }
345
346 pub fn right_ascii_trim(&mut self) {
350 let mut n = self.len;
351 while n > 0 && (self.chrs[n - 1] as char).is_ascii_whitespace() {
352 n -= 1;
354 }
355 assert!(self.is_char_boundary(n));
356 self.len = n;
357 } pub fn clear(&mut self) {
361 self.len = 0;
362 }
363
364 pub fn make_ascii_lowercase(&mut self) {
367 assert!(self.is_ascii());
368 for b in &mut self.chrs[..self.len] {
369 if *b >= 65 && *b <= 90 {
370 *b |= 32;
371 }
372 }
373 } pub fn make_ascii_uppercase(&mut self) {
378 assert!(self.is_ascii());
379 for b in &mut self.chrs[..self.len] {
380 if *b >= 97 && *b <= 122 {
381 *b -= 32;
382 }
383 }
384 }
385
386 pub fn to_ascii_upper(&self) -> Self {
390 let mut cp = self.clone();
391 cp.make_ascii_uppercase();
392 cp
393 }
394
395 pub fn to_ascii_lower(&self) -> Self {
399 let mut cp = *self;
400 cp.make_ascii_lowercase();
401 cp
402 }
403
404 pub fn case_insensitive_eq<TA>(&self, other: TA) -> bool
407 where
408 TA: AsRef<str>,
409 {
410 if self.len() != other.as_ref().len() {
411 return false;
412 }
413 let obytes = other.as_ref().as_bytes();
414 for i in 0..self.len() {
415 let mut c = self.chrs[i];
416 if (c > 64 && c < 91) {
417 c = c | 32;
418 } let mut d = obytes[i];
420 if (d > 64 && d < 91) {
421 d = d | 32;
422 } if c != d {
424 return false;
425 }
426 } true
428 } pub fn from_utf16(v: &[u16]) -> Result<Self, Self> {
434 let mut s = Self::new();
435 for c in char::decode_utf16(v.iter().cloned()) {
436 if let Ok(c1) = c {
437 if !s.push_char(c1) {
438 return Err(s);
439 }
440 } else {
441 return Err(s);
442 }
443 }
444 Ok(s)
445 } } impl<const N: usize> std::ops::Deref for fstr<N> {
449 type Target = str;
450 fn deref(&self) -> &Self::Target {
451 self.to_str()
452 }
453}
454
455impl<T: AsRef<str> + ?Sized, const N: usize> std::convert::From<&T> for fstr<N> {
456 fn from(s: &T) -> fstr<N> {
457 fstr::make(s.as_ref())
458 }
459}
460impl<T: AsMut<str> + ?Sized, const N: usize> std::convert::From<&mut T> for fstr<N> {
461 fn from(s: &mut T) -> fstr<N> {
462 fstr::make(s.as_mut())
463 }
464}
465
466impl<const N: usize> std::convert::From<String> for fstr<N> {
476 fn from(s: String) -> fstr<N> {
477 fstr::<N>::make(&s[..])
478 }
479}
480
481impl<const N: usize, const M: usize> std::convert::From<zstr<M>> for fstr<N> {
482 fn from(s: zstr<M>) -> fstr<N> {
483 fstr::<N>::make(&s.to_str())
484 }
485}
486
487impl<const N: usize, const M: usize> std::convert::From<tstr<M>> for fstr<N> {
488 fn from(s: tstr<M>) -> fstr<N> {
489 fstr::<N>::make(&s.to_str())
490 }
491}
492
493impl<const N: usize> std::cmp::PartialOrd for fstr<N> {
494 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
495 Some(self.cmp(other))
496 }
497}
498
499impl<const N: usize> std::cmp::Ord for fstr<N> {
500 fn cmp(&self, other: &Self) -> Ordering {
501 self.chrs[0..self.len].cmp(&other.chrs[0..other.len])
502 }
503}
504
505impl<const M: usize> fstr<M> {
506 pub fn resize<const N: usize>(&self) -> fstr<N> {
515 let length = if (self.len < N) { self.len } else { N };
517 let mut chars = [0u8; N];
518 chars[..length].clone_from_slice(&self.chrs[..length]);
519 fstr {
521 chrs: chars,
522 len: length,
523 }
524 } pub fn reallocate<const N: usize>(&self) -> Option<fstr<N>> {
528 if self.len() <= N {
529 Some(self.resize())
530 } else {
531 None
532 }
533 }
534} impl<const N: usize> std::convert::AsRef<str> for fstr<N> {
537 fn as_ref(&self) -> &str {
538 self.to_str()
539 }
540}
541impl<const N: usize> std::convert::AsMut<str> for fstr<N> {
542 fn as_mut(&mut self) -> &mut str {
543 unsafe { std::str::from_utf8_unchecked_mut(&mut self.chrs[0..self.len]) }
544 }
545}
546
547impl<const N: usize> std::fmt::Display for fstr<N> {
548 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
549 f.pad(self.to_str())
551 }
552}
553
554impl<const N: usize> PartialEq<&str> for fstr<N> {
555 fn eq(&self, other: &&str) -> bool {
556 &self.to_str() == other } }
559
560impl<const N: usize> PartialEq<&str> for &fstr<N> {
561 fn eq(&self, other: &&str) -> bool {
562 &self.to_str() == other
563 } }
565impl<'t, const N: usize> PartialEq<fstr<N>> for &'t str {
566 fn eq(&self, other: &fstr<N>) -> bool {
567 &other.to_str() == self
568 }
569}
570impl<'t, const N: usize> PartialEq<&fstr<N>> for &'t str {
571 fn eq(&self, other: &&fstr<N>) -> bool {
572 &other.to_str() == self
573 }
574}
575
576impl<const N: usize> Default for fstr<N> {
578 fn default() -> Self {
579 fstr::<N>::make("")
580 }
581}
582
583impl<const N: usize> std::fmt::Debug for fstr<N> {
584 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
585 f.pad(&self.to_str())
586 }
587} impl<const N: usize> fstr<N> {
590 pub fn substr(&self, start: usize, end: usize) -> fstr<N> {
593 let mut chars = [0u8; N];
594 let mut inds = self.char_indices();
595 let len = self.len();
596 if start >= len || end <= start {
597 return fstr {
598 chrs: chars,
599 len: 0,
600 };
601 }
602 let (si, _) = inds.nth(start).unwrap();
603 let last = if (end >= len) {
604 len
605 } else {
606 match inds.nth(end - start - 1) {
607 Some((ei, _)) => ei,
608 None => len,
609 } }; chars[0..last - si].clone_from_slice(&self.chrs[si..last]);
613 fstr {
620 chrs: chars,
621 len: end - start,
622 }
623 } }
625
626impl<const N: usize> core::fmt::Write for fstr<N> {
638 fn write_str(&mut self, s: &str) -> std::fmt::Result {
640 let rest = self.push(s);
641 if rest.len() > 0 {
642 return Err(core::fmt::Error::default());
643 }
644 Ok(())
645 } } impl<const N: usize, TA: AsRef<str>> Add<TA> for fstr<N> {
649 type Output = fstr<N>;
650 fn add(self, other: TA) -> fstr<N> {
651 let mut a2 = self;
652 a2.push(other.as_ref());
653 a2
654 }
655} impl<const N: usize> Add<&fstr<N>> for &str {
658 type Output = fstr<N>;
659 fn add(self, other: &fstr<N>) -> fstr<N> {
660 let mut a2 = fstr::from(self);
661 a2.push(other);
662 a2
663 }
664} impl<const N: usize> Add<fstr<N>> for &str {
667 type Output = fstr<N>;
668 fn add(self, other: fstr<N>) -> fstr<N> {
669 let mut a2 = fstr::from(self);
670 a2.push(&other);
671 a2
672 }
673} impl<const N: usize> core::hash::Hash for fstr<N> {
676 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
677 self.as_ref().hash(state);
678 }
679} impl<const N: usize> PartialEq for fstr<N> {
688 fn eq(&self, other: &Self) -> bool {
689 self.as_ref() == other.as_ref()
690 }
691}
692
693impl<const N: usize> core::str::FromStr for fstr<N> {
694 type Err = &'static str;
695 fn from_str(s: &str) -> Result<Self, Self::Err> {
696 if s.len() <= N {
697 Ok(fstr::from(s))
698 } else {
699 Err("capacity exceeded")
700 }
701 }
702}
703
704#[cfg(test)]
705mod tests {
706 use super::fstr;
707
708 #[test]
709 fn test_create_fstr_from_str_slice_success() {
710 let slice = &["12", "34", "567"];
711 let _: fstr<8> = fstr::const_create_from_str_slice(slice);
712 let slice = &["12", "34", "5678"];
713 let _: fstr<8> = fstr::const_create_from_str_slice(slice);
714 let slice = &["12", "34", "5678", "90000000"];
715 let _: fstr<8> = fstr::const_create_from_str_slice(slice);
716 }
717}