#![allow(unused_variables)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(unused_parens)]
#![allow(unused_assignments)]
#![allow(unused_mut)]
#![allow(unused_imports)]
#![allow(dead_code)]
//extern crate std;
//use std::string::String;
use crate::shared_structs::Strunion;
use crate::shared_structs::Strunion::*;
use crate::tstr;
use crate::zstr;

#[cfg(feature = "std")]
use crate::fstr;

use crate::{str12, str128, str16, str192, str24, str256, str32, str4, str48, str64, str8, str96};
use core::cmp::{min, Ordering};
use core::ops::Add;

////////////////////////////////////////////////////////////////////////
///////////// RC experiments
extern crate alloc;
use alloc::rc::Rc;
use alloc::string::String;
use core::cell::RefCell;

/// **This type is only available with the 'shared-str' option.**
/// A `Sharedstr` uses [Rc] and [RefCell] underneath to allow pointers to a [crate::Flexstr]
/// to be shared, and thus cloning is always done in constant time.
/// Similar to `Flexstr`, a `Sharedstr<N>` is represented either by a
/// `tstr<N>` or by an owned string if its length is greater than N-1, for N up
/// to 256.
///
/// **WARNING:**  this type uses certain unsafe features and allows mutations of
/// a shared string from multiple pointers, while allowing continued use of the
/// pointers after mutation. This violates a basic principle of the Rust borrow
/// checker.  Use with caution.
/// Example:
/// ```
///  # use fixedstr::*;
///  let mut a = Sharedstr::<8>::from("abc12");
///  let mut b = a.clone();
///  b.push('3');
///  assert!( a == "abc123" );
///  assert!( a==b && a.ptr_eq(&b) );
/// ```
/// Note that `==` always compares the contents while `ptr_eq` compares for
/// pointer-equality.
/// This type **does not support serde**, as expected of shared
/// pointers.  Convert to another type of string for serialization.
#[derive(Eq, Clone)]
pub struct Sharedstr<const N: usize = 32> {
    inner: Rc<RefCell<Strunion<N>>>,
}
impl<const N: usize> Sharedstr<N> {
    /// Creates a new `Sharedstr<N>` with given &str.
    pub fn make(s: &str) -> Self {
        if s.len() < N && N <= 256 {
            Sharedstr {
                inner: Rc::new(RefCell::new(fixed(tstr::<N>::from(s)))),
            }
        } else {
            Sharedstr {
                inner: Rc::new(RefCell::new(owned(String::from(s)))),
            }
        }
    } //make

    /// Creates a `Sharedstr<N>` by consuming a given string.  However, if the
    /// string has length less than N, then a fixed representation will be used.
    pub fn from_string(s: String) -> Self {
        if s.len() < N && N <= 256 {
            Sharedstr {
                inner: Rc::new(RefCell::new(fixed(tstr::<N>::from(&s[..])))),
            }
        } else {
            Sharedstr {
                inner: Rc::new(RefCell::new(owned(s))),
            }
        }
    }

    /// creates a `Sharedstr<N>` from a given `tstr<N>`
    pub fn from_tstr(s: tstr<N>) -> Self {
        Sharedstr {
            inner: Rc::new(RefCell::new(fixed(s))),
        }
    }

    /*
      #[cfg(feature="serde")]
      /// this function is only added for uniformity in serde implementation
      pub fn try_make(s: &str) -> Result<Sharedstr<N>, &str> {
           Ok(Sharedstr::make(s))
        }
    */

    /// length of the string in bytes. This is a constant-time operation.
    pub fn len(&self) -> usize {
        match &*self.inner.borrow() {
            fixed(s) => s.len(),
            owned(s) => s.len(),
        } //match
    } //len

    /// converts to `&str` type (may technically panic).
    pub fn as_str(&self) -> &str {
        unsafe {
            match self.inner.as_ptr().as_ref().unwrap() {
                fixed(s) => s.as_str(),
                owned(s) => s.as_str(),
            } //match
        } //unsafe
    }

    /// creates an empty string, equivalent to [Sharedstr::default]
    pub fn new() -> Self {
        Self::default()
    }

