Made work on stable: Added `.floor_char_boundary()` impl.

Fortune for stack-str's current commit: Middle blessing − 中吉
master
Avril 2 years ago
parent fb769265ca
commit c40b415a06
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -0,0 +1,35 @@
//! Extensions
#[inline(always)]
pub fn is_utf8_char_boundary(byte: u8) -> bool
{
//!
//! Copied from stdlib
(byte as i8) >= -0x40
}
pub trait StrExt
{
fn floor_char_boundary_impl(&self, index: usize) -> usize;
}
impl<T: ?Sized + AsRef<str>> StrExt for T
{
#[inline]
fn floor_char_boundary_impl(&self, index: usize) -> usize {
//!
//! copied from stdlib
let this = self.as_ref();
if index >= this.len() {
this.len()
} else {
let lower_bound = index.saturating_sub(3);
let new_index = this.as_bytes()[lower_bound..=index]
.iter()
.rposition(|&b| is_utf8_char_boundary(b));
// SAFETY: we know that the character boundary will be within four bytes
unsafe { lower_bound + new_index.unwrap_unchecked() }
}
}
}

@ -1,5 +1,3 @@
#![feature(round_char_boundary)]
use std::{
mem::{self, MaybeUninit,},
slice,
@ -12,7 +10,9 @@ use std::{
ops,
};
/// A `str` that lives entirely on the stack.
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
@ -20,9 +20,29 @@ pub struct StackString<const SIZE: usize>{
fill_ptr: usize,
buffer: MaybeUninit<[u8; SIZE]>,
}
#[derive(Debug)]
/// 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>
{
@ -34,12 +54,9 @@ impl<const SIZE: usize> fmt::Display for StrTooLargeError<SIZE>
}
mod small;
pub use small::SmallString;
//TODO: Document
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>
{
@ -49,23 +66,26 @@ impl<const SIZE: usize> StackString<SIZE>
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
{
@ -94,10 +114,12 @@ impl<const SIZE: usize> StackString<SIZE>
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
{
@ -105,6 +127,7 @@ impl<const SIZE: usize> StackString<SIZE>
std::str::from_utf8_unchecked_mut(self.as_raw_buf_mut())
}
}
/// A reference to the `str` inside.
#[inline]
pub fn as_str(&self) -> &str
{
@ -143,7 +166,7 @@ impl<const SIZE: usize> StackString<SIZE>
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(av)]); //TODO: implement floor_char_boundary() ourselves, and we probably don't need this recursive call.
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
@ -192,7 +215,7 @@ impl<const SIZE: usize> StackString<SIZE>
/// * `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) -> Option<&'i mut str>
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 {
@ -200,9 +223,9 @@ impl<const SIZE: usize> StackString<SIZE>
debug_assert_eq!(len, s.len(), "Bad append");
let _ = len;
Some(&mut self.as_mut_str()[av..])
Ok(&mut self.as_mut_str()[av..])
} else {
None
Err(StrTooLargeError(s.len()))
}
}
}
@ -233,11 +256,9 @@ impl<const SIZE: usize> std::str::FromStr for StackString<SIZE>
Err(StrTooLargeError(s.len()))
} else {
let mut o = Self::new();
if o.try_append_whole_str(s).is_none() {
Err(StrTooLargeError(s.len()))
} else {
Ok(o)
}
o.try_append_whole_str(s)?;
Ok(o)
}
}
}

Loading…
Cancel
Save