Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • markeffl/xrc
1 result
Show changes
Commits on Source (2)
......@@ -5,7 +5,7 @@ use core::marker::PhantomPinned;
use core::mem::{self, MaybeUninit};
use core::ops::{Deref, DerefMut};
use core::pin::Pin;
use core::ptr::NonNull;
use core::ptr::{self, NonNull};
pub trait Reclaim: Sized {
fn reclaim(self, unclaimed: Unclaimed<Self>);
......@@ -80,7 +80,15 @@ impl<T> Root<T> {
panic!("unclaimed called multiple times");
}
self.state.set(STATE_UNCLAIMED);
let ptr = unsafe { NonNull::from(self.get_unchecked_mut()) };
let ptr_erased = ptr.cast::<Root<Erased>>();
unsafe {
let target_root = ptr::addr_of_mut!((*(*ptr.as_ptr()).target.as_mut_ptr()).root);
target_root.write(Cell::new(Some(ptr_erased)));
}
Unclaimed { ptr }
}
}
......@@ -126,20 +134,19 @@ pub struct Unclaimed<T> {
impl<T> Unclaimed<T> {
pub fn claim(self, value: T) -> Xrc<T> {
let root_erased = self.ptr.cast::<Root<Erased>>();
let target = unsafe {
(*self.ptr.as_ptr()).target.write(ProjectTarget {
root: Cell::new(Some(root_erased)),
value,
})
};
unsafe {
debug_assert_eq!((*self.ptr.as_ptr()).state.get(), STATE_UNCLAIMED);
(*self.ptr.as_ptr()).state.set(STATE_SHARED_INIT);
}
// shared reborrow
let ptr = NonNull::from(&*target);
unsafe {
let target_value = ptr::addr_of_mut!((*(*self.ptr.as_ptr()).target.as_mut_ptr()).value);
target_value.write(value);
}
// shared read-only reborrow
let target = unsafe { (*self.ptr.as_ptr()).target.assume_init_ref() };
let ptr = NonNull::from(target);
Xrc { ptr }
}
}
......@@ -157,6 +164,7 @@ impl<T: ?Sized> Drop for Xrc<T> {
let state_ref = unsafe { &(*root.as_ptr()).state };
let state = state_ref.get();
debug_assert!(state <= STATE_SHARED_MAX);
if state != STATE_SHARED_INIT {
state_ref.set(state - 1);
return;
......@@ -178,6 +186,7 @@ impl<T> Clone for Xrc<T> {
let state_ref = unsafe { &(*root.as_ptr()).state };
let state = state_ref.get();
debug_assert!(state <= STATE_SHARED_MAX);
if state == STATE_SHARED_MAX {
panic!("ref count overflow");
}
......@@ -237,6 +246,7 @@ mod tests {
use std::pin::pin;
use std::ptr;
use std::rc::Rc;
use std::panic::{self, AssertUnwindSafe};
fn iter_pinned_mut<T>(slice: Pin<&mut [T]>) -> impl Iterator<Item = Pin<&mut T>> {
unsafe {
......@@ -254,6 +264,21 @@ mod tests {
assert_eq!(xrc.0, 42);
}
#[test]
fn unpin_hack() {
let mut root = pin!(Root::new());
let xrc = root.as_mut().unclaimed().claim(NoReclaim(42));
let res = panic::catch_unwind(AssertUnwindSafe(|| {
// This must not create an unique borrow ...
let _ = root.unclaimed();
}));
assert!(res.is_err());
// ... to not invalidate this shared read-only borrow.
assert_eq!(xrc.0, 42);
}
#[test]
#[ignore = "will abort"]
fn abort() {
......