1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
#![doc = include_str!("../README.md")]
#![cfg_attr(feature = "nightly", feature(generic_associated_types))]
use std::cell::Cell;
use std::marker::PhantomData;
use std::ops::Deref;
use std::ptr::null_mut;
use std::sync::Arc;
use parking_lot::{Mutex, MutexGuard};
type Inner = Arc<Mutex<*mut u8>>;
/// A `'static` handle through which a value with a covariant lifetime parameter can
/// temporarily be accessed.
///
/// `Lifelink<C>` implements [`Send`] and [`Sync`] when the wrapped values produced by
/// `C` are [`Send`].
///
/// See [`Lifelink::new`] for an example.
pub struct Lifelink<C: Ctor> {
inner: Inner,
_marker: PhantomData<C::Ty<'static>>,
}
// SAFETY: Inner is a Mutex, and `get` requires &mut self, so it's impossible to obtain
// multiple references to a Send-only type by Sending the Lifelink itself.
unsafe impl<C: SendCtor> Send for Lifelink<C> {}
unsafe impl<C: SendCtor> Sync for Lifelink<C> {}
/// Safe helper macro for creating a [`Lifelink`] value wrapping `thing`. The lifetime
/// of this [`Lifelink`] value will be managed by the Rust compiler, and the `thing`
/// passed in cannot be retrieved.
///
/// If you need a way to later retrieve ownership of the `thing` value passed in, see
/// the unsafe [`Lifelink::new`] constructor which this macro uses internally.
///
/// # Example
///
/// ```rust
/// use std::thread::spawn;
/// use std::sync::atomic::{AtomicUsize, Ordering};
/// use lifelink::{lifelink, Lifelink, RefCtor};
///
/// let answer = AtomicUsize::new(0);
///
/// lifelink!(lifelink: RefCtor<AtomicUsize> = &answer);
///
/// {
/// let guard = lifelink.get().unwrap();
/// assert_eq!(0, guard.load(Ordering::Relaxed));
/// guard.store(42, Ordering::Release);
/// }
///
/// assert_eq!(42, answer.load(Ordering::Acquire));
/// ```
#[macro_export]
macro_rules! lifelink {
($lifelink:ident : $ty:ty = $thing:expr) => {
let (mut $lifelink, _deathtouch) = unsafe { $crate::Lifelink::<$ty>::new($thing) };
};
}
impl<C: Ctor> Lifelink<C> {
/// Create a pair of [`Lifelink`] and [`Deathtouch`] values wrapping `thing`, which
/// will be kept alive and accessible through `Lifelink` until the [`Deathtouch`]
/// is dropped.
///
/// The safety of this function depends on the resulting [`Deathtouch`] value being
/// unwrapped or dropped. For a safe way to construct [`Lifelink`] in exchange for
/// the ability to access [`Deathtouch`], see the [`lifelink!`] macro.
///
/// # Safety
///
/// `C::Ty` values must be covariant over the lifetime parameter, and the resulting
/// [`Deathtouch`] value must be unwrapped or dropped (i.e. not forgotten). For more
/// details on the latter requirement, see https://github.com/chitoyuu/lifelink/issues/2.
///
/// # Example
///
/// ```rust
/// use std::thread::spawn;
/// use std::sync::atomic::{AtomicUsize, Ordering};
/// use lifelink::{Lifelink, RefCtor};
///
/// let answer = AtomicUsize::new(0);
///
/// let (mut lifelink, deathtouch) = unsafe { Lifelink::<RefCtor<AtomicUsize>>::new(&answer) };
///
/// {
/// let guard = lifelink.get().unwrap();
/// assert_eq!(0, guard.load(Ordering::Relaxed));
/// guard.store(42, Ordering::Release);
/// }
///
/// assert_eq!(42, deathtouch.unwrap().load(Ordering::Acquire));
/// ```
#[allow(clippy::needless_lifetimes)] // False positive
pub unsafe fn new<'a>(thing: C::Ty<'a>) -> (Lifelink<C>, Deathtouch<'a, C>) {
let thing = Box::new(thing);
let ptr = Box::into_raw(thing) as *mut u8;
let inner = Arc::new(Mutex::new(ptr));
let lifelink = Lifelink {
inner: Arc::clone(&inner),
_marker: PhantomData,
};
let deathtouch = Deathtouch {
inner,
_marker: PhantomData,
};
(lifelink, deathtouch)
}
/// Returns a guard value that implements [`Deref`] to the wrapped value. Care must be taken
/// to ensure that this value is dropped properly. Leaking the guard value may lead to a
/// deadlock.
pub fn get(&mut self) -> Option<Guard<'_, C>> {
let lock = self.inner.lock();
if lock.is_null() {
None
} else {
Some(Guard {
lock,
_marker: PhantomData,
})
}
}
}
/// A guard value that provides temporary access to the wrapped value. Care must be taken
/// to ensure that this value is dropped properly. Leaking the guard value may lead to a
/// deadlock.
///
/// `Guard<'_, C>` implements [`Send`] and [`Sync`] when the wrapped values produced by
/// `C` are [`Sync`].
pub struct Guard<'a, C: Ctor> {
lock: MutexGuard<'a, *mut u8>,
_marker: PhantomData<C::Ty<'static>>,
}
// SAFETY: Shared references are Send / Sync when and only when the value referred to is
// Sync.
unsafe impl<'a, C: SyncCtor> Send for Guard<'a, C> {}
unsafe impl<'a, C: SyncCtor> Sync for Guard<'a, C> {}
impl<'a, C> Deref for Guard<'a, C>
where
C: Ctor + Cov,
{
type Target = C::Ty<'a>;
fn deref(&self) -> &Self::Target {
let ptr: *mut u8 = *self.lock;
// SAFETY: User promised so by implementing `Cov`.
unsafe { &*(ptr as *const C::Ty<'a>) }
}
}
/// A guard value that preserves compile-time lifetime information from the value passed
/// to [`Lifelink::new`].
///
/// This will block the calling thread when unwrapped or dropped, until all [`Guard`]s
/// currently alive go out of the scope. The value can then no longer be accessed from the
/// corresponding [`Lifelink`].
///
/// Note that Unlike `cryo`, this does *not* attempt to wait until the [`Lifelink`] handle
/// itself is dropped, only the [`Guard`] values it produces. See the Caveats section of
/// README for more details.
pub struct Deathtouch<'a, C: Ctor> {
inner: Inner,
/// Invariant over 'a
_marker: PhantomData<Cell<&'a C::Ty<'a>>>,
}
// SAFETY: The only public interfaces of this type takes `self`, and waits until there are
// no other Guards alive.
unsafe impl<'a, C: SendCtor> Send for Deathtouch<'a, C> {}
impl<'a, C: Ctor> Deathtouch<'a, C> {
fn extract(&mut self) -> Option<C::Ty<'a>> {
let mut lock = self.inner.lock();
let ptr: *mut u8 = std::mem::replace(&mut *lock, null_mut());
if ptr.is_null() {
None
} else {
// SAFETY: this pointer is produced in Lifelink::new with Box::into_raw, and
// the Deathtouch type itself is invariant over 'a
unsafe { Some(*Box::from_raw(ptr as *mut C::Ty<'a>)) }
}
}
/// Unwrap the contained value and return it. This will block until there is no
/// other references to the value, so that compile-time lifetime invariants hold.
///
/// See the module-level documentation for examples.
pub fn unwrap(mut self) -> C::Ty<'a> {
self.extract().unwrap()
}
}
impl<'a, C: Ctor> Drop for Deathtouch<'a, C> {
fn drop(&mut self) {
self.extract();
}
}
/// Trait for type constructors that take one single lifetime parameter. See also
/// [`Cov`] for [`Deref`] on [`Guard`].
pub trait Ctor {
type Ty<'a>;
}
/// Trait for type constructors that produce types whose references are covariant over the
/// lifetime parameter.
///
/// For most valid types, this could implemented by simply invoking [`cov!`]:
///
/// ```rust
/// # use lifelink::*;
///
/// struct FooCtor;
/// struct Foo<'a>(&'a u8);
/// impl Ctor for FooCtor {
/// type Ty<'a> = Foo<'a>;
/// }
///
/// cov!(FooCtor);
/// ```
///
/// # Safety
///
/// References to types produced by this type constructor must be covariant over the lifetime
/// parameter.
///
/// This trait is `unsafe` for the reason that it is trivial to write a type-checking
/// implementation of `cov` for every type out there, simply by writing `panic!()`.
/// Lifetime variance is hard to figure out in a complex type. It's safest to use the [`cov!`]
/// macro for applicable types, unless you are really sure that you know better than the compiler.
pub unsafe trait Cov: Ctor {
fn cov<'r, 'a, 'b>(r: &'r Self::Ty<'a>) -> &'r Self::Ty<'b>
where
'a: 'b;
}
/// Macro that implements [`Cov`] safely for a [`Ctor`] type.
///
/// [`Cov::cov`] is implemented by simply returning the input reference and letting Rust coerce it.
/// This should work automatically for most types that are actually covariant. In case `cov!(MyType)`
/// does not compile, users would need to provide their own `unsafe` [`Cov`] implementation.
///
/// See [`Cov`] for an example.
#[macro_export]
macro_rules! cov {
(<$($tv:ident $(: $bound:tt $(+ $bounds:tt)*)?),*> $thing:ty) => {
unsafe impl<$($tv $(: $bound $(+ $bounds)*)?),*> $crate::Cov for $thing {
fn cov<'r, 'a, 'b>(r: &'r <Self as $crate::Ctor>::Ty<'a>) -> &'r <Self as $crate::Ctor>::Ty<'b>
where
'a: 'b,
{
r
}
}
};
($thing:ty) => {
$crate::cov!(<> $thing);
};
}
/// Marker trait implemented for [`Ctor`]s where the constructed types are `Send`.
pub trait SendCtor: Ctor {}
impl<C> SendCtor for C
where
C: Ctor,
for<'a> C::Ty<'a>: Send,
{
}
/// Marker trait implemented for [`Ctor`]s where the constructed types are [`Sync`].
pub trait SyncCtor: Ctor {}
impl<C> SyncCtor for C
where
C: Ctor,
for<'a> C::Ty<'a>: Sync,
{
}
/// Constructor of references to `'static` values, that implements [`Ctor`] and [`Cov`].
///
/// This is provided for convenience, although if all you need is this, consider using the
/// [`cryo`](https://crates.io/crates/cryo) crate, which is much more mature and compiles on
/// stable today!
pub struct RefCtor<T> {
_marker: PhantomData<T>,
}
impl<T: 'static> Ctor for RefCtor<T> {
type Ty<'a> = &'a T;
}
cov!(<T: 'static> RefCtor<T>);
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
#[test]
fn local() {
let answer = AtomicUsize::new(0);
let mut leaked;
{
lifelink!(lifelink: RefCtor<AtomicUsize> = &answer);
assert_eq!(
Some(0),
lifelink.get().map(|foo| foo.load(Ordering::Relaxed))
);
leaked = lifelink;
}
assert!(leaked.get().is_none());
}
#[test]
fn sync() {
use std::sync::mpsc::channel;
use std::thread::spawn;
let answer = AtomicUsize::new(0);
lifelink!(lifelink: RefCtor<AtomicUsize> = &answer);
let (send, recv) = channel();
spawn(move || {
let guard = lifelink.get().unwrap();
assert_eq!(0, guard.load(Ordering::Relaxed));
guard.store(42, Ordering::Release);
send.send(()).unwrap();
});
recv.recv_timeout(Duration::from_millis(20)).unwrap();
assert_eq!(42, answer.load(Ordering::Acquire));
}
}