Skip to content
Merged
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
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ impl LeanString {
/// assert_eq!(fancy_f.chars().count(), 3);
/// ```
#[inline]
pub fn len(&self) -> usize {
pub const fn len(&self) -> usize {
self.0.len()
}

Expand All @@ -281,7 +281,7 @@ impl LeanString {
/// assert!(!s.is_empty());
/// ```
#[inline]
pub fn is_empty(&self) -> bool {
pub const fn is_empty(&self) -> bool {
self.0.is_empty()
}

Expand Down Expand Up @@ -323,7 +323,7 @@ impl LeanString {
/// assert_eq!(s.as_str(), "foo");
/// ```
#[inline]
pub fn as_str(&self) -> &str {
pub const fn as_str(&self) -> &str {
self.0.as_str()
}

Expand All @@ -337,7 +337,7 @@ impl LeanString {
/// assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes());
/// ```
#[inline]
pub fn as_bytes(&self) -> &[u8] {
pub const fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}

Expand Down
33 changes: 19 additions & 14 deletions src/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,14 @@ impl Repr {

#[cfg(target_pointer_width = "64")]
#[inline]
pub(crate) fn len(&self) -> usize {
pub(crate) const fn len(&self) -> usize {
let last_byte = self.last_byte();

let inline_len = (last_byte as usize)
.wrapping_sub(LastByte::MASK_1100_0000 as usize)
.min(MAX_INLINE_SIZE);
let inline_len = {
let this = (last_byte as usize).wrapping_sub(LastByte::MASK_1100_0000 as usize);
// inline Ord::min because the trait impl is not const
if MAX_INLINE_SIZE < this { MAX_INLINE_SIZE } else { this }
};

let mut len = {
// SAFETY: `Repr` has the same size as `[usize; 2]` and is aligned as `usize`
Expand All @@ -130,7 +132,7 @@ impl Repr {

#[cfg(target_pointer_width = "32")]
#[inline]
pub(crate) fn len(&self) -> usize {
pub(crate) const fn len(&self) -> usize {
if self.is_heap_buffer() {
// SAFETY: We just checked the discriminant to make sure we're heap allocated
unsafe { self.as_heap_buffer() }.len()
Expand All @@ -139,14 +141,17 @@ impl Repr {
unsafe { self.as_static_buffer() }.len()
} else {
// Remaining is InlineBuffer
(self.last_byte() as usize)
.wrapping_sub(LastByte::MASK_1100_0000 as usize)
.min(MAX_INLINE_SIZE)
{
let this =
(self.last_byte() as usize).wrapping_sub(LastByte::MASK_1100_0000 as usize);
// inline Ord::min because the trait impl is not const
if MAX_INLINE_SIZE < this { MAX_INLINE_SIZE } else { this }
}
}
}

#[inline]
pub(crate) fn is_empty(&self) -> bool {
pub(crate) const fn is_empty(&self) -> bool {
self.len() == 0
}

Expand All @@ -164,13 +169,13 @@ impl Repr {
}

#[inline]
pub(crate) fn as_str(&self) -> &str {
pub(crate) const fn as_str(&self) -> &str {
// SAFETY: A `Repr` contains valid UTF-8
unsafe { str::from_utf8_unchecked(self.as_bytes()) }
}

#[inline]
pub(crate) fn as_bytes(&self) -> &[u8] {
pub(crate) const fn as_bytes(&self) -> &[u8] {
let len = self.len();

let ptr = if self.last_byte() >= LastByte::HeapMarker as u8 {
Expand Down Expand Up @@ -571,7 +576,7 @@ impl Repr {
}

#[inline(always)]
pub(crate) fn is_heap_buffer(&self) -> bool {
pub(crate) const fn is_heap_buffer(&self) -> bool {
self.last_byte() == LastByte::HeapMarker as u8
}

Expand Down Expand Up @@ -700,7 +705,7 @@ impl Repr {
}

#[inline(always)]
unsafe fn as_heap_buffer(&self) -> &HeapBuffer {
const unsafe fn as_heap_buffer(&self) -> &HeapBuffer {
// SAFETY: A `Repr` is transmuted from `HeapBuffer`
unsafe { &*(self as *const _ as *const HeapBuffer) }
}
Expand All @@ -712,7 +717,7 @@ impl Repr {
}

#[inline(always)]
unsafe fn as_static_buffer(&self) -> &StaticBuffer {
const unsafe fn as_static_buffer(&self) -> &StaticBuffer {
// SAFETY: A `Repr` is transmuted from `StaticBuffer`
unsafe { &*(self as *const _ as *const StaticBuffer) }
}
Expand Down
6 changes: 3 additions & 3 deletions src/repr/heap_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ impl HeapBuffer {
self.ptr
}

pub(super) fn len(&self) -> usize {
pub(super) const fn len(&self) -> usize {
#[cold]
fn len_on_heap(ptr: NonNull<u8>) -> usize {
const fn len_on_heap(ptr: NonNull<u8>) -> usize {
// SAFETY: We just checked that `len` is stored on the heap.
unsafe {
let len_ptr = ptr.sub(HeapBuffer::header_offset()).sub(size_of::<usize>());
Expand Down Expand Up @@ -449,7 +449,7 @@ mod internal {
return self.0 == Self::ON_THE_HEAP;
}

pub(super) fn as_usize(self) -> usize {
pub(super) const fn as_usize(self) -> usize {
let size = self.0 ^ Self::TAG;
let bytes = size.to_ne_bytes();
usize::from_le_bytes(bytes)
Expand Down
2 changes: 1 addition & 1 deletion src/repr/static_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl StaticBuffer {
Ok(Self { ptr, len })
}

pub(super) fn len(&self) -> usize {
pub(super) const fn len(&self) -> usize {
let len = self.len ^ Self::TAG;
let bytes = len.to_ne_bytes();
usize::from_le_bytes(bytes)
Expand Down
19 changes: 19 additions & 0 deletions tests/const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use lean_string::LeanString;

static S: LeanString = LeanString::from_static_str("hello world");

const STR: &str = S.as_str();

#[test]
fn use_const() {
assert_eq!(STR, "hello world");
}

#[test]
fn const_len() {
const {
let s = LeanString::from_static_str("hello");
assert!(s.len() == 5);
s
};
}
Loading