Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support non-str values in a Rodeo #32

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
11 changes: 7 additions & 4 deletions src/arenas/atomic_bucket.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{LassoError, LassoErrorKind, LassoResult};
use crate::{Internable, LassoError, LassoErrorKind, LassoResult};
use alloc::alloc::{alloc, dealloc, Layout};
use core::{
mem::{align_of, size_of},
Expand Down Expand Up @@ -183,13 +183,16 @@ impl UniqueBucketRef {
///
/// # Safety
///
/// The returned `&'static str` (and all copies of it) must be dropped
/// The returned `&'static V` (and all copies of it) must be dropped
/// before the current bucket is, as this bucket contains the backing
/// memory for the string.
/// Additionally, the underlying [`AtomicBucket`] must have enough room
/// to store the entire slice and the given slice must be valid utf-8 data.
///
pub unsafe fn push_slice(&mut self, slice: &[u8]) -> &'static str {
pub unsafe fn push_slice<V>(&mut self, slice: &[u8]) -> &'static V
where
V: ?Sized + Internable,
{
let len = self.len();

if cfg!(debug_assertions) {
Expand All @@ -214,7 +217,7 @@ impl UniqueBucketRef {
// Create a string from that slice
// Safety: The source string was valid utf8, so the created buffer will be as well

unsafe { core::str::from_utf8_unchecked(target) }
unsafe { V::from_slice(target) }
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/arenas/bucket.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{LassoError, LassoErrorKind, LassoResult};
use crate::{Internable, LassoError, LassoErrorKind, LassoResult};
use alloc::alloc::{alloc, dealloc, Layout};
use core::{mem, num::NonZeroUsize, ptr::NonNull, slice};

Expand Down Expand Up @@ -59,9 +59,9 @@ impl Bucket {
///
/// The current bucket must have room for all bytes of the slice and
/// the caller promises to forget the reference before the arena is dropped.
/// Additionally, `slice` must be valid UTF-8 and should come from an `&str`
/// Additionally, `slice` must be valid for the interned type and should come from an `&V`
///
pub(crate) unsafe fn push_slice(&mut self, slice: &[u8]) -> &'static str {
pub(crate) unsafe fn push_slice<V: ?Sized + Internable>(&mut self, slice: &[u8]) -> &'static V {
debug_assert!(!self.is_full());
debug_assert!(slice.len() <= self.capacity.get() - self.index);

Expand All @@ -77,8 +77,8 @@ impl Bucket {
self.index += slice.len();

// Create a string from that slice
// Safety: The source string was valid utf8, so the created buffer will be as well
core::str::from_utf8_unchecked(target)
// Safety: The source buffer was created by a call to V::as_bytes
V::from_slice(target)
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/arenas/lockfree.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use crate::{
arenas::atomic_bucket::{AtomicBucket, AtomicBucketList},
Capacity, LassoError, LassoErrorKind, LassoResult, MemoryLimits,
};
use crate::{arenas::atomic_bucket::{AtomicBucket, AtomicBucketList}, Capacity, Internable, LassoError, LassoErrorKind, LassoResult, MemoryLimits};
use core::{
fmt::{self, Debug},
num::NonZeroUsize,
Expand Down Expand Up @@ -79,12 +76,15 @@ impl LockfreeArena {
///
/// The reference passed back must be dropped before the arena that created it is
///
pub unsafe fn store_str(&self, string: &str) -> LassoResult<&'static str> {
pub unsafe fn store_str<V>(&self, string: &V) -> LassoResult<&'static V>
where
V: ?Sized + Internable,
{
// If the string is empty, simply return an empty string.
// This ensures that only strings with lengths greater
// than zero will be allocated within the arena
if string.is_empty() {
return Ok("");
return Ok(V::empty());
}

let slice = string.as_bytes();
Expand Down Expand Up @@ -284,7 +284,7 @@ mod tests {
let mut len = 4096;
for _ in 0..10 {
let large_string = "a".repeat(len);
let arena_string = unsafe { arena.store_str(&large_string) };
let arena_string = unsafe { arena.store_str::<str>(&large_string) };
assert_eq!(arena_string, Ok(large_string.as_str()));

len *= 2;
Expand Down
13 changes: 7 additions & 6 deletions src/arenas/single_threaded.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::{
arenas::bucket::Bucket, Capacity, LassoError, LassoErrorKind, LassoResult, MemoryLimits,
};
use crate::{arenas::bucket::Bucket, Capacity, Internable, LassoError, LassoErrorKind, LassoResult, MemoryLimits};
use alloc::{format, vec, vec::Vec};
use core::{fmt, num::NonZeroUsize};

Expand Down Expand Up @@ -50,12 +48,15 @@ impl Arena {
///
/// The reference passed back must be dropped before the arena that created it is
///
pub unsafe fn store_str(&mut self, string: &str) -> LassoResult<&'static str> {
pub unsafe fn store_str<V>(&mut self, string: &V) -> LassoResult<&'static V>
where
V: ?Sized + Internable,
{
// If the string is empty, simply return an empty string.
// This ensures that only strings with lengths greater
// than zero will be allocated within the arena
if string.is_empty() {
return Ok("");
return Ok(V::empty());
}

let slice = string.as_bytes();
Expand Down Expand Up @@ -196,7 +197,7 @@ mod tests {
let mut len = 4096;
for _ in 0..10 {
let large_string = "a".repeat(len);
let arena_string = unsafe { arena.store_str(&large_string) };
let arena_string = unsafe { arena.store_str::<str>(&large_string) };
assert_eq!(arena_string, Ok(large_string.as_str()));

len *= 2;
Expand Down
49 changes: 27 additions & 22 deletions src/interface/boxed.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
use super::{Interner, IntoReader, IntoResolver, Reader, Resolver};
use crate::{Key, LassoResult};
use crate::{Internable, Key, LassoResult};
#[cfg(feature = "no-std")]
use alloc::boxed::Box;

impl<K, I> Interner<K> for Box<I>
impl<K, V, I> Interner<K, V> for Box<I>
where
K: Key,
I: Interner<K> + ?Sized + 'static,
V: ?Sized + Internable,
I: Interner<K, V> + ?Sized + 'static,
{
#[cfg_attr(feature = "inline-more", inline)]
fn get_or_intern(&mut self, val: &str) -> K {
fn get_or_intern(&mut self, val: &V) -> K {
(&mut **self).get_or_intern(val)
}

#[cfg_attr(feature = "inline-more", inline)]
fn try_get_or_intern(&mut self, val: &str) -> LassoResult<K> {
fn try_get_or_intern(&mut self, val: &V) -> LassoResult<K> {
(&mut **self).try_get_or_intern(val)
}

#[cfg_attr(feature = "inline-more", inline)]
fn get_or_intern_static(&mut self, val: &'static str) -> K {
fn get_or_intern_static(&mut self, val: &'static V) -> K {
(&mut **self).get_or_intern_static(val)
}

#[cfg_attr(feature = "inline-more", inline)]
fn try_get_or_intern_static(&mut self, val: &'static str) -> LassoResult<K> {
fn try_get_or_intern_static(&mut self, val: &'static V) -> LassoResult<K> {
self.try_get_or_intern(val)
}
}

impl<K, I> IntoReader<K> for Box<I>
impl<K, V, I> IntoReader<K, V> for Box<I>
where
K: Key,
I: IntoReader<K> + ?Sized + 'static,
V: ?Sized + Internable,
I: IntoReader<K, V> + ?Sized + 'static,
{
type Reader = <I as IntoReader<K>>::Reader;
type Reader = <I as IntoReader<K, V>>::Reader;

#[cfg_attr(feature = "inline-more", inline)]
#[must_use]
Expand All @@ -55,28 +57,30 @@ where
}
}

impl<K, I> Reader<K> for Box<I>
impl<K, V, I> Reader<K, V> for Box<I>
where
K: Key,
I: Reader<K> + ?Sized + 'static,
V: ?Sized + Internable,
I: Reader<K, V> + ?Sized + 'static,
{
#[cfg_attr(feature = "inline-more", inline)]
fn get(&self, val: &str) -> Option<K> {
fn get(&self, val: &V) -> Option<K> {
(&**self).get(val)
}

#[cfg_attr(feature = "inline-more", inline)]
fn contains(&self, val: &str) -> bool {
fn contains(&self, val: &V) -> bool {
(&**self).contains(val)
}
}

impl<K, I> IntoResolver<K> for Box<I>
impl<K, V, I> IntoResolver<K, V> for Box<I>
where
K: Key,
I: IntoResolver<K> + ?Sized + 'static,
V: ?Sized + Internable,
I: IntoResolver<K, V> + ?Sized + 'static,
{
type Resolver = <I as IntoResolver<K>>::Resolver;
type Resolver = <I as IntoResolver<K, V>>::Resolver;

#[cfg_attr(feature = "inline-more", inline)]
#[must_use]
Expand All @@ -97,23 +101,24 @@ where
}
}

impl<K, I> Resolver<K> for Box<I>
impl<K, V, I> Resolver<K, V> for Box<I>
where
K: Key,
I: Resolver<K> + ?Sized + 'static,
V: ?Sized + Internable,
I: Resolver<K, V> + ?Sized + 'static,
{
#[cfg_attr(feature = "inline-more", inline)]
fn resolve<'a>(&'a self, key: &K) -> &'a str {
fn resolve<'a>(&'a self, key: &K) -> &'a V {
(&**self).resolve(key)
}

#[cfg_attr(feature = "inline-more", inline)]
fn try_resolve<'a>(&'a self, key: &K) -> Option<&'a str> {
fn try_resolve<'a>(&'a self, key: &K) -> Option<&'a V> {
(&**self).try_resolve(key)
}

#[cfg_attr(feature = "inline-more", inline)]
unsafe fn resolve_unchecked<'a>(&'a self, key: &K) -> &'a str {
unsafe fn resolve_unchecked<'a>(&'a self, key: &K) -> &'a V {
unsafe { (&**self).resolve_unchecked(key) }
}

Expand Down
Loading