#![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)]
//! fixed strings with circular-queue backing

use core::cmp::{min, Ordering, PartialOrd};
extern crate alloc;
use alloc::string::String;
use core::ops::Add;

/// **This type is only available with the `circular-str` option.**
///
/// A *circular string* is represented underneath by a fixed-size u8
/// array arranged as a circular queue. The string can wrap around
/// either end and thus becomes internally non-contiguous.
/// This allows for efficient implementations of operations such as
/// push, trim *in front* of the string.  However, `Deref<str>` is not
/// implemented as it cannot be done efficiently.  Instead, the
/// [cstr::to_strs] function returns a pair of string slices, the second
/// of which is non-empty if the string is not contiguous.  Additionally,
/// only single-byte characters are currently allowed, although this might
/// change in future by using a "ghost vector" at the end of the string.
/// An iterator [cstr::chars] is provided over all single-byte chars, which
/// also forms the foundation of other traits such as Eq, Ord, Hash, etc.
/// The Serialization (serde) and no-std options are both supported.
///
/// Each `cstr<N>` can hold up to N bytes and the maximum N is 65535.
/// Values of N that are exact powers of 2 are recommended to speed up
/// the `%` operation for computing indices in a ciruclar queue.
///
/// Examples:
/// ```
///  # use fixedstr::*;
///  let mut cb = cstr::<16>::make("abc123");
///  cb.push_str("xyz");
///  cb.push_front("9876");
///  assert_eq!(cb.pop_char().unwrap(), 'z');
///  assert_eq!(cb.pop_char_front().unwrap(), '9');
///  cb.push_str_front("000");
///  assert_eq!(cb.len(),14);
///  assert!(&cb == "000876abc123xy");
///  cb.truncate_left(10);
///  assert_eq!(&cb,"23xy");
///  cb.push_str("ijklmno  ");
///  cb.push_char_front(' ');
///  assert!(!cb.is_contiguous());
///  cb.trim_whitespaces();
///  assert!("23xyijklmno" == &cb);
///  assert!(&cb < "4abc");   // Ord trait
///  let mut a = cstr8::from("abc");
///  let ba:cstr8 = "123" + a; // concat &str on the left efficiently
///  assert_eq!(ba,"123abc");
/// ```
#[derive(Copy,Clone)]
pub struct cstr<const N : usize=32>
{
  chrs: [u8;N],
  front: u16,
  len: u16,
} //cstr 

impl<const N:usize> cstr<N>
{
   /// create `cstr` from `&str` with silent truncation; panics if
   /// N is greater than 65535
   pub fn make(src:&str) -> cstr<N> {
     if N<1 || N > 65535 { panic!("cstr strings are limited to a capacity between 1 and 65535");}
     let mut m = cstr::<N>::new();
     let length = core::cmp::min(N,src.len());
     m.chrs[..length].copy_from_slice(&src.as_bytes()[..length]);
     m.len = length as u16;
     m
   }//make

   /// version of make that also panics if the input string is not ascii.
   pub fn from_ascii(src:&str) -> cstr<N> {
     if N<1 ||  N > 65535 { panic!("cstr strings are limited to a maximum capacity of 65535");}
     if !src.is_ascii() { panic!("cstr string is not ascii");}
     let mut m = cstr::<N>::new();
     let length = core::cmp::min(N,src.len());
     m.chrs[..length].copy_from_slice(&src.as_bytes()[..length]);
     m.len = length as u16;
     m
   }//from_ascii

   /// version of make that does not truncate: returns original str slice
   /// as error.  Also checks if N is no greater than 65535 without panic.
   pub fn try_make(src:&str) -> Result<cstr<N>, &str> {
     let length = src.len();
     if length>N || N>65535 || N<1 {return Err(src);}
     let mut m = cstr::new();
     m.chrs[..].copy_from_slice(&src.as_bytes()[..length]);
     m.len = length as u16;
     Ok(m)
   }//try_make

   /// version of `try_make` that also checks if the input string is ascii.
   pub fn try_make_ascii(src:&str) -> Option<cstr<N>> {
     let length = src.len();
     if length>N || N>65535 || N<1 || !src.is_ascii() {return None;}
     let mut m = cstr::new();
     m.chrs[..].copy_from_slice(&src.as_bytes()[..length]);
     m.len = length as u16;
     Some(m)
   }//try_make

