Pstd reference-counted slice
⚓ Rust 📅 2026-04-03 👤 surdeus 👁️ 5I spent the last week or so writing this, made all kinds of blunders, I think I now have it correct.
The objective is a reference-counted slice (inc. string), which can be allocated not in Global, available on stable.
Here is the code. Are there still major problems with it? Any other comments? Thanks!
/// Reference-counted slice.
pub struct RcSlice<T, A: Allocator = Global> {
nn: NonNull<RcSliceInner<A>>,
pd: PhantomData<T>,
}
struct RcSliceInner<A: Allocator> {
cc: usize, // Clone count
slen: usize, // Length of slice
a: A,
}
impl<T, A: Allocator> RcSlice<T, A> {
/// Create a RcSlice from s in specified allocator.
pub fn new_in(s: &[T], a: A) -> Self
where
T: Clone,
{
unsafe {
let slen = s.len();
let (layout, off) = Self::layout(slen);
let nn = a.allocate(layout).unwrap();
let p = nn.as_ptr().cast::<RcSliceInner<A>>();
let inner = RcSliceInner { cc: 0, slen, a };
ptr::write(p, inner);
// Initialise the slice of allocated memory.
let to = (p as *mut u8).add(off) as *mut MaybeUninit<T>;
let to = std::slice::from_raw_parts_mut(to, slen);
to.write_clone_of_slice(s);
Self {
nn: NonNull::new_unchecked(p),
pd: PhantomData,
}
}
}
/// Get the layout for the inner fields followed by a slice of size slen, and the offset of the slice.
fn layout(slen: usize) -> (Layout, usize) {
unsafe {
Layout::new::<RcSliceInner<A>>()
.extend(Layout::array::<T>(slen).unwrap_unchecked())
.unwrap_unchecked()
}
}
/// Get a NonNull pointer to the slice.
fn slice(&self) -> NonNull<[T]> {
unsafe {
let p = self.nn.as_ptr();
let slen = (*p).slen;
let (_layout, off) = Self::layout(slen);
let p = (p as *mut u8).add(off) as *mut T;
let nn = NonNull::new_unchecked(p);
NonNull::slice_from_raw_parts(nn, slen)
}
}
}
impl<T, A: Allocator> Clone for RcSlice<T, A> {
fn clone(&self) -> Self {
unsafe {
let p = self.nn.as_ptr();
(*p).cc += 1;
}
Self {
nn: self.nn,
pd: PhantomData,
}
}
}
impl<T, A: Allocator> Drop for RcSlice<T, A> {
fn drop(&mut self) {
unsafe {
let p = self.nn.as_ptr();
if (*p).cc == 0 {
self.slice().drop_in_place();
let slen = (*p).slen;
let a = ptr::read(&(*p).a);
let (layout, _off) = Self::layout(slen);
let nn = NonNull::new_unchecked(p as *mut u8);
a.deallocate(nn, layout)
} else {
(*p).cc -= 1;
}
}
}
}
impl<T, A: Allocator> Deref for RcSlice<T, A> {
type Target = [T];
fn deref(&self) -> &[T] {
unsafe { self.slice().as_ref() }
}
}
2 posts - 1 participant
🏷️ Rust_feed