use std::{marker::PhantomData, mem::MaybeUninit};
use paste::paste;
mod adapt;
mod any;
mod local;
pub use adapt::*;
pub use any::*;
pub use local::*;
pub trait CxRep {
type BuildCx<'a>: Copy;
type RebuildCx<'a>: Copy;
}
pub trait Builder<R: CxRep> {
type State;
fn build(self, cx: R::BuildCx<'_>) -> Self::State;
fn rebuild(self, cx: R::RebuildCx<'_>, state: &mut Self::State);
}
macro_rules! tuple_builder {
($($a:ident),*) => {
#[allow(non_camel_case_types)]
impl<R: CxRep, $($a: Builder<R>,)*> Builder<R> for ($($a,)*) {
type State = ($($a::State,)*);
fn build(self, _cx: R::BuildCx<'_>) -> Self::State {
let ($($a,)*) = self;
#[allow(clippy::unused_unit)]
($($a.build(_cx),)*)
}
fn rebuild(self, _cx: R::RebuildCx<'_>, state: &mut Self::State) {
let ($($a,)*) = self;
let ($(paste!([< state_ $a >]),)*) = state;
$($a.rebuild(_cx, paste!([< state_ $a >]));)*
}
}
};
}
tuple_builder!();
tuple_builder!(a);
tuple_builder!(a, b);
tuple_builder!(a, b, c);
tuple_builder!(a, b, c, d);
tuple_builder!(a, b, c, d, e);
tuple_builder!(a, b, c, d, e, f);
tuple_builder!(a, b, c, d, e, f, g);
tuple_builder!(a, b, c, d, e, f, g, h);
pub trait State<Output>: AsAny {
fn run(&mut self, output: &mut Output);
}
macro_rules! tuple_state {
($($a:ident),*) => {
#[allow(non_camel_case_types)]
impl<$($a,)* O> State<O> for ($($a,)*)
where
$($a: State<O>,)*
{
fn run(&mut self, _output: &mut O) {
let ($($a,)*) = self;
$($a.run(_output);)*
}
}
};
}
tuple_state!();
tuple_state!(a);
tuple_state!(a, b);
tuple_state!(a, b, c);
tuple_state!(a, b, c, d);
tuple_state!(a, b, c, d, e);
tuple_state!(a, b, c, d, e, f);
tuple_state!(a, b, c, d, e, f, g);
tuple_state!(a, b, c, d, e, f, g, h);
pub struct Cx<'cx, 'state, State, R: CxRep> {
inner: CxInner<'cx, 'state, State, R>,
}
enum CxInner<'cx, 'state, State, R: CxRep> {
Build {
state: &'state mut MaybeUninit<State>,
cx: R::BuildCx<'cx>,
},
Rebuild {
state: &'state mut State,
cx: R::RebuildCx<'cx>,
},
}
pub struct Token<State> {
phantom: PhantomData<State>,
}
impl<'cx, 'state, State, R: CxRep> Cx<'cx, 'state, State, R> {
pub fn build<B: Builder<R, State = State>>(
self,
builder: B,
) -> Token<B::State> {
match self.inner {
CxInner::Build { state, cx } => {
let s = builder.build(cx);
state.write(s);
}
CxInner::Rebuild { state, cx } => builder.rebuild(cx, state),
}
Token {
phantom: PhantomData,
}
}
}
pub struct With<F, State> {
f: F,
phantom: PhantomData<State>,
}
impl<F, State, R: CxRep> Builder<R> for With<F, State>
where
F: FnOnce(Cx<State, R>) -> Token<State>,
{
type State = State;
fn build(self, cx: R::BuildCx<'_>) -> Self::State {
let mut state = MaybeUninit::<State>::uninit();
(self.f)(Cx {
inner: CxInner::Build {
state: &mut state,
cx,
},
});
unsafe { state.assume_init() }
}
fn rebuild(self, cx: R::RebuildCx<'_>, state: &mut Self::State) {
(self.f)(Cx {
inner: CxInner::Rebuild { state, cx },
});
}
}
pub fn with<F, State, R: CxRep>(f: F) -> With<F, State>
where
F: FnOnce(Cx<State, R>) -> Token<State>,
{
With {
f,
phantom: PhantomData,
}
}