   /// version of make that returns a pair consisting of the made
   /// `cstr` and the remainder `&str` that was truncated; panics if
   /// N is greater than 65535 (but does not check for ascii strings)
   pub fn make_remainder(src:&str) -> (cstr<N>,&str) {
     if N > 65535 || N<1 { panic!("cstr strings are limited to a capacity between 1 and 65535");}   
     let mut m = cstr::new();
     let length = core::cmp::min(N,src.len());
     m.chrs[..].copy_from_slice(&src.as_bytes()[..length]);
     m.len = length as u16;
     (m,&src[length..])
   }//try_make

   /// make from a pair of str slices, does not truncate, and checks that
   /// N is not greater than 65535 without panic.  The returned cstr will
   /// be contiguous.
   pub fn from_pair(left:&str, right:&str) -> Option<cstr<N>> {
     let (llen,rlen) = (left.len(), right.len());
     if llen+rlen > N || N > 65535 || N<1 { return None; }
     let mut m = cstr::new();
     m.len = (llen+rlen) as u16;
     m.chrs[..llen].copy_from_slice(&left.as_bytes()[..llen]);
     m.chrs[llen..].copy_from_slice(&right.as_bytes()[llen..]);
     Some(m)
   }//from_pair

   /// checks if the underlying representation of the string is contiguous
   /// (without wraparound).
   #[inline(always)]
   pub fn is_contiguous(&self) -> bool {
     (self.front as usize + self.len as usize) <= N
   }

   /// resets the internal representation of the cstr so that it is
   /// represented contiguously, without wraparound. **Calling this function
   /// has O(n) cost both in terms of speed and memory** as
   /// it requires a secondary buffer as well as copying.**
   pub fn reset(&mut self) {
     if self.front==0 {return;}
     let mut mhrs = [0;N];
     for i in 0..self.len as usize {
       mhrs[i] = self.chrs[self.index(i)];
     }
     self.chrs = mhrs;
     self.front = 0;
   }//reset

   /// clears string to empty string
   pub fn clear(&mut self) {
     self.len=0;
   }
   
   /// resets string to empty string and clears underlying buffer to contain
   /// all zeros.
   pub fn zero(&mut self) {
     self.chrs = [0;N];
     self.front = 0;
     self.len = 0;
   }

   /// guarantees a contiguous underlying representation of the string.
   /// This is an O(n) operation.
   pub fn make_contiguous(&mut self) {
     if !self.is_contiguous() { self.reset();}
   }

    /// returns the nth char of the fstr.  Since only single-byte characters
    /// are currently supported by the cstr type, this function is the same
    /// as [Self::nth_bytechar] except that n is checked against the length of the
    /// string.
    pub fn nth(&self, n: usize) -> Option<char> {
        if n<self.len as usize {
          Some(self.chrs[self.index(n)] as char)
        }
        else {None}
    }


    /// returns the nth byte of the string as a char, does not check n
    /// against length of array
    #[inline]
    pub fn nth_bytechar(&self, n: usize) -> char {
        self.chrs[self.index(n)] as char
    }

    /// sets the nth byte of the string to the supplied character.
    /// the character must fit in a single byte.  Returns true on success.
    pub fn set(&mut self, n:usize, c:char) -> bool {
      if c.len_utf8()>1 || n>= self.len as usize { false }
      else {
        self.chrs[self.index(n)] = c as u8;
        true
      }
    }//set

