use std::marker::PhantomData;
use crate::{Builder, CxRep, State};
pub struct Adapt<B, F, S, Output> {
builder: B,
f: F,
phantom: PhantomData<(S, Output)>,
}
impl<R: CxRep, B, F, S, Output> Builder<R> for Adapt<B, F, S, Output>
where
B: Builder<R>,
{
type State = AdaptState<B::State, F>;
fn build(self, cx: R::BuildCx<'_>) -> Self::State {
AdaptState {
inner: self.builder.build(cx),
f: self.f,
}
}
fn rebuild(self, cx: R::RebuildCx<'_>, state: &mut Self::State) {
state.f = self.f;
self.builder.rebuild(cx, &mut state.inner)
}
}
pub struct Thunk<'s, S> {
state: &'s mut S,
}
pub struct ThunkResult<S> {
phantom: PhantomData<S>,
}
impl<'s, S> Thunk<'s, S> {
pub fn run<Output>(self, output: &mut Output) -> ThunkResult<S>
where
S: State<Output>,
{
self.state.run(output);
ThunkResult {
phantom: PhantomData,
}
}
}
pub struct AdaptState<S, F> {
inner: S,
f: F,
}
impl<S: 'static, F, Output> State<Output> for AdaptState<S, F>
where
F: 'static + FnMut(Thunk<S>, &mut Output) -> ThunkResult<S>,
{
fn run(&mut self, output: &mut Output) {
(self.f)(
Thunk {
state: &mut self.inner,
},
output,
);
}
}
pub fn adapt<B, F, S, Output>(builder: B, f: F) -> Adapt<B, F, S, Output>
where
F: 'static + FnMut(Thunk<S>, &mut Output) -> ThunkResult<S>,
{
Adapt {
builder,
f,
phantom: PhantomData,
}
}
pub fn adapt_ref<B, F, S, Output, R>(
builder: B,
mut f: F,
) -> Adapt<
B,
impl 'static + FnMut(Thunk<S>, &mut Output) -> ThunkResult<S>,
S,
Output,
>
where
F: 'static + FnMut(&mut Output) -> &mut R,
S: State<R>,
{
adapt(builder, move |thunk, output| thunk.run(f(output)))
}