    /// length in number of characters as opposed to bytes: this is
    /// not necessarily a constant time operation.
    pub fn charlen(&self) -> usize {
        match &*self.inner.borrow() {
            fixed(s) => s.charlen(),
            owned(s) => s.chars().count(),
        } //match
    } //charlen

    /// alias for [Self::as_str]
    pub fn to_str(&self) -> &str {
        self.as_str()
    } //to_str

    /// retrieves a copy of the underlying fixed string, if it is a fixed string.
    /// Note that since the `tstr` type is not exported, this function should
    /// be used in conjunction with one of the public aliases [str4]-[str256].
    /// For example,
    /// ```
    ///   # use fixedstr::*;
    ///   let s = Sharedstr::<8>::from("abcd");
    ///   let t:str8 = s.get_str().unwrap();
    /// ```
    pub fn get_str(&self) -> Option<tstr<N>> {
        if let fixed(s) = &*self.inner.borrow() {
            Some(*s)
        } else {
            None
        }
    } //get_str

    /// if the underlying representation of the string is an owned string,
    /// return the owned string, leaving an empty string in its place.
    pub fn take_string(&mut self) -> Option<String> {
        if let (ss @ owned(_)) = &mut *self.inner.borrow_mut() {
            let mut temp = fixed(tstr::new());

            core::mem::swap(ss, &mut temp);
            if let owned(t) = temp {
                Some(t)
            } else {
                None
            }
        } else {
            None
        }
    } //take_owned

    /// this function returns a possibly cloned string
    pub fn to_string(self) -> String {
        match &*self.inner.borrow() {
            fixed(s) => s.to_string(),
            owned(s) => s.clone(),
        } //match
    } //to_string

    /// returns the nth char of the string, if it exists
    pub fn nth(&self, n: usize) -> Option<char> {
        self.to_str().chars().nth(n)
    }

    /// returns the nth byte of the string as a char.  This function
    /// is designed to be quicker than [Sharedstr::nth] and does not check
    /// for bounds.
    pub fn nth_bytechar(&self, n: usize) -> char {
        match &*self.inner.borrow() {
            fixed(s) => s.nth_ascii(n),
            owned(s) => s.as_bytes()[n] as char,
        }
    } //nth_bytechar

    /// alias for [Self::nth_bytechar]
    pub fn nth_ascii(&self, n: usize) -> char {
        self.nth_bytechar(n)
    }

    /// returns a u8-slice that represents the underlying string. The first
    /// byte of the slice is **not** the length of the string regarless of
    /// the internal representation.
    pub fn as_bytes(&self) -> &[u8] {
        self.as_str().as_bytes()
    } //as_bytes

    /// changes a character at character position i to c.  This function
    /// requires that c is in the same character class (ascii or unicode)
    /// as the char being replaced.  It never shuffles the bytes underneath.
    /// The function returns true if the change was successful.
    pub fn set(&mut self, i: usize, c: char) -> bool {
        match &mut *self.inner.borrow_mut() {
            fixed(s) => s.set(i, c),
            owned(s) => unsafe {
                let ref mut cbuf = [0u8; 4];
                c.encode_utf8(cbuf);
                let clen = c.len_utf8();
                if let Some((bi, rc)) = s.char_indices().nth(i) {
                    if clen == rc.len_utf8() {
                        s.as_bytes_mut()[bi..bi + clen].copy_from_slice(&cbuf[..clen]);
                        //self.chrs[bi + 1..bi + clen + 1].copy_from_slice(&cbuf[..clen]);
                        //for k in 0..clen {self.chrs[bi+k+1] = cbuf[k];}
                        return true;
                    }
                }
                return false;
            },
        } //match
    } //set

    /// returns whether the internal representation is a fixed string (tstr)
    pub fn is_fixed(&self) -> bool {
        match &*self.inner.borrow() {
            fixed(_) => true,
            owned(_) => false,
        }
    } //is_fixed

    /// returns whether the internal representation is an owned String
    pub fn is_owned(&self) -> bool {
        !self.is_fixed()
    }

    /// applies the destructive closure only if the internal representation
    /// is a fixed string
    pub fn if_fixed<F>(&mut self, f: F)
    where
        F: FnOnce(&mut tstr<N>),
    {
        if let fixed(s) = &mut *self.inner.borrow_mut() {
            f(s);
        }
    }