   /// pushes given string to the end of the string, returns remainder
   pub fn push_str<'t>(&mut self, src:&'t str) -> &'t str {
     let srclen = src.len();
     let slen = self.len as usize;
     let bytes = &src.as_bytes();
     let length = core::cmp::min(slen+srclen , N);
     let remain = if N>(slen+srclen) {0} else {(srclen+slen)-N};
     let mut i = 0;
     while i<srclen && i+slen<N {
       self.chrs[self.index(slen+i)] = bytes[i];
       i += 1;
     }//while
     self.len += i as u16;
     &src[srclen-remain..]
   }//push_str

   /// Pushes string to the **front** of the string, returns remainder.
   /// because of the circular-queue backing, this operation as the same
   /// cost as pushing to the back of the string ([Self::push_str]).
   /// This function does not check if the input string is ascii.
   pub fn push_front<'t>(&mut self, src:&'t str) -> &'t str {
     let srclen = src.len();
     let slen = self.len as usize;
     let bytes = &src.as_bytes();
     let length = core::cmp::min(slen+srclen , N);
     let remain = if N>=(slen+srclen) {0} else {(srclen+slen)-N};
     let mut i = 0;
     while i<srclen && i+slen<N {
       //self.front =(self.front + (N as u16) -1) % (N as u16);
       self.front = ((self.front as usize+N-1) % N) as u16;
       self.chrs[self.front as usize] = bytes[srclen-1-i];
       i += 1;
     }//while
     self.len += i as u16;     
     &src[..remain]
   }//push_front

   /// alias for [Self::push_front]
   pub fn push_str_front<'t>(&mut self, src:&'t str) -> &'t str {
      self.push_front(src)
   }

    /// Pushes a single character to the end of the string, returning
    /// true on success.  This function checks if the given character
    /// occupies a single-byte.
    pub fn push_char(&mut self, c:char) -> bool {
       let clen = c.len_utf8();
       if clen>1 || self.len as usize + clen > N {return false;}
       let mut buf = [0u8;4]; // char buffer
       let bstr = c.encode_utf8(&mut buf);
       self.push_str(bstr);
       true
    }// push_char

    /// Pushes a single character to the front of the string, returning
    /// true on success.  This function checks if the given character
    /// occupies a single-byte.
    pub fn push_char_front(&mut self, c:char) -> bool {
       let clen = c.len_utf8();
       if clen>1 || self.len as usize + clen > N {return false;}
       let newfront = (self.front as usize+N-1) % N;
       self.chrs[newfront] = c as u8;
       self.front = newfront as u16;
       self.len += 1;
       true
    }//push_char_front

    /// remove and return last character in string, if it exists
    pub fn pop_char(&mut self) -> Option<char> {
       if self.len()==0 {return None;}
       let lasti = ((self.front+self.len-1) as usize)% N;
       let firstchar = self.chrs[lasti] as char;
       self.len-=1;
       Some(firstchar)
       /*
       let (l,r) = self.to_strs();
       let right = if r.len()>0 {r} else {l};
       let (ci,lastchar) = right.char_indices().last().unwrap();
       self.len = if r.len()>0 {(l.len() + ci) as u16} else {ci as u16};
       Some(lastchar)
       */
    }//pop

    /// remove and return first character in string, if it exists
    pub fn pop_char_front(&mut self) -> Option<char> {
       if self.len()==0 {return None;}
       let firstchar = self.chrs[self.front as usize] as char;
       self.front = self.index16(1);
       self.len -= 1;
       Some(firstchar)
    }//pop_char_front


    /// alias for [Self::truncate]
    pub fn truncate_right(&mut self, n: usize) {
       if (n<self.len as usize) {
	 self.len = n as u16;
       }
    }

    /// right-truncates string up to byte position n.  No effect
    /// if n is greater than or equal to the length of the string.
    #[inline]
    pub fn truncate(&mut self, n: usize) { self.truncate_right(n); }

    /// left-truncates string up to byte position n.  No effect
    ///if n is greater than the length of the string.
    pub fn truncate_left(&mut self, n: usize) {
       if (n>0 && n<=self.len as usize) {
         /*
         let (a,b) = self.to_strs();
         if n<a.len() {
           assert!(a.is_char_boundary(n));
         }
         else {
           assert!(b.is_char_boundary(n-a.len()));         
         }
         */
         self.front = self.index16(n as u16);
	 self.len -= n as u16;
       }
    }//truncate_left

    /// alias for `truncate_left`
    pub fn truncate_front(&mut self, n:usize) { self.truncate_left(n); }

    /// finds the position of first character that satisfies given predicate
    pub fn find<P>(&self, predicate: P) -> Option<usize>
         where P : Fn(char) -> bool
    {
        let (a,b) = self.to_strs();
        if let Some(pos) = a.find(|x:char|predicate(x)) {
            Some(pos)
        }
        else if let Some(pos) = b.find(|x:char|predicate(x)) {
            Some(a.len() + pos)
        }
        else { None }
    }//find

    /// finds the position of last character that satisfies given predicate
    pub fn rfind<P>(&self, predicate: P) -> Option<usize>
         where P : Fn(char) -> bool
    {
        let (a,b) = self.to_strs();
        if let Some(pos) = b.find(|x:char|predicate(x)) {
            Some(a.len()+pos)
        }
        else if let Some(pos) = a.find(|x:char|predicate(x)) {
            Some(pos)
        }
        else { None }
    }//find

    /// finds position of first matching substring
    pub fn find_substr(&self, s:&str) -> Option<usize> {
        let (a,b) = self.to_strs();
        if let Some(pos) = a.find(s) {
            return Some(pos);
        }
	if s.len()>1 { //check middle
	  for i in 0..s.len()-1 {
	    let mid = s.len()-i-1;
	    if a.ends_with(&s[..mid]) && b.starts_with(&s[mid..]) {
	      return Some(a.len()-mid);
	    }
	  }// for each intermediate position
	}
        if let Some(pos) = b.find(s) {
          return Some(a.len() + pos);
        }
	else {None}
    }//find_substr

    /// finds position of last matching substring
    pub fn rfind_substr(&self, s:&str) -> Option<usize> {
        let (a,b) = self.to_strs();
        if let Some(pos) = b.find(s) {
            return Some(a.len()+pos);
        }
	if s.len()>1 { // check middle
	  for i in 0..s.len()-1 {
	    let mid = s.len()-i-1;
	    if b.starts_with(&s[mid..]) && a.ends_with(&s[..mid]) {
	       return Some(a.len()-mid);
	    }
	  }//for
	}
        if let Some(pos) = a.find(s) {
            Some(pos)
        }
        else { None }      
    }//find_substr

    /// **in-place** trimming of white spaces at the front of the string
    pub fn trim_left(&mut self) {
      let (a,b) = self.to_strs();
      let offset;
      if let Some(i) = a.find(|c:char|!c.is_whitespace()) {
         offset = i as u16;
      }
      else if let Some(k) = b.find(|c:char|!c.is_whitespace()) {
         offset = (a.len() + k) as u16;
      }
      else {
         offset = (a.len() + b.len()) as u16;
      }
      self.front = self.index16(offset); //((self.front as usize + offset)%N) as u16;
      self.len -= offset;
    }//trim_left

    /// **in-place** trimming of white spaces at the end of the string
    pub fn trim_right(&mut self) {
      let (a,b) = self.to_strs();
      let offset;
      if b.len()==0 {
        if let Some(k) = a.rfind(|c:char|!c.is_whitespace()) {
         offset = a.len() - k - 1;
        }
        else {
          offset = a.len();
        }
      }//contiguous
      else if let Some(i) = b.rfind(|c:char|!c.is_whitespace()) {
         offset = b.len() - i - 1;
      }
      else if let Some(k) = a.rfind(|c:char|!c.is_whitespace()) {
         offset = b.len() + (a.len() - k - 1)
      }
      else {
         offset = a.len() + b.len();
      }
      self.len -= offset as u16;
    }//trim_right

    /// **in-place** trimming of white spaces at either end of the string
    pub fn trim_whitespaces(&mut self) {
      self.trim_left();
      self.trim_right();
    }


   // convenience
   #[inline(always)]
   fn endi(&self) -> usize {  // index of last value plus 1
     //fastmod(self.front as usize + self.len as usize,N)
     (self.front as usize + self.len as usize )%N
   }// last

   #[inline(always)]
   fn index(&self, i:usize) -> usize {
     (self.front as usize +i)%N
   } // index of ith vale
   
   /// length of string in bytes
   #[inline(always)]
   pub fn len(&self) -> usize  { self.len as usize }

   /// construct new, empty string (same as `cstr::default`)
   #[inline(always)]   
   pub fn new() -> Self {
      Self::default()
   }//new

   /// returns a pair of string slices `(left,right)` which, when concatenated,
   /// will yield an equivalent string underneath.  In case of no wraparound,
   /// the right str will be empty.
   pub fn to_strs(&self) -> (&str,&str) {
     let answer;
     if self.len()==0 {answer = ("","");}
     else if self.is_contiguous() {
       let front = self.front as usize;
       answer = (core::str::from_utf8(&self.chrs[front .. front+(self.len as usize)]).unwrap(),
        "")
     }
     else {
       answer=(core::str::from_utf8(&self.chrs[self.front as usize .. ]).unwrap(),
        core::str::from_utf8(&self.chrs[.. self.endi()]).unwrap())
     }
     answer
   }//to_strs


   /// returns iterator over the characters of the string
   pub fn chars<'a>(&'a self) -> CircCharIter<'a> {
     let contig = self.is_contiguous();
     CircCharIter {
       first : if contig { &self.chrs[self.front as usize .. (self.front+self.len) as usize] }
               else { &self.chrs[self.front as usize ..] },
       second: if contig { &[] }
               else { &self.chrs[..self.endi()] },
       index : 0,           
     }
   }//chars

   /// alias for [Self.chars]
   pub fn iter<'a>(&'a self) -> CircCharIter<'a> {
     self.chars()
   }

   /// returns a copy of the same string that is contiguous underneath.
   /// This may call [cstr::reset], which is an O(n) operation.
   pub fn to_contiguous(&self) -> cstr<N> {
     let mut c = *self;
     if !c.is_contiguous() {c.reset();}
     c
   }

   /// returns a single str slice if the cstr is contiguous underneath,
   /// otherwise panics.
   pub fn force_str(&self) -> &str {
     let (a,b) = self.to_strs();
     if b.len()>0 {panic!("cstr cannot be transformed into a single str slice without calling reset()");}
     a
   }

   /// converts cstr to an owned string
   pub fn to_string(&self) -> String {
     let (a,b) = self.to_strs();
     let mut s = String::from(a);
     if b.len()>0 {s.push_str(b);}
     s
   }//to_string


    /// returns a copy of the portion of the string.  Will return empty
    /// string if indices are invalid. The returned string will be contiguous.
    pub fn substr(&self, start: usize, end: usize) -> cstr<N> {
      let mut s = cstr::<N>::default();
      if (end<=start || start as u16 > self.len-1 || end>self.len as usize)   {return s;}
      for i in start .. end {
       s.chrs[i-start] = self.chrs[self.index(i)];
      }
      s.len = (end-start) as u16;
      s
    }//substr

    /// in-place modification of ascii characters to lower-case.
    pub fn make_ascii_lowercase(&mut self) {
      for i in 0..self.len as usize {
        let b = &mut self.chrs[self.index(i)];
        if *b>=65 && *b<=90 { *b |= 32; }
      }
    }//make_ascii_lowercase

    /// in-place modification of ascii characters to upper-case.
    pub fn make_ascii_uppercase(&mut self) {
      for i in 0..self.len as usize {
        let b = &mut self.chrs[self.index(i)];
        if *b>=97 && *b<=122 { *b -= 32; } 
      }      
    }//make_ascii_uppercase
    
  /*
   /// returns an str slice representation by possibly calling
   /// [Self::reset] first, which is expensive.
   pub fn force_str(&mut self) -> &str {
     if !self.is_contiguous() {self.reset();}
     let(a,_) = self.to_strs();
     a
   }

   #[cfg(feature="serde")]
   /// for serde only, panics if underlying representation is not contiguous
   pub fn as_str(&self) -> &str {
     let(a,b) = self.to_strs();
     if b.len()>0 {panic!("serialization of cstr is only allowed after reset()");}
     a
   }
   
   #[inline]
   fn index_of(&self,i:usize) -> usize {
     fastmod(self.front as usize + i,N)
   }
   */

   #[inline(always)]
   fn index16(&self, i:u16) -> u16 {
     (self.front+i) % (N as u16)
     //let n = N as u16;
     //let mask = n-1;
     //if n&mask==0 { (self.front+i) & mask } else {(self.front+i) % n }
   }
}//main impl
///////////////////////////////////////////////////////////////


