use cratestack_core::CoolError;
use crate::codec::HttpClientCodec;
use crate::rpc::batch::BatchBuilder;
use crate::rpc::client::RpcClient;
use crate::rpc::error::RpcClientError;
#[must_use = "BatchableCall does nothing until `.await`ed or `.queue(&mut batch)`d"]
pub struct BatchableCall<C, O> {
rpc: RpcClient<C>,
op_id: String,
input_value: Result<serde_json::Value, CoolError>,
_output: std::marker::PhantomData<fn() -> O>,
}
impl<C, O> BatchableCall<C, O>
where
C: HttpClientCodec + Clone + Send + 'static,
O: serde::de::DeserializeOwned + Send + 'static,
{
pub fn new<I>(rpc: RpcClient<C>, op_id: impl Into<String>, input: &I) -> Self
where
I: serde::Serialize,
{
let input_value = serde_json::to_value(input)
.map_err(|error| CoolError::Codec(format!("encode batch input: {error}")));
Self {
rpc,
op_id: op_id.into(),
input_value,
_output: std::marker::PhantomData,
}
}
pub fn queue(self, batch: &mut BatchBuilder<C>) -> BatchHandle<O> {
let id = match self.input_value {
Ok(value) => batch.push_frame(self.op_id, value),
Err(error) => batch.push_failed_frame(error),
};
BatchHandle {
id,
_output: std::marker::PhantomData,
}
}
}
impl<C, O> std::future::IntoFuture for BatchableCall<C, O>
where
C: HttpClientCodec + Clone + Send + 'static,
O: serde::de::DeserializeOwned + Send + 'static,
{
type Output = Result<O, RpcClientError>;
type IntoFuture = std::pin::Pin<Box<dyn std::future::Future<Output = Self::Output> + Send>>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(async move {
let value = self.input_value.map_err(RpcClientError::Codec)?;
self.rpc
.call::<serde_json::Value, O>(&self.op_id, &value)
.await
})
}
}
pub struct BatchHandle<O> {
pub(crate) id: u64,
pub(crate) _output: std::marker::PhantomData<fn() -> O>,
}
impl<O> Clone for BatchHandle<O> {
fn clone(&self) -> Self {
Self {
id: self.id,
_output: std::marker::PhantomData,
}
}
}
impl<O> Copy for BatchHandle<O> {}
impl<O> std::fmt::Debug for BatchHandle<O> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BatchHandle").field("id", &self.id).finish()
}
}