    /// applies the destructive closure only if the internal representation
    /// is a fixed string
    pub fn if_owned<F>(&mut self, f: F)
    where
        F: FnOnce(&mut str),
    {
        if let owned(s) = &mut *self.inner.borrow_mut() {
            f(s);
        }
    }

    /// applies closure f if the internal representation is a fixed string,
    /// or closure g if the internal representation is an owned string.
    pub fn map_or<F, G, U>(&self, f: F, g: G) -> U
    where
        F: FnOnce(&tstr<N>) -> U,
        G: FnOnce(&str) -> U,
    {
        match &*self.inner.borrow() {
            fixed(s) => f(s),
            owned(s) => g(&s[..]),
        } //match
    } //map

    /// version of [Sharedstr::map_or] accepting FnMut closures
    pub fn map_or_mut<F, G, U>(&mut self, f: &mut F, g: &mut G) -> U
    where
        F: FnMut(&mut tstr<N>) -> U,
        G: FnMut(&mut str) -> U,
    {
        match &mut *self.inner.borrow_mut() {
            fixed(s) => f(s),
            owned(s) => g(&mut s[..]),
        } //match
    } //map

    /// appends the Sharedstr with the given slice,
    /// switching to the owned-String representation if necessary.  The function
    /// returns true if the resulting string uses a `tstr<N>` type, and
    /// false if the representation is an owned string.
    pub fn push_str(&mut self, s: &str) -> bool {
        let mut replacer = None;
        let answer;
        match &mut *self.inner.borrow_mut() {
            fixed(fs) if fs.len() + s.len() < N => {
                fs.push(s);
                answer = true;
            }
            fixed(fs) => {
                let fss = fs.to_string() + s;
                replacer = Some(owned(fss));
                //self.inner.replace(owned(fss));
                answer = false;
            }
            owned(ns) => {
                ns.push_str(s);
                answer = false;
            }
        } //match
        if let Some(r) = replacer {
            self.inner.replace(r);
        }
        answer
    } //push_str

    /// appends string with a single character, switching to the String
    /// representation if necessary.  Returns true if resulting string
    /// remains fixed.
    pub fn push(&mut self, c: char) -> bool {
        let clen = c.len_utf8();
        let answer;
        let mut replacer = None;
        match &mut *self.inner.borrow_mut() {
            owned(s) => {
                s.push(c);
                answer = false;
            }
            fixed(s) if s.len() + clen >= N => {
                let mut fss = s.to_string();
                fss.push(c);
                replacer = Some(owned(fss));
                //self.inner.replace(owned(fss));
                answer = false;
            }
            fixed(s) => {
                let mut buf = [0u8; 4];
                let bstr = c.encode_utf8(&mut buf);
                s.push(bstr);
                answer = true;
            }
        } //match
        if let Some(r) = replacer {
            self.inner.replace(r);
        }
        answer
    } //push

    /// alias for push
    pub fn push_char(&mut self, c: char) -> bool {
        self.push(c)
    }

    /// remove and return last character in string, if it exists
    pub fn pop(&mut self) -> Option<char> {
        if self.len() == 0 {
            return None;
        }
        let answer;
        let mut replacer = None;
        match &mut *self.inner.borrow_mut() {
            fixed(s) => {
                answer = s.pop_char();
            }
            owned(s) if s.len() > N => {
                answer = s.pop();
            }
            owned(s) => {
                // change representation
                answer = s.pop();
                replacer = Some(fixed(tstr::from(&s)));
            }
        } //match
        if let Some(r) = replacer {
            self.inner.replace(r);
        }
        answer
    } //pop

    /// alias for [Self::pop]
    pub fn pop_char(&mut self) -> Option<char> {
        self.pop()
    }

