Created
October 20, 2023 16:18
-
-
Save zicklag/ac91f5a9af3832f10baa3613756a7092 to your computer and use it in GitHub Desktop.
Arc<AtomicCell<T>> Static Lock
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::ptr::NonNull; | |
use bones_framework::prelude::borrow::{AtomicBorrow, AtomicBorrowMut}; | |
use crate::prelude::*; | |
/// Extension trait over [`Arc<AtomicCell>`] to allow obtaining a `'static` borrow guard. | |
pub trait ArcAtomicCellExt<T> { | |
fn lock_static(self) -> ArcRef<T>; | |
fn lock_static_mut(self) -> ArcRefMut<T>; | |
} | |
impl<T> ArcAtomicCellExt<T> for Arc<AtomicCell<T>> { | |
fn lock_static(self) -> ArcRef<T> { | |
let reflock = self.borrow(); | |
let (ptr, borrow) = Ref::into_split(reflock); | |
// SOUND: This transmutes the lifetime of the atomic borrow to 'static, so that we can | |
// store it without the lifetime. This is sound because it's reference refers to the arc | |
// that we are storing along with it. As long as we drop the borrow before we drop the | |
// arc, we should be fine. | |
// TODO: get some review to make sure that's correct. | |
let borrow = | |
unsafe { std::mem::transmute::<AtomicBorrow<'_>, AtomicBorrow<'static>>(borrow) }; | |
ArcRef { | |
arc: self, | |
ptr, | |
borrow, | |
} | |
} | |
fn lock_static_mut(self) -> ArcRefMut<T> { | |
let reflock = self.borrow_mut(); | |
let (ptr, borrow) = RefMut::into_split(reflock); | |
// SOUND: This transmutes the lifetime of the atomic borrow to 'static, so that we can | |
// store it without the lifetime. This is sound because it's reference refers to the arc | |
// that we are storing along with it. As long as we drop the borrow before we drop the | |
// arc, we should be fine. | |
// TODO: get some review to make sure that's correct. | |
let borrow = | |
unsafe { std::mem::transmute::<AtomicBorrowMut<'_>, AtomicBorrowMut<'static>>(borrow) }; | |
ArcRefMut { | |
arc: self, | |
ptr, | |
borrow, | |
} | |
} | |
} | |
/// A borrow lock on an [`Arc<AtomicCell>`]. | |
pub struct ArcRef<T: ?Sized> { | |
arc: Arc<AtomicCell<T>>, | |
ptr: NonNull<T>, | |
borrow: AtomicBorrow<'static>, | |
} | |
unsafe impl<T: Sync + Send + ?Sized> Sync for ArcRef<T> {} | |
unsafe impl<T: Send + Send + ?Sized> Send for ArcRef<T> {} | |
impl<T: ?Sized> std::ops::Deref for ArcRef<T> { | |
type Target = T; | |
fn deref(&self) -> &Self::Target { | |
// SOUND: We hold an atomic borrow | |
unsafe { self.ptr.as_ref() } | |
} | |
} | |
/// A mutable borrow lock on an [`Arc<AtomicCell>`]. | |
pub struct ArcRefMut<T: ?Sized> { | |
arc: Arc<AtomicCell<T>>, | |
ptr: NonNull<T>, | |
borrow: AtomicBorrowMut<'static>, | |
} | |
unsafe impl<T: Sync + Send + ?Sized> Sync for ArcRefMut<T> {} | |
unsafe impl<T: Send + Send + ?Sized> Send for ArcRefMut<T> {} | |
impl<T: ?Sized> std::ops::Deref for ArcRefMut<T> { | |
type Target = T; | |
fn deref(&self) -> &Self::Target { | |
// SOUND: We hold an atomic borrow | |
unsafe { self.ptr.as_ref() } | |
} | |
} | |
impl<T: ?Sized> std::ops::DerefMut for ArcRefMut<T> { | |
fn deref_mut(&mut self) -> &mut Self::Target { | |
// SOUND: we hold an atomic borrow | |
unsafe { self.ptr.as_mut() } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment