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