    /// this function truncates a string at the indicated byte position,
    /// returning true if the truncated string is fixed, and false if owned.
    /// The operation has no effect if n is larger than the length of the
    /// string.  The operation will **panic** if n is not on a character
    /// boundary, similar to [String::truncate].
    pub fn truncate(&mut self, n: usize) -> bool {
        let mut replacer = None;
        let answer;
        match &mut *self.inner.borrow_mut() {
            fixed(fs) if n < fs.len() => {
                fs.truncate_bytes(n);
                answer = true;
            }
            fixed(_) => {
                answer = true;
            }
            owned(s) if n < N => {
                assert!(s.is_char_boundary(n));
                replacer = Some(fixed(tstr::<N>::from(&s[..n])));
                answer = true;
            }
            owned(s) => {
                if n < s.len() {
                    s.truncate(n);
                }
                answer = false;
            }
        } //match
        if let Some(r) = replacer {
            self.inner.replace(r);
        }
        answer
    } //truncate

    /// resets string to empty
    pub fn clear(&mut self) {
        let mut replacer = None;
        match &mut *self.inner.borrow_mut() {
            fixed(s) => {
                s.clear();
            }
            owned(s) => {
                replacer = Some(fixed(tstr::default()));
            }
        }
        if let Some(r) = replacer {
            self.inner.replace(r);
        }
    } //clear

    /// returns string corresponding to slice indices as a copy or clone.
    pub fn substr(&self, start: usize, end: usize) -> Sharedstr<N> {
        match &*self.inner.borrow() {
            fixed(s) => Sharedstr {
                inner: Rc::new(RefCell::new(fixed(s.substr(start, end)))),
            },
            owned(s) => Self::from(&s[start..end]),
        }
    } //substr

    /// Splits the string into a `tstr<N>` portion and a String portion.
    /// The structure inherits the fixed part and the String returned will
    /// contain the extra bytes that does not fit.  Example:
    ///
    /// ```
    ///  # use fixedstr::*;
    ///   let mut fs:Sharedstr<4> = Sharedstr::from("abcdefg");
    ///   let extras = fs.split_off();
    ///   assert!( &fs=="abc" && &extras=="defg" && fs.is_fixed());
    /// ```
    pub fn split_off(&mut self) -> String {
        let answer;
        let mut replacer = None;
        match &mut *self.inner.borrow_mut() {
            fixed(s) => {
                answer = String::default();
            }
            owned(s) => {
                answer = String::from(&s[N - 1..]);
                replacer = Some(fixed(tstr::<N>::from(&s[..N - 1])));
            }
        } //match
        if let Some(r) = replacer {
            self.inner.replace(r);
        }
        answer
    } //split_off

    /// tests strings for content equality
    pub fn equals<T: AsRef<str>>(&self, other: &T) -> bool {
        self == other.as_ref()
    }

    /// tests if two instances of Sharedstr point to the same location,
    /// contrasts with `==`, which always tests for content-equality
    pub fn ptr_eq(&self, other: &Self) -> bool {
        Rc::ptr_eq(&self.inner, &other.inner)
    }

    /// creates a new, non-shared copy of the string
    pub fn deep_clone(&self) -> Self {
        Sharedstr::from(self.as_str())
    }

    /// returns the number of shared references to this string (strong `Rc`
    /// pointers)
    pub fn ptr_count(&self) -> usize {
        Rc::strong_count(&self.inner)
    }

    /// in-place modification of ascii characters to lower-case
    pub fn make_ascii_lowercase(&mut self) {
        match &mut *self.inner.borrow_mut() {
            fixed(s) => {
                s.make_ascii_lowercase();
            }
            owned(s) => {
                s.as_mut_str().make_ascii_lowercase();
            }
        } //match
    } //make_ascii_lowercase

    /// in-place modification of ascii characters to upper-case
    pub fn make_ascii_uppercase(&mut self) {
        match &mut *self.inner.borrow_mut() {
            fixed(s) => {
                s.make_ascii_uppercase();
            }
            owned(s) => {
                s.as_mut_str().make_ascii_uppercase();
            }
        } //match
    }

    /// Tests for ascii case-insensitive equality with another string.
    /// This function does not test if either string is ascii.
    pub fn case_insensitive_eq<TA>(&self, other: TA) -> bool
    where
        TA: AsRef<str>,
    {
        if self.len() != other.as_ref().len() {
            return false;
        }
        let obytes = other.as_ref().as_bytes();
        let sbytes = self.as_bytes();
        for i in 0..self.len() {
            let mut c = sbytes[i];
            if (c > 64 && c < 91) {
                c = c | 32;
            } // make lowercase
            let mut d = obytes[i];
            if (d > 64 && d < 91) {
                d = d | 32;
            } // make lowercase
            if c != d {
                return false;
            }
        } //for
        true
    } //case_insensitive_eq

