fixedstr_ext/
shared_string.rs

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