use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use crate::error::QrpcResult;
pub trait QrpcMessage: Send + Sync + Sized + 'static {
fn cmd_id(&self) -> u32;
fn encode_vec(&self) -> Vec<u8>;
fn decode_vec(cmd_id: u32, data: &[u8]) -> QrpcResult<Self>;
}
pub trait QrpcCallback<S, M>: Send + Sync + 'static
where
S: Send + Sync + 'static,
M: QrpcMessage,
{
fn call(
&self,
state: Arc<S>,
peer_id: String,
message: M,
) -> Pin<Box<dyn Future<Output=QrpcResult<()>> + Send>>;
}
impl<S, M, F, Fut> QrpcCallback<S, M> for F
where
S: Send + Sync + 'static,
M: QrpcMessage,
F: Fn(Arc<S>, String, M) -> Fut + Send + Sync + 'static,
Fut: Future<Output=QrpcResult<()>> + Send + 'static,
{
fn call(
&self,
state: Arc<S>,
peer_id: String,
message: M,
) -> Pin<Box<dyn Future<Output=QrpcResult<()>> + Send>> {
Box::pin((self)(state, peer_id, message))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::QrpcError;
#[derive(Clone)]
struct DemoMsg(Vec<u8>);
impl QrpcMessage for DemoMsg {
fn cmd_id(&self) -> u32 {
42
}
fn encode_vec(&self) -> Vec<u8> {
self.0.clone()
}
fn decode_vec(cmd_id: u32, data: &[u8]) -> QrpcResult<Self> {
if cmd_id != 42 {
return Err(QrpcError::MessageDecode("bad cmd".to_string()));
}
Ok(Self(data.to_vec()))
}
}
#[tokio::test]
async fn blanket_callback_impl_works() {
let state = Arc::new(7usize);
let cb = |s: Arc<usize>, peer: String, msg: DemoMsg| async move {
assert_eq!(*s, 7);
assert_eq!(peer, "peer-1");
assert_eq!(msg.0, b"ok");
Ok(())
};
QrpcCallback::call(&cb, state, "peer-1".to_string(), DemoMsg(b"ok".to_vec()))
.await
.expect("callback must succeed");
}
}