impl<const M: usize> cstr<M> {
    /// converts an `cstr<M>` to an `cstr<N>`. If the length of the string being
    /// converted is greater than N, the extra characters are ignored.
    /// This operation produces a new string that is contiguous underneath.
    pub fn resize<const N: usize>(&self) -> cstr<N> {
        let slen = self.len();
        let length = if (slen < N) { slen } else { N };
        let mut s = cstr::<N>::default();
        let (a,b) = self.to_strs();
        s.chrs[..a.len()].copy_from_slice(a.as_bytes());
        if b.len()>0 {
          s.chrs[a.len()..].copy_from_slice(b.as_bytes());
        }
        s.len = self.len;
        s
    } //resize

    /// version of resize that does not allow string truncation due to length
    pub fn reallocate<const N: usize>(&self) -> Option<cstr<N>> {
        if self.len() < N {
            Some(self.resize())
        } else {
            None
        }
    }
} //impl cstr<M>


impl<const N :usize> Default for cstr<N> {
  fn default() -> Self {
    cstr {
       chrs: [0;N],
       front: 0,
       len:0,
    }
  }
}//impl default

impl<const N: usize> core::fmt::Debug for cstr<N> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        let (a,b) = self.to_strs();
        f.pad(a)?;
        f.pad(b)
    }
} // Debug impl

