use std::marker::PhantomData;
use std::sync::Arc;
use std::time::Duration;
use dex_protocol::dex::Value as ProtoValue;
use crate::attribute::{AttributeLock, AttributeMap, AttributeMapLoad};
use crate::channel::{Channel, ChannelLoad, ChannelMap, ChannelMapLoad};
use crate::step::{ErasedValue, TypedValue};
use crate::value_mapper;
use crate::{Context, HandlerResult, SdkResult, StepMovement, Value};
pub struct Rpc<Input, Output> {
name: &'static str,
marker: PhantomData<fn(Input) -> Output>,
}
impl<Input, Output> Rpc<Input, Output> {
pub const fn new(name: &'static str) -> Self {
Self {
name,
marker: PhantomData,
}
}
pub fn timeout(self, timeout: Duration) -> RpcDefinition<Input, Output> {
RpcDefinition::from(self).timeout(timeout)
}
pub fn lock(self, lock: AttributeLock) -> RpcDefinition<Input, Output> {
RpcDefinition::from(self).lock(lock)
}
pub fn is_transactional(self) -> RpcDefinition<Input, Output> {
RpcDefinition::from(self).is_transactional()
}
pub fn load_attribute_map<T>(
self,
attribute_map: &AttributeMap<T>,
) -> RpcDefinition<Input, Output> {
RpcDefinition::from(self).load_attribute_map(attribute_map)
}
pub fn load_attribute_map_instance(
self,
load: AttributeMapLoad,
) -> RpcDefinition<Input, Output> {
RpcDefinition::from(self).load_attribute_map_instance(load)
}
pub fn load_channel<T>(self, channel: &Channel<T>) -> RpcDefinition<Input, Output> {
RpcDefinition::from(self).load_channel(channel)
}
pub fn load_channel_map<T>(self, channel_map: &ChannelMap<T>) -> RpcDefinition<Input, Output> {
RpcDefinition::from(self).load_channel_map(channel_map)
}
pub fn load_channel_map_instance(self, load: ChannelMapLoad) -> RpcDefinition<Input, Output> {
RpcDefinition::from(self).load_channel_map_instance(load)
}
pub(crate) fn name(&self) -> &'static str {
self.name
}
}
impl<Input, Output> Clone for Rpc<Input, Output> {
fn clone(&self) -> Self {
*self
}
}
impl<Input, Output> Copy for Rpc<Input, Output> {}
pub struct RpcDefinition<Input, Output> {
rpc: Rpc<Input, Output>,
timeout: Option<Duration>,
locks: Vec<AttributeLock>,
is_transactional: bool,
load_attribute_maps: Vec<AttributeMapLoad>,
load_channels: Vec<ChannelLoad>,
load_channel_maps: Vec<ChannelMapLoad>,
}
impl<Input, Output> RpcDefinition<Input, Output> {
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
pub fn lock(mut self, lock: AttributeLock) -> Self {
self.locks.push(lock);
self
}
pub fn is_transactional(mut self) -> Self {
self.is_transactional = true;
self
}
pub fn load_attribute_map<T>(mut self, attribute_map: &AttributeMap<T>) -> Self {
self.load_attribute_maps.push(AttributeMapLoad {
name: attribute_map.name().to_owned(),
instance: None,
});
self
}
pub fn load_attribute_map_instance(mut self, load: AttributeMapLoad) -> Self {
self.load_attribute_maps.push(load);
self
}
pub fn load_channel<T>(mut self, channel: &Channel<T>) -> Self {
self.load_channels.push(ChannelLoad {
name: channel.name().to_owned(),
});
self
}
pub fn load_channel_map<T>(mut self, channel_map: &ChannelMap<T>) -> Self {
self.load_channel_maps.push(ChannelMapLoad {
name: channel_map.name().to_owned(),
instance: None,
});
self
}
pub fn load_channel_map_instance(mut self, load: ChannelMapLoad) -> Self {
self.load_channel_maps.push(load);
self
}
}
impl<Input, Output> From<Rpc<Input, Output>> for RpcDefinition<Input, Output> {
fn from(rpc: Rpc<Input, Output>) -> Self {
Self {
rpc,
timeout: None,
locks: Vec::new(),
is_transactional: false,
load_attribute_maps: Vec::new(),
load_channels: Vec::new(),
load_channel_maps: Vec::new(),
}
}
}
pub struct RpcList<FlowType> {
definitions: Vec<Box<dyn RpcBinder<FlowType>>>,
}
impl<FlowType> RpcList<FlowType>
where
FlowType: Send + Sync + 'static,
{
pub fn new() -> Self {
Self {
definitions: Vec::new(),
}
}
pub fn function<Input, Output>(
mut self,
definition: impl Into<RpcDefinition<Input, Output>>,
handler: fn(&FlowType, &mut Context, Input) -> HandlerResult<RpcResult<Output>>,
) -> Self
where
Input: Value,
Output: Value,
{
self.definitions.push(Box::new(FunctionBinder {
definition: definition.into(),
handler,
}));
self
}
pub fn function_without_input<Output>(
mut self,
definition: impl Into<RpcDefinition<(), Output>>,
handler: fn(&FlowType, &mut Context) -> HandlerResult<RpcResult<Output>>,
) -> Self
where
Output: Value,
{
self.definitions.push(Box::new(FunctionWithoutInputBinder {
definition: definition.into(),
handler,
}));
self
}
pub fn procedure<Input>(
mut self,
definition: impl Into<RpcDefinition<Input, ()>>,
handler: fn(&FlowType, &mut Context, Input) -> HandlerResult<()>,
) -> Self
where
Input: Value,
{
self.definitions.push(Box::new(ProcedureBinder {
definition: definition.into(),
handler,
}));
self
}
pub fn procedure_without_input(
mut self,
definition: impl Into<RpcDefinition<(), ()>>,
handler: fn(&FlowType, &mut Context) -> HandlerResult<()>,
) -> Self {
self.definitions.push(Box::new(ProcedureWithoutInputBinder {
definition: definition.into(),
handler,
}));
self
}
pub(crate) fn bind(self, flow: Arc<FlowType>) -> Vec<RegisteredRpc> {
self.definitions
.into_iter()
.map(|definition| definition.bind(Arc::clone(&flow)))
.collect()
}
}
impl<FlowType> Default for RpcList<FlowType>
where
FlowType: Send + Sync + 'static,
{
fn default() -> Self {
Self::new()
}
}
pub struct RpcResult<Output> {
output: Output,
next_steps: Vec<StepMovement>,
cancel_step_types: Vec<&'static str>,
}
impl<Output: Value> RpcResult<Output> {
pub fn new(output: Output) -> Self {
Self {
output,
next_steps: Vec::new(),
cancel_step_types: Vec::new(),
}
}
pub fn then(mut self, movement: StepMovement) -> Self {
self.next_steps.push(movement);
self
}
pub fn cancel_step<SelectedStep>(mut self, step: &SelectedStep) -> Self
where
SelectedStep: crate::Step,
{
let step_type = step.step_type();
if !self.cancel_step_types.contains(&step_type) {
self.cancel_step_types.push(step_type);
}
self
}
pub fn output(&self) -> &Output {
&self.output
}
pub fn next_steps(&self) -> &[StepMovement] {
&self.next_steps
}
}
pub(crate) struct ErasedRpcResult {
pub(crate) output: Box<dyn ErasedValue>,
pub(crate) next_steps: Vec<StepMovement>,
pub(crate) cancel_step_types: Vec<&'static str>,
}
#[derive(Clone)]
pub(crate) struct RegisteredRpc {
pub(crate) name: &'static str,
pub(crate) timeout: Option<Duration>,
pub(crate) locks: Vec<AttributeLock>,
pub(crate) is_transactional: bool,
pub(crate) load_attribute_maps: Vec<AttributeMapLoad>,
pub(crate) load_channels: Vec<ChannelLoad>,
pub(crate) load_channel_maps: Vec<ChannelMapLoad>,
pub(crate) handler: Arc<dyn ErasedRpc>,
}
pub(crate) trait ErasedRpc: Send + Sync {
fn invoke(&self, context: &mut Context, input: &ProtoValue) -> HandlerResult<ErasedRpcResult>;
}
trait RpcBinder<FlowType>: Send + Sync {
fn bind(self: Box<Self>, flow: Arc<FlowType>) -> RegisteredRpc;
}
struct FunctionBinder<FlowType, Input, Output> {
definition: RpcDefinition<Input, Output>,
handler: fn(&FlowType, &mut Context, Input) -> HandlerResult<RpcResult<Output>>,
}
impl<FlowType, Input, Output> RpcBinder<FlowType> for FunctionBinder<FlowType, Input, Output>
where
FlowType: Send + Sync + 'static,
Input: Value,
Output: Value,
{
fn bind(self: Box<Self>, flow: Arc<FlowType>) -> RegisteredRpc {
registered_rpc(
self.definition,
Arc::new(BoundFunction {
flow,
handler: self.handler,
}),
)
}
}
struct BoundFunction<FlowType, Input, Output> {
flow: Arc<FlowType>,
handler: fn(&FlowType, &mut Context, Input) -> HandlerResult<RpcResult<Output>>,
}
impl<FlowType, Input, Output> ErasedRpc for BoundFunction<FlowType, Input, Output>
where
FlowType: Send + Sync + 'static,
Input: Value,
Output: Value,
{
fn invoke(&self, context: &mut Context, input: &ProtoValue) -> HandlerResult<ErasedRpcResult> {
let result = (self.handler)(&self.flow, context, value_mapper::decode_handler(input)?)?;
Ok(ErasedRpcResult {
output: Box::new(TypedValue(result.output)),
next_steps: result.next_steps,
cancel_step_types: result.cancel_step_types,
})
}
}
struct FunctionWithoutInputBinder<FlowType, Output> {
definition: RpcDefinition<(), Output>,
handler: fn(&FlowType, &mut Context) -> HandlerResult<RpcResult<Output>>,
}
impl<FlowType, Output> RpcBinder<FlowType> for FunctionWithoutInputBinder<FlowType, Output>
where
FlowType: Send + Sync + 'static,
Output: Value,
{
fn bind(self: Box<Self>, flow: Arc<FlowType>) -> RegisteredRpc {
registered_rpc(
self.definition,
Arc::new(BoundFunctionWithoutInput {
flow,
handler: self.handler,
}),
)
}
}
struct BoundFunctionWithoutInput<FlowType, Output> {
flow: Arc<FlowType>,
handler: fn(&FlowType, &mut Context) -> HandlerResult<RpcResult<Output>>,
}
impl<FlowType, Output> ErasedRpc for BoundFunctionWithoutInput<FlowType, Output>
where
FlowType: Send + Sync + 'static,
Output: Value,
{
fn invoke(&self, context: &mut Context, _input: &ProtoValue) -> HandlerResult<ErasedRpcResult> {
let result = (self.handler)(&self.flow, context)?;
Ok(ErasedRpcResult {
output: Box::new(TypedValue(result.output)),
next_steps: result.next_steps,
cancel_step_types: result.cancel_step_types,
})
}
}
struct ProcedureBinder<FlowType, Input> {
definition: RpcDefinition<Input, ()>,
handler: fn(&FlowType, &mut Context, Input) -> HandlerResult<()>,
}
impl<FlowType, Input> RpcBinder<FlowType> for ProcedureBinder<FlowType, Input>
where
FlowType: Send + Sync + 'static,
Input: Value,
{
fn bind(self: Box<Self>, flow: Arc<FlowType>) -> RegisteredRpc {
registered_rpc(
self.definition,
Arc::new(BoundProcedure {
flow,
handler: self.handler,
}),
)
}
}
struct BoundProcedure<FlowType, Input> {
flow: Arc<FlowType>,
handler: fn(&FlowType, &mut Context, Input) -> HandlerResult<()>,
}
impl<FlowType, Input> ErasedRpc for BoundProcedure<FlowType, Input>
where
FlowType: Send + Sync + 'static,
Input: Value,
{
fn invoke(&self, context: &mut Context, input: &ProtoValue) -> HandlerResult<ErasedRpcResult> {
(self.handler)(&self.flow, context, value_mapper::decode_handler(input)?)?;
Ok(empty_rpc_result())
}
}
struct ProcedureWithoutInputBinder<FlowType> {
definition: RpcDefinition<(), ()>,
handler: fn(&FlowType, &mut Context) -> HandlerResult<()>,
}
impl<FlowType> RpcBinder<FlowType> for ProcedureWithoutInputBinder<FlowType>
where
FlowType: Send + Sync + 'static,
{
fn bind(self: Box<Self>, flow: Arc<FlowType>) -> RegisteredRpc {
registered_rpc(
self.definition,
Arc::new(BoundProcedureWithoutInput {
flow,
handler: self.handler,
}),
)
}
}
struct BoundProcedureWithoutInput<FlowType> {
flow: Arc<FlowType>,
handler: fn(&FlowType, &mut Context) -> HandlerResult<()>,
}
impl<FlowType> ErasedRpc for BoundProcedureWithoutInput<FlowType>
where
FlowType: Send + Sync + 'static,
{
fn invoke(&self, context: &mut Context, _input: &ProtoValue) -> HandlerResult<ErasedRpcResult> {
(self.handler)(&self.flow, context)?;
Ok(empty_rpc_result())
}
}
fn registered_rpc<Input, Output>(
definition: RpcDefinition<Input, Output>,
handler: Arc<dyn ErasedRpc>,
) -> RegisteredRpc {
RegisteredRpc {
name: definition.rpc.name,
timeout: definition.timeout,
locks: definition.locks,
is_transactional: definition.is_transactional,
load_attribute_maps: definition.load_attribute_maps,
load_channels: definition.load_channels,
load_channel_maps: definition.load_channel_maps,
handler,
}
}
fn empty_rpc_result() -> ErasedRpcResult {
ErasedRpcResult {
output: Box::new(TypedValue(())),
next_steps: Vec::new(),
cancel_step_types: Vec::new(),
}
}
pub(crate) fn encode_rpc_output(output: &dyn ErasedValue) -> SdkResult<ProtoValue> {
output.encode()
}