    /// Decodes a UTF-16 encodeded slice. If a decoding error is encountered
    /// or capacity exceeded, an `Err(s)` is returned where s is the
    /// the encoded string up to the point of the error.
    pub fn from_utf16(v: &[u16]) -> Result<Self, Self> {
        let mut s = Self::new();
        for c in char::decode_utf16(v.iter().cloned()) {
            if let Ok(c1) = c {
                if !s.push_char(c1) {
                    return Err(s);
                }
            } else {
                return Err(s);
            }
        }
        Ok(s)
    } //from_utf16
} //impl Sharedstr

impl<const N: usize> Default for Sharedstr<N> {
    fn default() -> Self {
        Sharedstr {
            inner: Rc::new(RefCell::new(fixed(tstr::<N>::default()))),
        }
    }
}

#[cfg(feature = "flex-str")]
use crate::Flexstr;
#[cfg(feature = "flex-str")]
impl<const N: usize> Sharedstr<N> {
    /// converts and consumes Sharedstr into a Flexstr *if* there is
    /// exactly one strong reference to the Sharedstr.  On failure,
    /// the same Sharedstr is returned as a error.  This function is only available
    /// with the `flex-str` option.
    pub fn to_flexstr(self) -> Result<Flexstr<N>, Sharedstr<N>> {
        extern crate std;
        use crate::shared_structs::Strunion::*;
        use std::rc::Rc;
        match Rc::try_unwrap(self.inner) {
            Ok(x) => {
                match x.into_inner() {
                    fixed(s) => Ok(Flexstr::from_tstr(s)),
                    owned(s) => Ok(Flexstr::from_string(s)),
                } //inner match
            }
            Err(r) => Err(Sharedstr { inner: r }),
        } //outer match
    } //to_flexstr
} //impl Sharestr

impl<const N: usize> core::ops::Deref for Sharedstr<N> {
    type Target = str;
    fn deref(&self) -> &Self::Target {
        self.as_str()
    }
}

/*
impl<const N: usize> core::hash::Hash for Sharedstr<N> {
    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
        (&*self.inner.borrow()).hash(state)
    }
} //hash
*/

impl<T: AsRef<str> + ?Sized, const N: usize> core::convert::From<&T> for Sharedstr<N> {
    fn from(s: &T) -> Self {
        Self::make(s.as_ref())
    }
}
impl<T: AsMut<str> + ?Sized, const N: usize> core::convert::From<&mut T> for Sharedstr<N> {
    fn from(s: &mut T) -> Self {
        Self::make(s.as_mut())
    }
}

impl<const N: usize> core::cmp::PartialOrd for Sharedstr<N> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<const N: usize> core::cmp::Ord for Sharedstr<N> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.as_str().cmp(other.as_str())
    }
}

impl<const N: usize> core::convert::AsRef<str> for Sharedstr<N> {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}
impl<const N: usize> core::convert::AsMut<str> for Sharedstr<N> {
    fn as_mut(&mut self) -> &mut str {
        unsafe {
            match self.inner.as_ptr().as_mut().unwrap() {
                fixed(f) => f.as_mut(),
                owned(s) => s.as_mut(),
            } //match
        } //unsafe
    } //as_mut
}

impl<const N: usize> PartialEq<&str> for Sharedstr<N> {
    fn eq(&self, other: &&str) -> bool {
        &self.to_str() == other // see below
    } //eq
}

impl<const N: usize> PartialEq<&str> for &Sharedstr<N> {
    fn eq(&self, other: &&str) -> bool {
        &self.to_str() == other
    } //eq
}
impl<'t, const N: usize> PartialEq<Sharedstr<N>> for &'t str {
    fn eq(&self, other: &Sharedstr<N>) -> bool {
        &other.to_str() == self
    }
}
impl<'t, const N: usize> PartialEq<&Sharedstr<N>> for &'t str {
    fn eq(&self, other: &&Sharedstr<N>) -> bool {
        &other.to_str() == self
    }
}