impl<const N: usize> core::fmt::Display for cstr<N> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        let (a,b) = self.to_strs();
        write!(f, "{}{}", a,b)
    }
}

/////////// need Eq, Ord, etc.  and special iterator implementation
impl<const N: usize> PartialEq<&str> for cstr<N> {
    fn eq(&self, other: &&str) -> bool {
        &self == other
    }//eq
}

impl<const N: usize> PartialEq<&str> for &cstr<N> {
    fn eq(&self, other: &&str) -> bool {
        let (a,b) = self.to_strs();
        let (alen, blen) = (a.len(), b.len());
        alen+blen==other.len() &&
          a == &other[..alen]  &&  (blen==0 || b == &other[alen..]) 
    } //eq
}

/*
impl<T:AsRef<str>, const N: usize> PartialEq<&T> for &cstr<N> {
    fn eq(&self, other: &&T) -> bool {
        let (a,b) = self.to_strs();
        let (alen, blen) = (a.len(), b.len());
        let oref = other.as_ref();
        alen+blen==oref.len() &&
          a == &oref[..alen]  &&  (blen==0 || b == &oref[alen..]) 
    } //eq
}
*/

impl<const N: usize> PartialEq<cstr<N>> for &str {
    fn eq(&self, other: &cstr<N>) -> bool {
        let (a,b) = other.to_strs();
        let (alen, blen) = (a.len(), b.len());
        alen+blen==self.len() &&
          a == &self[..alen]  &&  (blen==0 || b == &self[alen..]) 
    } //eq
}

