Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
target
Cargo.lock

/.vscode
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ name = "inlinable_string"

description = "The `inlinable_string` crate provides the `InlinableString` type -- an owned, grow-able UTF-8 string that stores small strings inline and avoids heap-allocation -- and the `StringExt` trait which abstracts string operations over both `std::string::String` and `InlinableString` (or even your own custom string type)."

version = "0.1.15"
edition = "2018"
version = "0.1.16"
edition = "2024"
license = "Apache-2.0/MIT"
keywords = ["string", "inline", "inlinable"]
readme = "./README.md"
Expand All @@ -21,6 +21,7 @@ version = "1"
[features]
nightly = []
no_std = []
as_mut = []

[dev-dependencies]
serde_test = "1"
64 changes: 4 additions & 60 deletions src/inline_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ pub struct NotEnoughSpaceError;

impl AsRef<str> for InlineString {
fn as_ref(&self) -> &str {
self.assert_sanity();
unsafe { str::from_utf8_unchecked(&self.bytes[..self.len()]) }
}
}
Expand All @@ -80,18 +79,18 @@ impl AsRef<[u8]> for InlineString {
}
}

#[cfg(feature = "as_mut")]
impl AsMut<str> for InlineString {
fn as_mut(&mut self) -> &mut str {
self.assert_sanity();
let length = self.len();
unsafe { str::from_utf8_unchecked_mut(&mut self.bytes[..length]) }
}
}

#[cfg(feature = "as_mut")]
impl AsMut<[u8]> for InlineString {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
self.assert_sanity();
let length = self.len();
&mut self.bytes[0..length]
}
Expand All @@ -113,15 +112,12 @@ impl<'a> From<&'a str> for InlineString {
ptr::copy_nonoverlapping(string.as_ptr(), ss.bytes.as_mut_ptr(), string_len);
}
ss.length = string_len as u8;

ss.assert_sanity();
ss
}
}

impl fmt::Display for InlineString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
self.assert_sanity();
write!(f, "{}", self as &str)
}
}
Expand All @@ -147,7 +143,6 @@ impl ops::Index<ops::Range<usize>> for InlineString {

#[inline]
fn index(&self, index: ops::Range<usize>) -> &str {
self.assert_sanity();
&self[..][index]
}
}
Expand All @@ -157,7 +152,6 @@ impl ops::Index<ops::RangeTo<usize>> for InlineString {

#[inline]
fn index(&self, index: ops::RangeTo<usize>) -> &str {
self.assert_sanity();
&self[..][index]
}
}
Expand All @@ -167,7 +161,6 @@ impl ops::Index<ops::RangeFrom<usize>> for InlineString {

#[inline]
fn index(&self, index: ops::RangeFrom<usize>) -> &str {
self.assert_sanity();
&self[..][index]
}
}
Expand All @@ -177,39 +170,34 @@ impl ops::Index<ops::RangeFull> for InlineString {

#[inline]
fn index(&self, _index: ops::RangeFull) -> &str {
self.assert_sanity();
unsafe { str::from_utf8_unchecked(&self.bytes[..self.len()]) }
}
}

impl ops::IndexMut<ops::Range<usize>> for InlineString {
#[inline]
fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str {
self.assert_sanity();
&mut self[..][index]
}
}

impl ops::IndexMut<ops::RangeTo<usize>> for InlineString {
#[inline]
fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
self.assert_sanity();
&mut self[..][index]
}
}

impl ops::IndexMut<ops::RangeFrom<usize>> for InlineString {
#[inline]
fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
self.assert_sanity();
&mut self[..][index]
}
}

impl ops::IndexMut<ops::RangeFull> for InlineString {
#[inline]
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
self.assert_sanity();
let length = self.len();
unsafe { str::from_utf8_unchecked_mut(&mut self.bytes[..length]) }
}
Expand All @@ -220,15 +208,13 @@ impl ops::Deref for InlineString {

#[inline]
fn deref(&self) -> &str {
self.assert_sanity();
unsafe { str::from_utf8_unchecked(&self.bytes[..self.len()]) }
}
}

