Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimentation with trait objects in Yoke #743

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions utils/yoke/src/dyn_impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use crate::Yoke;
use crate::Yokeable;
use stable_deref_trait::StableDeref;
use std::borrow::Cow;
use std::mem;
use std::ops::Deref;

pub trait Foo<'a> {
fn foo(&self) -> char;
}

/// Example implementation of trait Foo
impl<'s> Foo<'s> for Cow<'s, str> {
fn foo(&self) -> char {
self.chars().next().unwrap_or('?')
}
}

impl<'a, 's, T: Foo<'s> > Foo<'s> for &'a T {
fn foo(&self) -> char {
<T as Foo<'s>>::foo(*self)
}
}

pub struct FooWrap<'a> {
pub inner: &'a dyn Foo<'a>,
}

unsafe impl<'a> Yokeable<'a> for FooWrap<'static> {
type Output = FooWrap<'a>;

fn transform(&'a self) -> &'a Self::Output {
// needs unsafe because the compiler has trouble with covariant trait object lifetimes
unsafe { mem::transmute(self) }
}

unsafe fn make(from: Self::Output) -> Self {
mem::transmute(from)
}

fn with_mut<F>(&'a mut self, f: F)
where
F: 'static + for<'b> FnOnce(&'b mut Self::Output),
{
// Cast away the lifetime of Self
unsafe { f(mem::transmute::<&'a mut Self, &'a mut Self::Output>(self)) }
}
}

trait DynHelper {
type Yokeable: for<'a> Yokeable<'a>;
type Cart: StableDeref;

fn attach<'de>(
data: &'de <Self::Cart as Deref>::Target,
) -> <Self::Yokeable as Yokeable<'de>>::Output;

fn make_cart(input: Box<Self>) -> Self::Cart;
}

impl<'a> DynHelper for dyn Foo<'a> + 'a {
type Yokeable = FooWrap<'static>;
type Cart = Box<dyn Foo<'static>>;

fn attach<'de>(data: &'de dyn Foo<'static>) -> FooWrap<'de> {
let inner: &'de dyn Foo<'de> = unsafe { mem::transmute(data) };
FooWrap { inner }
}

fn make_cart(input: Box<dyn Foo<'a> + 'a>) -> Box<dyn Foo<'static>> {
unsafe { mem::transmute(input) }
}
}

impl<'b, Y, C> Foo<'b> for Yoke<Y, C>
where
Y: for<'a> Yokeable<'a>,
for<'a> &'a <Y as Yokeable<'a>>::Output: Foo<'a>,
{
fn foo(&self) -> char {
self.get().foo()
}
}

fn yoke_from_box<'b, D>(input: Box<D>) -> Yoke<<D as DynHelper>::Yokeable, <D as DynHelper>::Cart>
where
D: DynHelper + ?Sized,
{
let cart: <D as DynHelper>::Cart = <D as DynHelper>::make_cart(input);
Yoke::<<D as DynHelper>::Yokeable, <D as DynHelper>::Cart>::attach_to_cart_badly(
cart,
<D as DynHelper>::attach,
)
}

#[test]
fn test_dyn() {
let source_data = "zyx".to_string();

let string_yoke: Yoke<Cow<'static, str>, &str> =
Yoke::<Cow<'static, str>, &str>::attach_to_cart_badly(&source_data, |s| Cow::Borrowed(s));

let boxed: Box<dyn Foo<'_>> = Box::new(string_yoke);

let dyn_yoke: Yoke<FooWrap<'static>, Box<dyn Foo<'static>>> = yoke_from_box(boxed);

assert_eq!(dyn_yoke.get().inner.foo(), 'z');
}
1 change: 1 addition & 0 deletions utils/yoke/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// them out is good even when redundant
#![allow(clippy::needless_lifetimes)]

mod dyn_impls;
mod yoke;
mod yokeable;

Expand Down