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