impl<const N: usize> PartialEq<&cstr<N>> for &str {
    fn eq(&self, other: &&cstr<N>) -> bool {
        let (a,b) = other.to_strs();
        let (alen, blen) = (a.len(), b.len());
        alen+blen==self.len() &&
          a == &self[..alen]  &&  (blen==0 || b == &self[alen..]) 
    } //eq
}

/// character interator, returned by [cstr::chars]
pub struct CircCharIter<'a> {
  first : &'a [u8],
  second: &'a [u8],
  index : usize,
}
impl<'a> Iterator for CircCharIter<'a> {
  type Item = char;
  fn next(&mut self) -> Option<Self::Item> {
    if self.index<self.first.len() {
      self.index += 1;
      Some(self.first[self.index-1] as char)
    }
    else if self.index-self.first.len() < self.second.len() {
      self.index += 1;
      Some(self.second[self.index-self.first.len()-1] as char)
    }
    else { None }
  }//next
}// impl CircCharIter

impl<const N: usize> PartialEq for cstr<N> {
    fn eq(&self, other: &Self) -> bool {
       let mut schars = self.chars();
       let mut ochars = other.chars();
       loop {
         match (schars.next(), ochars.next()) {
           (None,None) => {break;},
           (Some(x), Some(y)) if x==y => {},
           _ => { return false; },
         }//match
       }//loop
       true
    }//eq for Self
}// PartialEq
impl<const N:usize> Eq for cstr<N> {}

impl<const N: usize> Ord for cstr<N> {
  fn cmp(&self, other:&Self) -> Ordering {
       let mut schars = self.chars();
       let mut ochars = other.chars();
       let mut answer = Ordering::Equal;
       loop {
         match (schars.next(), ochars.next()) {
           (Some(x), Some(y)) if x.cmp(&y)==Ordering::Equal => {},
           (Some(x), Some(y)) => { answer = x.cmp(&y); break; },
           (None,None) => {break;}
           (None,_) => { answer = Ordering::Less; break; },
           (_,None) => { answer = Ordering::Greater; break; },
         }//match
       }//loop
       answer  
  }//cmp
}//Ord