impl<const N: usize> core::fmt::Debug for Sharedstr<N> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.pad(&self.to_str())
    }
} // Debug impl

impl<const N: usize> core::fmt::Display for Sharedstr<N> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        //write!(f, "{}", self.to_str())
        f.pad(self.to_str())
    }
}

impl<const N: usize> core::fmt::Write for Sharedstr<N> {
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
        self.push_str(s);
        Ok(())
    } //write_str
} //core::fmt::Write trait

impl<const N: usize> core::convert::From<String> for Sharedstr<N> {
    /// *will consume owned string and convert it to a fixed
    /// representation if its length is less than N*
    fn from(s: String) -> Self {
        if s.len() >= N {
            Sharedstr {
                inner: Rc::new(RefCell::new(owned(s))),
            }
        } else {
            Sharedstr {
                inner: Rc::new(RefCell::new(fixed(tstr::<N>::from(&s[..])))),
            }
        }
    }
} //from String

impl<const M: usize> Sharedstr<M> {
    /// returns a copy/clone of the string with new fixed capacity N.
    /// Example:
    /// ```
    ///  # use fixedstr::Sharedstr;
    ///  let mut a:Sharedstr<4> = Sharedstr::from("ab");
    ///  let mut b:Sharedstr<8> = a.resize();
    ///  b.push_str("cdef");
    ///  assert!(b.is_fixed());
    ///  a.push_str("1234");
    ///  assert!(a.is_owned());
    /// ```
    pub fn resize<const N: usize>(&self) -> Sharedstr<N> {
        Sharedstr::from(self)
    }
}

impl<const N: usize, TA: AsRef<str>> Add<TA> for &Sharedstr<N> {
    type Output = Sharedstr<N>;
    fn add(self, other: TA) -> Self::Output {
        match (&*self.inner.borrow(), other.as_ref()) {
            (owned(a), b) => {
                let mut a2 = a.clone();
                a2.push_str(other.as_ref());
                Sharedstr {
                    inner: Rc::new(RefCell::new(owned(a2))),
                }
            }
            (fixed(a), b) if a.len() + b.len() >= N => {
                let mut a2 = a.to_string();
                a2.push_str(b);
                Sharedstr {
                    inner: Rc::new(RefCell::new(owned(a2))),
                }
            }
            (fixed(a), b) => {
                let mut a2 = *a; //copy
                a2.push(b);
                Sharedstr {
                    inner: Rc::new(RefCell::new(fixed(a2))),
                }
            }
        } //match
    }
} //Add, Rhs = &str

impl<const N: usize> Add<&Sharedstr<N>> for &str {
    type Output = Sharedstr<N>;
    fn add(self, other: &Sharedstr<N>) -> Sharedstr<N> {
        let mut a2 = Sharedstr::from(self);
        a2.push_str(other);
        a2
    }
} //Add &str on left

impl<const N: usize> Add<Sharedstr<N>> for &str {
    type Output = Sharedstr<N>;
    fn add(self, other: Sharedstr<N>) -> Sharedstr<N> {
        let mut a2 = Sharedstr::from(self);
        a2.push_str(&other);
        a2
    }
} //Add &str on left

impl<const N: usize> core::hash::Hash for Sharedstr<N> {
    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
        self.as_ref().hash(state);
    }
} //hash

impl<const N: usize> core::cmp::PartialEq for Sharedstr<N> {
    fn eq(&self, other: &Self) -> bool {
        self.as_ref() == other.as_ref()
    }
} //eq

impl<const N: usize> core::str::FromStr for Sharedstr<N> {
    type Err = &'static str;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Sharedstr::from(s))
    }
}

/// convenient type aliases for [Sharedstr]
pub type sharedstr8 = Sharedstr<8>;
pub type sharedstr16 = Sharedstr<16>;
pub type sharedstr32 = Sharedstr<32>;
pub type sharedstr64 = Sharedstr<64>;
pub type sharedstr128 = Sharedstr<128>;
pub type sharedstr256 = Sharedstr<256>;
