~jplatte/oref

9f9d60dc36e2dfa44a6bce85a42b051828de7adc — Jonas Platte 9 months ago
Initial commit
4 files changed, 79 insertions(+), 0 deletions(-)

A .gitignore
A Cargo.toml
A src/handle.rs
A src/lib.rs
A  => .gitignore +2 -0
@@ 1,2 @@
/target
Cargo.lock

A  => Cargo.toml +8 -0
@@ 1,8 @@
[package]
name = "oref"
version = "0.1.0"
authors = ["Jonas Platte <jplatte+git@posteo.de>"]
edition = "2018"

[dependencies]
stable_deref_trait = "1.1.1"

A  => src/handle.rs +15 -0
@@ 1,15 @@
use std::marker::PhantomData;

use stable_deref_trait::StableDeref;

pub trait GetHandle {
    type Handle<'a>;
}

pub struct GetDeref<T: StableDeref> {
    _phantom: PhantomData<T>,
}

impl<T: StableDeref + 'static> GetHandle for GetDeref<T> {
    type Handle<'a> = &'a T::Target;
}

A  => src/lib.rs +54 -0
@@ 1,54 @@
#![feature(generic_associated_types)]

use stable_deref_trait::StableDeref;

mod handle;

use handle::{GetDeref, GetHandle};

pub struct ORef<T, H>
where
    T: StableDeref,
    H: GetHandle,
{
    owner: T,
    //         really 'unsafe
    handle: H::Handle<'static>,
}

impl<T> ORef<T, GetDeref<T>>
where
    T: StableDeref + 'static,
{
    pub fn new(owner: T) -> Self {
        // Safety: We are extenting a reference to parts of owner to static lifetime. This is only
        // safe because
        //
        // * we ensure through StableDeref that what is borrowed lives for as long as owner lives
        // * we never actually give out self.handle, only a copy of it with a shorter lifetime
        let handle: &'static T::Target = unsafe { &*(owner.deref() as *const T::Target) };

        Self { owner, handle }
    }
}

impl<T, H> ORef<T, H>
where
    T: StableDeref,
    H: GetHandle,
{
    pub fn map<I, F>(self, f: F) -> ORef<T, I>
    where
        I: GetHandle,
        F: FnOnce(H::Handle<'static>) -> I::Handle<'static>,
        // ^ This is unsound, as the 'static handle or something it deref's to can be "stolen" by
        //   the map function. However, the correct variant of this code (see below) currently
        //   doesn't compile due to https://github.com/rust-lang/rust/issues/49601
        // F: for<'a> FnOnce(H::Handle<'a>) -> I::Handle<'a>,
    {
        ORef {
            owner: self.owner,
            handle: f(self.handle),
        }
    }
}