Skip to content

Commit

Permalink
Future-proof as_ptr impls
Browse files Browse the repository at this point in the history
Introduce a bit of future proof code to properly "close the brackets"
around some operations (todays there are no-ops).

Provide a bit of documentation for it, explaining the gymnastics there.
  • Loading branch information
vorner committed Dec 25, 2022
1 parent eaeae27 commit fd04e20
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
* Avoid violating stacked borrows (AFAIK these are still experimental and not
normative, but better safe than sorry). (#80).
* The `AccessConvert` wrapper is needed less often in practice (#77).

# 1.5.1
Expand Down
23 changes: 22 additions & 1 deletion src/ref_cnt.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::mem;
use std::ptr;
use std::rc::Rc;
use std::sync::Arc;
Expand Down Expand Up @@ -92,9 +93,29 @@ unsafe impl<T> RefCnt for Arc<T> {
Arc::into_raw(me) as *mut T
}
fn as_ptr(me: &Arc<T>) -> *mut T {
// Slightly convoluted way to do this, but this avoids stacked borrows violations. The same
// intention as
//
// me as &T as *const T as *mut T
//
// We first create a "shallow copy" of me - one that doesn't really own its ref count
// (that's OK, me _does_ own it, so it can't be destroyed in the meantime).
// Then we can use into_raw (which preserves not having the ref count).
//
// We need to "revert" the changes we did. In current std implementation, the combination
// of from_raw and forget is no-op. But formally, into_raw shall be paired with from_raw
// and that read shall be paired with forget to properly "close the brackets". In future
// versions of STD, these may become something else that's not really no-op (unlikely, but
// possible), so we future-proof it a bit.

// SAFETY: &T cast to *const T will always be aligned, initialised and valid for reads
let ptr = Arc::into_raw(unsafe { std::ptr::read(me) });
ptr as *mut T
let ptr = ptr as *mut T;

// SAFETY: We got the pointer from into_raw just above
mem::forget(unsafe { Arc::from_raw(ptr) });

ptr
}
unsafe fn from_ptr(ptr: *const T) -> Arc<T> {
Arc::from_raw(ptr)
Expand Down

0 comments on commit fd04e20

Please sign in to comment.