-
Notifications
You must be signed in to change notification settings - Fork 9
Implement AllocRef
on Box
, Rc
, and Arc
#54
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
Comments
AllocRef
on Box
, Rc
, and Arc
AllocRef
on Box
I feel that this is something that we can always add later if needed. I don't think there is a solid use case for this at the moment. |
AllocRef
on Box
AllocRef
on Box
, Rc
, and Arc
While the use cases for |
Implementing |
I am currently using My #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct CallbackAllocator {
ctx: Option<NonNull<c_void>>,
alloc: Option<unsafe extern "C" fn(Option<NonNull<c_void>>, usize) -> Option<NonNull<c_void>>>,
free: Option<unsafe extern "C" fn(Option<NonNull<c_void>>, NonNull<c_void>) -> ()>,
}
As per @TimDiekmann's comment here, I believe there is a use case for pub enum Expr<L, A>
where
L: LiteralEncoding,
A: Allocator,
{
/// `a`
SingleLiteral(SingleLiteral<L::Single>),
/// `\\` or `\+`
EscapedLiteral(Escaped<L::Single>),
/// `\<1-9>`
Backref(Backref),
/// `^` or `$`
Anchor(Anchor),
/// `[a-z]` or `\w` or `\s-`
CharSelector(SingleCharSelector<L::Single, A>),
/// `<expr><op>`
Postfix {
inner: Box<Expr<L, A>, A>,
op: PostfixOp,
},
/// `(<expr>)`
Group {
kind: GroupKind,
inner: Box<Expr<L, A>, A>,
},
/// `<expr>\|<expr>`
Alternation { cases: Vec<Box<Expr<L, A>, A>, A> },
/// `<expr><expr>`
Concatenation {
components: Vec<Box<Expr<L, A>, A>, A>,
},
} However, I believe this also means I need to clone my 24-byte To solve this problem right now, I'm going to try creating an intermediate Please feel free to let me know if I'm doing anything incorrect. Relying on a reference via |
Hmmm, it looks like I might have misjudged, and I think pub struct Arc<
T: ?Sized,
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
> {
ptr: NonNull<ArcInner<T>>,
phantom: PhantomData<ArcInner<T>>,
alloc: A,
} For my problem, I've simply made an unsafe allocator struct that keeps track of a raw pointer (see cosmicexplorer/emacs-regexp@22aabb9): #[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct SharedAllocator(pub *const CallbackAllocator);
static_assertions::assert_eq_size!(usize, SharedAllocator);
impl SharedAllocator {
pub fn from_alloc(
alloc: CallbackAllocator,
) -> (Self, NonNull<CallbackAllocator>, CallbackAllocator) {
let boxed_alloc: Box<CallbackAllocator, CallbackAllocator> = Box::new_in(alloc, alloc);
let (boxed_alloc, alloc) = Box::into_raw_with_allocator(boxed_alloc);
let boxed_alloc: NonNull<CallbackAllocator> = unsafe { NonNull::new_unchecked(boxed_alloc) };
(
Self(unsafe { mem::transmute(boxed_alloc) }),
boxed_alloc,
alloc,
)
}
} I'm sorry for the noise, but I think my problem is not suited for this issue. Thanks! |
The "most optimal" design would probably be to only have a single copy of the allocator stored at the AST root, and pass it down as necessary. Unfortunately, this is fundamentally unsafe and isn't super compatible with dtor cleanup, as now cleanup requires access to external state. In this case, if you have the ability to break ABI, I'd have the C client create the vtable structure and give you But, generally, when |
Maybe don't trust this as it's entirely untested but this scratched an itch: an pub struct AllocArc<A: Allocator> {
inner: NonNull<MaybeUninit<A>>,
}
unsafe impl<A: Allocator> Send for AllocArc<A> where for<'a> Arc<A, &'a A>: Send {}
unsafe impl<A: Allocator> Sync for AllocArc<A> where for<'a> Arc<A, &'a A>: Sync {}
impl<A: Allocator> Drop for AllocArc<A> {
fn drop(&mut self) {
// SAFETY: questionable
unsafe {
let alloc: &A = self;
let this = ManuallyDrop::new(Arc::from_raw_in(self.inner.as_ptr(), alloc));
if Arc::strong_count(&this) == 1 {
assert_eq!(Arc::weak_count(&this), 1);
// move alloc to stack to drop it *after* freeing the Arc
let ref alloc: A = self.inner.as_ref().assume_init_read();
Arc::decrement_strong_count_in(self.inner.as_ptr(), alloc);
} else {
Arc::decrement_strong_count_in(self.inner.as_ptr(), alloc);
}
}
}
}
impl<A: Allocator> Clone for AllocArc<A> {
fn clone(&self) -> Self {
// SAFETY: questionable
unsafe {
let alloc: &A = self;
Arc::increment_strong_count_in(self.inner.as_ptr(), alloc);
}
Self { ..*self }
}
}
impl<A: Allocator> AllocArc<A> {
pub fn new(alloc: A) -> Self {
let this = Arc::into_raw(Arc::new_in(MaybeUninit::uninit(), &alloc));
let mut inner = NonNull::new(this.cast_mut()).unwrap();
unsafe { inner.as_mut().write(alloc) };
Self { inner }
}
}
impl<A: Allocator> Deref for AllocArc<A> {
type Target = A;
fn deref(&self) -> &A {
unsafe {
self.inner.as_ref().assume_init_ref()
}
}
}
unsafe impl<A: Allocator> Allocator for AllocArc<A> {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
(**self).allocate(layout)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
(**self).deallocate(ptr, layout)
}
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
(**self).allocate_zeroed(layout)
}
unsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
(**self).grow(ptr, old_layout, new_layout)
}
unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
(**self).grow_zeroed(ptr, old_layout, new_layout)
}
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
(**self).shrink(ptr, old_layout, new_layout)
}
} |
This could probably work if you allow the |
Uh oh!
There was an error while loading. Please reload this page.
As requested in #53 and implemented in rust-lang/rust#71442,
AllocRef
is implemented on mutable references. Does anything stop us from implement it onBox
,Rc
, orArc
?The text was updated successfully, but these errors were encountered: