//! Library for fixed-sized strings using const generics. Rust will
//! probably provide something equivalent and more full-featured but
//! I can't wait...
// Fixed, :Copy strings of constant maximum size. Size of each fstr is
// N or less. The actual length of the string (<= N) is stored in a
// field inside the struct for quick access.
#[derive(Copy,Clone,Debug,Eq,PartialEq,Hash)]
pub struct fstr<const N:usize>
{
chrs : [char;N],
len : usize // length will be <=N
}//fstr
impl<const N:usize> fstr<N>
{
pub fn new(s:&str) -> fstr<N>
{
let mut chars = ['\0'; N];
let mut i = 0;
for c in s.chars()
{
if i<N { chars[i] = c; i+=1; } else {break;}
}
fstr {
chrs: chars,
len: i,
}
}//new
/// returns the length of the string, which will be less than or
/// equal to the maximum size. This operation runs in O(1) time.
pub fn len(&self)->usize { self.len }
pub fn to_string(&self) -> String
{
self.chrs[0..self.len].iter().collect()
}
/// this will allow non-mutable access to the chars underneath
pub fn get<'t>(&'t self) -> &'t [char;N] {&self.chrs}
/// changes a char to c if i is less than the length of the string.
/// returns true if change was successful.
pub fn set(&mut self,i:usize, c:char) -> bool
{
if i<self.len {self.chrs[i]=c; true} else {false}
}
/// adds chars to end of current string up to maximum size N of fstr<N>,
/// returns true if all chars in s were added, false if some were ignored
pub fn push(&mut self,s:&str) -> bool
{
let mut i = self.len;
for c in s.chars()
{
if i<N {self.chrs[i] = c; i+=1;} else {self.len=N; return false;}
}
self.len = i;
true
}
/// returns the nth char of the fstr
pub fn nth(&self,n:usize) -> Option<char>
{
if n<self.len {Some(self.chrs[n])} else {None}
}
}//impl fstr<N>
impl<const N:usize> std::convert::From<String> for fstr<N>
{
fn from(s:String) -> fstr<N>
{
fstr::<N>::new(&s[..])
}
}
impl<const M:usize> fstr<M>
{
pub fn resize<const N:usize>(&self) -> fstr<N>
{
let length = if (self.len<N) {self.len} else {N};
let mut chars = ['\0';N];
for i in 0..length {chars[i] = self.chrs[i];}
fstr {
chrs: chars,
len: length,
}
}//resize
}
impl<const N:usize> std::convert::From<&str> for fstr<N>
{
fn from(s:&str) -> fstr<N>
{
fstr::<N>::new(s)
}
}
pub struct fstriter<const N:usize>
{
fs : fstr<N>,
i : usize,
}
impl<const N:usize> Iterator for fstriter<N>
{
type Item = char;
fn next(&mut self) -> Option<char>
{
if self.i<self.fs.len {self.i+=1; Some(self.fs.chrs[self.i-1])} else {None}
}
}
impl<const N:usize> IntoIterator for fstr<N>
{
type Item = char;
type IntoIter = fstriter<N>;
fn into_iter(self) -> fstriter<N>
{
fstriter {
fs : self,
i : 0,
}
}
}//IntoIterator
impl<const N:usize> std::fmt::Display for fstr<N>
{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
write!(f,"{}",self.to_string())
}
}
impl<const N:usize> PartialEq<&str> for fstr<N>
{
fn eq(&self, other:&&str) -> bool
{
self==other // see below
}//eq
}
impl<const N:usize> PartialEq<&str> for &fstr<N>
{
fn eq(&self, other:&&str) -> bool
{
if other.len()!=self.len {return false;}
let mut i = 0;
for c in other.chars()
{
if c!=self.chrs[i] {return false;}
i +=1;
}
return true;
}//eq
}
impl<'t, const N:usize> PartialEq<fstr<N>> for &'t str
{
fn eq(&self, other:&fstr<N>) -> bool
{ other==self }
}
impl<'t, const N:usize> PartialEq<&fstr<N>> for &'t str
{
fn eq(&self, other:&&fstr<N>) -> bool
{ other==self }
}
///Convert fstr to slice
impl<IndexType,const N:usize> std::ops::Index<IndexType> for fstr<N>
where IndexType:std::slice::SliceIndex<[char]>,
{
type Output = IndexType::Output;
fn index(&self, index:IndexType)-> &Self::Output
{
&self.chrs[index]
}
}//impl Index
// couldn't get it to work properly, [char] is not same as &str
// because there's no allocated string!
impl<const N:usize> fstr<N>
{
/// returns a copy of the portion of the string, string could be truncated
/// if indices are out of range. Similar to slice [start..end]
pub fn substr(&self,start:usize, end:usize) -> fstr<N>
{
let mut chars = ['\0';N];
if start>=self.len { return fstr{chrs:chars, len:0}; }
let mut i = start;
while i<end && i<self.len
{
chars[i-start] = self.chrs[i];
i += 1;
}
fstr { chrs: chars, len:i }
}//substr
}
pub type str8 = fstr<8>; // a type for small strings
pub type str16 = fstr<16>;
pub type str32 = fstr<32>;
pub type str64 = fstr<64>;
pub type str128 = fstr<128>;