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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions libs/@local/hashql/core/src/heap/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ use bump_scope::{Bump, BumpBox, BumpScope};

use super::{BumpAllocator, bump::ResetAllocator};

pub struct Checkpoint(bump_scope::Checkpoint);
#[expect(
clippy::field_scoped_visibility_modifiers,
reason = "constructed and destructured by sibling allocator types"
)]
pub struct Checkpoint(pub(super) bump_scope::Checkpoint);

/// Internal arena allocator.
#[derive(Debug)]
Expand Down Expand Up @@ -155,7 +159,11 @@ unsafe impl alloc::Allocator for Allocator {
}
}

pub struct AllocatorScope<'scope>(BumpScope<'scope>);
#[expect(
clippy::field_scoped_visibility_modifiers,
reason = "constructed by sibling allocator types in scoped callbacks"
)]
pub struct AllocatorScope<'scope>(pub(super) BumpScope<'scope>);

impl BumpAllocator for AllocatorScope<'_> {
type Checkpoint = Checkpoint;
Expand Down
62 changes: 62 additions & 0 deletions libs/@local/hashql/core/src/heap/convert.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Allocator-aware conversion traits.

use alloc::rc::Rc;
use core::alloc::Allocator;

use super::CollectIn as _;
Expand Down Expand Up @@ -58,6 +59,26 @@ impl<A: Allocator> FromIn<String, A> for Box<str, A> {
}
}

impl<A: Allocator> FromIn<&str, A> for Rc<str, A> {
#[inline]
fn from_in(value: &str, allocator: A) -> Self {
// This is very much the same as Rc::from(), but without the specialization
let mut slice = Rc::new_uninit_slice_in(value.len(), allocator);

// SAFETY: We have just created the slice, so we're guaranteed to have exclusive access.
let slice_ref = unsafe { Rc::get_mut_unchecked(&mut slice) };
slice_ref.write_copy_of_slice(value.as_bytes());

// SAFETY: We have just written to the slice, so we're guaranteed to have initialized it.
let slice = unsafe { slice.assume_init() };

let (ptr, alloc) = Rc::into_raw_with_allocator(slice);

// SAFETY: str has the same layout as `[u8]`, so this is safe.
unsafe { Self::from_raw_in(ptr as *const str, alloc) }
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -109,4 +130,45 @@ mod tests {
let boxed: Box<str, &Heap> = String::from("foo").into_in(&heap);
assert_eq!(&*boxed, "foo");
}

#[test]
fn str_into_rc_str() {
let heap = Heap::new();

let rc: Rc<str, &Heap> = "hello".into_in(&heap);
assert_eq!(&*rc, "hello");

let rc: Rc<str, &Heap> = Rc::from_in("world", &heap);
assert_eq!(&*rc, "world");
}

#[expect(clippy::non_ascii_literal)]
#[test]
fn str_into_rc_str_unicode() {
let heap = Heap::new();

let rc: Rc<str, &Heap> = "ζ—₯本θͺž πŸŽ‰".into_in(&heap);
assert_eq!(&*rc, "ζ—₯本θͺž πŸŽ‰");
}

#[test]
fn str_into_rc_str_empty() {
let heap = Heap::new();

let rc: Rc<str, &Heap> = "".into_in(&heap);
assert_eq!(&*rc, "");
assert_eq!(rc.len(), 0);
}

#[test]
fn rc_str_clone_shares_data() {
let heap = Heap::new();

let rc1: Rc<str, &Heap> = "shared".into_in(&heap);
let rc2 = Rc::clone(&rc1);

assert_eq!(&*rc1, "shared");
assert_eq!(&*rc2, "shared");
assert!(Rc::ptr_eq(&rc1, &rc2));
}
}
2 changes: 2 additions & 0 deletions libs/@local/hashql/core/src/heap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ mod bump;
mod clone;
mod convert;
mod iter;
mod pool;
mod scratch;
mod transfer;

Expand All @@ -110,6 +111,7 @@ pub use self::{
clone::{CloneIn, TryCloneIn},
convert::{FromIn, IntoIn},
iter::{CollectIn, FromIteratorIn},
pool::{ScratchPool, ScratchPoolGuard},
scratch::Scratch,
transfer::TransferInto,
};
Expand Down
Loading
Loading