pub use postcard_schema::{Schema, key::Key};
pub trait Endpoint {
type Request: Schema;
type Response: Schema;
const PATH: &'static str;
const REQ_KEY: Key;
const RESP_KEY: Key;
}
pub trait Topic {
type Message: Schema + ?Sized;
const PATH: &'static str;
const TOPIC_KEY: Key;
}
#[macro_export]
macro_rules! endpoint {
($tyname:ident, $req:tt $(< $req_lt:lifetime >)?, $resp:tt $(< $resp_lt:lifetime >)? $(,)?) => {
pub struct $tyname < $($req_lt,)? $($resp_lt)? > {
$(
_req_lt: core::marker::PhantomData<& $req_lt ()>,
)?
$(
_resp_lt: core::marker::PhantomData<& $resp_lt ()>,
)?
_priv: core::marker::PhantomData<()>,
}
impl < $($req_lt,)? $($resp_lt)? > $crate::traits::Endpoint for $tyname < $($req_lt,)? $($resp_lt)? > {
type Request = $req $(< $req_lt >)?;
type Response = $resp $(< $resp_lt >)?;
const PATH: &'static str = stringify!($tyname);
const REQ_KEY: $crate::traits::Key = $crate::traits::Key::for_path::<$req>(stringify!($tyname));
const RESP_KEY: $crate::traits::Key = $crate::traits::Key::for_path::<$resp>(stringify!($tyname));
}
};
($tyname:ident, $req:tt $(< $req_lt:lifetime >)?, $resp:tt $(< $resp_lt:lifetime >)?, $path:expr $(,)?) => {
pub struct $tyname < $($req_lt,)? $($resp_lt)? > {
$(
_req_lt: core::marker::PhantomData<& $req_lt ()>,
)?
$(
_resp_lt: core::marker::PhantomData<& $resp_lt ()>,
)?
_priv: core::marker::PhantomData<()>,
}
impl < $($req_lt,)? $($resp_lt)? > $crate::traits::Endpoint for $tyname < $($req_lt,)? $($resp_lt)? > {
type Request = $req $(< $req_lt >)?;
type Response = $resp $(< $resp_lt >)?;
const PATH: &'static str = $path;
const REQ_KEY: $crate::traits::Key = $crate::traits::Key::for_path::<$req>($path);
const RESP_KEY: $crate::traits::Key = $crate::traits::Key::for_path::<$resp>($path);
}
};
}
#[macro_export]
macro_rules! topic {
($tyname:ident, $msg:tt $(< $msg_lt:lifetime >)? $(,)?) => {
pub struct $tyname $(< $msg_lt >)? {
$(
_plt: core::marker::PhantomData<& $msg_lt ()>,
)?
_priv: core::marker::PhantomData<()>,
}
impl $(< $msg_lt >)? $crate::traits::Topic for $tyname $(< $msg_lt >)? {
type Message = $msg $(< $msg_lt >)?;
const PATH: &'static str = stringify!($tyname);
const TOPIC_KEY: $crate::traits::Key = $crate::traits::Key::for_path::<$msg>(stringify!($tyname));
}
};
($tyname:ident, $msg:tt $(< $msg_lt:lifetime >)?, $path:expr $(,)?) => {
pub struct $tyname $(< $msg_lt >)? {
$(
_plt: core::marker::PhantomData<& $msg_lt ()>,
)?
_priv: core::marker::PhantomData<()>,
}
impl $(< $msg_lt >)? $crate::traits::Topic for $tyname $(< $msg_lt >)? {
type Message = $msg $(< $msg_lt >)?;
const PATH: &'static str = $path;
const TOPIC_KEY: $crate::traits::Key = $crate::traits::Key::for_path::<$msg>($path);
}
};
}
#[cfg(test)]
mod test {
use postcard_schema::Schema;
use serde::{Deserialize, Serialize};
use crate::topic;
use crate::traits::{Endpoint, Topic};
#[derive(Schema, Debug, PartialEq, Serialize, Deserialize)]
pub struct Stir<'a> {
s: &'a str,
}
#[test]
fn test_topic_macro() {
topic!(OwnedTopic1, u32, "owned1/u32/topic");
topic!(OwnedTopic2, u32, "owned2/u32/topic",);
topic!(OwnedTopic3, u32);
topic!(OwnedTopic4, u32,);
assert_eq!(OwnedTopic1::PATH, "owned1/u32/topic");
assert_eq!(OwnedTopic2::PATH, "owned2/u32/topic");
assert_eq!(OwnedTopic3::PATH, "OwnedTopic3");
assert_eq!(OwnedTopic4::PATH, "OwnedTopic4");
topic!(BorrowedTopic1, Stir<'a>, "borrowed1/str/topic");
topic!(BorrowedTopic2, Stir<'a>, "borrowed2/str/topic",);
topic!(BorrowedTopic3, Stir<'a>);
topic!(BorrowedTopic4, Stir<'a>,);
assert_eq!(BorrowedTopic1::PATH, "borrowed1/str/topic");
assert_eq!(BorrowedTopic2::PATH, "borrowed2/str/topic",);
assert_eq!(BorrowedTopic3::PATH, "BorrowedTopic3");
assert_eq!(BorrowedTopic4::PATH, "BorrowedTopic4");
}
#[test]
fn test_endpoint_macro() {
endpoint!(OwnedEp1, u32, u32, "owned1/u32/ep");
endpoint!(OwnedEp2, u32, u32, "owned2/u32/ep",);
endpoint!(OwnedEp3, u32, u32);
endpoint!(OwnedEp4, u32, u32,);
assert_eq!(OwnedEp1::PATH, "owned1/u32/ep");
assert_eq!(OwnedEp2::PATH, "owned2/u32/ep");
assert_eq!(OwnedEp3::PATH, "OwnedEp3");
assert_eq!(OwnedEp4::PATH, "OwnedEp4");
endpoint!(ReqBRespOEp1, Stir<'a>, u32, "reqbrespo1/ep");
endpoint!(ReqBRespOEp2, Stir<'a>, u32, "reqbrespo2/ep",);
endpoint!(ReqBRespOEp3, Stir<'a>, u32);
endpoint!(ReqBRespOEp4, Stir<'a>, u32,);
assert_eq!(ReqBRespOEp1::PATH, "reqbrespo1/ep");
assert_eq!(ReqBRespOEp2::PATH, "reqbrespo2/ep");
assert_eq!(ReqBRespOEp3::PATH, "ReqBRespOEp3");
assert_eq!(ReqBRespOEp4::PATH, "ReqBRespOEp4");
endpoint!(ReqORespBEp1, u32, Stir<'a>, "reqorespb1/ep");
endpoint!(ReqORespBEp2, u32, Stir<'a>, "reqorespb2/ep",);
endpoint!(ReqORespBEp3, u32, Stir<'a>);
endpoint!(ReqORespBEp4, u32, Stir<'a>,);
assert_eq!(ReqORespBEp1::PATH, "reqorespb1/ep");
assert_eq!(ReqORespBEp2::PATH, "reqorespb2/ep");
assert_eq!(ReqORespBEp3::PATH, "ReqORespBEp3");
assert_eq!(ReqORespBEp4::PATH, "ReqORespBEp4");
endpoint!(ReqBRespBEp1, Stir<'a>, Stir<'b>, "reqbrespb1/ep");
endpoint!(ReqBRespBEp2, Stir<'a>, Stir<'b>, "reqbrespb2/ep",);
endpoint!(ReqBRespBEp3, Stir<'a>, Stir<'b>);
endpoint!(ReqBRespBEp4, Stir<'a>, Stir<'b>,);
assert_eq!(ReqBRespBEp1::PATH, "reqbrespb1/ep");
assert_eq!(ReqBRespBEp2::PATH, "reqbrespb2/ep");
assert_eq!(ReqBRespBEp3::PATH, "ReqBRespBEp3");
assert_eq!(ReqBRespBEp4::PATH, "ReqBRespBEp4");
}
}