impl ops::DerefMut for InlineString {
#[inline]
fn deref_mut(&mut self) -> &mut str {
self.assert_sanity();
let length = self.len();
unsafe { str::from_utf8_unchecked_mut(&mut self.bytes[..length]) }
}
Expand All @@ -244,8 +230,6 @@ impl Default for InlineString {
impl PartialEq<InlineString> for InlineString {
#[inline]
fn eq(&self, rhs: &InlineString) -> bool {
self.assert_sanity();
rhs.assert_sanity();
PartialEq::eq(&self[..], &rhs[..])
}
}
Expand Down Expand Up @@ -273,19 +257,6 @@ impl_eq! { InlineString, &'a str }
impl_eq! { borrow::Cow<'a, str>, InlineString }

impl InlineString {
#[cfg_attr(feature = "nightly", allow(inline_always))]
#[inline(always)]
fn assert_sanity(&self) {
debug_assert!(
self.length as usize <= INLINE_STRING_CAPACITY,
"inlinable_string: internal error: length greater than capacity"
);
debug_assert!(
str::from_utf8(&self.bytes[0..self.length as usize]).is_ok(),
"inlinable_string: internal error: contents are not valid UTF-8!"
);
}

/// Creates a new string buffer initialized with the empty string.
///
/// # Examples
Expand Down Expand Up @@ -317,7 +288,6 @@ impl InlineString {
/// ```
#[inline]
pub fn into_bytes(mut self) -> [u8; INLINE_STRING_CAPACITY] {
self.assert_sanity();
for i in self.len()..INLINE_STRING_CAPACITY {
self.bytes[i] = 0;
}
Expand All @@ -337,8 +307,6 @@ impl InlineString {
/// ```
#[inline]
pub fn push_str(&mut self, string: &str) -> Result<(), NotEnoughSpaceError> {
self.assert_sanity();

let string_len = string.len();
let new_length = self.len() + string_len;

Expand All @@ -354,8 +322,6 @@ impl InlineString {
);
}
self.length = new_length as u8;

self.assert_sanity();
Ok(())
}

Expand All @@ -374,8 +340,6 @@ impl InlineString {
/// ```
#[inline]
pub fn push(&mut self, ch: char) -> Result<(), NotEnoughSpaceError> {
self.assert_sanity();

let char_len = ch.len_utf8();
let new_length = self.len() + char_len;

Expand All @@ -388,8 +352,6 @@ impl InlineString {
ch.encode_utf8(&mut slice);
}
self.length = new_length as u8;

self.assert_sanity();
Ok(())
}

Expand All @@ -405,7 +367,6 @@ impl InlineString {
/// ```
#[inline]
pub fn as_bytes(&self) -> &[u8] {
self.assert_sanity();
&self.bytes[0..self.len()]
}

Expand All @@ -427,8 +388,6 @@ impl InlineString {
/// ```
#[inline]
pub fn truncate(&mut self, new_len: usize) {
self.assert_sanity();

assert!(
self.is_char_boundary(new_len),
"inlinable_string::InlineString::truncate: new_len is not a character
Expand All @@ -437,7 +396,6 @@ impl InlineString {
assert!(new_len <= self.len());

self.length = new_len as u8;
self.assert_sanity();
}

/// Removes the last character from the string buffer and returns it.
Expand All @@ -456,13 +414,10 @@ impl InlineString {
/// ```
#[inline]
pub fn pop(&mut self) -> Option<char> {
self.assert_sanity();

match self.char_indices().rev().next() {
None => None,
Some((idx, ch)) => {
self.length = idx as u8;
self.assert_sanity();
Some(ch)
}
}
Expand All @@ -488,7 +443,6 @@ impl InlineString {
/// ```
#[inline]
pub fn remove(&mut self, idx: usize) -> char {
self.assert_sanity();
assert!(idx < self.len());

let ch = self
Expand All @@ -513,8 +467,6 @@ impl InlineString {
);
}
self.length -= char_len as u8;

self.assert_sanity();
ch
}

Expand All @@ -528,6 +480,7 @@ impl InlineString {
return Err(NotEnoughSpaceError);
}

unsafe {
let ptr = self.bytes.as_mut_ptr().add(idx);

// Shift the latter part.
Expand All @@ -538,6 +491,7 @@ impl InlineString {
);
// Copy the bytes into the buffer.
ptr::copy(bytes.as_ptr(), self.bytes.as_mut_ptr().add(idx), amt);
}
// `amt` is less than `u8::MAX` becuase `INLINE_STRING_CAPACITY < u8::MAX` holds.
self.length += amt as u8;

Expand All @@ -562,7 +516,6 @@ impl InlineString {
/// this function will panic.
#[inline]
pub fn insert(&mut self, idx: usize, ch: char) -> Result<(), NotEnoughSpaceError> {
self.assert_sanity();
assert!(idx <= self.len());

let mut bits = [0; 4];
Expand All @@ -571,8 +524,6 @@ impl InlineString {
unsafe {
self.insert_bytes(idx, bits)?;
}

self.assert_sanity();
Ok(())
}

Expand All @@ -589,14 +540,12 @@ impl InlineString {
/// ```
#[inline]
pub fn insert_str(&mut self, idx: usize, string: &str) -> Result<(), NotEnoughSpaceError> {
self.assert_sanity();
assert!(idx <= self.len());

unsafe {
self.insert_bytes(idx, string.as_bytes())?;
}

self.assert_sanity();
Ok(())
}

Expand All @@ -622,7 +571,6 @@ impl InlineString {
/// ```
#[inline]
pub unsafe fn as_mut_slice(&mut self) -> &mut [u8] {
self.assert_sanity();
&mut self.bytes[0..self.length as usize]
}

Expand All @@ -638,7 +586,6 @@ impl InlineString {
/// ```
#[inline]
pub fn len(&self) -> usize {
self.assert_sanity();
self.length as usize
}

Expand All @@ -656,7 +603,6 @@ impl InlineString {
/// ```
#[inline]
pub fn is_empty(&self) -> bool {
self.assert_sanity();
self.length == 0
}

Expand All @@ -673,9 +619,7 @@ impl InlineString {
/// ```
#[inline]
pub fn clear(&mut self) {
self.assert_sanity();
self.length = 0;
self.assert_sanity();
}
}

Expand Down
Loading