#[macro_export]
macro_rules! protocol {
(
$(#[version($version:expr)])?
pub mod $protocol_name:ident {
$(
$(#[$command_attr:meta])*
$command:ident $(<$($command_lifetime:lifetime),*>)?
$( ( $tuple_ty:ty ) )? $( {
$(
$(#[$command_field_attr:meta])*
$command_field:ident : $command_field_ty:ty
),* $(,)?
} )?
$(->
$(#[$reply_attr:meta])*
{
$(
$(#[$reply_field_attr:meta])*
$reply_field:ident : $reply_field_ty:ty
),* $(,)?
}
)?
$(return $plain_reply:ty)?
);* $(;)?
}
) => {
$crate::paste! { pub mod $protocol_name {
use super::*;
pub const PROTOCOL_ID: u64 = {
const PROTOCOL_NAME: &str = concat!(
env!("CARGO_PKG_NAME"),
"::",
stringify!($protocol_name)
);
const VERSION: u32 = $crate::protocol!(@version $($version)?);
$crate::protocol_id(PROTOCOL_NAME, VERSION) };
pub const PROTOCOL_NAME: &str = stringify!($protocol_name);
pub const PROTOCOL_CRATE: &str = env!("CARGO_PKG_NAME");
pub const PROTOCOL_VERSION: u32 = $crate::protocol!(@version $($version)?);
pub struct ProtocolMarker;
impl $crate::ProtocolMetadata for ProtocolMarker { const PROTOCOL_ID: u64 = PROTOCOL_ID;
const PROTOCOL_NAME: &'static str = PROTOCOL_NAME;
const PROTOCOL_CRATE: &'static str = PROTOCOL_CRATE;
const PROTOCOL_VERSION: u32 = PROTOCOL_VERSION;
}
$(
pub mod $command {
use super::*;
$crate::protocol!(@request_struct
$(#[$command_attr])*
Request $(<$($command_lifetime),*>)?
$( ( $tuple_ty ) )?
$( {
$(
$(#[$command_field_attr])*
$command_field : $command_field_ty
),*
} )?
);
$crate::protocol!(@maybe_response_struct
$command
$(-> $(#[$reply_attr])* {
$(
$(#[$reply_field_attr])*
$reply_field : $reply_field_ty
),*
})?
$(return $plain_reply)?
);
}
)*
#[derive( $crate::Serialize, $crate::Deserialize)] #[allow(non_camel_case_types)]
pub enum Requests {
$(
$command($command::Request $(<$($command_lifetime),*>)?),
)*
}
pub trait Sender: $crate::RpcProtocolSender {
$(
$crate::protocol!(@sender_trait_method
in_paste
$command $(<$($command_lifetime),*>)?
$( ( $tuple_ty ) )?
$( {
$(
$command_field : $command_field_ty
),*
} )?
$(-> {
$(
$reply_field : $reply_field_ty
),*
})?
$(return $plain_reply)?
);
)*
}
pub trait Receive: Clone + Send + Sync + 'static {
$(
$crate::protocol!(@handler_fn
$command $(<$($command_lifetime),*>)?
$( ( $tuple_ty ) )?
$( {
$(
$command_field : $command_field_ty
),*
} )?
$(-> {
$(
$reply_field : $reply_field_ty
),*
})?
$(return $plain_reply)?
);
)*
fn into_receiver(self) -> Receiver<Self>
where
Self: Sized,
{
Receiver::new(self)
}
}
#[derive(Clone)]
pub struct Receiver<R: Receive> {
handler: R,
}
impl<R: Receive> std::fmt::Debug for Receiver<R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(stringify!(Receiver)).finish()
}
}
impl<R: Receive + 'static> Receiver<R> {
pub fn new(handler: R) -> Self {
Self { handler }
}
pub fn handler(&self) -> &R {
&self.handler
}
}
pub struct ReceiverWrapper<R: Receive> {
receiver: Receiver<R>,
}
impl<R: Receive> ReceiverWrapper<R> {
pub fn new(handler: R) -> Self {
Self {
receiver: Receiver::new(handler),
}
}
}
impl<R: Receive + 'static> $crate::ProtocolHandler for ReceiverWrapper<R> { fn handle_packet(
&self,
peer: &$crate::SocketPeer,
buf: Vec<u8>,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = anyhow::Result<Option<Vec<u8>>>> + Send + '_>> {
Box::pin(async move {
let request_wrapper: Requests = $crate::bincode::deserialize(&buf)?; let handler = self.receiver.handler.clone();
match request_wrapper {
$(
Requests::$command(request) => {
$crate::protocol!(@handler_body
handler,
request,
$command
$( ( $tuple_ty ) )?
$( {
$(
$command_field : $command_field_ty
),*
} )?
$(-> {
$(
$reply_field : $reply_field_ty
),*
})?
$(return $plain_reply)?
)
}
)*
}
})
}
}
impl<R: Receive + 'static> $crate::ReceiveRpcProtocol for Receiver<R> { async fn handle_packet(
&self,
_protocol_id: u64,
peer: &$crate::SocketPeer,
buf: Vec<u8>,
) -> anyhow::Result<Option<Vec<u8>>> {
let wrapper = ReceiverWrapper::new(self.handler.clone());
use $crate::ProtocolHandler; wrapper.handle_packet(peer, buf).await
}
}
}
}
};
(@version $version:expr) => { $version };
(@version) => { 1 };
(@request_struct $(#[$attr:meta])* Request $(<$($lifetime:lifetime),*>)? ( $tuple_ty:ty )) => {
$(#[$attr])*
#[derive( $crate::Serialize, $crate::Deserialize)] pub struct Request $(<$($lifetime),*>)? (pub $tuple_ty);
};
(@request_struct $(#[$attr:meta])* Request $(<$($lifetime:lifetime),*>)? { $($(#[$field_attr:meta])* $field:ident : $ft:ty),+ }) => {
$(#[$attr])*
#[derive( $crate::Serialize, $crate::Deserialize)] pub struct Request $(<$($lifetime),*>)? {
$($(#[$field_attr])* pub $field: $ft,)+
}
};
(@request_struct $(#[$attr:meta])* Request $(<$($lifetime:lifetime),*>)?) => {
$(#[$attr])*
#[derive( $crate::Serialize, $crate::Deserialize)] pub struct Request $(<$($lifetime),*>)? ;
};
(@maybe_response_struct $command:ident -> $(#[$attr:meta])* { $($(#[$field_attr:meta])* $field:ident : $ft:ty),* }) => {
$(#[$attr])*
#[derive( $crate::Serialize, $crate::Deserialize)] pub struct Response {
$($(#[$field_attr])* pub $field: $ft,)*
}
};
(@maybe_response_struct $command:ident return $plain_reply:ty) => {};
(@maybe_response_struct $command:ident) => {};
(@sender_trait_method in_paste $command:ident { $($command_field:ident : $command_field_ty:ty),* } -> { $($reply_field:ident : $reply_field_ty:ty),* }) => {
fn $command(&self, $($command_field: $command_field_ty,)*)
-> impl std::future::Future<Output = anyhow::Result<$command::Response>> + Send
{
async move {
let request = Requests::$command($command::Request { $($command_field,)* });
self.peer().send_message_with_response_to_protocol(PROTOCOL_ID, &request).await
}
}
};
(@sender_trait_method in_paste $command:ident { $($command_field:ident : $command_field_ty:ty),* } return $plain_reply:ty) => {
fn $command(&self, $($command_field: $command_field_ty,)*)
-> impl std::future::Future<Output = anyhow::Result<$plain_reply>> + Send
{
async move {
let request = Requests::$command($command::Request { $($command_field,)* });
self.peer().send_message_with_response_to_protocol(PROTOCOL_ID, &request).await
}
}
};
(@sender_trait_method in_paste $command:ident { $($command_field:ident : $command_field_ty:ty),* }) => {
fn $command(&self, $($command_field: $command_field_ty,)*)
-> impl std::future::Future<Output = anyhow::Result<()>> + Send
{
async move {
let request = Requests::$command($command::Request { $($command_field,)* });
self.peer().send_message_to_protocol(PROTOCOL_ID, &request).await
}
}
};
(@sender_trait_method in_paste $command:ident -> { $($reply_field:ident : $reply_field_ty:ty),* }) => {
fn $command(&self)
-> impl std::future::Future<Output = anyhow::Result<$command::Response>> + Send
{
async move {
let request = Requests::$command($command::Request);
self.peer().send_message_with_response_to_protocol(PROTOCOL_ID, &request).await
}
}
};
(@sender_trait_method in_paste $command:ident return $plain_reply:ty) => {
fn $command(&self)
-> impl std::future::Future<Output = anyhow::Result<$plain_reply>> + Send
{
async move {
let request = Requests::$command($command::Request);
self.peer().send_message_with_response_to_protocol(PROTOCOL_ID, &request).await
}
}
};
(@sender_trait_method in_paste $command:ident) => {
fn $command(&self)
-> impl std::future::Future<Output = anyhow::Result<()>> + Send
{
async move {
let request = Requests::$command($command::Request);
self.peer().send_message_to_protocol(PROTOCOL_ID, &request).await
}
}
};
(@handler_fn $command:ident { $($command_field:ident : $command_field_ty:ty),* } -> { $($reply_field:ident : $reply_field_ty:ty),* }) => {
fn $command(
&self,
$($command_field: $command_field_ty,)*
) -> impl std::future::Future<Output = anyhow::Result<$command::Response>> + Send + Sync;
};
(@handler_fn $command:ident { $($command_field:ident : $command_field_ty:ty),* } return $plain_reply:ty) => {
fn $command(
&self,
$($command_field: $command_field_ty,)*
) -> impl std::future::Future<Output = anyhow::Result<$plain_reply>> + Send + Sync;
};
(@handler_fn $command:ident { $($command_field:ident : $command_field_ty:ty),* }) => {
fn $command(
&self,
$($command_field: $command_field_ty,)*
) -> impl std::future::Future<Output = anyhow::Result<()>> + Send + Sync;
};
(@handler_fn $command:ident -> { $($reply_field:ident : $reply_field_ty:ty),* }) => {
fn $command(
&self,
) -> impl std::future::Future<Output = anyhow::Result<$command::Response>> + Send + Sync;
};
(@handler_fn $command:ident return $plain_reply:ty) => {
fn $command(
&self,
) -> impl std::future::Future<Output = anyhow::Result<$plain_reply>> + Send + Sync;
};
(@handler_fn $command:ident) => {
fn $command(
&self,
) -> impl std::future::Future<Output = anyhow::Result<()>> + Send + Sync;
};
(@handler_body $handler:ident, $request:ident, $command:ident { $($command_field:ident : $command_field_ty:ty),* } -> { $($reply_field:ident : $reply_field_ty:ty),* }) => {
{
let response = $handler.$command($($request.$command_field,)*).await?;
Ok(Some($crate::bincode::serialize(&response)?))
}
};
(@handler_body $handler:ident, $request:ident, $command:ident { $($command_field:ident : $command_field_ty:ty),* } return $plain_reply:ty) => {
{
let response = $handler.$command($($request.$command_field,)*).await?;
Ok(Some($crate::bincode::serialize(&response)?))
}
};
(@handler_body $handler:ident, $request:ident, $command:ident { $($command_field:ident : $command_field_ty:ty),* }) => {
{
$handler.$command($($request.$command_field,)*).await?;
Ok(None)
}
};
(@handler_body $handler:ident, $request:ident, $command:ident -> { $($reply_field:ident : $reply_field_ty:ty),* }) => {
{
let response = $handler.$command().await?;
Ok(Some($crate::bincode::serialize(&response)?))
}
};
(@handler_body $handler:ident, $request:ident, $command:ident return $plain_reply:ty) => {
{
let response = $handler.$command().await?;
Ok(Some($crate::bincode::serialize(&response)?))
} };
(@handler_body $handler:ident, $request:ident, $command:ident) => {
{
$handler.$command().await?;
Ok(None)
}
};
}
pub use protocol;