Tcp relay update; refactoring type tag
This commit is contained in:
parent
bc862cfac6
commit
18bd3c63f4
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "messagebus"
|
name = "messagebus"
|
||||||
version = "0.9.9"
|
version = "0.9.10"
|
||||||
authors = ["Andrey Tkachenko <andrey@aidev.ru>"]
|
authors = ["Andrey Tkachenko <andrey@aidev.ru>"]
|
||||||
repository = "https://github.com/andreytkachenko/messagebus.git"
|
repository = "https://github.com/andreytkachenko/messagebus.git"
|
||||||
keywords = ["futures", "async", "tokio", "message", "bus"]
|
keywords = ["futures", "async", "tokio", "message", "bus"]
|
||||||
@ -17,7 +17,8 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
messagebus_derive = "0.2.4"
|
messagebus_derive = "0.2.5"
|
||||||
|
|
||||||
tokio = { version = "1", features = ["parking_lot", "rt-multi-thread", "sync", "time"] }
|
tokio = { version = "1", features = ["parking_lot", "rt-multi-thread", "sync", "time"] }
|
||||||
parking_lot = "0.11"
|
parking_lot = "0.11"
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
@ -30,6 +31,7 @@ erased-serde = "0.3"
|
|||||||
serde = "1"
|
serde = "1"
|
||||||
serde_derive = "1"
|
serde_derive = "1"
|
||||||
dashmap = "4.0"
|
dashmap = "4.0"
|
||||||
|
ctor = "0.1.21"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "messagebus_derive"
|
name = "messagebus_derive"
|
||||||
version = "0.2.4"
|
version = "0.2.5"
|
||||||
authors = ["Andrey Tkachenko <andrey@aidev.ru>"]
|
authors = ["Andrey Tkachenko <andrey@aidev.ru>"]
|
||||||
repository = "https://github.com/andreytkachenko/messagebus.git"
|
repository = "https://github.com/andreytkachenko/messagebus.git"
|
||||||
keywords = ["futures", "async", "tokio", "message", "bus"]
|
keywords = ["futures", "async", "tokio", "message", "bus"]
|
||||||
|
@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
// use proc_macro::{TokenStream};
|
||||||
use quote::quote;
|
use proc_macro2::{Ident, Span, TokenStream};
|
||||||
|
use quote::{ToTokens, quote};
|
||||||
|
use std::collections::hash_map;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
use std::hash::Hasher;
|
||||||
use syn::parse::{Parse, ParseStream};
|
use syn::parse::{Parse, ParseStream};
|
||||||
use syn::{parenthesized, Result};
|
use syn::{parenthesized, Result};
|
||||||
use syn::{punctuated::Punctuated, token::Comma, DeriveInput};
|
use syn::{punctuated::Punctuated, token::Comma, DeriveInput};
|
||||||
@ -126,6 +129,7 @@ fn type_tag_part(
|
|||||||
fn type_tag_() -> messagebus::TypeTag { format!(#type_name, #type_values).into() }
|
fn type_tag_() -> messagebus::TypeTag { format!(#type_name, #type_values).into() }
|
||||||
fn type_tag(&self) -> messagebus::TypeTag { Self::type_tag_() }
|
fn type_tag(&self) -> messagebus::TypeTag { Self::type_tag_() }
|
||||||
fn type_name(&self) -> std::borrow::Cow<str> { Self::type_tag_() }
|
fn type_name(&self) -> std::borrow::Cow<str> { Self::type_tag_() }
|
||||||
|
fn type_layout(&self) -> std::alloc::Layout { std::alloc::Layout::for_value(self) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -134,6 +138,7 @@ fn type_tag_part(
|
|||||||
fn type_tag_() -> messagebus::TypeTag { #type_name.into() }
|
fn type_tag_() -> messagebus::TypeTag { #type_name.into() }
|
||||||
fn type_tag(&self) -> messagebus::TypeTag { Self::type_tag_() }
|
fn type_tag(&self) -> messagebus::TypeTag { Self::type_tag_() }
|
||||||
fn type_name(&self) -> std::borrow::Cow<str> { Self::type_tag_() }
|
fn type_name(&self) -> std::borrow::Cow<str> { Self::type_tag_() }
|
||||||
|
fn type_layout(&self) -> std::alloc::Layout { std::alloc::Layout::for_value(self) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,7 +201,7 @@ impl Parse for Tags {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(Message, attributes(type_tag, message, namespace))]
|
#[proc_macro_derive(Message, attributes(type_tag, message, namespace))]
|
||||||
pub fn derive_message(input: TokenStream) -> TokenStream {
|
pub fn derive_message(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
let mut tags = Tags::default();
|
let mut tags = Tags::default();
|
||||||
let mut type_tag = None;
|
let mut type_tag = None;
|
||||||
let mut namespace = None;
|
let mut namespace = None;
|
||||||
@ -231,12 +236,32 @@ pub fn derive_message(input: TokenStream) -> TokenStream {
|
|||||||
for mut param in impl_generics.params.pairs_mut() {
|
for mut param in impl_generics.params.pairs_mut() {
|
||||||
match &mut param.value_mut() {
|
match &mut param.value_mut() {
|
||||||
syn::GenericParam::Lifetime(_) => {}
|
syn::GenericParam::Lifetime(_) => {}
|
||||||
syn::GenericParam::Type(param) => {
|
syn::GenericParam::Type(params) => {
|
||||||
let bound: syn::TypeParamBound =
|
let bound: syn::TypeParamBound =
|
||||||
syn::parse_str("messagebus::MessageBounds").unwrap();
|
syn::parse_str("messagebus::MessageBounds").unwrap();
|
||||||
param.bounds.push(bound);
|
|
||||||
|
params.bounds.push(bound);
|
||||||
|
|
||||||
|
if tags.has_shared {
|
||||||
|
let bound: syn::TypeParamBound =
|
||||||
|
syn::parse_str("messagebus::__reexport::serde::Serialize").unwrap();
|
||||||
|
|
||||||
|
params.bounds.push(bound);
|
||||||
|
|
||||||
|
let bound: syn::TypeParamBound =
|
||||||
|
syn::parse_str("messagebus::__reexport::serde::Deserialize<'de>").unwrap();
|
||||||
|
|
||||||
|
params.bounds.push(bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
if tags.has_clone {
|
||||||
|
let bound: syn::TypeParamBound =
|
||||||
|
syn::parse_str("core::clone::Clone").unwrap();
|
||||||
|
|
||||||
|
params.bounds.push(bound);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
syn::GenericParam::Const(_param) => {}
|
syn::GenericParam::Const(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,6 +269,23 @@ pub fn derive_message(input: TokenStream) -> TokenStream {
|
|||||||
let shared_part = shared_part(&ast, tags.has_shared);
|
let shared_part = shared_part(&ast, tags.has_shared);
|
||||||
let clone_part = clone_part(&ast, tags.has_clone);
|
let clone_part = clone_part(&ast, tags.has_clone);
|
||||||
|
|
||||||
|
let init = Ident::new(&format!("__init_{}", hash(ast.clone().into_token_stream())), Span::call_site());
|
||||||
|
let init_impl = if tags.has_shared && impl_generics.params.is_empty() {
|
||||||
|
quote! {
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
#[messagebus::ctor::ctor]
|
||||||
|
fn #init() {
|
||||||
|
messagebus::register_shared_message::<#name>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote!{}
|
||||||
|
};
|
||||||
|
|
||||||
|
if !impl_generics.params.is_empty() && tags.has_shared {
|
||||||
|
impl_generics.params.push(syn::GenericParam::Lifetime(syn::LifetimeDef::new(syn::Lifetime::new("'de", Span::call_site()))))
|
||||||
|
}
|
||||||
|
|
||||||
let tokens = quote! {
|
let tokens = quote! {
|
||||||
#type_tag_part
|
#type_tag_part
|
||||||
|
|
||||||
@ -256,13 +298,15 @@ pub fn derive_message(input: TokenStream) -> TokenStream {
|
|||||||
#shared_part
|
#shared_part
|
||||||
#clone_part
|
#clone_part
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#init_impl
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens.into()
|
tokens.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(Error, attributes(type_tag, namespace))]
|
#[proc_macro_derive(Error, attributes(type_tag, namespace))]
|
||||||
pub fn derive_error(input: TokenStream) -> TokenStream {
|
pub fn derive_error(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
let mut type_tag = None;
|
let mut type_tag = None;
|
||||||
let mut namespace = None;
|
let mut namespace = None;
|
||||||
|
|
||||||
@ -292,3 +336,9 @@ pub fn derive_error(input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
tokens.into()
|
tokens.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hash(input: TokenStream) -> u64 {
|
||||||
|
let mut hasher = hash_map::DefaultHasher::new();
|
||||||
|
hasher.write(input.to_string().as_bytes());
|
||||||
|
hasher.finish()
|
||||||
|
}
|
@ -33,8 +33,6 @@ async fn main() {
|
|||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let (b, poller) = Bus::build()
|
let (b, poller) = Bus::build()
|
||||||
.register_shared_message::<Req>()
|
|
||||||
.register_shared_message::<Resp>()
|
|
||||||
.register_relay(relay)
|
.register_relay(relay)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -70,8 +70,6 @@ async fn main() {
|
|||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let (b, poller) = Bus::build()
|
let (b, poller) = Bus::build()
|
||||||
.register_shared_message::<Req>()
|
|
||||||
.register_shared_message::<Resp>()
|
|
||||||
.register_relay(relay)
|
.register_relay(relay)
|
||||||
.register(TmpReceiver)
|
.register(TmpReceiver)
|
||||||
.subscribe_async::<Req>(8, Default::default())
|
.subscribe_async::<Req>(8, Default::default())
|
||||||
|
@ -30,8 +30,6 @@ async fn main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let (b, poller) = Bus::build()
|
let (b, poller) = Bus::build()
|
||||||
.register_shared_message::<Req>()
|
|
||||||
.register_shared_message::<Resp>()
|
|
||||||
.register_relay(relay)
|
.register_relay(relay)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -67,8 +67,6 @@ async fn main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let (b, poller) = Bus::build()
|
let (b, poller) = Bus::build()
|
||||||
.register_shared_message::<Req>()
|
|
||||||
.register_shared_message::<Resp>()
|
|
||||||
.register_relay(relay)
|
.register_relay(relay)
|
||||||
.register(TmpReceiver)
|
.register(TmpReceiver)
|
||||||
.subscribe_async::<Req>(8, Default::default())
|
.subscribe_async::<Req>(8, Default::default())
|
||||||
|
@ -288,7 +288,7 @@ pub struct ProtocolPacket<'a> {
|
|||||||
impl<'a> ProtocolPacket<'a> {
|
impl<'a> ProtocolPacket<'a> {
|
||||||
pub fn deserialize(
|
pub fn deserialize(
|
||||||
self,
|
self,
|
||||||
bus: &Bus,
|
_bus: &Bus,
|
||||||
) -> Result<ProtocolItem, crate::error::Error>
|
) -> Result<ProtocolItem, crate::error::Error>
|
||||||
{
|
{
|
||||||
let type_tag: Option<TypeTag> = if self.header.flags.contains(ProtocolHeaderFlags::TYPE_TAG) {
|
let type_tag: Option<TypeTag> = if self.header.flags.contains(ProtocolHeaderFlags::TYPE_TAG) {
|
||||||
@ -309,7 +309,7 @@ impl<'a> ProtocolPacket<'a> {
|
|||||||
} else if self.header.flags.contains(ProtocolHeaderFlags::TT_AND_BODY) {
|
} else if self.header.flags.contains(ProtocolHeaderFlags::TT_AND_BODY) {
|
||||||
let body = self.body.ok_or_else(|| crate::error::Error::ProtocolParseError("No body".to_string()))?;
|
let body = self.body.ok_or_else(|| crate::error::Error::ProtocolParseError("No body".to_string()))?;
|
||||||
let res = generic_deserialize(self.header.body_type, body.as_ref(), |de| {
|
let res = generic_deserialize(self.header.body_type, body.as_ref(), |de| {
|
||||||
bus.deserialize_message(type_tag.clone().unwrap(), de)
|
messagebus::deserialize_shared_message(type_tag.clone().unwrap(), de)
|
||||||
.map_err(|x| x.map_msg(|_| ()))
|
.map_err(|x| x.map_msg(|_| ()))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -436,7 +436,6 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_proto_pack_event() {
|
fn test_proto_pack_event() {
|
||||||
let (bus, _) = Bus::build()
|
let (bus, _) = Bus::build()
|
||||||
.register_shared_message::<TestSharedMessage>()
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let pkt = ProtocolPacket {
|
let pkt = ProtocolPacket {
|
||||||
@ -476,7 +475,6 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_proto_pack_event_error() {
|
fn test_proto_pack_event_error() {
|
||||||
let (bus, _) = Bus::build()
|
let (bus, _) = Bus::build()
|
||||||
.register_shared_message::<TestSharedMessage>()
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let pkt = ProtocolPacket {
|
let pkt = ProtocolPacket {
|
||||||
|
@ -1,21 +1,15 @@
|
|||||||
use core::{marker::PhantomData, pin::Pin};
|
use core::{marker::PhantomData, pin::Pin};
|
||||||
|
|
||||||
use std::{collections::{HashMap, HashSet}, sync::{Arc, atomic::{AtomicU64, Ordering}}};
|
use std::{collections::HashSet, sync::{Arc, atomic::{AtomicU64, Ordering}}};
|
||||||
|
|
||||||
use futures::{Future, FutureExt};
|
use futures::{Future, FutureExt};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use crate::{AsyncBatchHandler, AsyncBatchSynchronizedHandler, AsyncHandler, AsyncSynchronizedHandler, BatchHandler, BatchSynchronizedHandler, Bus, BusInner, Handler, Message, Relay, SharedMessage, SynchronizedHandler, TypeTag, Untyped, envelop::IntoSharedMessage, error::{Error, StdSyncSendError}, receiver::{
|
use crate::{AsyncBatchHandler, AsyncBatchSynchronizedHandler, AsyncHandler, AsyncSynchronizedHandler, BatchHandler, BatchSynchronizedHandler, Bus, BusInner, Handler, Message, Relay, SynchronizedHandler, Untyped, error::StdSyncSendError, receiver::{
|
||||||
BusPollerCallback, Receiver, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
BusPollerCallback, Receiver, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver,
|
||||||
UntypedPollerCallback,
|
UntypedPollerCallback,
|
||||||
}, receivers};
|
}, receivers};
|
||||||
|
|
||||||
type MessageDeserializerCallback = Box<
|
|
||||||
dyn Fn(&mut dyn erased_serde::Deserializer<'_>) -> Result<Box<dyn SharedMessage>, Error>
|
|
||||||
+ Send
|
|
||||||
+ Sync,
|
|
||||||
>;
|
|
||||||
|
|
||||||
static RECEVIER_ID_SEQ: AtomicU64 = AtomicU64::new(1);
|
static RECEVIER_ID_SEQ: AtomicU64 = AtomicU64::new(1);
|
||||||
|
|
||||||
pub trait ReceiverSubscriberBuilder<T, M, R, E>:
|
pub trait ReceiverSubscriberBuilder<T, M, R, E>:
|
||||||
@ -204,23 +198,8 @@ impl<T, F, P, B> RegisterEntry<SyncEntry, T, F, P, B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MessageTypeDescriptor {
|
|
||||||
de: MessageDeserializerCallback,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MessageTypeDescriptor {
|
|
||||||
#[inline]
|
|
||||||
pub fn deserialize_boxed(
|
|
||||||
&self,
|
|
||||||
de: &mut dyn erased_serde::Deserializer<'_>,
|
|
||||||
) -> Result<Box<dyn SharedMessage>, Error> {
|
|
||||||
(self.de)(de)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
message_types: HashMap<TypeTag, MessageTypeDescriptor>,
|
|
||||||
receivers: HashSet<Receiver>,
|
receivers: HashSet<Receiver>,
|
||||||
pollings: Vec<BusPollerCallback>,
|
pollings: Vec<BusPollerCallback>,
|
||||||
}
|
}
|
||||||
@ -228,28 +207,11 @@ pub struct Module {
|
|||||||
impl Module {
|
impl Module {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
message_types: HashMap::new(),
|
|
||||||
receivers: HashSet::new(),
|
receivers: HashSet::new(),
|
||||||
pollings: Vec::new(),
|
pollings: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_shared_message<
|
|
||||||
M: Message + Clone + serde::Serialize + serde::de::DeserializeOwned,
|
|
||||||
>(
|
|
||||||
mut self,
|
|
||||||
) -> Self {
|
|
||||||
println!("insert {}", M::type_tag_());
|
|
||||||
self.message_types.insert(
|
|
||||||
M::type_tag_(),
|
|
||||||
MessageTypeDescriptor {
|
|
||||||
de: Box::new(move |de| Ok(M::deserialize(de)?.into_shared())),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register_relay<S: Relay + Send + Sync + 'static>(mut self, inner: S) -> Self {
|
pub fn register_relay<S: Relay + Send + Sync + 'static>(mut self, inner: S) -> Self {
|
||||||
let receiver = Receiver::new_relay::<S>(RECEVIER_ID_SEQ.fetch_add(1, Ordering::Relaxed), inner);
|
let receiver = Receiver::new_relay::<S>(RECEVIER_ID_SEQ.fetch_add(1, Ordering::Relaxed), inner);
|
||||||
self.pollings.push(receiver.start_polling());
|
self.pollings.push(receiver.start_polling());
|
||||||
@ -303,7 +265,6 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_module(mut self, module: Module) -> Self {
|
pub fn add_module(mut self, module: Module) -> Self {
|
||||||
self.message_types.extend(module.message_types);
|
|
||||||
self.pollings.extend(module.pollings);
|
self.pollings.extend(module.pollings);
|
||||||
self.receivers.extend(module.receivers);
|
self.receivers.extend(module.receivers);
|
||||||
|
|
||||||
@ -322,16 +283,6 @@ impl BusBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn register_shared_message<
|
|
||||||
M: Message + Clone + serde::Serialize + serde::de::DeserializeOwned,
|
|
||||||
>(
|
|
||||||
self,
|
|
||||||
) -> Self {
|
|
||||||
let inner = self.inner.register_shared_message::<M>();
|
|
||||||
|
|
||||||
BusBuilder { inner }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register_relay<S: Relay + Send + Sync + 'static>(self, inner: S) -> Self {
|
pub fn register_relay<S: Relay + Send + Sync + 'static>(self, inner: S) -> Self {
|
||||||
let inner = self.inner.register_relay(inner);
|
let inner = self.inner.register_relay(inner);
|
||||||
|
|
||||||
@ -388,7 +339,7 @@ impl BusBuilder {
|
|||||||
|
|
||||||
pub fn build(self) -> (Bus, impl Future<Output = ()>) {
|
pub fn build(self) -> (Bus, impl Future<Output = ()>) {
|
||||||
let bus = Bus {
|
let bus = Bus {
|
||||||
inner: Arc::new(BusInner::new(self.inner.receivers, self.inner.message_types)),
|
inner: Arc::new(BusInner::new(self.inner.receivers)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut futs = Vec::with_capacity(self.inner.pollings.len() * 2);
|
let mut futs = Vec::with_capacity(self.inner.pollings.len() * 2);
|
||||||
|
@ -3,7 +3,7 @@ use core::{
|
|||||||
fmt,
|
fmt,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{borrow::Cow, sync::Arc};
|
use std::{alloc::Layout, borrow::Cow, sync::Arc};
|
||||||
|
|
||||||
pub trait MessageBounds: TypeTagged + fmt::Debug + Unpin + Send + Sync + 'static {}
|
pub trait MessageBounds: TypeTagged + fmt::Debug + Unpin + Send + Sync + 'static {}
|
||||||
impl<T: TypeTagged + fmt::Debug + Unpin + Send + Sync + 'static> MessageBounds for T {}
|
impl<T: TypeTagged + fmt::Debug + Unpin + Send + Sync + 'static> MessageBounds for T {}
|
||||||
@ -17,6 +17,7 @@ pub trait TypeTagged {
|
|||||||
|
|
||||||
fn type_tag(&self) -> TypeTag;
|
fn type_tag(&self) -> TypeTag;
|
||||||
fn type_name(&self) -> Cow<str>;
|
fn type_name(&self) -> Cow<str>;
|
||||||
|
fn type_layout(&self) -> Layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Message: MessageBounds {
|
pub trait Message: MessageBounds {
|
||||||
@ -48,6 +49,9 @@ macro_rules! gen_impls {
|
|||||||
fn type_name(&self) -> Cow<str> {
|
fn type_name(&self) -> Cow<str> {
|
||||||
type_name::<$t>().into()
|
type_name::<$t>().into()
|
||||||
}
|
}
|
||||||
|
fn type_layout(&self) -> Layout {
|
||||||
|
Layout::for_value(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gen_impls!{ $($rest)* }
|
gen_impls!{ $($rest)* }
|
||||||
@ -64,6 +68,9 @@ macro_rules! gen_impls {
|
|||||||
fn type_name(&self) -> Cow<str> {
|
fn type_name(&self) -> Cow<str> {
|
||||||
type_name::<$t>().into()
|
type_name::<$t>().into()
|
||||||
}
|
}
|
||||||
|
fn type_layout(&self) -> Layout {
|
||||||
|
Layout::for_value(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -90,6 +97,9 @@ impl<T: TypeTagged> TypeTagged for Arc<T> {
|
|||||||
fn type_name(&self) -> Cow<str> {
|
fn type_name(&self) -> Cow<str> {
|
||||||
T::type_name(&*self)
|
T::type_name(&*self)
|
||||||
}
|
}
|
||||||
|
fn type_layout(&self) -> Layout {
|
||||||
|
Layout::for_value(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: TypeTagged> TypeTagged for Box<T> {
|
impl<T: TypeTagged> TypeTagged for Box<T> {
|
||||||
@ -103,6 +113,9 @@ impl<T: TypeTagged> TypeTagged for Box<T> {
|
|||||||
fn type_name(&self) -> Cow<str> {
|
fn type_name(&self) -> Cow<str> {
|
||||||
T::type_name(&*self)
|
T::type_name(&*self)
|
||||||
}
|
}
|
||||||
|
fn type_layout(&self) -> Layout {
|
||||||
|
Layout::for_value(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Message for () {
|
impl Message for () {
|
||||||
@ -226,6 +239,9 @@ mod tests {
|
|||||||
fn type_name(&self) -> Cow<str> {
|
fn type_name(&self) -> Cow<str> {
|
||||||
type_name::<Self>().into()
|
type_name::<Self>().into()
|
||||||
}
|
}
|
||||||
|
fn type_layout(&self) -> Layout {
|
||||||
|
Layout::for_value(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Message for Msg0 {
|
impl Message for Msg0 {
|
||||||
@ -279,6 +295,9 @@ mod tests {
|
|||||||
fn type_name(&self) -> Cow<str> {
|
fn type_name(&self) -> Cow<str> {
|
||||||
type_name::<Self>().into()
|
type_name::<Self>().into()
|
||||||
}
|
}
|
||||||
|
fn type_layout(&self) -> Layout {
|
||||||
|
Layout::for_value(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Message for Msg1 {
|
impl Message for Msg1 {
|
||||||
@ -341,6 +360,9 @@ mod tests {
|
|||||||
fn type_name(&self) -> Cow<str> {
|
fn type_name(&self) -> Cow<str> {
|
||||||
type_name::<Self>().into()
|
type_name::<Self>().into()
|
||||||
}
|
}
|
||||||
|
fn type_layout(&self) -> Layout {
|
||||||
|
Layout::for_value(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Message for Msg2 {
|
impl Message for Msg2 {
|
||||||
|
@ -58,6 +58,9 @@ impl TypeTagged for GenericError {
|
|||||||
fn type_name(&self) -> TypeTag {
|
fn type_name(&self) -> TypeTag {
|
||||||
type_name::<GenericError>().into()
|
type_name::<GenericError>().into()
|
||||||
}
|
}
|
||||||
|
fn type_layout(&self) -> std::alloc::Layout {
|
||||||
|
std::alloc::Layout::for_value(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
@ -1,8 +1,21 @@
|
|||||||
use core::iter::FromIterator;
|
use core::iter::FromIterator;
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use crate::{error::StdSyncSendError, Bus, Message};
|
use crate::{error::StdSyncSendError, Bus, Message};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait AsyncProducer<'a, M: Message>: Send {
|
||||||
|
type Error: StdSyncSendError;
|
||||||
|
type Context: Send + 'a;
|
||||||
|
type Response: Message;
|
||||||
|
|
||||||
|
async fn start(&'a self, msg: M, bus: &Bus) -> Result<Self::Context, Self::Error>;
|
||||||
|
async fn next(&'a self, ctx: &mut Self::Context, bus: &Bus) -> Result<ControlFlow<Self::Response>, Self::Error>;
|
||||||
|
async fn finish(&'a self, _ctx: Self::Context, _bus: &Bus) -> Result<(), Self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub trait Handler<M: Message>: Send + Sync {
|
pub trait Handler<M: Message>: Send + Sync {
|
||||||
type Error: StdSyncSendError;
|
type Error: StdSyncSendError;
|
||||||
type Response: Message;
|
type Response: Message;
|
||||||
|
47
src/lib.rs
47
src/lib.rs
@ -7,6 +7,13 @@ pub mod receivers;
|
|||||||
mod relay;
|
mod relay;
|
||||||
mod stats;
|
mod stats;
|
||||||
mod trait_object;
|
mod trait_object;
|
||||||
|
pub mod type_tag;
|
||||||
|
|
||||||
|
|
||||||
|
pub mod __reexport {
|
||||||
|
pub use serde;
|
||||||
|
pub use ctor;
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
@ -25,7 +32,7 @@ use smallvec::SmallVec;
|
|||||||
use std::{collections::{HashMap, HashSet}, sync::Arc};
|
use std::{collections::{HashMap, HashSet}, sync::Arc};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
use builder::{BusBuilder, MessageTypeDescriptor};
|
use builder::BusBuilder;
|
||||||
use error::{Error, SendError, StdSyncSendError};
|
use error::{Error, SendError, StdSyncSendError};
|
||||||
use receiver::{Permit, Receiver};
|
use receiver::{Permit, Receiver};
|
||||||
use stats::Stats;
|
use stats::Stats;
|
||||||
@ -39,8 +46,10 @@ pub use receiver::{
|
|||||||
SendUntypedReceiver, TypeTagAccept,
|
SendUntypedReceiver, TypeTagAccept,
|
||||||
};
|
};
|
||||||
pub use relay::Relay;
|
pub use relay::Relay;
|
||||||
|
pub use ctor;
|
||||||
|
pub use type_tag::{register_shared_message, deserialize_shared_message};
|
||||||
pub type Untyped = Arc<dyn Any + Send + Sync>;
|
pub type Untyped = Arc<dyn Any + Send + Sync>;
|
||||||
|
|
||||||
type LookupQuery = (TypeTag, Option<TypeTag>, Option<TypeTag>);
|
type LookupQuery = (TypeTag, Option<TypeTag>, Option<TypeTag>);
|
||||||
|
|
||||||
static ID_COUNTER: AtomicU64 = AtomicU64::new(1);
|
static ID_COUNTER: AtomicU64 = AtomicU64::new(1);
|
||||||
@ -62,7 +71,6 @@ impl Default for SendOptions {
|
|||||||
|
|
||||||
pub struct BusInner {
|
pub struct BusInner {
|
||||||
receivers: HashSet<Receiver>,
|
receivers: HashSet<Receiver>,
|
||||||
message_types: HashMap<TypeTag, MessageTypeDescriptor>,
|
|
||||||
lookup: HashMap<LookupQuery, SmallVec<[Receiver; 4]>>,
|
lookup: HashMap<LookupQuery, SmallVec<[Receiver; 4]>>,
|
||||||
closed: AtomicBool,
|
closed: AtomicBool,
|
||||||
maintain: Mutex<()>,
|
maintain: Mutex<()>,
|
||||||
@ -71,7 +79,6 @@ pub struct BusInner {
|
|||||||
impl BusInner {
|
impl BusInner {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
receivers: HashSet<Receiver>,
|
receivers: HashSet<Receiver>,
|
||||||
message_types: HashMap<TypeTag, MessageTypeDescriptor>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut lookup = HashMap::new();
|
let mut lookup = HashMap::new();
|
||||||
for recv in receivers.iter() {
|
for recv in receivers.iter() {
|
||||||
@ -85,6 +92,10 @@ impl BusInner {
|
|||||||
.or_insert_with(HashSet::new)
|
.or_insert_with(HashSet::new)
|
||||||
.insert(recv.clone());
|
.insert(recv.clone());
|
||||||
|
|
||||||
|
lookup.entry((msg.clone(), None, Some(err.clone())))
|
||||||
|
.or_insert_with(HashSet::new)
|
||||||
|
.insert(recv.clone());
|
||||||
|
|
||||||
lookup.entry((msg, Some(resp), Some(err)))
|
lookup.entry((msg, Some(resp), Some(err)))
|
||||||
.or_insert_with(HashSet::new)
|
.or_insert_with(HashSet::new)
|
||||||
.insert(recv.clone());
|
.insert(recv.clone());
|
||||||
@ -98,7 +109,6 @@ impl BusInner {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
message_types,
|
|
||||||
receivers,
|
receivers,
|
||||||
lookup,
|
lookup,
|
||||||
closed: AtomicBool::new(false),
|
closed: AtomicBool::new(false),
|
||||||
@ -585,7 +595,9 @@ impl Bus {
|
|||||||
|
|
||||||
if let Some(rs) = self.inner.lookup.get(&(tt.clone(), None, None))
|
if let Some(rs) = self.inner.lookup.get(&(tt.clone(), None, None))
|
||||||
.and_then(|rs| rs.first()) {
|
.and_then(|rs| rs.first()) {
|
||||||
let msg = self.deserialize_message(tt.clone(), de)?;
|
|
||||||
|
let msg = deserialize_shared_message(tt.clone(), de)?;
|
||||||
|
|
||||||
Ok(rs.send_boxed(self, mid, msg.upcast_box(), false, rs.reserve(&tt).await)?)
|
Ok(rs.send_boxed(self, mid, msg.upcast_box(), false, rs.reserve(&tt).await)?)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::NoReceivers)
|
Err(Error::NoReceivers)
|
||||||
@ -606,7 +618,7 @@ impl Bus {
|
|||||||
let mut iter = self.select_receivers(tt.clone(), options, None, None, true);
|
let mut iter = self.select_receivers(tt.clone(), options, None, None, true);
|
||||||
if let Some(rc) = iter.next() {
|
if let Some(rc) = iter.next() {
|
||||||
let (mid, rx) = rc.add_response_waiter_boxed().unwrap();
|
let (mid, rx) = rc.add_response_waiter_boxed().unwrap();
|
||||||
let msg = self.deserialize_message(tt.clone(), de)?;
|
let msg = deserialize_shared_message(tt.clone(), de)?;
|
||||||
|
|
||||||
rc.send_boxed(
|
rc.send_boxed(
|
||||||
self,
|
self,
|
||||||
@ -622,21 +634,6 @@ impl Bus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserialize_message(
|
|
||||||
&self,
|
|
||||||
tt: TypeTag,
|
|
||||||
de: &mut dyn erased_serde::Deserializer<'_>,
|
|
||||||
) -> Result<Box<dyn SharedMessage>, Error<Box<dyn Message>>> {
|
|
||||||
let md = self
|
|
||||||
.inner
|
|
||||||
.message_types
|
|
||||||
.get(&tt)
|
|
||||||
.ok_or(Error::TypeTagNotRegistered(tt))?;
|
|
||||||
|
|
||||||
md.deserialize_boxed(de)
|
|
||||||
.map_err(|err| err.specify::<Box<dyn Message>>())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stats(&self) -> impl Iterator<Item = Stats> + '_ {
|
pub fn stats(&self) -> impl Iterator<Item = Stats> + '_ {
|
||||||
self.inner
|
self.inner
|
||||||
.receivers
|
.receivers
|
||||||
@ -653,9 +650,9 @@ impl Bus {
|
|||||||
eid: Option<TypeTag>,
|
eid: Option<TypeTag>,
|
||||||
is_req: bool,
|
is_req: bool,
|
||||||
) -> impl Iterator<Item = &Receiver> + '_ {
|
) -> impl Iterator<Item = &Receiver> + '_ {
|
||||||
let vec = self.inner.lookup.get(&(tid.clone(), rid.clone(), eid.clone())).unwrap();
|
self.inner.lookup.get(&(tid.clone(), rid.clone(), eid.clone()))
|
||||||
|
.into_iter()
|
||||||
vec.iter()
|
.flatten()
|
||||||
.filter(move |r| r.accept(is_req, &tid, rid.as_ref(), eid.as_ref()))
|
.filter(move |r| r.accept(is_req, &tid, rid.as_ref(), eid.as_ref()))
|
||||||
.filter(move |r| match options {
|
.filter(move |r| match options {
|
||||||
SendOptions::Except(id) => id != r.id(),
|
SendOptions::Except(id) => id != r.id(),
|
||||||
|
82
src/type_tag.rs
Normal file
82
src/type_tag.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
|
use crate::envelop::IntoSharedMessage;
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::{Message, SharedMessage, TypeTag};
|
||||||
|
|
||||||
|
static TYPE_REGISTRY: TypeRegistry = TypeRegistry::new();
|
||||||
|
|
||||||
|
type MessageDeserializerCallback = Box<
|
||||||
|
dyn Fn(&mut dyn erased_serde::Deserializer<'_>) -> Result<Box<dyn SharedMessage>, Error>
|
||||||
|
+ Send
|
||||||
|
+ Sync,
|
||||||
|
>;
|
||||||
|
|
||||||
|
pub struct MessageTypeDescriptor {
|
||||||
|
de: MessageDeserializerCallback,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MessageTypeDescriptor {
|
||||||
|
#[inline]
|
||||||
|
pub fn deserialize_boxed(
|
||||||
|
&self,
|
||||||
|
de: &mut dyn erased_serde::Deserializer<'_>,
|
||||||
|
) -> Result<Box<dyn SharedMessage>, Error> {
|
||||||
|
(self.de)(de)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct TypeRegistry {
|
||||||
|
message_types: RwLock<Option<HashMap<TypeTag, MessageTypeDescriptor>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeRegistry {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
message_types: parking_lot::const_rwlock(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize(
|
||||||
|
&self,
|
||||||
|
tt: TypeTag,
|
||||||
|
de: &mut dyn erased_serde::Deserializer<'_>,
|
||||||
|
) -> Result<Box<dyn SharedMessage>, Error<Box<dyn Message>>> {
|
||||||
|
let guard = self
|
||||||
|
.message_types
|
||||||
|
.read();
|
||||||
|
let md = guard
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| Error::TypeTagNotRegistered(tt.clone()))?
|
||||||
|
.get(&tt)
|
||||||
|
.ok_or(Error::TypeTagNotRegistered(tt))?;
|
||||||
|
|
||||||
|
md.deserialize_boxed(de)
|
||||||
|
.map_err(|err| err.specify::<Box<dyn Message>>())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register<M: Message + serde::Serialize + serde::de::DeserializeOwned>(&self) {
|
||||||
|
println!("insert {}", M::type_tag_());
|
||||||
|
|
||||||
|
self.message_types.write()
|
||||||
|
.get_or_insert_with(HashMap::new)
|
||||||
|
.insert(
|
||||||
|
M::type_tag_(),
|
||||||
|
MessageTypeDescriptor {
|
||||||
|
de: Box::new(move |de| Ok(M::deserialize(de)?.into_shared())),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn deserialize_shared_message(tt: TypeTag, de: &mut dyn erased_serde::Deserializer<'_>) -> Result<Box<dyn SharedMessage>, Error<Box<dyn Message>>> {
|
||||||
|
TYPE_REGISTRY.deserialize(tt, de)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn register_shared_message<M: Message + serde::Serialize + serde::de::DeserializeOwned>() {
|
||||||
|
TYPE_REGISTRY.register::<M>();
|
||||||
|
}
|
@ -52,7 +52,6 @@ impl AsyncHandler<Msg> for TmpReceiver {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test() {
|
async fn test() {
|
||||||
let (b, poller) = Bus::build()
|
let (b, poller) = Bus::build()
|
||||||
.register_shared_message::<Msg>()
|
|
||||||
.register(TmpReceiver)
|
.register(TmpReceiver)
|
||||||
.subscribe_async::<Msg>(8, Default::default())
|
.subscribe_async::<Msg>(8, Default::default())
|
||||||
.done()
|
.done()
|
||||||
|
@ -6,7 +6,7 @@ use std::sync::{
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use messagebus::{
|
use messagebus::{
|
||||||
derive::{Error as MbError, Message},
|
derive::{Error as MbError, Message},
|
||||||
error, AsyncHandler, Bus, Message, MessageBounds,
|
error, AsyncHandler, Bus, Message,
|
||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@ -22,14 +22,13 @@ impl<M: Message> From<error::Error<M>> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Message)]
|
#[derive(Debug, Clone, serde_derive::Serialize, serde_derive::Deserialize, Message)]
|
||||||
|
#[message(clone, shared)]
|
||||||
struct Msg;
|
struct Msg;
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde_derive::Serialize, serde_derive::Deserialize, Message)]
|
#[derive(Debug, Clone, serde_derive::Serialize, serde_derive::Deserialize, Message)]
|
||||||
#[message(clone, shared)]
|
#[message(clone, shared)]
|
||||||
struct SharedMsg<T: serde::Serialize + MessageBounds + Clone>(
|
struct SharedMsg<T>(T);
|
||||||
#[serde(bound(deserialize = "T: serde::Deserialize<'de>"))] T,
|
|
||||||
);
|
|
||||||
|
|
||||||
struct TmpReceiverContext {
|
struct TmpReceiverContext {
|
||||||
sync1: AtomicBool,
|
sync1: AtomicBool,
|
||||||
|
Loading…
Reference in New Issue
Block a user