use crate::{JsonRpcAlg, JsonRpcApiAlg, JsonRpcMethodAlg, JsonRpcProgramAlg};
use alux_ext::{ApplyAlg, HandlerContextAlg, OperationAlg};
use core::marker::PhantomData;
pub trait CompileJsonRpcProgram<Compiler> {
type Methods;
fn compile_jsonrpc_program(self, compiler: &Compiler) -> Self::Methods;
}
#[derive(Debug, Default)]
pub struct Empty;
#[derive(Debug)]
pub struct Merge<Left, Right> {
left: Left,
right: Right,
}
#[derive(Debug)]
pub struct Named<Program>(Program);
#[derive(Debug, Default)]
pub struct Positional;
#[derive(Debug, Default)]
pub struct NamedParams;
#[derive(Debug)]
pub struct Method<Handler, Params = Positional> {
name: &'static str,
handler: Handler,
marker: PhantomData<fn(Params)>,
}
#[derive(Debug)]
pub struct Operation<Handler, Params = Positional> {
handler: Handler,
marker: PhantomData<fn(Params)>,
}
#[derive(Debug)]
pub struct JsonRpcProgram<Program>(Program);
#[derive(Debug, Default)]
pub struct JsonRpcProgramBuilder;
impl JsonRpcProgramBuilder {
pub fn methods(&self) -> JsonRpcProgram<Empty> {
JsonRpcProgram(Empty)
}
pub fn op<Handler>(&self, handler: Handler) -> Operation<Handler> {
Operation { handler, marker: PhantomData }
}
pub fn program<Program>(&self, program: Program) -> JsonRpcProgram<Named<Program>> {
JsonRpcProgram(Named(program))
}
}
impl<Program> JsonRpcProgram<Program> {
pub fn merge<Other>(self, other: JsonRpcProgram<Other>) -> JsonRpcProgram<Merge<Program, Other>> {
JsonRpcProgram(Merge { left: self.0, right: other.0 })
}
pub fn method<Handler, Params>(
self,
name: &'static str,
operation: Operation<Handler, Params>,
) -> JsonRpcProgram<Merge<Program, Method<Handler, Params>>> {
self.merge(JsonRpcProgram(Method { name, handler: operation.handler, marker: PhantomData }))
}
pub fn into_program(self) -> Program {
self.0
}
}
impl<Handler, Params> Operation<Handler, Params> {
pub fn positional(self) -> Operation<Handler> {
Operation { handler: self.handler, marker: PhantomData }
}
pub fn named(self) -> Operation<Handler, NamedParams> {
Operation { handler: self.handler, marker: PhantomData }
}
}
impl<Compiler> CompileJsonRpcProgram<Compiler> for Empty
where
Compiler: JsonRpcAlg,
{
type Methods = Compiler::Methods;
fn compile_jsonrpc_program(self, compiler: &Compiler) -> Self::Methods {
compiler.jsonrpc_empty()
}
}
impl<Compiler, Left, Right, Methods> CompileJsonRpcProgram<Compiler> for Merge<Left, Right>
where
Compiler: JsonRpcAlg<Methods = Methods>,
Left: CompileJsonRpcProgram<Compiler, Methods = Methods>,
Right: CompileJsonRpcProgram<Compiler, Methods = Methods>,
{
type Methods = Methods;
fn compile_jsonrpc_program(self, compiler: &Compiler) -> Self::Methods {
compiler
.jsonrpc_merge(self.left.compile_jsonrpc_program(compiler), self.right.compile_jsonrpc_program(compiler))
}
}
impl<Compiler, Program> CompileJsonRpcProgram<Compiler> for Named<Program>
where
Program: JsonRpcProgramAlg<Compiler>,
{
type Methods = Program::Methods;
fn compile_jsonrpc_program(self, compiler: &Compiler) -> Self::Methods {
self.0.compile_jsonrpc(compiler)
}
}
trait ParamsAlg {
fn finish<Compiler, Context, Args, Output, Handler>(
compiler: &Compiler,
name: &'static str,
arg_names: &'static [&'static str],
handler: Handler,
) -> Compiler::Methods
where
Compiler: JsonRpcAlg + JsonRpcMethodAlg<Context, Args, Output>,
Handler: ApplyAlg<Context, Args, Output = Output> + Send + Sync + 'static;
}
impl ParamsAlg for Positional {
fn finish<Compiler, Context, Args, Output, Handler>(
compiler: &Compiler,
name: &'static str,
_arg_names: &'static [&'static str],
handler: Handler,
) -> Compiler::Methods
where
Compiler: JsonRpcAlg + JsonRpcMethodAlg<Context, Args, Output>,
Handler: ApplyAlg<Context, Args, Output = Output> + Send + Sync + 'static,
{
compiler.finish_jsonrpc_positional_method(name, handler)
}
}
impl ParamsAlg for NamedParams {
fn finish<Compiler, Context, Args, Output, Handler>(
compiler: &Compiler,
name: &'static str,
arg_names: &'static [&'static str],
handler: Handler,
) -> Compiler::Methods
where
Compiler: JsonRpcAlg + JsonRpcMethodAlg<Context, Args, Output>,
Handler: ApplyAlg<Context, Args, Output = Output> + Send + Sync + 'static,
{
compiler.finish_jsonrpc_named_method(name, arg_names, handler)
}
}
impl<Compiler, Handler, Params, Handle> CompileJsonRpcProgram<Compiler> for Method<Handler, Params>
where
Compiler: JsonRpcApiAlg
+ HandlerContextAlg<Handler::Context, Handle = Handle>
+ JsonRpcMethodAlg<Handle, Handler::Args, Handler::Output>,
Handler: OperationAlg + ApplyAlg<Handle, Handler::Args> + Send + Sync + 'static,
Params: ParamsAlg,
{
type Methods = Compiler::Methods;
fn compile_jsonrpc_program(self, compiler: &Compiler) -> Self::Methods {
Params::finish(compiler, self.name, Handler::ARG_NAMES, self.handler)
}
}