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;
|
pub mod model_01;
|
||||||
#[cfg(any())]
|
#[cfg(any())]
|
||||||
pub mod model_02; // ICE
|
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