fixedstr/
lib.rs

1//! **Library for several alternative string types using const generics.**
2//!
3//!
4//!  - The size of some types such as [str8] and [zstr]\<8\>
5//!    are 8 bytes, compared to 16 bytes for `&str` on 64bit systems,
6//!    providing more efficient ways of representing small strings.
7//!  -  Most types (except the optional [Flexstr] and [Sharedstr]) can be
8//!    copied and stack-allocated.
9//!  -  `#![no_std]` is supported by all but the optional [fstr] type.
10//!     Features that use the alloc crate can also be optionally excluded.
11//!  -  Unicode is supported by all but the optional [cstr] type.
12//!  -  Serde serialization is supported by all but the optional [Sharedstr] type.
13//!  -  Select functions are `const`, including const constructors.
14//!
15//!
16//! **COMPATIBILITY NOTICES**:
17//!
18//! > **With Version 0.5.0, the default availability of some
19//!   string types have changed.**  The default configuration is minimalized.
20//!   The `std`, `flex-str` and `shared-str`
21//!   options are no longer enabled by default.  The crate now
22//!   supports **`#![no_std]`** by default.  The `std` option only enables the
23//!   [fstr] type, which prints warnings to stderr. **However,** unless
24//!   you require one of the types [fstr], [Flexstr] or [Sharedstr], your
25//!   build configurations most likely will work as before: the builds will just be
26//!   smaller.  If `default-features=false` is already part of your
27//!   configuration, it should also work as before.
28//!
29//! > Another change that could potentially affect backwards compatibility is that
30//!   zstr's `Index<usize>` and `IndexMut<usize>` traits, which allow
31//!   arbitrary modifications to underlying bytes, is now only available
32//!   with the optional `experimental` feature.  Previously, they were
33//!   available as default features.
34//!
35//! **Other Important Recent Updates:**
36//!
37//! >  **Version 0.5.1 introduced the new *`no-alloc`* option**.  In addition to support
38//!    for no_std (for all but the fstr type), this option disables compilation of
39//!    any features that use the alloc crate.  This may make some no_std implementations
40//!    easier. The default build is no longer minimal (see below).
41//!
42//! >  As of Version 0.4.6, all string types except for `fstr` support
43//! **`#![no_std]`**.
44//!
45//! >  Starting in Version 0.4.2, the underlying representation of the zero-terminated [zstr]
46//! type no longer allows non-zero bytes after the first zero.  In particular,
47//! the [zstr::from_raw] function now enforces this rule.
48//!
49//! >  Starting in Version 0.4.0, warnings about
50//! capacity being exceeded are only sent to stderr when using the fstr type.
51//! For other types, truncation is done silently. Consider using the
52//! `try_make` function or the [core::str::FromStr] trait.
53//!
54//! <hr>
55//!
56//! **CRATE OVERVIEW**
57//!
58//! The two string types that are always provided by this crate are **[zstr]** and **[tstr]**.
59//! However, [tstr] is not public by default and should be referenced
60//! through the type aliases [str4], [str8], [str16], ...  [str256].
61//!
62//! - A **[zstr]\<N\>** is represented by a `[u8;N]` array underneath
63//!   and can hold zero-terminated, utf-8 strings of up to N-1 bytes.
64//! Furthermore, no non-zero bytes can follow the first zero. This
65//! allows the length of a `zstr<N>` string to be found in O(log N) time.
66//!
67//! - The types **[str4]** through **[str256]** are aliases for internal types
68//! [tstr]\<4\> through [tstr]\<256\> respectively.  These strings are stored
69//! in `[u8;N]` arrays with the first byte holding the length of the
70//! string.  Each `tstr<N>` can store strings of up to N-1 bytes, with
71//! maximum N=256. Because Rust does not currently provide
72//! a way to specify conditions (or type casts) on const generics at
73//! compile time, the tstr type is not public by
74//! default and can only be used through the aliases.  The `pub-tstr` option
75//! makes the `tstr` type public but is not recommended: any `tstr<N>` with
76//! `N>256` is not valid and will result in erroneous behavior.
77//!
78//! In addition, the following string types are available as options:
79//!
80//! - A **[fstr]\<N\>** stores a string of up to N bytes.
81//! It's represented by a `[u8;N]` array and a separate usize variable
82//! holding the length.  This type is **enabled with either the `std` or
83//! `fstr` option** and some functions will print warnings to stderr when
84//! capacity is exceeded. This is the only type that does not support
85//! `no_std`, but serde is supported.
86//! - The type **[cstr]**, which is **made available
87//! with the `circular-str` option**, uses a fixed u8 array
88//! that is arranged as a circular queue (aka ring buffer).  This allows
89//! efficient implementations of pushing/triming characters *in front* of
90//! the string without additional memory allocation.  The downside of these
91//! strings is that the underlying representation can be non-contiguous as it allows
92//! wrap-around.  As a result, there is no efficient way to implement
93//! `Deref<str>`.  Additionally, cstr is the only string type of the crate
94//! that does not support Unicode. **Only single-byte characters** are
95//! currently supported. There is, however, an iterator over all characters
96//! and most common traits are implemented.  Serde and no-std are both supported.
97//! - The **[Flexstr]\<N\>** type becomes available with the **`flex-str` option**.
98//!   This type uses an internal enum that is either a tstr\<N\>
99//!   or an owned String (alloc::string::String) in case the length of the string exceeds N-1.
100//!   This type is designed for situations where strings only
101//!   occasionally exceed the limit of N-1 bytes. This type does not implement
102//!   the `Copy` trait.  Serde and no_std are supported.
103//! - The **[Sharedstr]\<N\>** type becomes available with the **`shared-str`
104//!   option**. This type is similar to a [Flexstr]\<N\> but uses a
105//!   `Rc<RefCell<..>>` underneath to allow strings to be shared as well as
106//!   mutated.  This type does not implement `Copy` but `Clone` is done
107//!   in constant time.  no_std is supported but **not serde**.
108//!
109//! **SUMMARY OF OPTIONAL FEATURES**
110//!
111//! - ***serde*** : Serialization was initially contributed
112//!   by [wallefan](https://github.com/wallefan) and adopted to other types
113//!   (except `Sharedstr`).  This feature enables the Serialize/Deserialize
114//!   traits.
115//! - ***circular-str***: this feature makes available the **[cstr]** type.
116//! - ***flex-str***: this feature makes available the **[Flexstr]** type.  
117//! - ***shared-str***: this feature makes available the **[Sharedstr]** type.
118//! - ***std***: this feature cancels `no_std` by enabling the **[fstr]** type.
119//!   An alias for this feature name is 'fstr'.
120//! - ***pub-tstr***: this feature will make the tstr type public. It is not
121//!   recommended: use instead the type aliases [str4] - [str256], which are
122//!   always available.
123//! - **no-alloc**: this *anti-feature* disables any features that requires the alloc (or std)
124//!   crate.  It will disable *entirely* the fstr, Flexstr and Sharedstr types: using
125//!   `no-alloc` together with `flex-str`, for example, will not enable the Flexstr type.
126//!   It also disables the features in [tstr], [zstr] and [cstr] that require the
127//!   alloc crate, in particular any use of alloc::string::String.  Using this feature
128//!   is *stronger than no_std*.  Note that when compiled with the `all-features` option, this feature will be included, which will exclude other features.
129//! - ***experimental***: the meaning of this feature may change.  Currently
130//!   it implements custom Indexing traits for the zstr type, including
131//!   `IndexMut<usize>`, which allows individual bytes to be changed
132//!   arbitrarily.  Experimental features are not part of the documentation.
133//!
134//! None of these features is provided by default, so specifying
135//! `default-features=false` has no effect.
136//!
137//! **SAMPLE BUILD CONFIGURATIONS**
138//!
139//! The simplest way to install this create is to **`cargo add fixedstr`** in your
140//! crate or add `fixedstr = "0.5"` to your dependencies in Cargo.toml.
141//! The default build makes available the [zstr] type and the type aliases
142//! [str4] - [str256] for [tstr].  Serde is not available with this build
143//! but no_std is supported, substituting some std features with those from the
144//! alloc crate.
145//!
146//! For **the smallest possible build**, do **`cargo add fixedstr --features no-alloc`**
147//! in your crate or add the following in Cargo.toml.
148//! ```ignore
149//!   [dependencies]
150//!   fixedstr = {version="0.5", features=["no-alloc"]}
151//! ```
152//!
153//! To further enable serde serialization, add the following instead:
154//! ```ignore
155//!   [dependencies]
156//!   fixedstr = {version="0.5", features=["serde","no-alloc"]}
157//! ```
158//! and to exclude `cstr` but include all other features (except `no-alloc`):
159//! ```ignore
160//!   [dependencies]
161//!   fixedstr = {version="0.5", features=["std","flex-str","shared-str","serde","pub-tstr","experimental"]}
162//! ```
163//! <br>
164//!
165//! **Do not** install this crate with the `--all-features` option unless you
166//! understand that it would include `no-alloc`, which will disable several
167//! types and other features of the crate.
168//!
169//!  ## Examples
170//!
171//!```
172//! use fixedstr::*;
173//! let a = str8::from("abcdefg"); //creates new string from &str
174//! let a1 = a; // copied, not moved
175//! let a2:&str = a.to_str();
176//! let a3:String = a.to_string();
177//! assert_eq!(a.nth_ascii(2), 'c');
178//! let ab = a.substr(1,5);  // copies substring to new str8
179//! assert_eq!(ab,"bcde");  // can compare with &str
180//! assert_eq!(&a[1..4],"bcd"); // implements Index
181//! assert!(a<ab);  // implements Ord (and Hash, Debug, Display, other traits)
182//! let mut u:zstr<8> = zstr::from("aλb"); //unicode support
183//! {assert_eq!(u.nth(1).unwrap(),'λ');} // nth returns Option<char>
184//! assert!(u.set(1,'μ'));  // changes a character of the same character class
185//! assert!(!u.set(1,'c')); // .set returns false on failure
186//! assert!(u.set(2,'c'));
187//! assert_eq!(u, "aμc");
188//! assert_eq!(u.len(),4);  // length in bytes
189//! assert_eq!(u.charlen(),3);  // length in chars
190//! let mut ac:str16 = a.resize(); // copies to larger capacity string
191//! let remainder:&str = ac.push("hijklmnopqrst");  //appends string, returns left over
192//! assert_eq!(ac.len(),15);
193//! assert_eq!(remainder, "pqrst");
194//! ac.truncate(10); // shortens string in place
195//! assert_eq!(&ac,"abcdefghij");
196//! let (upper,lower) = (str8::make("ABC"), str8::make("abc"));
197//! assert_eq!(upper, lower.to_ascii_upper()); // no owned String needed
198//!  
199//! let c1 = str8::from("abcdef"); // string concatenation with + for strN types  
200//! let c2 = str8::from("xyz123");
201//! let c3 = c1 + c2;       
202//! assert_eq!(c3,"abcdefxyz123");   
203//! assert_eq!(c3.capacity(),15);  // type of c3 is str16
204//!
205//! let c4 = str_format!(str16,"abc {}{}{}",1,2,3); // impls core::fmt::Write
206//! assert_eq!(c4,"abc 123");  // str_format! truncates if capacity exceeded
207//! let c5 = try_format!(str8,"abcdef{}","ghijklmn");
208//! assert!(c5.is_none());  // try_format! returns None if capacity exceeded
209//!
210//! #[cfg(feature = "shared-str")]
211//! #[cfg(not(feature = "no-alloc"))]
212//! {
213//!   let mut s:Sharedstr<8> = Sharedstr::from("abcd");
214//!   let mut s2 = s.clone(); // O(1) cost
215//!   s.push_char('e');
216//!   s2.set(0,'A');
217//!   assert_eq!(s2, "Abcde");
218//!   assert!(s==s2 && s.ptr_eq(&s2));
219//! }
220//!
221//! #[cfg(feature = "experimental")]
222//! {
223//!   let mut s = <zstr<8>>::from("abcd");
224//!   s[0] = b'A';       // implements IndexMut<usize> (only for zstr)
225//!   assert_eq!(&s[0..3],"Abc");
226//! }
227//! ```
228//!
229// #![doc = document_features::document_features!()]
230
231#![allow(unused_variables)]
232#![allow(non_snake_case)]
233#![allow(non_camel_case_types)]
234#![allow(unused_parens)]
235#![allow(unused_assignments)]
236#![allow(unused_mut)]
237#![allow(unused_imports)]
238#![allow(dead_code)]
239#![no_std]
240
241#[cfg(feature = "std")]
242#[cfg(not(feature = "no-alloc"))]
243mod full_fixed;
244#[cfg(feature = "std")]
245#[cfg(not(feature = "no-alloc"))]
246pub use full_fixed::*;
247
248//#[cfg(feature = "flex-str")]
249//mod shared_structs;
250
251#[cfg(not(feature = "no-alloc"))]
252#[cfg(any(feature = "shared-str", feature = "flex-str"))]
253mod shared_structs;
254
255#[cfg(feature = "flex-str")]
256#[cfg(not(feature = "no-alloc"))]
257mod flexible_string;
258#[cfg(feature = "flex-str")]
259#[cfg(not(feature = "no-alloc"))]
260pub use flexible_string::*;
261
262#[cfg(feature = "shared-str")]
263#[cfg(not(feature = "no-alloc"))]
264mod shared_string;
265#[cfg(feature = "shared-str")]
266#[cfg(not(feature = "no-alloc"))]
267pub use shared_string::*;
268
269mod zero_terminated;
270pub use zero_terminated::*;
271
272mod tiny_internal;
273use tiny_internal::*;
274#[cfg(feature = "pub_tstr")]
275pub use tiny_internal::*;
276
277#[cfg(feature = "circular-str")]
278mod circular_string;
279#[cfg(feature = "circular-str")]
280pub use circular_string::*;
281
282#[cfg(not(feature = "no-alloc"))]
283extern crate alloc;
284
285/*
286#[cfg(feature = "compressed-str")]
287#[cfg(not(feature = "no-alloc"))]
288mod compressed;
289#[cfg(feature = "compressed-str")]
290#[cfg(not(feature = "no-alloc"))]
291pub use compressed::*;
292*/
293
294
295//////// Unifying Trait Approach
296#[cfg(feature = "experimental")]
297pub trait Fixedstr<const N:usize> {
298  type Target;
299  
300  fn make<TA : AsRef<str>>(s:TA) -> Self::Target;
301  
302  fn create<TA : AsRef<str>>(s:TA) -> Self::Target {
303    Self::make(s)
304  } // won't compile
305  fn try_make<TA:AsRef<str>>(s:TA) -> Result<Self::Target,TA> {
306    if s.as_ref().len()<N {Ok(Self::make(s))} else {Err(s)}
307  }
308
309  /*const*/ fn const_make(s:&str) -> Self::Target;
310  /*const*/ fn const_try_make(s:&str) -> Option<Self::Target>;
311
312  fn new() -> Self::Target {
313    Self::make("")
314  }
315
316  /*const*/ fn len(&self) -> usize;
317  fn charlen(&self) -> usize;
318  /*const*/ fn capacity(&self) -> usize { N-1 }
319
320  fn to_str(&self) -> &str;
321  fn as_str(&self) -> &str;
322  
323  #[cfg(not(feature = "no-alloc"))]
324  fn to_string(&self) -> alloc::string::String {
325        alloc::string::String::from(self.to_str())
326  }
327
328  fn set(&mut self, i: usize, c: char) -> bool;
329
330  fn push_str<'t>(&mut self, src: &'t str) -> &'t str;
331  
332  fn push_char(&mut self, c: char) -> bool;
333
334  fn pop_char(&mut self) -> Option<char>;
335  
336  fn nth(&self, n: usize) -> Option<char>;
337  
338  fn nth_bytechar(&self, n: usize) -> char;
339  
340  fn truncate(&mut self, n: usize);
341  
342  fn truncate_bytes(&mut self, n: usize);
343
344  fn truncate_unchecked(&mut self, n: usize);
345  
346  fn clear(&mut self);
347  
348  fn right_ascii_trim(&mut self);
349  
350  fn make_ascii_lowercase(&mut self);
351
352  fn make_ascii_uppercase(&mut self);
353
354  fn case_insensitive_eq<TA:AsRef<str>>(&self, other: TA) -> bool;
355
356  fn is_ascii(&self) -> bool {
357        self.to_str().is_ascii()
358  }
359
360  
361}//trait Fixedstr
362
363
364
365
366//#[macro_use]
367//extern crate static_assertions;
368
369
370
371
372
373#[cfg(feature = "serde")]
374mod serde_support {
375    use super::*;
376    use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
377    macro_rules! generate_impl {
378        ($ty: ident, $visitor: ident) => {
379            impl<const N: usize> Serialize for $ty<N> {
380                fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
381                    serializer.serialize_str(self.as_str())
382                }
383            }
384            impl<'de, const N: usize> Deserialize<'de> for $ty<N> {
385                fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
386                    deserializer.deserialize_str($visitor)
387                }
388            }
389            struct $visitor<const N: usize>;
390            impl<'de, const N: usize> Visitor<'de> for $visitor<N> {
391                type Value = $ty<N>;
392                fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
393                    f.write_str("a string")
394                }
395                fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Self::Value, E> {
396                    $ty::try_make(s).map_err(|_| E::custom("string too long"))
397                }
398            }
399        };
400    }
401    generate_impl!(zstr, ZstrVisitor);
402    generate_impl!(tstr, TstrVisitor);
403    #[cfg(feature = "std")]
404    #[cfg(not(feature = "no-alloc"))]
405    generate_impl!(fstr, FstrVisitor);
406    #[cfg(feature = "flex-str")]
407    #[cfg(not(feature = "no-alloc"))]
408    generate_impl!(Flexstr, FlexstrVisitor);
409
410    #[cfg(feature = "circular-str")]
411    impl<const N: usize> Serialize for cstr<N> {
412        fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
413            let s = self.to_contiguous(); //self.to_string();
414            let (a, _) = s.to_strs();
415            serializer.serialize_str(a)
416        }
417    } //serialize
418
419    #[cfg(feature = "circular-str")]
420    struct CstrVisitor<const N: usize>;
421    #[cfg(feature = "circular-str")]
422    impl<'de, const N: usize> Visitor<'de> for CstrVisitor<N> {
423        type Value = cstr<N>;
424        fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
425            f.write_str("a string")
426        }
427        fn visit_str<E: serde::de::Error>(self, s: &str) -> Result<Self::Value, E> {
428            cstr::try_make(s).map_err(|_| E::custom("string too long"))
429        }
430    }
431
432    #[cfg(feature = "circular-str")]
433    impl<'de, const N: usize> Deserialize<'de> for cstr<N> {
434        fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
435            deserializer.deserialize_str(CstrVisitor)
436        }
437    }
438} //serde
439
440/// Types for small strings that use an efficient representation
441/// underneath.  Alias for internal type [tstr]\<8\>.
442/// A str8 is 8 bytes and can hold string of up to 7 bytes.
443/// See documentation for the aliased [tstr] type.
444///
445/// Example:
446/// ```
447///  # use fixedstr::str8;
448///  let mut s = str8::from("aλc");
449///  assert_eq!(s.capacity(),7);
450///  assert_eq!(s.push("1234567"), "4567");
451///  assert_eq!(s,"aλc123");
452///  assert_eq!(s.charlen(), 6);
453///  assert_eq!(s.len(), 7);  
454/// ```
455
456pub type str8 = tstr<8>;
457/// A str16 can hold a string of up to 15 bytes. See docs for [fstr] or [zstr].
458/// The size of str16 is 16 bytes, which is the same as for &str on 64bit
459/// systems.
460pub type str16 = tstr<16>;
461/// A str32 can hold a string of up to 31 bytes. See docs for [fstr] or [zstr]
462pub type str32 = tstr<32>;
463/// A str64 can hold a string of up to 63 bytes. See docs for [fstr] or [zstr]
464pub type str64 = tstr<64>;
465/// A str28 can hold a string of up to 127 bytes. See docs for [fstr] or [zstr]
466pub type str128 = tstr<128>;
467
468/// Each type strN is represented underneath by a `[u8;N]` with N<=256.
469/// The first byte of the array always holds the length of the string.
470/// Each such type can hold a string of up to N-1 bytes, with max size=255.
471/// These types represent the best combination of [fstr] and [zstr] in
472/// terms of speed and memory efficiency.
473///<br>
474/// In addition, the str4-str128 types implement [core::ops::Add] in a way that
475/// two str8 strings will always concatenate to str16, and similarly for
476/// all other strN types up to str128.
477///```
478///  # use fixedstr::*;
479///  let c1 = str8::from("abcd");
480///  let c2 = str8::from("xyz");
481///  let c3 = c1 + c2;
482///  assert_eq!(c3,"abcdxyz");
483///  assert_eq!(c3.capacity(),15);
484///```
485
486pub type str256 = tstr<256>;
487
488/// Alias for internal type `tstr<4>`.
489/// <br>Holds strings of up to three single-byte chars, good enough to represent abbreviations
490/// such as those for states and airports. Each str<4> is exactly 32 bits.
491/// Alias for internal type `tstr<4>`.   See documentation for [tstr].
492pub type str4 = tstr<4>;
493pub type str12 = tstr<12>;
494pub type str24 = tstr<24>;
495pub type str48 = tstr<48>;
496pub type str96 = tstr<96>;
497pub type str192 = tstr<192>;
498
499
500#[macro_export]
501/// creates a formated string of given type (by implementing [core::fmt::Write]):
502/// ```
503///    # use fixedstr::*;
504///    let s = str_format!(str8,"abc{}{}{}",1,2,3);
505///    assert_eq!(s,"abc123");
506/// ```
507/// will truncate if capacity exceeded, without warning. See [try_format!]
508/// for version that does not truncate.
509macro_rules! str_format {
510  ($ty_size:ty, $($args:tt)*) => {
511     {use core::fmt::Write;
512     let mut fstr0 = <$ty_size>::new();
513     let res=write!(&mut fstr0, $($args)*);
514     fstr0}
515  };
516}
517
518#[macro_export]
519/// version of [str_format]! that returns an Option of the given type.
520/// ```
521///   # use fixedstr::*;
522///  let s = try_format!(str32,"abcdefg{}","hijklmnop").unwrap();
523///  let s2 = try_format!(str8,"abcdefg{}","hijklmnop");
524///  assert!(s2.is_none());
525/// ```
526macro_rules! try_format {
527  ($ty_size:ty, $($args:tt)*) => {
528     {use core::fmt::Write;
529     let mut fstr0 = <$ty_size>::new();
530     let result = write!(&mut fstr0, $($args)*);
531     if result.is_ok() {Some(fstr0)} else {None}}
532  };
533}
534
535/*
536//////////// to string trait
537pub trait ToTstr<const N: usize> {
538  fn to_tstr(&self) -> tstr<N>;
539}//tostring trait
540*/
541
542#[macro_export]
543/// Macro for converting any expression that implements the Display trait
544/// into the specified type, similar to `to_string` but without necessary
545/// heap allocation.  Truncation is automatic and silent. Example:
546///```
547///  # use fixedstr::*;
548///  let fs = to_fixedstr!(str8,-0132*2);
549///  assert_eq!(&fs,"-264");
550///```
551/// For version that does not truncate, use [convert_to_str!].
552macro_rules! to_fixedstr {
553    ($ty_size:ty, $x:expr) => {{
554        use core::fmt::Write;
555        let mut fstr0 = <$ty_size>::new();
556        let res = write!(&mut fstr0, "{}", $x);
557        fstr0
558    }};
559}
560
561#[macro_export]
562/// Version of [to_fixedstr!] that returns None instead of truncating .
563///```
564///  # use fixedstr::*;
565///  let fsopt = convert_to_str!(zstr<16>,0.013128009);
566///  assert!(matches!(fsopt.as_deref(),Some("0.013128009")))
567///```
568macro_rules! convert_to_str {
569    ($ty_size:ty, $x:expr) => {{
570        use core::fmt::Write;
571        let mut fstr0 = <$ty_size>::new();
572        let res = write!(&mut fstr0, "{}", $x);
573        if res.is_ok() {
574            Some(fstr0)
575        } else {
576            None
577        }
578    }};
579}
580
581/////////////////////////////////////////////////////  Testing ...
582
583#[cfg(test)]
584mod tests {
585    use super::*;
586    #[test]
587    fn testmain() {
588        nostdtest();
589        ztests();
590
591        #[cfg(feature = "std")]
592        #[cfg(not(feature = "no-alloc"))]
593        maintest();
594        #[cfg(all(feature = "flex-str", feature = "std"))]
595        #[cfg(not(feature = "no-alloc"))]
596        flextest();
597        #[cfg(feature = "std")]
598        #[cfg(not(feature = "no-alloc"))]
599        tinytests();
600        #[cfg(all(feature = "std", feature = "flex-str"))]
601        #[cfg(not(feature = "no-alloc"))]
602        poppingtest();
603        #[cfg(all(feature = "std", feature = "shared-str"))]
604        #[cfg(not(feature = "no-alloc"))]
605        strptrtests();
606        #[cfg(feature = "pub-tstr")]
607        consttests();
608    } //testmain
609
610    #[cfg(feature = "std")]
611    #[cfg(feature = "shared-str")]
612    #[cfg(not(feature = "no-alloc"))]
613    fn strptrtests() {
614        extern crate std;
615        use std::fmt::Write;
616        use std::string::String;
617        let mut a = Sharedstr::<8>::from("abc12");
618        let mut b = a.clone();
619        let mut c = Sharedstr::<8>::from("abc");
620        c.push_str("12");
621        assert!(a == c);
622        assert!(a == "abc12");
623        b.push('3');
624        assert!(a == "abc123");
625        assert!("abc123" == b);
626    } //strptrtests
627
628    /// test struct
629    struct AB(i32, u32);
630    impl core::fmt::Display for AB {
631        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
632            write!(f, "{},{}", self.0, self.1)
633        }
634    }
635
636    #[cfg(all(feature = "std", feature = "flex-str"))]
637    #[cfg(not(feature = "no-alloc"))]
638    fn poppingtest() {
639        extern crate std;
640        use std::println;
641        let mut a = Flexstr::<8>::from("abcdef");
642        assert_eq!(a.pop_char().unwrap(), 'f');
643        println!("a: {}", &a);
644        let a = flexstr16::from("abcd");
645        let c: flexstr16 = &a + "efg";
646        assert_eq!(&c, "abcdefg");
647
648        let mut ab = AB(-5, 22 + 1);
649        let abfs = to_fixedstr!(zstr<16>, &ab);
650        assert_eq!(&abfs, "-5,23");
651        let abfs2 = convert_to_str!(zstr<3>, 10003);
652        assert!(abfs2.is_none());
653    } //poppingtest
654
655    fn nostdtest() {
656        let a: str8 = str8::from("abcdef"); //a str8 can hold up to 7 bytes
657        let a2 = a; // copied, not moved
658        let ab = a.substr(1, 5); // copies substring to new string
659        assert_eq!(ab, "bcde"); // compare for equality with &str
660        assert_eq!(&a[..3], "abc"); // impls Deref<str>
661        assert!(a < ab); // and Ord, Hash, Eq, Debug, Display, other common traits
662        let astr: &str = a.to_str(); // convert to &str
663        let azstr: zstr<16> = zstr::from(a); // so is zstr
664        let mut a32: str32 = a.resize(); // same kind of string but with 31-byte capacity
665        a32 = "abc" + a32;
666        let mut u = str8::from("aλb"); //unicode support
667        assert_eq!(u.nth(1), Some('λ')); // get nth character
668        assert_eq!(u.nth_bytechar(3), 'b'); // get nth byte as ascii character
669        assert!(u.set(1, 'μ')); // changes a character of the same character class
670        assert!(!u.set(1, 'c')); // .set returns false on failure
671        assert!(u.set(2, 'c'));
672        assert_eq!(u, "aμc");
673        assert_eq!(u.len(), 4); // length in bytes
674        assert_eq!(u.charlen(), 3); // length in chars
675        let mut ac: str16 = a.reallocate().unwrap(); //copies to larger capacity type
676        let remainder = ac.push_str("ghijklmnopq"); //append up to capacity, returns remainder
677        assert_eq!(ac.len(), 15);
678        assert_eq!(remainder, "pq");
679        ac.truncate(9); // keep first 9 chars
680        assert_eq!(&ac, "abcdefghi");
681        let (upper, lower) = (str8::make("ABC"), str8::make("abc"));
682        assert_eq!(upper, lower.to_ascii_upper()); // no owned String needed
683
684        let c1 = str8::from("abcd"); // string concatenation with + for strN types
685        let c2 = str8::from("xyz");
686        assert!(c2.case_insensitive_eq("XyZ"));
687        let c2b = str16::from("xYz");
688        assert!(c2.case_insensitive_eq(&c2b));
689        let mut c3 = c1 + c2;
690        assert_eq!(c3, "abcdxyz");
691        assert_eq!(c3.capacity(), 15); // type of c3 is str16
692        c3 = "00" + c3 + "."; // cat with &str on left or right
693        assert_eq!(c3, "00abcdxyz.");
694
695        let c4 = str_format!(str16, "abc {}{}{}", 1, 2, 3); // impls std::fmt::Write
696        assert_eq!(c4, "abc 123"); //str_format! truncates if capacity exceeded
697        let c5 = try_format!(str8, "abcdef{}", "ghijklmn");
698        assert!(c5.is_none()); // try_format! returns None if capacity exceeded
699
700        let fs = to_fixedstr!(str8, -0132);
701        assert_eq!(&fs, "-132");
702
703        // testing for constants
704        const C:str16 = str16::const_make("abcd");
705        //const C:zstr<8> = zstr::const_make("abcd");
706        let xarray = [0u8;C.len()];
707        assert_eq!(C,"abcd");
708        assert_eq!(xarray.len(),4);
709
710        //cstr tests
711        #[cfg(feature = "circular-str")]
712        {
713            use crate::circular_string::*;
714            let mut cb = cstr::<16>::make("abc123");
715            assert!(cb.is_contiguous());
716            cb.push_str("xyz");
717            cb.push_front("9876");
718            assert_eq!(cb.pop_char().unwrap(), 'z');
719            assert_eq!(cb.pop_char_front().unwrap(), '9');
720            cb.push_str_front("000");
721            assert_eq!(cb.len(), 14);
722            assert!(&cb == "000876abc123xy");
723            cb.truncate_left(10);
724            assert_eq!(&cb, "23xy");
725            cb.push_str("ijklmno  ");
726            cb.push_char_front(' ');
727            assert!(&cb == " 23xyijklmno  ");
728            assert!(!cb.is_contiguous());
729            //  cb.trim_left();
730            //  assert!(&cb == "23xyijklmno ");
731            //  cb.trim_right();
732            cb.trim_whitespaces();
733            assert!("23xyijklmno" == &cb);
734            assert!(&cb < "4abc");
735
736            let mut a = cstr::<8>::make("12345678");
737            assert_eq!(a.len(), 8);
738            a.truncate_front(4);
739            assert_eq!(a.len(), 4);
740            assert!(a.is_contiguous());
741            assert!(&a == "5678");
742            a.push_str("abc");
743            assert!(&a == "5678abc");
744            let mut findopt = a.find_substr("8abc");
745            assert_eq!(findopt.unwrap(), 3);
746            findopt = a.rfind_substr("678abc");
747            assert_eq!(findopt.unwrap(), 1);
748            let mut rem = a.push_str("123456");
749            assert_eq!(rem, "23456");
750            a.truncate_left(4);
751            assert_eq!(&a, "abc1");
752            rem = a.push_front("qrstuvw");
753            assert_eq!(&a, "tuvwabc1");
754            assert_eq!(rem, "qrs");
755            rem = a.push_str("");
756            assert_eq!(&a, "tuvwabc1");
757            assert_eq!(rem, "");
758            a.truncate(5);
759            let mut ba = "123" + a;
760            assert_eq!(ba, "123tuvwa");
761            ba.truncate_left(4);
762            a.truncate_left(1);
763            assert_eq!(a, ba);
764
765            #[cfg(feature = "std")]
766            {
767                let bb = cstr::<8>::from("qgg");
768                extern crate std;
769                use std::collections::HashSet;
770                let mut hh = HashSet::new();
771                hh.insert(bb);
772                assert!(hh.get(&bb).is_some());
773            }
774        } //cstr tests
775    } //nostdtest
776
777    fn ztests() {
778        let a: zstr<8> = zstr::from("abcdefg"); //creates zstr from &str
779        let ab = a.substr(1, 5); // copies, not move substring to new string
780        assert_eq!(ab, "bcde"); // can compare equality with &str
781        assert!(ab.case_insensitive_eq("bCdE"));
782        let mut u: zstr<8> = zstr::from("aλb"); //unicode support
783        assert!(u.set(1, 'μ')); // changes a character of the same character class
784        assert!(!u.set(1, 'c')); // .set returns false on failure
785        assert!(u.set(2, 'c'));
786        assert_eq!(u, "aμc");
787        assert_eq!(u.len(), 4); // length in bytes
788        assert_eq!(u.charlen(), 3); // length in chars
789        let mut ac: zstr<16> = a.resize(); // copies to larger capacity string
790        let remainder = ac.push("hijklmnopqrst"); //appends string, returns left over
791        assert_eq!(ac.len(), 15);
792        assert_eq!(remainder, "pqrst");
793        ac.truncate(10);
794        assert_eq!(&ac, "abcdefghij");
795        //println!("ac {}, remainder: {}, len {}", &ac, &remainder, &ac.len());
796        assert_eq!(ac.len(), 10);
797        ac.pop_char();
798        ac.pop_char();
799        assert_eq!(ac.len(), 8);
800        let mut c4 = str_format!(zstr<16>, "abc {}", 123);
801        assert_eq!(c4, "abc 123");
802        let rem = c4.push_str("123456789abcdef");
803        assert_eq!(c4, "abc 12312345678");
804        assert_eq!(rem, "9abcdef");
805
806        let b = [65u8, 66, 67, 0, 0, 68, 0, 69, 0, 70, 0, 71];
807        let mut bz: zstr<16> = zstr::from_raw(&b);
808        bz.push("abcd   \t \n\n");
809        //println!("bz: {}, len {}", &bz, bz.len());
810        bz.right_ascii_trim();
811        bz.reverse_bytes();
812        bz.make_ascii_lowercase();
813        //println!("bz after trim, reverse: {}, len {}", &bz, bz.len());
814    } //ztr tests
815
816    #[cfg(feature = "std")]
817    #[cfg(not(feature = "no-alloc"))]
818    fn maintest() {
819        extern crate std;
820        use std::fmt::Write;
821        use std::println;
822        use std::string::String;
823        let s1: fstr<16> = fstr::from("abc");
824        let mut s2: fstr<8> = fstr::from("and xyz");
825        let s2r = s2.push(" and 1234");
826        println!("s1,s2,s2r,s2.len: {}, {}, {}, {}", s1, &s2, &s2r, s2.len());
827        println!("{}", &s1 == "abc");
828        let s3 = s1; // copied, not moved
829        println!("{}", "abc" == &s1);
830        println!("{}, {} ", s1 == s3, s1 == s2.resize());
831
832        let mut s4: fstr<256> = s3.resize();
833        s4.push("ccccccccccccccccccccccccccccccccccccccccccccccccccccccz");
834        println!("{}, length {}", &s4, s4.len());
835        let mut s5: fstr<32> = s4.resize();
836        println!("{}, length {}", &s5, s5.len());
837        println!("{:?}, length {}", &s5[0..10], s5.len());
838        println!("s2.substr {}", s2.substr(2, 6));
839        println!("{}", s2.substr(2, 6).len());
840        let mut s4: fstr<64> = s1.resize();
841        let owned_string: String = s4.to_string();
842        println!("owned s4: {}", &owned_string);
843        let str_slice: &str = s4.to_str();
844        println!("as &str: {}", &str_slice[0..2]);
845        s4 = s1.resize();
846        let s5 = fstr::<8>::new();
847        let ss5 = s5.as_str();
848
849        let mut s6 = fstr::<32>::new();
850        let result = write!(&mut s6, "hello {}, {}, {}", 1, 2, 3);
851        assert_eq!(s6, "hello 1, 2, 3");
852        println!("s6 is {}, result is {:?}", &s6, &result);
853
854        let s7 = str_format!(fstr<32>, "abc {}, {}", 1, 10);
855        println!("s7 is {}", &s7);
856        let s8 = try_format!(fstr<32>, "abcdefg {}, {}", 1, 10);
857        println!("s8 is {}", &s8.unwrap());
858
859        let mut f1 = fstr::<16>::from("abcdefg");
860        let f2 = f1.to_ascii_uppercase();
861        //f1 = f2; // copy?
862
863        #[cfg(feature = "experimental")]
864        {
865            let mut s = <zstr<8>>::from("abcd");
866            s[0] = b'A'; // impls IndexMut for zstr (not for fstr nor strN types)
867            assert_eq!('A', s.nth_ascii(0));
868        }
869
870        use std::collections::HashMap;
871        let mut hm = HashMap::new();
872        hm.insert(str8::from("abc"), 1);
873        assert!(hm.contains_key(&str8::from("abc")));
874
875        let mut a: fstr<8> = fstr::from("abcdef");
876        let rem = a.push("g");
877        assert!(rem == "" && &a == "abcdefg");
878
879        ftests();
880    } //maintest
881
882    #[cfg(feature = "std")]
883    #[cfg(not(feature = "no-alloc"))]
884    fn ftests() {
885        extern crate std;
886        use std::{println, string::String, format};
887        let a: fstr<8> = fstr::from("abcdefg"); //creates fstr from &str
888        let a1: fstr<8> = a; // copied, not moved
889        let a2: &str = a.to_str();
890        let a3: String = a.to_string();
891        assert_eq!(a.nth_ascii(2), 'c');
892        let ab = a.substr(1, 5); // copies substring to new fstr
893        assert!(ab == "bcde" && a1 == a); // can compare with &str and itself
894        assert!(a < ab); // implements Ord trait (and Hash
895        let mut u: fstr<8> = fstr::from("aλb"); //unicode support
896        u.nth(1).map(|x| assert_eq!(x, 'λ')); // nth returns Option<char>
897                                              //for x in u.nth(1) {assert_eq!(x,'λ');} // nth returns Option<char>
898        assert!(u.set(1, 'μ')); // changes a character of the same character class
899        assert!(!u.set(1, 'c')); // .set returns false on failure
900        assert!(u.set(2, 'c'));
901        assert_eq!(u, "aμc");
902        assert_eq!(u.len(), 4); // length in bytes
903        assert_eq!(u.charlen(), 3); // length in chars
904        let mut ac: fstr<16> = a.resize(); // copies to larger capacity string
905        let remainder: &str = ac.push("hijklmnopqrst"); //appends string, returns left over
906        assert_eq!(ac.len(), 16);
907        assert_eq!(remainder, "qrst");
908        ac.truncate(10); // shortens string in place
909        assert_eq!(&ac, "abcdefghij");
910        println!("ac {}, remainder: {}", &ac, &remainder);
911
912        assert_eq!(ac.pop_char().unwrap(), 'j');
913        assert_eq!(ac, "abcdefghi");
914
915        let ac2: fstr<16> = fstr::make("abcd");
916        ac.truncate(4);
917        assert_eq!(ac, ac2);
918
919        let mut z8 = zstr::<16>::from("abc12");
920        let z8o = str_format!(zstr<16>,"xxx {}3",z8);
921        assert_eq!(z8o, "xxx abc123");
922        let zoo = format!("xx{}yy",z8o);
923        assert_eq!(zoo,"xxxxx abc123yy");
924    } //ftr tests
925
926    #[cfg(all(feature = "std", feature = "flex-str"))]
927    #[cfg(not(feature = "no-alloc"))]
928    fn flextest() {
929        extern crate std;
930        use std::fmt::Write;
931        use std::println;
932        use std::string::String;
933        println!("starting Flexstr tests...");
934        let mut a: Flexstr<8> = Flexstr::from("abcdef");
935        a.truncate(5);
936        assert_eq!(a, "abcde"); // can compare equality with &str
937        assert_eq!(&a[..3], "abc"); // impls Index
938        println!("Flexstr slice: {}", &a[1..4]);
939        let ab = Flexstr::<8>::from("bcdefghijklmnop");
940        assert!(a.is_fixed());
941        assert!(!ab.is_fixed());
942        let a2: str8 = a.get_str().unwrap();
943        assert!(a < ab); // impls Ord, (and Hash, Debug, Eq, other common traits)
944        let astr: &str = a.to_str(); // convert to &str (zero copy)
945        let aowned: String = a.to_string(); // convert to owned string
946                                            //let b = a.take_string();
947        let mut u = Flexstr::<8>::from("aλb"); //unicode support
948        assert_eq!(u.nth(1), Some('λ')); // get nth character
949        assert_eq!(u.nth_ascii(3), 'b'); // get nth byte as ascii character
950        assert!(u.set(1, 'μ')); // changes a character of the same character class
951        assert!(!u.set(1, 'c')); // .set returns false on failure
952        assert!(u.set(2, 'c'));
953        assert_eq!(u, "aμc");
954        assert_eq!(u.len(), 4); // length in bytes
955        assert_eq!(u.charlen(), 3); // length in chars
956        let mut v: Flexstr<4> = Flexstr::from("aμcxyz");
957        v.set(1, 'λ');
958        println!("v: {}", &v);
959
960        let mut u2: Flexstr<16> = u.resize();
961        u2.push_str("aaaaaaaa");
962        println!("{} len {}", &u2, u2.len());
963        assert!(u2.is_fixed());
964
965        let mut s: Flexstr<8> = Flexstr::from("abcdef");
966        assert!(s.is_fixed());
967        s.push_str("ghijk");
968        assert!(s.is_owned());
969        s.truncate(7);
970        assert!(s.is_fixed());
971        let ab = Flexstr::<32>::from("bcdefghijklmnop");
972        println!("size of ab: {}", std::mem::size_of::<Flexstr<32>>());
973
974        let mut vv = Flexstr::<8>::from("abcd");
975        vv.push('e');
976        //vv.push('λ');
977        println!("vv: {}", &vv);
978
979        vv.push_str("abcdefasdfasdfadfssfs");
980        let vvs = vv.split_off();
981        println!("vv: {},  vvs: {}", &vv, &vvs);
982
983        let mut fs: Flexstr<4> = Flexstr::from("abcdefg");
984        let extras = fs.split_off();
985        assert!(&fs == "abc" && &extras == "defg" && fs.is_fixed());
986
987        let fss = fs.to_string();
988        assert!(&fss == "abc");
989    } //flextest
990
991    #[cfg(feature = "std")]
992    #[cfg(not(feature = "no-alloc"))]
993    fn tinytests() {
994        extern crate std;
995        use std::fmt::Write;
996        use std::println;
997        use std::string::String;
998        println!("starting tstr tests...");
999        let a: str8 = str8::from("abcdef");
1000        let a2 = a; // copied, not moved
1001        let ab = a.substr(1, 5); // copies, not move substring to new string
1002        assert_eq!(ab, "bcde"); // can compare equality with &str
1003        assert_eq!(&a[..3], "abc"); // impls Index
1004        assert_eq!(ab.len(), 4);
1005        println!("str8: {}", &a);
1006        assert!(a < ab); // impls Ord, (and Hash, Debug, Eq, other common traits)
1007        let astr: &str = a.to_str(); // convert to &str (zero copy)
1008        let aowned: String = a.to_string(); // convert to owned string
1009        let afstr: fstr<8> = fstr::from(a); // fstr is another fixedstr crate type
1010        let azstr: zstr<16> = zstr::from(a); // so is zstr
1011        let a32: str32 = a.resize(); // same type of string with 31-byte capacity
1012        let mut u = str8::from("aλb"); //unicode support
1013        assert_eq!(u.nth(1), Some('λ')); // get nth character
1014        assert_eq!(u.nth_ascii(3), 'b'); // get nth byte as ascii character
1015        assert!(u.set(1, 'μ')); // changes a character of the same character class
1016        assert!(!u.set(1, 'c')); // .set returns false on failure
1017        assert!(u.set(2, 'c'));
1018        assert_eq!(u, "aμc");
1019        assert_eq!(u.len(), 4); // length in bytes
1020        assert_eq!(u.charlen(), 3); // length in chars
1021        let mut ac: str16 = a.reallocate().unwrap(); //copies to larger capacity type
1022        let remainder = ac.push("ghijklmnopq"); //append up to capacity, returns remainder
1023        assert_eq!(ac.len(), 15);
1024        assert_eq!(remainder, "pq");
1025        println!("ac {}, remainder: {}", &ac, &remainder);
1026        ac.truncate(9); // keep first 9 chars
1027        assert_eq!(&ac, "abcdefghi");
1028        println!("ac {}, remainder: {}", &ac, &remainder);
1029
1030        let mut s = str8::from("aλc");
1031        assert_eq!(s.capacity(), 7);
1032        assert_eq!(s.push("1234567"), "4567");
1033        assert_eq!(s, "aλc123");
1034        assert_eq!(s.charlen(), 6); // length in chars
1035        assert_eq!(s.len(), 7); // length in bytes
1036
1037        println!("size of str8: {}", std::mem::size_of::<str8>());
1038        println!("size of zstr<8>: {}", std::mem::size_of::<zstr<8>>());
1039        println!("size of &str: {}", std::mem::size_of::<&str>());
1040        println!("size of &str8: {}", std::mem::size_of::<&str8>());
1041
1042        let mut toosmall: fstr<8> = fstr::make("abcdefghijkl");
1043        let mut toosmallz: zstr<8> = zstr::make("abcdefghijkl");
1044        let mut toosmallt: str8 = str8::make("abcdefghijkl");
1045        println!("toosmall: {}", toosmall);
1046        let waytoosmall: fstr<4> = toosmall.resize();
1047        let way2: zstr<4> = toosmallz.resize();
1048        let mut way3: str16 = str16::make("abcdefedefsfsdfsd");
1049        let way4: str8 = way3.resize();
1050        way3 = way4.resize();
1051        println!("way3: {}, length {}", way3, way3.len());
1052
1053        // converting to other fixedstr crate types
1054        let b: str8 = str8::from("abcdefg");
1055        let mut b2: fstr<32> = fstr::from(b);
1056        b2.push("hijklmnop");
1057        println!("b2 is {}", &b2);
1058        let mut b3: zstr<300> = zstr::from(b);
1059        b3.push("hijklmnopqrstuvw");
1060        println!("b3 is {}", &b3);
1061        let mut b4 = str128::from(b2);
1062        b4.push("xyz");
1063        println!("b4 is {}", &b4);
1064
1065        let (upper, lower) = (str8::make("ABC"), str8::make("abc"));
1066        assert_eq!(upper, lower.to_ascii_upper());
1067
1068        let c1 = str8::from("abcdef");
1069        let c2 = str8::from("xyz123");
1070        let c3 = c1 + c2 + "999";
1071        assert_eq!(c3, "abcdefxyz123999");
1072        assert_eq!(c3.capacity(), 15);
1073        //println!("c3 is {}, capacity {}",&c3, &c3.capacity());
1074
1075        let c4 = str_format!(str16, "abc {}{}{}", 1, 2, 3);
1076        assert_eq!(c4, "abc 123");
1077        //    let c4 = str_format!(str16,"abc {}",&c1);
1078        //    println!("c4 is {}",&c4);
1079        //assert_eq!(c4,"abc abcdef");
1080        let c5 = try_format!(str8, "abc {}{}", &c1, &c2);
1081        assert!(c5.is_none());
1082        let s = try_format!(str32, "abcdefg{}", "hijklmnop").unwrap();
1083        let s2 = try_format!(str8, "abcdefg{}", "hijklmnop");
1084        assert!(s2.is_none());
1085
1086        let mut c4b = str16::from("abc 12345");
1087        c4b.truncate(7);
1088        assert_eq!(c4, c4b);
1089
1090        let zb = ztr8::from("abc");
1091        let mut zc = ztr8::from("abcde");
1092        zc.truncate(3);
1093        assert_eq!(zb, zc);
1094    } //tiny tests
1095
1096    #[cfg(feature = "pub-tstr")]
1097    fn consttests() {
1098       let ls = tstr::<{tstr_limit(258)}>::from("abcd");
1099       assert_eq!(ls.capacity(),255);
1100    }//consttests
1101} //tests mod