Use pin-weak from crates.io

This commit is contained in:
Olivier Goffart 2020-08-03 09:18:04 +02:00
parent cb67e40c32
commit 2e74fa43cd
5 changed files with 2 additions and 153 deletions

View file

@ -23,7 +23,6 @@ members = [
'helper_crates/const-field-offset',
'helper_crates/vtable',
'helper_crates/vtable/macro',
'helper_crates/pin-weak',
'xtask',
'tests/driver',
'tests/driver_lib',

View file

@ -12,7 +12,7 @@ once_cell = "1.4"
sixtyfps-rs-macro= { path = "sixtyfps-rs-macro" }
const-field-offset = { path = "../../helper_crates/const-field-offset" }
vtable = { path = "../../helper_crates/vtable" }
pin-weak = { path = "../../helper_crates/pin-weak" }
pin-weak = "1"
sixtyfps_corelib = { path="../../sixtyfps_runtime/corelib" }
# FIXME: should be under a feature or somehow done differently
sixtyfps_rendering_backend_gl = { path="../../sixtyfps_runtime/rendering_backends/gl" }

View file

@ -1,9 +0,0 @@
[package]
name = "pin-weak"
version = "0.1.0"
authors = ["Olivier Goffart <ogoffart@sixtyfps.io>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View file

@ -1,141 +0,0 @@
/*!
This create provides weak pointers for `Pin<std::rc::Rc<T>>` and `Pin<std::rc::Arc<T>>`
## Motivation
`Pin<std::rc::Rc<T>>` and `Pin<std::rc::Arc<T>>` cannot be converted safely to
their `Weak<T>` equivalent if `T` does not implement `Unpin`.
That's because it would otherwise be possible to do something like this:
```
# use std::{pin::Pin, marker::PhantomPinned, rc::{Rc, Weak}};
struct SomeStruct(PhantomPinned);
let pinned = Rc::pin(SomeStruct(PhantomPinned));
// This is unsafe ...
let weak = unsafe {
Rc::downgrade(&Pin::into_inner_unchecked(pinned.clone()))
};
// ... because otherwise it would be possible to move the content of pinned:
let mut unpinned_rc = weak.upgrade().unwrap();
std::mem::drop((pinned, weak));
// unpinned_rc is now the only reference so this will work:
let x = std::mem::replace(
Rc::get_mut(&mut unpinned_rc).unwrap(),
SomeStruct(PhantomPinned),
);
```
In that example, `x` is the original `SomeStruct` which we moved in memory,
**that is undefined behavior**, do not do that at home.
## `PinWeak`
This crate simply provide a `rc::PinWeak` and `sync::PinWeak` which allow to
get weak pointer from `Pin<std::rc::Rc>` and `Pin<srd::sync::Arc>`.
This is safe because you can one can only get back a `Pin` out of it when
trying to upgrade the weak pointer.
`PinWeak` can be created using the `PinWeak` downgrade function.
## Example
```
use pin_weak::rc::*;
# use std::marker::PhantomPinned;
struct SomeStruct(PhantomPinned, usize);
let pinned = Rc::pin(SomeStruct(PhantomPinned, 42));
let weak = PinWeak::downgrade(pinned.clone());
assert_eq!(weak.upgrade().unwrap().1, 42);
std::mem::drop(pinned);
assert!(weak.upgrade().is_none());
```
*/
#![no_std]
extern crate alloc;
/// The implementation is in a macro because it is repeated for Arc and Rc
macro_rules! implementation {
($Rc:ident, $Weak:ident, $rc_lit:literal) => {
#[doc(no_inline)]
/// re-exported for convinience
pub use core::pin::Pin;
/// This is a safe wrapper around something that could be compared to `Pin<Weak<T>>`
///
/// The typical way to obtain a `PinWeak` is to call `PinWeak::downgrade`
#[derive(Debug)]
pub struct PinWeak<T: ?Sized>(Weak<T>);
impl<T> Default for PinWeak<T> {
fn default() -> Self { Self(Weak::default()) }
}
impl<T: ?Sized> Clone for PinWeak<T> {
fn clone(&self) -> Self { Self(self.0.clone()) }
}
impl<T: ?Sized> PinWeak<T> {
/// Equivalent function to `
#[doc = $rc_lit]
/// ::downgrade`, but taking a `Pin<
#[doc = $rc_lit]
/// <T>>` instead.
pub fn downgrade(rc: Pin<$Rc<T>>) -> Self {
// Safety: we will never return anythning else than a Pin<Rc>
unsafe { Self($Rc::downgrade(&Pin::into_inner_unchecked(rc))) }
}
/// Equivalent function to `Weak::upgrade` but returning a `Pin<
#[doc = $rc_lit]
/// <T>>` instead.
pub fn upgrade(&self) -> Option<Pin<$Rc<T>>> {
// Safety: the weak was contructed from a Pin<Rc<T>>
self.0.upgrade().map(|rc| unsafe { Pin::new_unchecked(rc) })
}
}
#[test]
fn test() {
struct Foo {
_p: core::marker::PhantomPinned,
u: u32,
}
impl Foo {
fn new(u: u32) -> Self {
Self { _p: core::marker::PhantomPinned, u }
}
}
let c = $Rc::pin(Foo::new(44));
let weak1 = PinWeak::downgrade(c.clone());
assert_eq!(weak1.upgrade().unwrap().u, 44);
assert_eq!(weak1.clone().upgrade().unwrap().u, 44);
let weak2 = PinWeak::downgrade(c.clone());
assert_eq!(weak2.upgrade().unwrap().u, 44);
assert_eq!(weak1.upgrade().unwrap().u, 44);
// note that this moves c and therefore it will be dropped
let weak3 = PinWeak::downgrade(c);
assert!(weak3.upgrade().is_none());
assert!(weak2.upgrade().is_none());
assert!(weak1.upgrade().is_none());
assert!(weak1.clone().upgrade().is_none());
let def = PinWeak::<alloc::boxed::Box<&'static mut ()>>::default();
assert!(def.upgrade().is_none());
assert!(def.clone().upgrade().is_none());
}
};
}
pub mod rc {
#[doc(no_inline)]
/// re-exported for convinience
pub use alloc::rc::{Rc, Weak};
implementation! {Rc, Weak, "Rc"}
}
pub mod sync {
#[doc(no_inline)]
/// re-exported for convinience
pub use alloc::sync::{Arc, Weak};
implementation! {Arc, Weak, "Arc"}
}

View file

@ -41,4 +41,4 @@ pathfinder_geometry = "0.5.1"
cbindgen = "0.14.2"
[dev-dependencies]
pin-weak = { path = "../../helper_crates/pin-weak" }
pin-weak = "1"