TraitFn
I've ran out of cat sounds to put in commit messages
This commit is contained in:
parent
deb96a3692
commit
b28faf500a
@ -2,3 +2,4 @@ pub mod model_00;
|
||||
pub mod model_01;
|
||||
#[cfg(any())]
|
||||
pub mod model_02; // ICE
|
||||
pub mod model_03;
|
||||
|
273
src/model_03.rs
Normal file
273
src/model_03.rs
Normal file
@ -0,0 +1,273 @@
|
||||
use std::{
|
||||
marker::PhantomData,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use futures::Future;
|
||||
use pin_project::pin_project;
|
||||
|
||||
pub trait Trait {
|
||||
type Associated: ?Sized + Trait;
|
||||
type In<'out: 'tmp, 'tmp, I: 'tmp>;
|
||||
type Out<'out, A>;
|
||||
}
|
||||
|
||||
pub trait Impl<T: ?Sized + Trait>: Sized {
|
||||
type Associated: Impl<T::Associated>;
|
||||
fn method<'out: 'tmp, 'tmp>(_: T::In<'out, 'tmp, Self>) -> T::Out<'out, Self::Associated>
|
||||
where
|
||||
Self: 'tmp;
|
||||
}
|
||||
|
||||
pub enum Empty {}
|
||||
|
||||
impl Trait for Empty {
|
||||
type Associated = Self;
|
||||
type In<'out: 'tmp, 'tmp, I: 'tmp> = Self;
|
||||
type Out<'out, A> = Self;
|
||||
}
|
||||
|
||||
impl<I> Impl<Empty> for I {
|
||||
type Associated = I;
|
||||
fn method<'out: 'tmp, 'tmp>(
|
||||
empty: <Empty as Trait>::In<'out, 'tmp, Self>,
|
||||
) -> <Empty as Trait>::Out<'out, Self::Associated>
|
||||
where
|
||||
Self: 'tmp,
|
||||
{
|
||||
empty
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Is<That, T: ?Sized>(That, T);
|
||||
|
||||
impl<That, T: ?Sized + Trait> Trait for Is<That, T> {
|
||||
type Associated = T;
|
||||
type In<'out: 'tmp, 'tmp, I: 'tmp> = I;
|
||||
type Out<'out, A> = That;
|
||||
}
|
||||
|
||||
impl<That: Impl<T>, T: ?Sized + Trait> Impl<Is<Self, T>> for That {
|
||||
type Associated = Self;
|
||||
|
||||
fn method<'out: 'tmp, 'tmp>(
|
||||
this: <Is<That, T> as Trait>::In<'out, 'tmp, Self>,
|
||||
) -> <Is<That, T> as Trait>::Out<'out, Self::Associated>
|
||||
where
|
||||
Self: 'tmp,
|
||||
{
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
pub struct To<T: ?Sized>(T);
|
||||
|
||||
impl<T: ?Sized + Trait> Trait for To<T> {
|
||||
type Associated = T;
|
||||
type In<'out: 'tmp, 'tmp, I: 'tmp> = I;
|
||||
type Out<'out, A> = A;
|
||||
}
|
||||
|
||||
impl<I: FnOnce() -> Output, Output: Impl<T>, T: ?Sized + Trait> Impl<To<T>> for I {
|
||||
type Associated = Output;
|
||||
|
||||
fn method<'out: 'tmp, 'tmp>(
|
||||
this: <To<T> as Trait>::In<'out, 'tmp, Self>,
|
||||
) -> <To<T> as Trait>::Out<'out, Self::Associated>
|
||||
where
|
||||
Self: 'tmp,
|
||||
{
|
||||
this()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TraitFn<In: ?Sized + Trait> {
|
||||
type Out: ?Sized + Trait;
|
||||
fn run(self, _: impl Impl<In>) -> impl Impl<Self::Out>;
|
||||
}
|
||||
|
||||
pub trait Functor {
|
||||
type W<T: ?Sized + Trait>: ?Sized + Trait;
|
||||
fn pure<A: ?Sized + Trait>(_: impl Impl<A>) -> impl Impl<Self::W<A>>;
|
||||
fn map<A: ?Sized + Trait, F: TraitFn<A>>(
|
||||
_: impl Impl<Self::W<A>>,
|
||||
_: F,
|
||||
) -> impl Impl<Self::W<F::Out>>;
|
||||
}
|
||||
|
||||
pub struct Verbatim;
|
||||
|
||||
impl Functor for Verbatim {
|
||||
type W<T: ?Sized + Trait> = T;
|
||||
|
||||
fn pure<A: ?Sized + Trait>(a: impl Impl<A>) -> impl Impl<Self::W<A>> {
|
||||
a
|
||||
}
|
||||
|
||||
fn map<A: ?Sized + Trait, F: TraitFn<A>>(
|
||||
a: impl Impl<Self::W<A>>,
|
||||
f: F,
|
||||
) -> impl Impl<Self::W<F::Out>> {
|
||||
f.run(a)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Call<T: ?Sized + Trait> {
|
||||
type Output: Impl<T>;
|
||||
fn call(self) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Trait, I: Impl<To<T>>> Call<T> for I {
|
||||
type Output = I::Associated;
|
||||
|
||||
fn call(self) -> Self::Output {
|
||||
I::method(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Lazy;
|
||||
|
||||
impl Functor for Lazy {
|
||||
type W<T: ?Sized + Trait> = To<T>;
|
||||
|
||||
fn pure<A: ?Sized + Trait>(a: impl Impl<A>) -> impl Impl<Self::W<A>> {
|
||||
|| a
|
||||
}
|
||||
|
||||
fn map<A: ?Sized + Trait, F: TraitFn<A>>(
|
||||
a: impl Impl<Self::W<A>>,
|
||||
f: F,
|
||||
) -> impl Impl<Self::W<F::Out>> {
|
||||
|| f.run(a.call())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Composition<Uo, Ui>(Uo, Ui);
|
||||
|
||||
impl<Uo: Functor, Ui: Functor> Functor for Composition<Ui, Uo> {
|
||||
type W<T: ?Sized + Trait> = Uo::W<Ui::W<T>>;
|
||||
|
||||
fn pure<A: ?Sized + Trait>(a: impl Impl<A>) -> impl Impl<Self::W<A>> {
|
||||
Uo::pure(Ui::pure(a))
|
||||
}
|
||||
|
||||
fn map<A: ?Sized + Trait, F: TraitFn<A>>(
|
||||
a: impl Impl<Self::W<A>>,
|
||||
f: F,
|
||||
) -> impl Impl<Self::W<F::Out>> {
|
||||
struct Tmp<A: ?Sized, F, Uo, Ui>(F, PhantomData<(Uo, Ui, A)>);
|
||||
impl<A: ?Sized + Trait, F: TraitFn<A>, Uo: Functor, Ui: Functor> TraitFn<Ui::W<A>>
|
||||
for Tmp<A, F, Uo, Ui>
|
||||
{
|
||||
type Out = Ui::W<F::Out>;
|
||||
|
||||
fn run(self, a: impl Impl<Ui::W<A>>) -> impl Impl<Self::Out> {
|
||||
Ui::map(a, self.0)
|
||||
}
|
||||
}
|
||||
Uo::map(a, Tmp::<A, F, Uo, Ui>(f, PhantomData))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Into_<T: ?Sized + Trait> {
|
||||
fn into_<A>(self) -> A
|
||||
where
|
||||
Self: Impl<Is<A, T>>,
|
||||
{
|
||||
Self::method(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Trait, I> Into_<T> for I {}
|
||||
|
||||
impl<A, B, F: FnOnce(A) -> B, T: ?Sized + Trait> TraitFn<Is<A, T>> for F {
|
||||
type Out = Is<B, Empty>;
|
||||
|
||||
fn run(self, a: impl Impl<Is<A, T>>) -> impl Impl<Self::Out> {
|
||||
self(a.into_())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn generic_test<U: Functor>() -> impl Impl<U::W<Is<i32, Empty>>> {
|
||||
let x = U::pure::<Is<_, Empty>>(5);
|
||||
let x = U::map(x, |x| x + 1);
|
||||
let x = U::map(x, |x| x + 1);
|
||||
let x = U::map(x, |x| x + 1);
|
||||
let x = U::map(x, |x| x + 1);
|
||||
U::map(x, |x| x + 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doubly_lazy() {
|
||||
type U = Composition<Lazy, Lazy>;
|
||||
let x = generic_test::<U>();
|
||||
let x = x.call().call().into_::<i32>();
|
||||
assert_eq!(x, 10);
|
||||
}
|
||||
|
||||
pub struct FutureTo<T: ?Sized>(T);
|
||||
|
||||
impl<T: ?Sized + Trait> Trait for FutureTo<T> {
|
||||
type Associated = T;
|
||||
type In<'out: 'tmp, 'tmp, I: 'tmp> = (Pin<&'tmp mut I>, &'tmp mut Context<'out>);
|
||||
type Out<'out, A> = Poll<A>;
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Trait, Output: Impl<T>, F: Future<Output = Output>> Impl<FutureTo<T>> for F {
|
||||
type Associated = F::Output;
|
||||
|
||||
fn method<'out: 'tmp, 'tmp>(
|
||||
(this, cx): <FutureTo<T> as Trait>::In<'out, 'tmp, Self>,
|
||||
) -> <FutureTo<T> as Trait>::Out<'out, Self::Associated>
|
||||
where
|
||||
Self: 'tmp,
|
||||
{
|
||||
this.poll(cx)
|
||||
}
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
struct TraitFuture<F, T: ?Sized>(#[pin] F, PhantomData<T>);
|
||||
|
||||
impl<T: ?Sized + Trait, F: Impl<FutureTo<T>>> Future for TraitFuture<F, T> {
|
||||
type Output = F::Associated;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
F::method((self.project().0, cx))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoFuture_<T: ?Sized + Trait>: Impl<FutureTo<T>> {
|
||||
fn into_future_(self) -> impl Future<Output = Self::Associated> {
|
||||
TraitFuture(self, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Trait, I: Impl<FutureTo<T>>> IntoFuture_<T> for I {}
|
||||
|
||||
pub struct Futures;
|
||||
|
||||
impl Functor for Futures {
|
||||
type W<T: ?Sized + Trait> = FutureTo<T>;
|
||||
|
||||
fn pure<A: ?Sized + Trait>(a: impl Impl<A>) -> impl Impl<Self::W<A>> {
|
||||
async { a }
|
||||
}
|
||||
|
||||
fn map<A: ?Sized + Trait, F: TraitFn<A>>(
|
||||
a: impl Impl<Self::W<A>>,
|
||||
f: F,
|
||||
) -> impl Impl<Self::W<F::Out>> {
|
||||
async { f.run(a.into_future_().await) }
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_futures() {
|
||||
type U = Futures;
|
||||
let x = generic_test::<U>();
|
||||
let x = futures::executor::block_on(x.into_future_()).into_::<i32>();
|
||||
assert_eq!(x, 10);
|
||||
}
|
Loading…
Reference in New Issue
Block a user