diff --git a/src/model_03.rs b/src/model_03.rs index b0ed681..832e345 100644 --- a/src/model_03.rs +++ b/src/model_03.rs @@ -10,12 +10,12 @@ use pin_project::pin_project; pub trait Trait { type Associated: ?Sized + Trait; type In<'out: 'tmp, 'tmp, I: 'tmp>; - type Out<'out, A>; + type Out<'out, I: Impl>; } pub trait Impl: Sized { type Associated: Impl; - fn method<'out: 'tmp, 'tmp>(_: T::In<'out, 'tmp, Self>) -> T::Out<'out, Self::Associated> + fn method<'out: 'tmp, 'tmp>(_: T::In<'out, 'tmp, Self>) -> T::Out<'out, Self> where Self: 'tmp; } @@ -45,7 +45,7 @@ pub struct Is(That, T); impl Trait for Is { type Associated = T; type In<'out: 'tmp, 'tmp, I: 'tmp> = I; - type Out<'out, A> = That; + type Out<'out, I: Impl> = That; } impl, T: ?Sized + Trait> Impl> for That { @@ -66,7 +66,7 @@ pub struct To(T); impl Trait for To { type Associated = T; type In<'out: 'tmp, 'tmp, I: 'tmp> = I; - type Out<'out, A> = A; + type Out<'out, I: Impl> = I::Associated; } impl Output, Output: Impl, T: ?Sized + Trait> Impl> for I { @@ -74,7 +74,7 @@ impl Output, Output: Impl, T: ?Sized + Trait> Impl> for fn method<'out: 'tmp, 'tmp>( this: as Trait>::In<'out, 'tmp, Self>, - ) -> as Trait>::Out<'out, Self::Associated> + ) -> as Trait>::Out<'out, Self> where Self: 'tmp, { @@ -282,7 +282,7 @@ pub struct FutureTo(T); impl Trait for FutureTo { type Associated = T; type In<'out: 'tmp, 'tmp, I: 'tmp> = (Pin<&'tmp mut I>, &'tmp mut Context<'out>); - type Out<'out, A> = Poll; + type Out<'out, I: Impl> = Poll; } impl, F: Future> Impl> for F { @@ -290,7 +290,7 @@ impl, F: Future> Impl( (this, cx): as Trait>::In<'out, 'tmp, Self>, - ) -> as Trait>::Out<'out, Self::Associated> + ) -> as Trait>::Out<'out, Self> where Self: 'tmp, { @@ -368,3 +368,151 @@ fn doubly_futures() { let x = futures::executor::block_on(Futures::flatten(x).into_future_()).into_::(); assert_eq!(x, 10); } + +struct TracePure; + +struct TraceMap(T); + +struct TraceJoin(T0, T1); + +struct TraceFlatten(T0, T1); + +pub trait AsTrace { + fn as_trace(&self) -> Trace; +} + +pub enum Trace<'trace> { + Pure, + Flatten(&'trace dyn AsTrace, &'trace dyn AsTrace), + Map(&'trace dyn AsTrace), + Join(&'trace dyn AsTrace, &'trace dyn AsTrace), +} + +impl AsTrace for TracePure { + fn as_trace(&self) -> Trace { + Trace::Pure + } +} + +impl AsTrace for TraceMap { + fn as_trace(&self) -> Trace { + Trace::Map(&self.0) + } +} + +impl AsTrace for TraceJoin { + fn as_trace(&self) -> Trace { + Trace::Join(&self.0, &self.1) + } +} + +impl AsTrace for TraceFlatten { + fn as_trace(&self) -> Trace { + Trace::Flatten(&self.0, &self.1) + } +} + +struct DynTrace(I, fn(&I) -> Trace); + +impl AsTrace for DynTrace { + fn as_trace(&self) -> Trace { + self.1(&self.0) + } +} + +struct WithTrace { + value: Option, + trace: T, +} + +impl AsTrace for WithTrace { + fn as_trace(&self) -> Trace { + self.trace.as_trace() + } +} + +pub struct Traced(Etc); + +impl Trait for Traced { + type Associated = Etc; + type In<'out: 'tmp, 'tmp, I: 'tmp> = I; + type Out<'out, I: Impl> = (I::Associated, I, fn(&I) -> Trace); +} + +impl> Impl> for WithTrace { + type Associated = A; + + fn method<'out: 'tmp, 'tmp>( + mut this: as Trait>::In<'out, 'tmp, Self>, + ) -> as Trait>::Out<'out, Self> + where + Self: 'tmp, + { + let value = this.value.take().expect("duplicate tracing extraction"); + (value, this, Self::as_trace) + } +} + +trait SplitTrace { + type Value; + fn split_trace(self) -> (Self::Value, impl AsTrace); +} + +impl>> SplitTrace for I { + type Value = I::Associated; + + fn split_trace(self) -> (Self::Value, impl AsTrace) { + let (value, this, method) = I::method(self); + (value, DynTrace(this, method)) + } +} + +pub struct Traces; + +impl Functor for Traces { + type W = Traced; + + fn pure(a: impl Impl) -> impl Impl> { + WithTrace { + value: Some(a), + trace: TracePure, + } + } + + fn map>( + a: impl Impl>, + f: F, + ) -> impl Impl> { + let (a, ta) = a.split_trace(); + WithTrace { + value: Some(f.run(a)), + trace: TraceMap(ta), + } + } +} + +impl Applicative for Traces { + fn map2>( + a: impl Impl>, + b: impl Impl>, + f: F, + ) -> impl Impl> { + let (a, ta) = a.split_trace(); + let (b, tb) = b.split_trace(); + WithTrace { + value: Some(f.run(a, b)), + trace: TraceJoin(ta, tb), + } + } +} + +impl Monad for Traces { + fn flatten(a: impl Impl>>) -> impl Impl> { + let (a, to) = a.split_trace(); + let (a, ti) = a.split_trace(); + WithTrace { + value: Some(a), + trace: TraceFlatten(to, ti), + } + } +}