use std::marker::PhantomData;
use std::ptr::NonNull;
+//---------- public types ----------
+
+/// Pointer to manually-memory-managed `T`
+///
+/// Ensuring that `Ptr`s are freed at the right time is up to the caller.
+/// But aliasing, drop, etc., is (largely) handled by the library.
+pub struct Ptr<T> {
+ /// # SAFETY
+ ///
+ /// Invariants (only while valid, but we can rely on them
+ /// since our caller is not allowed to call any of our methods
+ /// on an invalid Ptr):
+ ///
+ /// * Always points to a valid T on the heap: was `Box<T>`.
+ /// * All references given out are compatible with the borrow
+ /// of the `NoAliasSingleton` (possibly via `IsRefToken`
+ /// or `IsMutToken`.
+ //
+ // XXXX check variance
+ ptr: NonNull<T>,
+}
+
/// Singleton, used for compile-time alias checking
#[derive(Debug)] // Not Clone or Copy
#[non_exhaustive] // unsafe to construct
pub struct NoAliasSingleton {
}
+/// `&NoAliasSingleton`, but a ZST
+///
+/// We don't actually ever need to look at the data for the singleton.
+/// So the actual pointer is redundant, and, here, absent.
+#[derive(Debug, Clone, Copy)]
+pub struct RefToken<'a>(
+ PhantomData<&'a NoAliasSingleton>,
+);
+
+/// `&mut NoAliasSingleton`, but a ZST
+///
+/// See [`RefToken`]
+#[derive(Debug)]
+pub struct MutToken<'a>(
+ PhantomData<&'a mut NoAliasSingleton>,
+);
+
+impl<'a> MutToken<'a> {
+ ///
+ ///
+ /// SAFETY
+ ///
+ pub unsafe fn new_unchecked() -> Self { MutToken(PhantomData) }
+}
+
+//---------- IsRefToken and IsMutToken traits ----------
+
/// Token-like: `&self` implies `&NoAliasSingleton`
///
/// Implemented for `NoAliasSingleton` and the ZST reference tokens,
}
}
-/// Token-like `&mut self` implies `&mut NoAliasSingleton`
+/// Token-like: `&mut self` implies `&mut NoAliasSingleton`
///
/// Implemented for `NoAliasSingleton` and `MutToken`,
/// and `&mut`-references to them.
pub unsafe trait IsMutToken<'a>: IsRefToken<'a> + Sized + Sealed {
/// Obtain a new ZST token from something that might be a real object.
#[inline]
- fn mut_token<'r>(self) -> MutToken<'r>
- where 'a: 'r,
- {
+ fn mut_token<'r>(self) -> MutToken<'r> where 'a: 'r {
MutToken(PhantomData)
}
- fn multi_static<'r>(self) -> MultiStatic<'r, ()>
- where 'a: 'r,
- {
+ fn multi_static<'r>(self) -> MultiStatic<'r, ()> where 'a: 'r {
MultiStatic {
tok: self.mut_token(),
l: (),
}
}
- fn multi_runtime<'r>(self) -> MultiRuntime<'r>
- where 'a: 'r,
- {
+ fn multi_runtime<'r>(self) -> MultiRuntime<'r> where 'a: 'r {
MultiRuntime {
_tok: self.mut_token(),
ref_given: HashSet::new(),
impl<T: Sealed> Sealed for & T {}
impl<T: Sealed> Sealed for &mut T {}
-/// `&NoAliasSingleton`, but a ZST
-///
-/// We don't actually ever need to look at the data for the singleton.
-/// So the actual pointer is redundant, and, here, absent.
-#[derive(Debug, Clone, Copy)]
-pub struct RefToken<'a>(
- PhantomData<&'a NoAliasSingleton>,
-);
-
-/// `&mut NoAliasSingleton`, but a ZST
-///
-/// See [`RefToken`]
-#[derive(Debug)]
-pub struct MutToken<'a>(
- PhantomData<&'a mut NoAliasSingleton>,
-);
-
-impl<'a> MutToken<'a> {
- ///
- ///
- /// SAFETY
- ///
- pub unsafe fn new_unchecked() -> Self { MutToken(PhantomData) }
-}
-
-pub struct Ptr<T> {
- /// # SAFETY
- ///
- /// Invariants (only while valid, but we can rely on them
- /// since our caller is not allowed to call any of our methods
- /// on an invalid Ptr):
- ///
- /// * Always points to a valid T on the heap: was `Box<T>`.
- /// * All references given out are compatible with the borrow
- /// of the `NoAliasSingleton` (possibly via `IsRefToken`
- /// or `IsMutToken`.
- //
- // XXXX check variance
- ptr: NonNull<T>,
-}
+//---------- principal API for borrowing etc. ----------
-impl<T> Clone for Ptr<T> {
- fn clone(&self) -> Self { *self }
-}
+impl<T> Clone for Ptr<T> { fn clone(&self) -> Self { *self } }
impl<T> Copy for Ptr<T> {}
-impl<T> Debug for Ptr<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_tuple("Ptr").field(&self.ptr).finish()
- }
-}
-
impl<T> Ptr<T> {
pub fn new_heap(t: T) -> Self {
let b = Box::new(t);
Ptr { ptr }
}
-/*
- /// SAFETY
- ///
- /// All copies of the returned `Ptr` become invalid
- /// when the borrow of `t` ends.
- /// No-one must use them after that.
- ///
- /// You must not call `deallocate` on the return value.
-TODO lifetime is hard
- pub unsafe fn new_borrowed<'t>(t: Pin<&'t mut T>) -> Self { todo!() }
-*/
-
#[inline]
pub fn borrow<'a>(self, tok: impl IsRefToken<'a>) -> &'a T {
let _ = tok;
};
*t
}
-}
-pub trait OptionPtrExt<T> {
- fn as_ptr(self) -> Option<*mut T>;
-}
-impl<T> OptionPtrExt<T> for Option<Ptr<T>> {
- fn as_ptr(self) -> Option<*mut T> {
- self.map(|p| p.ptr.as_ptr())
- }
+/*
+ /// SAFETY
+ ///
+ /// All copies of the returned `Ptr` become invalid
+ /// when the borrow of `t` ends.
+ /// No-one must use them after that.
+ ///
+ /// You must not call `deallocate` on the return value.
+TODO lifetime is hard
+ pub unsafe fn new_borrowed<'t>(t: Pin<&'t mut T>) -> Self { todo!() }
+*/
}
impl NoAliasSingleton {
pub unsafe fn init() -> Self { NoAliasSingleton {} }
}
+//---------- helpful impls ----------
+
+pub trait OptionPtrExt<T> {
+ fn as_ptr(self) -> Option<*mut T>;
+}
+impl<T> OptionPtrExt<T> for Option<Ptr<T>> {
+ fn as_ptr(self) -> Option<*mut T> {
+ self.map(|p| p.ptr.as_ptr())
+ }
+}
+
+impl<T> Debug for Ptr<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_tuple("Ptr").field(&self.ptr).finish()
+ }
+}
+
+//---------- multi-borrowing, runtime-checked ----------
+
#[derive(Debug)]
pub struct BorrowConflict;
+type BorrowResult<T> = Result<T, BorrowConflict>;
+
+pub struct MultiRuntime<'a> {
+ _tok: MutToken<'a>,
+ ref_given: HashSet<NonNull<()>>,
+ mut_given: HashSet<NonNull<()>>,
+}
+
+impl<'a> MultiRuntime<'a> {
+ #[inline]
+ pub fn borrow<'r, T>(&mut self, p: Ptr<T>) -> BorrowResult<&'r T>
+ where 'a: 'r
+ {
+ self.borrow_inner_check(p.ptr.cast())?;
+ Ok(unsafe { p.ptr.as_ref() })
+ }
+
+ fn borrow_inner_check(&mut self, p: NonNull<()>) -> BorrowResult<()> {
+ if self.mut_given.contains(&p) {
+ return Err(BorrowConflict)
+ }
+ self.ref_given.insert(p);
+ Ok(())
+ }
+
+ #[inline]
+ pub fn borrow_mut<'r, T>(&mut self, mut p: Ptr<T>)
+ -> BorrowResult<&'r mut T>
+ where 'a: 'r
+ {
+ self.borrow_mut_inner_check(p.ptr.cast())?;
+ Ok(unsafe { p.ptr.as_mut() })
+ }
+
+ fn borrow_mut_inner_check(&mut self, p: NonNull<()>) -> BorrowResult<()> {
+ if self.ref_given.contains(&p) {
+ return Err(BorrowConflict)
+ }
+ if !self.mut_given.insert(p) {
+ return Err(BorrowConflict)
+ }
+ Ok(())
+ }
+}
+
+//---------- multi-borrowing ----------
+
pub struct MultiStatic<'a, L> {
tok: MutToken<'a>,
l: L,
}
-fn forbid_alias(this: *const (), new: NonNull<()>)
- -> Result<(), BorrowConflict>
-{
+fn forbid_alias(this: *const (), new: NonNull<()>) -> BorrowResult<()> {
if this == new.as_ptr() { return Err(BorrowConflict) }
Ok(())
}
pub unsafe trait MultiStaticList {
- fn alias_check_ref(&self, p: NonNull<()>) -> Result<(), BorrowConflict>;
- fn alias_check_mut(&self, p: NonNull<()>) -> Result<(), BorrowConflict>;
+ fn alias_check_ref(&self, p: NonNull<()>) -> BorrowResult<()>;
+ fn alias_check_mut(&self, p: NonNull<()>) -> BorrowResult<()>;
}
unsafe impl MultiStaticList for () {
- fn alias_check_ref(&self, _: NonNull<()>) -> Result<(), BorrowConflict> {
+ fn alias_check_ref(&self, _: NonNull<()>) -> BorrowResult<()> {
Ok(())
}
- fn alias_check_mut(&self, _: NonNull<()>) -> Result<(), BorrowConflict> {
+ fn alias_check_mut(&self, _: NonNull<()>) -> BorrowResult<()> {
Ok(())
}
}
unsafe impl<L: MultiStaticList> MultiStaticList for (L, *const ()) {
- fn alias_check_ref(&self, p: NonNull<()>) -> Result<(), BorrowConflict> {
+ fn alias_check_ref(&self, p: NonNull<()>) -> BorrowResult<()> {
self.0.alias_check_ref(p)
}
- fn alias_check_mut(&self, p: NonNull<()>) -> Result<(), BorrowConflict> {
+ fn alias_check_mut(&self, p: NonNull<()>) -> BorrowResult<()> {
forbid_alias(self.1, p)?;
self.0.alias_check_mut(p)
}
}
unsafe impl<L: MultiStaticList> MultiStaticList for (L, NonNull<()>) {
- fn alias_check_ref(&self, p: NonNull<()>) -> Result<(), BorrowConflict> {
+ fn alias_check_ref(&self, p: NonNull<()>) -> BorrowResult<()> {
forbid_alias(self.1.as_ptr(), p)?;
self.0.alias_check_ref(p)
}
- fn alias_check_mut(&self, p: NonNull<()>) -> Result<(), BorrowConflict> {
+ fn alias_check_mut(&self, p: NonNull<()>) -> BorrowResult<()> {
forbid_alias(self.1.as_ptr(), p)?;
self.0.alias_check_mut(p)
}
}
}
}
-
-pub struct MultiRuntime<'a> {
- _tok: MutToken<'a>,
- ref_given: HashSet<NonNull<()>>,
- mut_given: HashSet<NonNull<()>>,
-}
-
-impl<'a> MultiRuntime<'a> {
- #[inline]
- pub fn borrow<'r, T>(&mut self, p: Ptr<T>)
- -> Result<&'r T, BorrowConflict>
- where 'a: 'r
- {
- self.borrow_inner_check(p.ptr.cast())?;
- Ok(unsafe { p.ptr.as_ref() })
- }
-
- fn borrow_inner_check(&mut self, p: NonNull<()>)
- -> Result<(), BorrowConflict>
- {
- if self.mut_given.contains(&p) {
- return Err(BorrowConflict)
- }
- self.ref_given.insert(p);
- Ok(())
- }
-
- #[inline]
- pub fn borrow_mut<'r, T>(&mut self, mut p: Ptr<T>)
- -> Result<&'r mut T, BorrowConflict>
- where 'a: 'r
- {
- self.borrow_mut_inner_check(p.ptr.cast())?;
- Ok(unsafe { p.ptr.as_mut() })
- }
-
- fn borrow_mut_inner_check(&mut self, p: NonNull<()>)
- -> Result<(), BorrowConflict>
-{
- if self.ref_given.contains(&p) {
- return Err(BorrowConflict)
- }
- if !self.mut_given.insert(p) {
- return Err(BorrowConflict)
- }
- Ok(())
- }
-}