impl<const N: usize> PartialOrd for cstr<N> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
       Some(self.cmp(other))
       /*
       let mut schars = self.chars();
       let mut ochars = other.chars();
       let mut answer = Ordering::Equal;
       loop {
         match (schars.next(), ochars.next()) {
           (Some(x), Some(y)) if x.cmp(&y)==Ordering::Equal => {},
           (Some(x), Some(y)) => { answer = x.cmp(&y); break; },
           (None,None) => {break;}
           (None,_) => { answer = Ordering::Less; break; },
           (_,None) => { answer = Ordering::Greater; break; },
         }//match
       }//loop
       Some(answer)
       */
    }//partial_cmp
}// PartialOrd


impl<const N: usize> PartialOrd<&str> for cstr<N> {
    fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
       let mut schars = self.chars();
       let mut ochars = other.chars();
       let mut answer = Ordering::Equal;
       loop {
         match (schars.next(), ochars.next()) {
           (Some(x), Some(y)) if x.cmp(&y)==Ordering::Equal => {},
           (Some(x), Some(y)) => { answer = x.cmp(&y); break; },
           (None,None) => {break;}
           (None,_) => { answer = Ordering::Less; break; },
           (_,None) => { answer = Ordering::Greater; break; },
         }//match
       }//loop
       Some(answer)
    }//partial_cmp
}// PartialOrd

impl<const N: usize> PartialOrd<&str> for &cstr<N> {
    fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
       let mut schars = self.chars();
       let mut ochars = other.chars();
       let mut answer = Ordering::Equal;
       loop {
         match (schars.next(), ochars.next()) {
           (Some(x), Some(y)) if x.cmp(&y)==Ordering::Equal => {},
           (Some(x), Some(y)) => { answer = x.cmp(&y); break; },
           (None,None) => {break;}
           (None,_) => { answer = Ordering::Less; break; },
           (_,None) => { answer = Ordering::Greater; break; },
         }//match
       }//loop
       Some(answer)
    }//partial_cmp
}// PartialOrd


impl<const N:usize> core::hash::Hash for cstr<N> {
  fn hash<H:core::hash::Hasher>(&self, state:&mut H) {
    for i in (self.len as usize..0).rev() {
      self.nth_bytechar(i-1).hash(state);
    }
    //for c in self.chars() { c.hash(state); }
  }
}//hash

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

impl<const N: usize> core::fmt::Write for cstr<N> {
    fn write_str(&mut self, s: &str) -> core::fmt::Result
    {
        if s.len() + self.len() > N {
            return Err(core::fmt::Error::default());
        }
        self.push_str(s);
        Ok(())
    } //write_str
} //core::fmt::Write trait

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

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

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

impl<const N:usize> Add for &cstr<N> {
  type Output = cstr<N>;
  fn add(self, other:&cstr<N>) -> cstr<N> {
    let mut a2 = *self;
    let (l,r) = other.to_strs();
    a2.push_str(l);
    if r.len()>0 { a2.push_str(r); }
    a2
  }
}//Add &str

impl<const N:usize> Add for cstr<N> {
  type Output = cstr<N>;
  fn add(self, other:cstr<N>) -> cstr<N> {
    let mut a2 = self;
    let (l,r) = other.to_strs();
    a2.push_str(l);
    if r.len()>0 { a2.push_str(r); }
    a2
  }
}//Add &str

/*
////////// fast x % n for n that are powers of 2
#[inline(always)]
fn fastmod(x:usize, n:usize) -> usize {
    x % n
//  let mask = n-1;
//  if n&mask==0 { x & mask } else {x % n}
}//fastmod
*/

////// aliases
/// Convenient aliases for [cstr] using exact powers of 2
pub type cstr1k = cstr<1024>;
pub type cstr8 = cstr<8>;
pub type cstr16 = cstr<16>;
pub type cstr32 = cstr<32>;
pub type cstr64 = cstr<64>;
pub type cstr128 = cstr<128>;
pub type cstr256 = cstr<256>;
pub type cstr512 = cstr<512>;

