fixedstr_ext/flexible_string.rs
1//! This module implements **[Flexstr]**, which uses an internal enum
2//! to hold either a fixed string of up to a maximum length, or an owned [String].
3
4#![allow(unused_variables)]
5#![allow(non_snake_case)]
6#![allow(non_camel_case_types)]
7#![allow(unused_parens)]
8#![allow(unused_assignments)]
9#![allow(unused_mut)]
10#![allow(unused_imports)]
11#![allow(dead_code)]
12extern crate alloc;
13use crate::tstr;
14use crate::zstr;
15
16#[cfg(feature = "std")]
17use crate::fstr;
18
19use crate::shared_structs::Strunion;
20use crate::shared_structs::Strunion::*;
21use crate::{str12, str128, str16, str192, str24, str256, str32, str4, str48, str64, str8, str96};
22use alloc::string::String;
23use alloc::vec::Vec;
24use core::cmp::{min, Ordering};
25use core::ops::Add;
26
27/// **This type is only available with the `flex-str` option.**
28/// A `Flexstr<N>` is represented internally as a `tstr<N>` if the length of
29/// the string is less than N bytes, and by an owned String otherwise.
30/// The structure satisfies the following axiom:
31/// > *For N <= 256, a `Flexstr<N>` is represented internally by an
32/// owned String if and only if the length of the string is greater than
33/// or equal to N*.
34///
35/// For example, a `Flexstr<16>` will hold a string of up to 15 bytes
36/// in an u8-array of size 16. The first byte of the array holds the length of
37/// the string. If subsequent operations such as [Flexstr::push_str]
38/// extends the string past 15 bytes, the representation will switch to an owned
39/// String. Conversely, an operation such as [Flexstr::truncate]
40/// may switch the representation back to a fixed string.
41/// The default N is 32. **The largest N for which the axiom holds
42/// is 256.** For all N>256, the internal representation is always an owned
43/// string.
44///
45/// Example:
46/// ```ignore
47/// let mut s:Flexstr<8> = Flexstr::from("abcdef");
48/// assert!(s.is_fixed());
49/// s.push_str("ghijk");
50/// assert!(s.is_owned());
51/// s.truncate(7);
52/// assert!(s.is_fixed());
53/// ```
54///
55/// The intended use of this datatype is for
56/// situations when the lengths of strings are *usually* less than N, with
57/// only occasional exceptions that require a different representation.
58/// However, unlike the other string types in this crate, a Flexstr cannot be
59/// copied and is thus subject to **move semantics**. The serde serialization
60/// option is also supported (`features serde`).
61///
62/// In addition, this type impls the `Add` trait for string concatenation:
63///
64/// ```ignore
65/// let a = flexstr8::from("abcd");
66/// let b = &a + "efg";
67/// assert_eq!(&b,"abcdefg");
68/// ```
69///
70#[derive(Clone, Eq)]
71pub struct Flexstr<const N: usize = 32> {
72 inner: Strunion<N>,
73}
74impl<const N: usize> Flexstr<N> {
75 /// Creates a new `Flexstr<N>` with given &str.
76 pub fn make(s: &str) -> Self {
77 if s.len() < N && N <= 256 {
78 Flexstr {
79 inner: fixed(tstr::<N>::from(s)),
80 }
81 } else {
82 Flexstr {
83 inner: owned(String::from(s)),
84 }
85 }
86 } //make
87
88 /// Creates a `Flexstr<N>` by consuming a given string. However, if the
89 /// string has length less than N, then a fixed representation will be used.
90 pub fn from_string(s: String) -> Self {
91 if s.len() < N && N <= 256 {
92 Flexstr {
93 inner: fixed(tstr::<N>::from(&s[..])),
94 }
95 } else {
96 Flexstr { inner: owned(s) }
97 }
98 }
99
100 /// creates a `Flexstr<N>` from a given `tstr<N>`
101 pub fn from_tstr(s: tstr<N>) -> Self {
102 Flexstr { inner: fixed(s) }
103 }
104
105 #[cfg(feature = "serde")]
106 /// this function is only added for uniformity in serde implementation
107 pub fn try_make(s: &str) -> Result<Flexstr<N>, &str> {
108 Ok(Flexstr::make(s))
109 }
110
111 /// length of the string in bytes. This is a constant-time operation.
112 #[inline]
113 pub fn len(&self) -> usize {
114 match &self.inner {
115 fixed(s) => s.len(),
116 owned(s) => s.len(),
117 } //match
118 } //len
119
120 /// creates an empty string, equivalent to [Flexstr::default]
121 #[inline]
122 pub fn new() -> Self {
123 Self::default()
124 }
125
126 /// length in number of characters as opposed to bytes: this is
127 /// not necessarily a constant time operation.
128 pub fn charlen(&self) -> usize {
129 match &self.inner {
130 fixed(s) => s.charlen(),
131 owned(s) => {
132 s.chars().count()
133 //let v: Vec<_> = s.chars().collect();
134 //v.len()
135 }
136 } //match
137 } //charlen
138
139 /// converts fstr to &str, possibly using using [core::str::from_utf8_unchecked]. Since
140 /// Flexstr can only be built from valid utf8 sources, this function
141 /// is safe.
142 pub fn to_str(&self) -> &str {
143 match &self.inner {
144 fixed(s) => s.to_str(),
145 owned(s) => &s[..],
146 } //match
147 } //to_str
148
149 /// same functionality as [Flexstr::to_str], but only uses
150 ///[core::str::from_utf8] and may technically panic.
151 pub fn as_str(&self) -> &str //{self.to_str()}
152 {
153 match &self.inner {
154 fixed(s) => s.as_str(),
155 owned(s) => &s[..],
156 } //match
157 }
158
159 /// version of [Flexstr::as_str] that does not call `unwrap`
160 pub fn as_str_safe(&self) -> Result<&str, core::str::Utf8Error> {
161 match &self.inner {
162 fixed(s) => s.as_str_safe(),
163 owned(s) => Ok(&s[..]),
164 } //match
165 }
166
167 /// retrieves a copy of the underlying fixed string, if it is a fixed string.
168 /// Note that since the `tstr` type is not exported, this function should
169 /// be used in conjunction with one of the public aliases [str4]-[str256].
170 /// For example,
171 /// ```ignore
172 /// let s = Flexstr::<8>::from("abcd");
173 /// let t:str8 = s.get_str().unwrap();
174 /// ```
175 pub fn get_str(&self) -> Option<tstr<N>> {
176 if let fixed(s) = &self.inner {
177 Some(*s)
178 } else {
179 None
180 }
181 } //get_str
182
183 /// if the underlying representation of the string is an owned string,
184 /// return the owned string, leaving an empty string in its place.
185 pub fn take_string(&mut self) -> Option<String> {
186 if let owned(s) = &mut self.inner {
187 let mut temp = fixed(tstr::new());
188 core::mem::swap(&mut self.inner, &mut temp);
189 if let owned(t) = temp {
190 Some(t)
191 } else {
192 None
193 }
194 } else {
195 None
196 }
197 } //take_owned
198
199 /// this function consumes the Flexstr and returns an owned string
200 pub fn to_string(self) -> String {
201 match self.inner {
202 fixed(s) => s.to_string(),
203 owned(s) => s,
204 } //match
205 } //to_string
206
207 /// returns the nth char of the string, if it exists
208 pub fn nth(&self, n: usize) -> Option<char> {
209 self.to_str().chars().nth(n)
210 }
211
212 /// returns the nth byte of the string as a char. This function
213 /// is designed to be quicker than [Flexstr::nth] and does not check
214 /// for bounds.
215 pub fn nth_bytechar(&self, n: usize) -> char {
216 match &self.inner {
217 fixed(s) => s.nth_ascii(n),
218 owned(s) => s.as_bytes()[n] as char,
219 }
220 } //nth_bytechar
221
222 /// alias for [Self::nth_bytechar] (for backwards compatibility)
223 pub fn nth_ascii(&self, n: usize) -> char {
224 self.nth_bytechar(n)
225 }
226
227 /// returns a u8-slice that represents the underlying string. The first
228 /// byte of the slice is **not** the length of the string regarless of
229 /// the internal representation.
230 pub fn as_bytes(&self) -> &[u8] {
231 match &self.inner {
232 fixed(f) => f.as_bytes(),
233 owned(s) => s.as_bytes(),
234 } //match
235 }
236
237 /// returns mutable u8-slice of string underneath. Function requires
238 /// call to [String::as_mut_str] and is therefore marked unsafe.
239 pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
240 match &mut self.inner {
241 fixed(f) => f.as_bytes_mut(),
242 owned(s) => s.as_mut_str().as_bytes_mut(),
243 } //match
244 }
245
246 /// changes a character at character position i to c. This function
247 /// requires that c is in the same character class (ascii or unicode)
248 /// as the char being replaced. It never shuffles the bytes underneath.
249 /// The function returns true if the change was successful.
250 pub fn set(&mut self, i: usize, c: char) -> bool {
251 match &mut self.inner {
252 fixed(s) => s.set(i, c),
253 owned(s) => unsafe {
254 let ref mut cbuf = [0u8; 4];
255 c.encode_utf8(cbuf);
256 let clen = c.len_utf8();
257 if let Some((bi, rc)) = s.char_indices().nth(i) {
258 if clen == rc.len_utf8() {
259 s.as_bytes_mut()[bi..bi + clen].copy_from_slice(&cbuf[..clen]);
260 //self.chrs[bi + 1..bi + clen + 1].copy_from_slice(&cbuf[..clen]);
261 //for k in 0..clen {self.chrs[bi+k+1] = cbuf[k];}
262 return true;
263 }
264 }
265 return false;
266 },
267 } //match
268 } //set
269
270 /// returns whether the internal representation is a fixed string (tstr)
271 pub fn is_fixed(&self) -> bool {
272 match &self.inner {
273 fixed(_) => true,
274 owned(_) => false,
275 }
276 } //is_fixed
277
278 /// returns whether the internal representation is an owned String
279 pub fn is_owned(&self) -> bool {
280 !self.is_fixed()
281 }
282
283 /// applies the destructive closure only if the internal representation
284 /// is a fixed string
285 pub fn if_fixed<F>(&mut self, f: F)
286 where
287 F: FnOnce(&mut tstr<N>),
288 {
289 if let fixed(s) = &mut self.inner {
290 f(s);
291 }
292 }
293
294 /// applies the destructive closure only if the internal representation
295 /// is a fixed string
296 pub fn if_owned<F>(&mut self, f: F)
297 where
298 F: FnOnce(&mut str),
299 {
300 if let owned(s) = &mut self.inner {
301 f(s);
302 }
303 }
304
305 /// applies closure f if the internal representation is a fixed string,
306 /// or closure g if the internal representation is an owned string.
307 pub fn map_or<F, G, U>(&self, f: F, g: G) -> U
308 where
309 F: FnOnce(&tstr<N>) -> U,
310 G: FnOnce(&str) -> U,
311 {
312 match &self.inner {
313 fixed(s) => f(s),
314 owned(s) => g(&s[..]),
315 } //match
316 } //map
317
318 /// version of [Flexstr::map_or] accepting FnMut closures
319 pub fn map_or_mut<F, G, U>(&mut self, f: &mut F, g: &mut G) -> U
320 where
321 F: FnMut(&mut tstr<N>) -> U,
322 G: FnMut(&mut str) -> U,
323 {
324 match &mut self.inner {
325 fixed(s) => f(s),
326 owned(s) => g(&mut s[..]),
327 } //match
328 } //map
329
330 /// This function will append the Flexstr with the given slice,
331 /// switching to the owned-String representation if necessary. The function
332 /// returns true if the resulting string uses a `tstr<N>` type, and
333 /// false if the representation is an owned string.
334 pub fn push_str(&mut self, s: &str) -> bool {
335 match &mut self.inner {
336 fixed(fs) if fs.len() + s.len() < N => {
337 fs.push(s);
338 true
339 }
340 fixed(fs) => {
341 let fss = fs.to_string() + s;
342 self.inner = owned(fss);
343 false
344 }
345 owned(ns) => {
346 ns.push_str(s);
347 false
348 }
349 } //match
350 } //push_str
351
352 /// appends string with a single character, switching to the String
353 /// representation if necessary. Returns true if resulting string
354 /// remains fixed.
355 pub fn push(&mut self, c: char) -> bool {
356 let clen = c.len_utf8();
357 match &mut self.inner {
358 owned(s) => {
359 s.push(c);
360 false
361 }
362 fixed(s) if s.len() + clen >= N => {
363 let mut fss = s.to_string();
364 fss.push(c);
365 self.inner = owned(fss);
366 false
367 }
368 fixed(s) => {
369 let mut buf = [0u8; 4];
370 let bstr = c.encode_utf8(&mut buf);
371 s.push(bstr);
372 true
373 }
374 } //match
375 } //push
376
377 /// alias for push
378 #[inline]
379 pub fn push_char(&mut self, c: char) -> bool {
380 self.push(c)
381 }
382
383 /// remove and return last character in string, if it exists
384 pub fn pop(&mut self) -> Option<char> {
385 if self.len() == 0 {
386 return None;
387 }
388 match &mut self.inner {
389 fixed(s) => s.pop_char(),
390 owned(s) if s.len() > N => s.pop(),
391 owned(s) => {
392 // change representation
393 let lastchar = s.pop();
394 self.inner = fixed(tstr::from(&s));
395 lastchar
396 }
397 } //match
398 } //pop
399
400 /// alias for [Self::pop]
401 pub fn pop_char(&mut self) -> Option<char> {
402 self.pop()
403 }
404
405 /// this function truncates a string at the indicated byte position,
406 /// returning true if the truncated string is fixed, and false if owned.
407 /// The operation has no effect if n is larger than the length of the
408 /// string. The operation will **panic** if n is not on a character
409 /// boundary, similar to [String::truncate].
410 pub fn truncate(&mut self, n: usize) -> bool {
411 match &mut self.inner {
412 fixed(fs) if n < fs.len() => {
413 fs.truncate_bytes(n);
414 true
415 }
416 fixed(_) => true,
417 owned(s) if n < N => {
418 assert!(s.is_char_boundary(n));
419 self.inner = fixed(tstr::<N>::from(&s[..n]));
420 true
421 }
422 owned(s) => {
423 if n < s.len() {
424 s.truncate(n);
425 }
426 false
427 }
428 } //match
429 } //truncate
430
431 /// resets string to empty
432 pub fn clear(&mut self) {
433 match &mut self.inner {
434 fixed(s) => {
435 s.clear();
436 }
437 owned(s) => {
438 self.inner = fixed(tstr::default());
439 }
440 }
441 } //clear
442
443 /// returns string corresponding to slice indices as a copy or clone.
444 pub fn substr(&self, start: usize, end: usize) -> Flexstr<N> {
445 match &self.inner {
446 fixed(s) => Flexstr {
447 inner: fixed(s.substr(start, end)),
448 },
449 owned(s) => Self::from(&s[start..end]),
450 }
451 } //substr
452
453 /// Splits the string into a `tstr<N>` portion and a String portion.
454 /// The structure inherits the fixed part and the String returned will
455 /// contain the extra bytes that does not fit. Example:
456 ///
457 /// ```
458 /// # use fixedstr_ext::*;
459 /// let mut fs:Flexstr<4> = Flexstr::from("abcdefg");
460 /// let extras = fs.split_off();
461 /// assert!( &fs=="abc" && &extras=="defg" && fs.is_fixed());
462 /// ```
463 pub fn split_off(&mut self) -> String {
464 match &mut self.inner {
465 fixed(s) => String::default(),
466 owned(s) => {
467 let answer = String::from(&s[N - 1..]);
468 self.inner = fixed(tstr::<N>::from(&s[..N - 1]));
469 answer
470 }
471 } //match
472 } //split_off
473
474 /// in-place modification of ascii string to lower-case
475 pub fn make_ascii_lowercase(&mut self) {
476 match &mut self.inner {
477 fixed(s) => {
478 s.make_ascii_lowercase();
479 }
480 owned(s) => {
481 s.as_mut_str().make_ascii_lowercase();
482 }
483 } //match
484 } //make_ascii_lowercase
485
486 /// in-place modification of ascii string to upper-case
487 pub fn make_ascii_uppercase(&mut self) {
488 match &mut self.inner {
489 fixed(s) => {
490 s.make_ascii_uppercase();
491 }
492 owned(s) => {
493 s.as_mut_str().make_ascii_uppercase();
494 }
495 } //match
496 }
497
498 /// Tests for ascii case-insensitive equality with another string.
499 /// This function does not test if either string is ascii.
500 pub fn case_insensitive_eq<TA>(&self, other: TA) -> bool
501 where
502 TA: AsRef<str>,
503 {
504 if self.len() != other.as_ref().len() {
505 return false;
506 }
507 let obytes = other.as_ref().as_bytes();
508 let sbytes = self.as_bytes();
509 for i in 0..self.len() {
510 let mut c = sbytes[i];
511 if (c > 64 && c < 91) {
512 c = c | 32;
513 } // make lowercase
514 let mut d = obytes[i];
515 if (d > 64 && d < 91) {
516 d = d | 32;
517 } // make lowercase
518 if c != d {
519 return false;
520 }
521 } //for
522 true
523 } //case_insensitive_eq
524
525 /// Decodes a UTF-16 encodeded slice. If a decoding error is encountered
526 /// or capacity exceeded, an `Err(s)` is returned where s is the
527 /// the encoded string up to the point of the error.
528 pub fn from_utf16(v: &[u16]) -> Result<Self, Self> {
529 let mut s = Self::new();
530 for c in char::decode_utf16(v.iter().cloned()) {
531 if let Ok(c1) = c {
532 if !s.push_char(c1) {
533 return Err(s);
534 }
535 } else {
536 return Err(s);
537 }
538 }
539 Ok(s)
540 } //from_utf16
541} //impl<N>
542
543impl<const N: usize> Default for Flexstr<N> {
544 fn default() -> Self {
545 Flexstr {
546 inner: fixed(tstr::<N>::default()),
547 }
548 }
549}
550
551/*
552impl<const N:usize> core::hash::Hash for Flexstr<N>
553{
554 fn hash<H:core::hash::Hasher>(&self, state:&mut H) {
555 self.as_str().hash(state)
556 }
557}//hash
558*/
559
560impl<const N: usize> core::ops::Deref for Flexstr<N> {
561 type Target = str;
562 fn deref(&self) -> &Self::Target {
563 self.to_str()
564 }
565}
566
567impl<T: AsRef<str> + ?Sized, const N: usize> core::convert::From<&T> for Flexstr<N> {
568 fn from(s: &T) -> Self {
569 Self::make(s.as_ref())
570 }
571}
572
573impl<T: AsMut<str> + ?Sized, const N: usize> core::convert::From<&mut T> for Flexstr<N> {
574 fn from(s: &mut T) -> Self {
575 Self::make(s.as_mut())
576 }
577}
578
579impl<const N: usize> core::cmp::PartialOrd for Flexstr<N> {
580 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
581 //Some(self.chrs[0..self.len].cmp(other.chrs[0..other.len]))
582 Some(self.cmp(other))
583 }
584}
585
586impl<const N: usize> core::cmp::Ord for Flexstr<N> {
587 fn cmp(&self, other: &Self) -> Ordering {
588 self.to_str().cmp(other.to_str())
589 }
590}
591
592impl<const N: usize> core::convert::AsRef<str> for Flexstr<N> {
593 fn as_ref(&self) -> &str {
594 self.to_str()
595 }
596}
597impl<const N: usize> core::convert::AsMut<str> for Flexstr<N> {
598 fn as_mut(&mut self) -> &mut str {
599 match &mut self.inner {
600 fixed(f) => f.as_mut(),
601 owned(s) => s.as_mut(),
602 } //match
603 }
604}
605
606impl<const N: usize> PartialEq<&str> for Flexstr<N> {
607 fn eq(&self, other: &&str) -> bool {
608 &self.to_str() == other // see below
609 } //eq
610}
611
612impl<const N: usize> PartialEq<&str> for &Flexstr<N> {
613 fn eq(&self, other: &&str) -> bool {
614 &self.to_str() == other
615 } //eq
616}
617impl<'t, const N: usize> PartialEq<Flexstr<N>> for &'t str {
618 fn eq(&self, other: &Flexstr<N>) -> bool {
619 &other.to_str() == self
620 }
621}
622impl<'t, const N: usize> PartialEq<&Flexstr<N>> for &'t str {
623 fn eq(&self, other: &&Flexstr<N>) -> bool {
624 &other.to_str() == self
625 }
626}
627
628impl<const N: usize> core::fmt::Debug for Flexstr<N> {
629 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
630 f.pad(&self.to_str())
631 }
632} // Debug impl
633
634impl<const N: usize> core::fmt::Display for Flexstr<N> {
635 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
636 //write!(f, "{}", self.to_str())
637 f.pad(self.to_str())
638 }
639}
640
641impl<const N: usize> core::fmt::Write for Flexstr<N> {
642 fn write_str(&mut self, s: &str) -> core::fmt::Result {
643 self.push_str(s);
644 Ok(())
645 } //write_str
646} //core::fmt::Write trait
647
648impl<const N: usize> core::convert::From<String> for Flexstr<N> {
649 /// *will consume owned string and convert it to a fixed
650 /// representation if its length is less than N*
651 fn from(s: String) -> Self {
652 if s.len() >= N {
653 Flexstr { inner: owned(s) }
654 } else {
655 Flexstr {
656 inner: fixed(tstr::<N>::from(&s[..])),
657 }
658 }
659 }
660} //from String
661
662impl<const M: usize> Flexstr<M> {
663 /// returns a copy/clone of the string with new fixed capacity N.
664 /// Example:
665 /// ```
666 /// # use fixedstr_ext::Flexstr;
667 /// let mut a:Flexstr<4> = Flexstr::from("ab");
668 /// let mut b:Flexstr<8> = a.resize();
669 /// b.push_str("cdef");
670 /// assert!(b.is_fixed());
671 /// a.push_str("1234");
672 /// assert!(a.is_owned());
673 /// ```
674 pub fn resize<const N: usize>(&self) -> Flexstr<N> {
675 Flexstr::from(self)
676 }
677}
678
679/* redundant
680impl<const N:usize> Add for &Flexstr<N> {
681 type Output = Flexstr<N>;
682 fn add(self, other:Self) -> Self::Output {
683 match (&self.inner, &other.inner) {
684 (owned(a),b) => {
685 let mut a2 = a.clone();
686 a2.push_str(&other);
687 Flexstr{inner:owned(a2)}
688 },
689 (a,owned(b)) => {
690 let mut a2 = self.clone().to_string();
691 a2.push_str(&other);
692 Flexstr{inner:owned(a2)}
693 },
694 (fixed(a), fixed(b)) if a.len() + b.len() >= N => {
695 let mut a2 = a.to_string();
696 a2.push_str(&b);
697 Flexstr{inner:owned(a2)}
698 },
699 (fixed(a), fixed(b)) => {
700 let mut a2 = *a; //copy
701 a2.push(&b);
702 Flexstr{inner:fixed(a2)}
703 }
704 }//match
705 }
706}//Add
707*/
708
709impl<const N: usize, TA: AsRef<str>> Add<TA> for &Flexstr<N> {
710 type Output = Flexstr<N>;
711 fn add(self, other: TA) -> Self::Output {
712 match (&self.inner, other.as_ref()) {
713 (owned(a), b) => {
714 let mut a2 = a.clone();
715 a2.push_str(other.as_ref());
716 Flexstr { inner: owned(a2) }
717 }
718 (fixed(a), b) if a.len() + b.len() >= N => {
719 let mut a2 = a.to_string();
720 a2.push_str(b);
721 Flexstr { inner: owned(a2) }
722 }
723 (fixed(a), b) => {
724 let mut a2 = *a; //copy
725 a2.push(b);
726 Flexstr { inner: fixed(a2) }
727 }
728 } //match
729 }
730} //Add, Rhs = &str
731
732impl<const N: usize> Add<&Flexstr<N>> for &str {
733 type Output = Flexstr<N>;
734 fn add(self, other: &Flexstr<N>) -> Flexstr<N> {
735 let mut a2 = Flexstr::from(self);
736 a2.push_str(other);
737 a2
738 }
739} //Add &str on left
740
741impl<const N: usize> Add<Flexstr<N>> for &str {
742 type Output = Flexstr<N>;
743 fn add(self, other: Flexstr<N>) -> Flexstr<N> {
744 let mut a2 = Flexstr::from(self);
745 a2.push_str(&other);
746 a2
747 }
748} //Add &str on left
749
750impl<const N: usize> core::hash::Hash for Flexstr<N> {
751 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
752 self.as_ref().hash(state);
753 }
754} //hash
755
756impl<const N: usize> core::cmp::PartialEq for Flexstr<N> {
757 fn eq(&self, other: &Self) -> bool {
758 self.as_ref() == other.as_ref()
759 }
760} //eq
761
762impl<const N: usize> core::str::FromStr for Flexstr<N> {
763 type Err = &'static str;
764 fn from_str(s: &str) -> Result<Self, Self::Err> {
765 Ok(Flexstr::from(s))
766 }
767}
768
769/// convenient type aliases for [Flexstr]
770pub type flexstr8 = Flexstr<8>;
771pub type flexstr16 = Flexstr<16>;
772pub type flexstr32 = Flexstr<32>;
773pub type flexstr64 = Flexstr<64>;
774pub type flexstr128 = Flexstr<128>;
775pub type flexstr256 = Flexstr<256>;