use std ::{
mem ::{ self , MaybeUninit , } ,
slice ,
str ,
ptr ,
fmt , error ,
borrow ::Borrow ,
ops ,
} ;
mod ext ; use ext ::* ;
/// A `String` that lives entirely on the stack.
#[ derive(Debug, Clone) ]
#[ cfg_attr(feature= " copy " , derive(Copy)) ]
#[ repr(C) ] // Needed for SmallString
pub struct StackString < const SIZE : usize > {
fill_ptr : usize ,
buffer : MaybeUninit < [ u8 ; SIZE ] > ,
}
/// Error returned when trying to create a `StackString` from a string that is too large to fit in it.
#[ derive(Debug, PartialEq, Eq, PartialOrd, Ord) ]
pub struct StrTooLargeError < const SIZE : usize > ( usize ) ;
mod small ;
pub use small ::SmallString ;
impl < const SIZE : usize > StrTooLargeError < SIZE >
{
/// The invalid string's size
#[ inline ]
pub const fn invalid_size ( & self ) -> usize
{
self . 0
}
/// The maximum allowed size
#[ inline ]
pub const fn max_size ( ) -> usize
{
SIZE
}
}
impl < const SIZE : usize > error ::Error for StrTooLargeError < SIZE > { }
impl < const SIZE : usize > fmt ::Display for StrTooLargeError < SIZE >
{
#[ inline ]
fn fmt ( & self , f : & mut fmt ::Formatter < ' _ > ) -> fmt ::Result
{
write! ( f , "string could not fit into {SIZE} bytes: was {} bytes long" , self . 0 )
}
}
impl < const SIZE : usize > StackString < SIZE >
{
/// Try to create a `StackString` from an exact-sized buffer.
#[ inline ]
pub fn try_from_utf8_array ( sz : [ u8 ; SIZE ] ) -> Result < Self , std ::str ::Utf8Error >
{
let s = std ::str ::from_utf8 ( & sz ) ? . len ( ) ;
Ok ( Self {
fill_ptr : s ,
buffer : MaybeUninit ::new ( sz ) ,
} )
}
/// The maximum capacity of this instance
#[ inline ]
pub const fn capacity ( & self ) -> usize
{
SIZE
}
/// The length of the string.
#[ inline ]
pub const fn len ( & self ) -> usize
{
self . fill_ptr
}
/// The amount of memory left before the instance becomes full.
#[ inline ]
pub const fn available ( & self ) -> usize
{
SIZE - self . fill_ptr
}
/// Create a new, empty `StackString`
#[ inline ]
pub const fn new ( ) -> Self
{
Self {
fill_ptr : 0 ,
buffer : MaybeUninit ::uninit ( ) ,
}
}
#[ inline(always) ]
fn buf_end ( & mut self ) -> * mut u8
{
unsafe {
( self . buffer . as_mut_ptr ( ) as * mut u8 ) . add ( self . fill_ptr )
}
}
#[ inline(always) ]
fn as_raw_buf_mut ( & mut self ) -> & mut [ u8 ]
{
unsafe {
slice ::from_raw_parts_mut ( self . buffer . as_mut_ptr ( ) as * mut u8 , self . fill_ptr )
}
}
#[ inline(always) ]
fn as_raw_buf ( & self ) -> & [ u8 ]
{
unsafe {
// MaybeUninit::slice_assume_init_ref(&self.buffer.as_bytes()[..self.fill_ptr]);
slice ::from_raw_parts ( self . buffer . as_ptr ( ) as * const u8 , self . fill_ptr )
}
}
/// A mutable reference to the `str` inside
#[ inline ]
pub fn as_mut_str ( & mut self ) -> & mut str
{
unsafe {
std ::str ::from_utf8_unchecked_mut ( self . as_raw_buf_mut ( ) )
}
}
/// A reference to the `str` inside.
#[ inline ]
pub fn as_str ( & self ) -> & str
{
unsafe {
std ::str ::from_utf8_unchecked ( self . as_raw_buf ( ) )
}
}
/// Append as much of `s` into `self` as possible, return the number of bytes appeneded.
///
/// This function guarantees:
/// * if `s` cannot fit wholely into `self`, the lowest valid UTF-8 codepoint of `s` that will fit into `self` is used instead
/// # Returns
/// The number of bytes copied from `s`.
#[ inline(always) ]
pub fn append_from_str ( & mut self , s : & str ) -> usize
{
let sl = s . len ( ) ;
if self . fill_ptr > = SIZE | | sl = = 0 {
return 0 ;
}
let av = self . available ( ) ;
let sl = if sl < = av {
// Can fit whole `str` in
unsafe {
ptr ::copy_nonoverlapping ( s . as_bytes ( ) . as_ptr ( ) , self . buf_end ( ) , sl ) ;
}
sl
} else if s . is_char_boundary ( av ) {
// Can only fit part in, check if on codepoint boundary
unsafe {
ptr ::copy_nonoverlapping ( s . as_bytes ( ) . as_ptr ( ) , self . buf_end ( ) , av ) ;
}
av
} else {
// Can only fit part in, find the char boundary below `av` and append that.
return self . append_from_str ( & s [ .. s . floor_char_boundary_impl ( av ) ] ) ; //TODO: implement floor_char_boundary() ourselves, and we probably don't need this recursive call.
} ;
self . fill_ptr + = sl ;
sl
}
/// Append as much of `s` into `self` as possible.
///
/// This function has the same guarantees as `append_from_str()`.
///
/// # Returns
/// * `Ok(s)` - if the entire string was appeneded: The part of `self` that now contains `s`.
/// * `Err(s)` - if the entire string was **not** appeneded: The part of `s` that was not copied into `self`. The difference between the returned string and the parameter `s` is how much was copied into `self.
#[ inline ]
pub fn try_append_from_str < ' inner , ' outer > ( & ' inner mut self , s : & ' outer str ) -> Result < & ' inner mut str , & ' outer str >
{
match self . append_from_str ( s ) {
whole if whole = = s . len ( ) = > {
let substr = self . fill_ptr - whole ;
Ok ( & mut self . as_mut_str ( ) [ substr .. ] )
} ,
copied /* if copied < s.len() */ = > Err ( & s [ copied .. ] ) ,
}
}
/// Append as much of `s` into `self` as possible.
///
/// This function has the same guarantees as `append_from_str()`.
///
/// # Returns
/// A tuple containing the copied part of `s`, and the part of `s` that `self` did not have space for.
#[ inline ]
pub fn append_from_str_split < ' i , ' o > ( & ' i mut self , s : & ' o str ) -> ( & ' i mut str , & ' o str )
{
let end = self . fill_ptr ;
let written = self . append_from_str ( s ) ;
if written = = s . len ( ) {
( & mut self . as_mut_str ( ) [ end .. ] , "" )
} else {
( & mut self . as_mut_str ( ) [ end .. written ] , & s [ written .. ] )
}
}
/// Attempt to append the whole string `s` into `self`.
///
/// # Returns
/// * `Some(substr)` - If all of `s` fits in to `self`: the substring of `self` that now contains `s`.
/// * `None` - If `s` was too large to fit entirely in to `self`
#[ inline ]
pub fn try_append_whole_str < ' i > ( & ' i mut self , s : & str ) -> Result < & ' i mut str , StrTooLargeError < SIZE > >
{
let av = self . available ( ) ;
if s . len ( ) < = av {
let len = self . append_from_str ( s ) ;
debug_assert_eq! ( len , s . len ( ) , "Bad append" ) ;
let _ = len ;
Ok ( & mut self . as_mut_str ( ) [ av .. ] )
} else {
Err ( StrTooLargeError ( s . len ( ) ) )
}
}
}
impl < const SIZE : usize > Borrow < str > for StackString < SIZE >
{
#[ inline ]
fn borrow ( & self ) -> & str {
self . as_str ( )
}
}
impl < const SIZE : usize > ops ::Deref for StackString < SIZE >
{
type Target = str ;
#[ inline ]
fn deref ( & self ) -> & Self ::Target {
self . as_str ( )
}
}
impl < const SIZE : usize > std ::str ::FromStr for StackString < SIZE >
{
type Err = StrTooLargeError < SIZE > ;
#[ inline ]
fn from_str ( s : & str ) -> Result < Self , Self ::Err > {
if s . len ( ) > SIZE {
Err ( StrTooLargeError ( s . len ( ) ) )
} else {
let mut o = Self ::new ( ) ;
o . try_append_whole_str ( s ) ? ;
Ok ( o )
}
}
}
impl < const SIZE : usize > TryFrom < String > for StackString < SIZE >
{
type Error = StrTooLargeError < SIZE > ;
#[ inline ]
fn try_from ( from : String ) -> Result < Self , Self ::Error >
{
from . parse ( )
}
}
impl < ' a , const SIZE : usize > TryFrom < & ' a str > for StackString < SIZE >
{
type Error = StrTooLargeError < SIZE > ;
#[ inline ]
fn try_from ( from : & ' a str ) -> Result < Self , Self ::Error >
{
from . parse ( )
}
}
impl < const SIZE : usize > TryFrom < [ u8 ; SIZE ] > for StackString < SIZE >
{
type Error = std ::str ::Utf8Error ;
#[ inline ]
fn try_from ( from : [ u8 ; SIZE ] ) -> Result < Self , Self ::Error >
{
Self ::try_from_utf8_array ( from )
}
}
impl < const SIZE : usize > fmt ::Display for StackString < SIZE >
{
#[ inline ]
fn fmt ( & self , f : & mut fmt ::Formatter < ' _ > ) -> fmt ::Result
{
f . write_str ( self . as_str ( ) )
}
}
impl < const SIZE : usize > fmt ::Write for StackString < SIZE >
{
#[ inline ]
fn write_str ( & mut self , s : & str ) -> fmt ::Result {
self . try_append_whole_str ( s ) . map_err ( | _ | fmt ::Error ::default ( ) ) ? ;
Ok ( ( ) )
}
#[ inline ]
fn write_char ( & mut self , c : char ) -> fmt ::Result {
let l = c . len_utf8 ( ) ;
if l > self . available ( ) {
Err ( fmt ::Error ::default ( ) )
} else {
let end = self . fill_ptr ;
let end = c . encode_utf8 ( & mut ( self . as_raw_buf_mut ( ) ) [ end .. ] ) . len ( ) ;
self . fill_ptr + = end ;
Ok ( ( ) )
}
}
}
const _ : ( ) = {
use std ::io ::{
self , Write
} ;
impl < const SIZE : usize > Write for StackString < SIZE >
{
#[ inline ]
fn write ( & mut self , buf : & [ u8 ] ) -> std ::io ::Result < usize > {
let buf = std ::str ::from_utf8 ( buf ) . map_err ( | e | io ::Error ::new ( io ::ErrorKind ::InvalidData , e ) ) ? ;
Ok ( self . append_from_str ( buf ) )
}
#[ inline ]
fn flush ( & mut self ) -> io ::Result < ( ) > {
Ok ( ( ) )
}
#[ inline ]
fn write_all ( & mut self , buf : & [ u8 ] ) -> io ::Result < ( ) > {
let buf = std ::str ::from_utf8 ( buf ) . map_err ( | e | io ::Error ::new ( io ::ErrorKind ::InvalidData , e ) ) ? ;
self . try_append_whole_str ( buf ) . map_err ( | e | io ::Error ::new ( io ::ErrorKind ::InvalidData , e ) ) . map ( | _ | ( ) )
}
}
} ;