diff --git a/src/std.rs b/src/std.rs index 8821a3d..e1e0eaa 100644 --- a/src/std.rs +++ b/src/std.rs @@ -7,6 +7,7 @@ pub mod inlining; mod local_origin; pub mod nullable; pub mod point; +pub mod tracing; mod typeless; use std::{error::Error, fmt::Display, rc::Rc}; diff --git a/src/std/collections/stack.rs b/src/std/collections/stack.rs index b2b5a07..eac33fc 100644 --- a/src/std/collections/stack.rs +++ b/src/std/collections/stack.rs @@ -274,10 +274,12 @@ mod tests { let traced = stack.clone().vec(); assert_eq!(traced.length(), 0); assert_eq!(traced.width(), 0); + assert_eq!(format!("{}", traced.t), "."); let stack: T = Rc::new(stack).trace()?; let traced = stack.clone().vec(); assert_eq!(traced.length(), 3); assert_eq!(traced.width(), 1); + assert_eq!(format!("{}", traced.t), "( ? -> ? -> ? )"); Ok(()) } } diff --git a/src/std/tracing.rs b/src/std/tracing.rs new file mode 100644 index 0000000..4364a45 --- /dev/null +++ b/src/std/tracing.rs @@ -0,0 +1,189 @@ +mod trace; +mod traced; + +use crate::core::*; +use crate::func::*; +use trace::*; +pub use traced::Traced; + +pub struct TracedDiagnostic; + +pub struct TracedClass; + +trait WithTrace: Sized { + fn with_trace(self, t: TraceBox) -> Traced; +} + +impl WithTrace for A { + fn with_trace(self, t: TraceBox) -> Traced { + Traced { a: self, t } + } +} + +impl Traced { + pub fn wrapped(self, event: &str) -> Self { + Traced { + a: self.a, + t: self.t.wrapped(event), + } + } + + pub fn after_resolution(self) -> Self { + self.after(TraceBox::resolution()) + } + + fn after(self, t: TraceBox) -> Self { + Traced { + a: self.a, + t: self.t.after(t), + } + } + + fn before(self, t: TraceBox) -> Self { + Traced { + a: self.a, + t: self.t.before(t), + } + } + + pub fn length(&self) -> usize { + self.t.length() + } + + pub fn width(&self) -> usize { + self.t.width() + } +} + +impl WeakFunctor for TracedClass { + type F<'a, A: 'a> = Traced; +} + +impl Functor for TracedClass { + fn fmap<'a, A: 'a, B: 'a>(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> + where + Self: 'a, + { + f(fa.a).with_trace(fa.t) + } + + fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> + where + Self: 'a, + { + b.with_trace(fa.t) + } + + fn void<'a, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> + where + Self: 'a, + { + ().with_trace(fa.t) + } +} + +impl ApplicativeSeq for TracedClass { + fn seq<'a, A: 'a, B: 'a>( + ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, + fa: Self::F<'a, A>, + ) -> Self::F<'a, B> + where + Self: 'a, + { + (ff.a)(fa.a).with_trace(TraceBox::parallel(ff.t, fa.t)) + } +} + +impl ApplicativeLA2 for TracedClass { + fn la2<'a, A: 'a, B: 'a, C: 'a>( + f: impl 'a + FnOnce(A, B) -> C, + fa: Self::F<'a, A>, + fb: Self::F<'a, B>, + ) -> Self::F<'a, C> + where + Self: 'a, + { + f(fa.a, fb.a).with_trace(TraceBox::parallel(fa.t, fb.t)) + } +} + +impl ApplicativeTuple for TracedClass { + fn tuple<'a, A: 'a, B: 'a>((fa, fb): (Self::F<'a, A>, Self::F<'a, B>)) -> Self::F<'a, (A, B)> + where + Self: 'a, + { + (fa.a, fb.a).with_trace(TraceBox::parallel(fa.t, fb.t)) + } +} + +impl Applicative for TracedClass { + fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { + a.with_trace(TraceBox::pure()) + } + + fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> + where + Self: 'a, + { + fb.a.with_trace(TraceBox::parallel(fa.t, fb.t)) + } + + fn discard_second<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, A> + where + Self: 'a, + { + fa.a.with_trace(TraceBox::parallel(fa.t, fb.t)) + } +} + +impl Monad for TracedClass { + fn bind<'a, A: 'a, B: 'a>( + fa: Self::F<'a, A>, + f: impl 'a + FnOnce(A) -> Self::F<'a, B>, + ) -> Self::F<'a, B> + where + Self: 'a, + { + f(fa.a).after(fa.t) + } + + fn ibind<'a, A: 'a, B: 'a>( + mut a: A, + mut f: impl 'a + FnMut(A) -> Self::F<'a, IState>, + ) -> Self::F<'a, B> + where + Self: 'a, + { + let mut t = TraceBox::pure(); + loop { + let fa = f(a); + t = fa.t.after(t); + match fa.a { + IState::Pending(next_a) => a = next_a, + IState::Done(b) => return b.with_trace(t), + } + } + } + + fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> + where + Self::F<'a, A>: 'a, + Self: 'a, + { + ffa.a.after(ffa.t) + } +} + +impl Diagnostic for TracedDiagnostic { + fn after(fa: Traced, event: &str) -> Traced { + fa.after(TraceBox::event(event)) + } + + fn before(fa: Traced, event: &str) -> Traced { + fa.before(TraceBox::event(event)) + } + + fn wrapped(fa: Traced, event: &str) -> Traced { + fa.wrapped(event) + } +} diff --git a/src/std/tracing/trace.rs b/src/std/tracing/trace.rs new file mode 100644 index 0000000..b07d46a --- /dev/null +++ b/src/std/tracing/trace.rs @@ -0,0 +1,178 @@ +use std::{cmp::max, fmt::Display}; + +#[derive(Debug)] +enum Trace { + Pure, + InvolvesOneResolution, + Event(String), + Parallel(TraceBox, TraceBox), + Sequential { first: TraceBox, second: TraceBox }, + Wrapped { name: String, trace: TraceBox }, +} + +#[derive(Debug)] +pub struct TraceBox { + trace: Box, +} + +impl Trace { + fn fmt_parallel(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Trace::Parallel(a, b) => { + f.write_fmt(format_args!("{} | {}", ParallelBox(a), ParallelBox(b))) + } + trace @ _ => f.write_fmt(format_args!("{}", trace)), + } + } + + fn fmt_sequential(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Trace::Sequential { first, second } => f.write_fmt(format_args!( + "{} -> {}", + SequentialBox(first), + SequentialBox(second) + )), + trace @ _ => f.write_fmt(format_args!("{}", trace)), + } + } +} + +struct ParallelBox<'a>(&'a TraceBox); + +struct SequentialBox<'a>(&'a TraceBox); + +impl<'a> Display for ParallelBox<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.trace.fmt_parallel(f) + } +} + +impl<'a> Display for SequentialBox<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.trace.fmt_sequential(f) + } +} + +impl Display for Trace { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Trace::Pure => f.write_fmt(format_args!(".")), + Trace::InvolvesOneResolution => f.write_fmt(format_args!("?")), + Trace::Event(event) => f.write_fmt(format_args!("{}", event)), + Trace::Parallel(a, b) => { + f.write_fmt(format_args!("( {} | {} )", ParallelBox(a), ParallelBox(b))) + } + Trace::Sequential { first, second } => f.write_fmt(format_args!( + "( {} -> {} )", + SequentialBox(first), + SequentialBox(second) + )), + Trace::Wrapped { name, trace } => f.write_fmt(format_args!("{} @ {}", name, trace)), + } + } +} + +impl Display for TraceBox { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("{}", self.trace)) + } +} + +impl From for TraceBox { + fn from(value: Trace) -> Self { + TraceBox { + trace: value.into(), + } + } +} + +impl From for Trace { + fn from(value: TraceBox) -> Self { + *value.trace + } +} + +impl Trace { + fn sequential(ta: Self, tb: Self) -> Self { + match (ta, tb) { + (Trace::Pure, a) => a, + (a, Trace::Pure) => a, + (a, b) => Trace::Sequential { + first: a.into(), + second: b.into(), + }, + } + } + + fn length(&self) -> usize { + match self { + Self::Pure => 0, + Self::InvolvesOneResolution => 1, + Self::Event(_) => 0, + Self::Parallel(a, b) => max(a.length(), b.length()), + Self::Sequential { first, second } => first.length() + second.length(), + Self::Wrapped { trace, .. } => trace.length(), + } + } + + fn width(&self) -> usize { + match self { + Self::Pure => 0, + Self::InvolvesOneResolution => 1, + Self::Event(_) => 0, + Self::Parallel(a, b) => a.width() + b.width(), + Self::Sequential { first, second } => max(first.width(), second.width()), + Self::Wrapped { trace, .. } => trace.width(), + } + } + + fn parallel(ta: Self, tb: Self) -> Self { + match (ta, tb) { + (Trace::Pure, a) => a, + (a, Trace::Pure) => a, + (a, b) => Trace::Parallel(a.into(), b.into()), + } + } +} + +impl TraceBox { + pub fn pure() -> Self { + Trace::Pure.into() + } + + pub fn resolution() -> Self { + Trace::InvolvesOneResolution.into() + } + + pub fn event(event: &str) -> Self { + Trace::Event(event.into()).into() + } + + pub fn wrapped(self, event: &str) -> Self { + Trace::Wrapped { + name: event.into(), + trace: self, + } + .into() + } + + pub fn after(self, t: Self) -> Self { + Trace::sequential(t.into(), self.into()).into() + } + + pub fn before(self, t: Self) -> Self { + Trace::sequential(self.into(), t.into()).into() + } + + pub fn parallel(ta: Self, tb: Self) -> Self { + Trace::parallel(ta.into(), tb.into()).into() + } + + pub fn length(&self) -> usize { + self.trace.length() + } + + pub fn width(&self) -> usize { + self.trace.width() + } +} diff --git a/src/std/tracing/traced.rs b/src/std/tracing/traced.rs new file mode 100644 index 0000000..0df3391 --- /dev/null +++ b/src/std/tracing/traced.rs @@ -0,0 +1,6 @@ +use super::trace::*; + +pub struct Traced { + pub a: A, + pub t: TraceBox, +} diff --git a/src/testing/traced.rs b/src/testing/traced.rs index 9d8ff24..ac9a22e 100644 --- a/src/testing/traced.rs +++ b/src/testing/traced.rs @@ -1,10 +1,7 @@ -use std::cmp::max; - use super::*; use crate::core::*; use crate::func::*; - -pub struct TracedDiagnostic; +use crate::std::tracing::*; pub struct TestContextTraced; @@ -20,263 +17,6 @@ impl Context for TestContextTraced { } } -pub struct TracedClass; - -pub enum Trace { - Pure, - InvolvesOneResolution, - Event(String), - Parallel(Box, Box), - Sequential { - first: Box, - second: Box, - }, - Wrapped { - name: String, - trace: Box, - }, -} - -pub struct Traced { - a: A, - t: Box, -} - -trait WithTrace: Sized { - fn with_trace(self, t: Box) -> Traced; -} - -impl WithTrace for A { - fn with_trace(self, t: Box) -> Traced { - Traced { a: self, t } - } -} - -impl Trace { - fn pure() -> Box { - Self::Pure.into() - } - - fn resolution() -> Box { - Self::InvolvesOneResolution.into() - } - - fn event(event: &str) -> Box { - Self::Event(event.into()).into() - } - - fn wrapped(self: Box, event: &str) -> Box { - Self::Wrapped { - name: event.into(), - trace: self, - } - .into() - } - - fn after(self: Box, t: Box) -> Box { - match (*self, *t) { - (Self::Pure, a) => a.into(), - (a, Self::Pure) => a.into(), - (a, b) => Self::Sequential { - first: b.into(), - second: a.into(), - } - .into(), - } - } - - fn before(self: Box, t: Box) -> Box { - match (*self, *t) { - (Self::Pure, a) => a.into(), - (a, Self::Pure) => a.into(), - (a, b) => Self::Sequential { - first: a.into(), - second: b.into(), - } - .into(), - } - } - - fn parallel(ta: Box, tb: Box) -> Box { - match (*ta, *tb) { - (Self::Pure, a) => a.into(), - (a, Self::Pure) => a.into(), - (a, b) => Self::Parallel(a.into(), b.into()).into(), - } - } - - fn length(&self) -> usize { - match self { - Self::Pure => 0, - Self::InvolvesOneResolution => 1, - Self::Event(_) => 0, - Self::Parallel(a, b) => max(a.length(), b.length()), - Self::Sequential { first, second } => first.length() + second.length(), - Self::Wrapped { name: _, trace } => trace.length(), - } - } - - fn width(&self) -> usize { - match self { - Self::Pure => 0, - Self::InvolvesOneResolution => 1, - Self::Event(_) => 0, - Self::Parallel(a, b) => a.width() + b.width(), - Self::Sequential { first, second } => max(first.width(), second.width()), - Self::Wrapped { name: _, trace } => trace.width(), - } - } -} - -impl Traced { - fn wrapped(self, event: &str) -> Self { - Traced { - a: self.a, - t: self.t.wrapped(event), - } - } - fn after(self, t: Box) -> Self { - Traced { - a: self.a, - t: self.t.after(t), - } - } - - fn before(self, t: Box) -> Self { - Traced { - a: self.a, - t: self.t.before(t), - } - } - - pub fn length(&self) -> usize { - self.t.length() - } - - pub fn width(&self) -> usize { - self.t.width() - } -} - -impl WeakFunctor for TracedClass { - type F<'a, A: 'a> = Traced; -} - -impl Functor for TracedClass { - fn fmap<'a, A: 'a, B: 'a>(f: impl 'a + FnOnce(A) -> B, fa: Self::F<'a, A>) -> Self::F<'a, B> - where - Self: 'a, - { - f(fa.a).with_trace(fa.t) - } - - fn replace<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, b: B) -> Self::F<'a, B> - where - Self: 'a, - { - b.with_trace(fa.t) - } - - fn void<'a, A: 'a>(fa: Self::F<'a, A>) -> Self::F<'a, ()> - where - Self: 'a, - { - ().with_trace(fa.t) - } -} - -impl ApplicativeSeq for TracedClass { - fn seq<'a, A: 'a, B: 'a>( - ff: Self::F<'a, impl 'a + FnOnce(A) -> B>, - fa: Self::F<'a, A>, - ) -> Self::F<'a, B> - where - Self: 'a, - { - (ff.a)(fa.a).with_trace(Trace::parallel(ff.t, fa.t)) - } -} - -impl ApplicativeLA2 for TracedClass { - fn la2<'a, A: 'a, B: 'a, C: 'a>( - f: impl 'a + FnOnce(A, B) -> C, - fa: Self::F<'a, A>, - fb: Self::F<'a, B>, - ) -> Self::F<'a, C> - where - Self: 'a, - { - f(fa.a, fb.a).with_trace(Trace::parallel(fa.t, fb.t)) - } -} - -impl ApplicativeTuple for TracedClass { - fn tuple<'a, A: 'a, B: 'a>((fa, fb): (Self::F<'a, A>, Self::F<'a, B>)) -> Self::F<'a, (A, B)> - where - Self: 'a, - { - (fa.a, fb.a).with_trace(Trace::parallel(fa.t, fb.t)) - } -} - -impl Applicative for TracedClass { - fn pure<'a, A: 'a>(a: A) -> Self::F<'a, A> { - a.with_trace(Trace::pure()) - } - - fn discard_first<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, B> - where - Self: 'a, - { - fb.a.with_trace(Trace::parallel(fa.t, fb.t)) - } - - fn discard_second<'a, A: 'a, B: 'a>(fa: Self::F<'a, A>, fb: Self::F<'a, B>) -> Self::F<'a, A> - where - Self: 'a, - { - fa.a.with_trace(Trace::parallel(fa.t, fb.t)) - } -} - -impl Monad for TracedClass { - fn bind<'a, A: 'a, B: 'a>( - fa: Self::F<'a, A>, - f: impl 'a + FnOnce(A) -> Self::F<'a, B>, - ) -> Self::F<'a, B> - where - Self: 'a, - { - f(fa.a).after(fa.t) - } - - fn ibind<'a, A: 'a, B: 'a>( - mut a: A, - mut f: impl 'a + FnMut(A) -> Self::F<'a, IState>, - ) -> Self::F<'a, B> - where - Self: 'a, - { - let mut t = Trace::pure(); - loop { - let fa = f(a); - t = fa.t.after(t); - match fa.a { - IState::Pending(next_a) => a = next_a, - IState::Done(b) => return b.with_trace(t), - } - } - } - - fn join<'a, A: 'a>(ffa: Self::F<'a, Self::F<'a, A>>) -> Self::F<'a, A> - where - Self::F<'a, A>: 'a, - Self: 'a, - { - ffa.a.after(ffa.t) - } -} - struct TracedResolver<'a> { resolver: Rc>, } @@ -300,7 +40,7 @@ impl<'a> Resolver<'a, TestContextTraced> for TracedResolver<'a> { }, self.resolver.clone().resolve(address), ) - .after(Trace::resolution()) + .after_resolution() } } @@ -314,17 +54,3 @@ impl<'a, A: Mentionable<'a, TestContextTraced>> Traceable<'a> for A { TypelessMentionable::from_typed(self).cast_full(factory, TracedResolver::new) } } - -impl Diagnostic for TracedDiagnostic { - fn after<'a, A>(fa: Traced, event: &'a str) -> Traced { - fa.after(Trace::event(event)) - } - - fn before<'a, A>(fa: Traced, event: &'a str) -> Traced { - fa.before(Trace::event(event)) - } - - fn wrapped<'a, A>(fa: Traced, event: &'a str) -> Traced { - fa.wrapped(event) - } -}