Relays + example (test)
This commit is contained in:
parent
3bb2fe7492
commit
9a887d4821
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
/target
|
||||
/derive/target
|
||||
Cargo.lock
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "messagebus"
|
||||
version = "0.6.5"
|
||||
version = "0.8.0"
|
||||
authors = ["Andrey Tkachenko <andrey@aidev.ru>"]
|
||||
repository = "https://github.com/andreytkachenko/messagebus.git"
|
||||
keywords = ["futures", "async", "tokio", "message", "bus"]
|
||||
|
213
src/builder.rs
213
src/builder.rs
@ -1,9 +1,17 @@
|
||||
use std::{collections::HashMap, marker::PhantomData, pin::Pin, sync::Arc};
|
||||
|
||||
use futures::{Future, FutureExt};
|
||||
use smallvec::SmallVec;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::{AsyncBatchHandler, AsyncBatchSynchronizedHandler, AsyncHandler, AsyncSynchronizedHandler, BatchHandler, BatchSynchronizedHandler, Bus, BusInner, Handler, IntoBoxedMessage, Message, SynchronizedHandler, Untyped, envelop::TypeTag, error::{Error, StdSyncSendError}, receiver::{Receiver, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver}, receivers, relay::TypeMap};
|
||||
use crate::{
|
||||
envelop::TypeTag,
|
||||
error::{Error, StdSyncSendError},
|
||||
receiver::{Receiver, ReciveTypedReceiver, SendTypedReceiver, SendUntypedReceiver},
|
||||
receivers, AsyncBatchHandler, AsyncBatchSynchronizedHandler, AsyncHandler,
|
||||
AsyncSynchronizedHandler, BatchHandler, BatchSynchronizedHandler, Bus, BusInner, Handler,
|
||||
IntoBoxedMessage, Message, Relay, SynchronizedHandler, Untyped,
|
||||
};
|
||||
|
||||
pub trait ReceiverSubscriberBuilder<T, M, R, E>:
|
||||
SendUntypedReceiver + SendTypedReceiver<M> + ReciveTypedReceiver<R, E>
|
||||
@ -31,49 +39,35 @@ pub struct SyncEntry;
|
||||
pub struct UnsyncEntry;
|
||||
|
||||
#[must_use]
|
||||
pub struct RegisterEntry<K, T, F, B> {
|
||||
pub struct RegisterEntry<K, T, F, P, B> {
|
||||
item: Untyped,
|
||||
payload: B,
|
||||
builder: F,
|
||||
receivers: HashMap<
|
||||
TypeTag,
|
||||
Vec<(
|
||||
Receiver,
|
||||
Box<
|
||||
dyn FnOnce(
|
||||
Untyped,
|
||||
)
|
||||
-> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
>,
|
||||
Option<Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>>,
|
||||
)>,
|
||||
>,
|
||||
poller: P,
|
||||
receivers: HashMap<TypeTag, Receiver>,
|
||||
pollers: Vec<Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>>,
|
||||
_m: PhantomData<(K, T)>,
|
||||
}
|
||||
|
||||
impl<K, T: 'static, F, B> RegisterEntry<K, T, F, B>
|
||||
impl<K, T: 'static, F, P, B> RegisterEntry<K, T, F, P, B>
|
||||
where
|
||||
F: FnMut(
|
||||
&mut B,
|
||||
(TypeTag, Receiver),
|
||||
Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
Option<Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>>,
|
||||
),
|
||||
F: FnMut(&mut B, TypeTag, Receiver),
|
||||
P: FnMut(&mut B, Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>),
|
||||
{
|
||||
pub fn done(mut self) -> B {
|
||||
for (tid, v) in self.receivers {
|
||||
for (r, poller, poller2) in v {
|
||||
let poller = poller(self.item.clone());
|
||||
|
||||
(self.builder)(&mut self.payload, (tid.clone(), r), poller, poller2);
|
||||
(self.builder)(&mut self.payload, tid, v);
|
||||
}
|
||||
|
||||
for p in self.pollers {
|
||||
(self.poller)(&mut self.payload, p);
|
||||
}
|
||||
|
||||
self.payload
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F, B> RegisterEntry<UnsyncEntry, T, F, B> {
|
||||
impl<T, F, P, B> RegisterEntry<UnsyncEntry, T, F, P, B> {
|
||||
pub fn subscribe<M, S, R, E>(mut self, queue: u64, cfg: S::Config) -> Self
|
||||
where
|
||||
T: Send + 'static,
|
||||
@ -86,10 +80,9 @@ impl<T, F, B> RegisterEntry<UnsyncEntry, T, F, B> {
|
||||
|
||||
let receiver = Receiver::new::<M, R, E, S>(queue, inner);
|
||||
let poller2 = receiver.start_polling();
|
||||
self.receivers
|
||||
.entry(M::type_tag_())
|
||||
.or_insert_with(Vec::new)
|
||||
.push((receiver, poller, poller2));
|
||||
self.receivers.insert(M::type_tag_(), receiver);
|
||||
self.pollers.push(poller(self.item.clone()));
|
||||
self.pollers.push(poller2);
|
||||
|
||||
self
|
||||
}
|
||||
@ -143,7 +136,7 @@ impl<T, F, B> RegisterEntry<UnsyncEntry, T, F, B> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F, B> RegisterEntry<SyncEntry, T, F, B> {
|
||||
impl<T, F, P, B> RegisterEntry<SyncEntry, T, F, P, B> {
|
||||
pub fn subscribe<M, S, R, E>(mut self, queue: u64, cfg: S::Config) -> Self
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@ -156,10 +149,9 @@ impl<T, F, B> RegisterEntry<SyncEntry, T, F, B> {
|
||||
|
||||
let receiver = Receiver::new::<M, R, E, S>(queue, inner);
|
||||
let poller2 = receiver.start_polling();
|
||||
self.receivers
|
||||
.entry(M::type_tag_())
|
||||
.or_insert_with(Vec::new)
|
||||
.push((receiver, poller, poller2));
|
||||
self.receivers.insert(M::type_tag_(), receiver);
|
||||
self.pollers.push(poller(self.item.clone()));
|
||||
self.pollers.push(poller2);
|
||||
|
||||
self
|
||||
}
|
||||
@ -233,16 +225,16 @@ impl MessageTypeDescriptor {
|
||||
}
|
||||
|
||||
pub struct Module {
|
||||
message_types: Vec<(TypeTag, MessageTypeDescriptor)>,
|
||||
receivers: Vec<(TypeTag, Receiver)>,
|
||||
message_types: HashMap<TypeTag, MessageTypeDescriptor>,
|
||||
receivers: HashMap<TypeTag, SmallVec<[Receiver; 4]>>,
|
||||
pollings: Vec<Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>>,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
message_types: Vec::new(),
|
||||
receivers: Vec::new(),
|
||||
message_types: HashMap::new(),
|
||||
receivers: HashMap::new(),
|
||||
pollings: Vec::new(),
|
||||
}
|
||||
}
|
||||
@ -252,24 +244,40 @@ impl Module {
|
||||
>(
|
||||
mut self,
|
||||
) -> Self {
|
||||
self.message_types.push((
|
||||
self.message_types.insert(
|
||||
M::type_tag_(),
|
||||
MessageTypeDescriptor {
|
||||
de: Box::new(move |de| Ok(M::deserialize(de)?.into_boxed())),
|
||||
},
|
||||
));
|
||||
);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn register_relay<S: SendUntypedReceiver + Send + Sync + 'static>(queue: u64, map: TypeMap, inner: S) {
|
||||
let receiver = Receiver::new_relay::<S>(queue, map, inner);
|
||||
let poller2 = receiver.start_polling();
|
||||
pub fn register_relay<S: Relay + Send + Sync + 'static>(
|
||||
mut self,
|
||||
inner: S,
|
||||
queue: u64,
|
||||
) -> Self {
|
||||
let receiver = Receiver::new_relay::<S>(queue, inner);
|
||||
self.pollings.push(receiver.start_polling());
|
||||
|
||||
// self.receivers
|
||||
// .entry(M::type_tag_())
|
||||
// .or_insert_with(Vec::new)
|
||||
// .push((receiver, poller, poller2));
|
||||
let mut receiver_added = false;
|
||||
receiver.iter_types(&mut |msg, _, _| {
|
||||
self.receivers
|
||||
.entry(msg.clone())
|
||||
.or_insert_with(SmallVec::new)
|
||||
.push(receiver.clone());
|
||||
|
||||
if !receiver_added {
|
||||
receiver_added = true;
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn register<T: Send + Sync + 'static>(
|
||||
@ -278,25 +286,19 @@ impl Module {
|
||||
) -> RegisterEntry<
|
||||
SyncEntry,
|
||||
T,
|
||||
impl FnMut(
|
||||
&mut Self,
|
||||
(TypeTag, Receiver),
|
||||
Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
Option<Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>>,
|
||||
),
|
||||
impl FnMut(&mut Self, TypeTag, Receiver),
|
||||
impl FnMut(&mut Self, Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>),
|
||||
Self,
|
||||
> {
|
||||
RegisterEntry {
|
||||
item: Arc::new(item) as Untyped,
|
||||
payload: self,
|
||||
builder: |p: &mut Self, val, poller, poller2| {
|
||||
p.receivers.push(val);
|
||||
p.pollings.push(poller);
|
||||
if let Some(poller2) = poller2 {
|
||||
p.pollings.push(poller2);
|
||||
}
|
||||
builder: |p: &mut Self, tt, r| {
|
||||
p.receivers.entry(tt).or_insert_with(SmallVec::new).push(r);
|
||||
},
|
||||
poller: |p: &mut Self, poller| p.pollings.push(poller),
|
||||
receivers: HashMap::new(),
|
||||
pollers: Vec::new(),
|
||||
_m: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -307,25 +309,21 @@ impl Module {
|
||||
) -> RegisterEntry<
|
||||
UnsyncEntry,
|
||||
T,
|
||||
impl FnMut(
|
||||
&mut Self,
|
||||
(TypeTag, Receiver),
|
||||
Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
Option<Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>>,
|
||||
),
|
||||
impl FnMut(&mut Self, TypeTag, Receiver),
|
||||
impl FnMut(&mut Self, Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>),
|
||||
Self,
|
||||
> {
|
||||
let item = Arc::new(Mutex::new(item)) as Untyped;
|
||||
|
||||
RegisterEntry {
|
||||
item: Arc::new(Mutex::new(item)) as Untyped,
|
||||
item,
|
||||
payload: self,
|
||||
builder: |p: &mut Self, val, poller, poller2| {
|
||||
p.receivers.push(val);
|
||||
p.pollings.push(poller);
|
||||
if let Some(poller2) = poller2 {
|
||||
p.pollings.push(poller2);
|
||||
}
|
||||
builder: |p: &mut Self, tt, r| {
|
||||
p.receivers.entry(tt).or_insert_with(SmallVec::new).push(r);
|
||||
},
|
||||
poller: |p: &mut Self, poller| p.pollings.push(poller),
|
||||
receivers: HashMap::new(),
|
||||
pollers: Vec::new(),
|
||||
_m: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -360,31 +358,35 @@ impl BusBuilder {
|
||||
BusBuilder { inner }
|
||||
}
|
||||
|
||||
pub fn register_relay<S: Relay + Send + Sync + 'static>(self, inner: S, queue: u64) -> Self {
|
||||
let inner = self.inner.register_relay(inner, queue);
|
||||
|
||||
BusBuilder { inner }
|
||||
}
|
||||
|
||||
pub fn register<T: Send + Sync + 'static>(
|
||||
self,
|
||||
item: T,
|
||||
) -> RegisterEntry<
|
||||
SyncEntry,
|
||||
T,
|
||||
impl FnMut(
|
||||
&mut Self,
|
||||
(TypeTag, Receiver),
|
||||
Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
Option<Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>>,
|
||||
),
|
||||
impl FnMut(&mut Self, TypeTag, Receiver),
|
||||
impl FnMut(&mut Self, Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>),
|
||||
Self,
|
||||
> {
|
||||
RegisterEntry {
|
||||
item: Arc::new(item) as Untyped,
|
||||
payload: self,
|
||||
builder: |p: &mut Self, val, poller, poller2| {
|
||||
p.inner.receivers.push(val);
|
||||
p.inner.pollings.push(poller);
|
||||
if let Some(poller2) = poller2 {
|
||||
p.inner.pollings.push(poller2);
|
||||
}
|
||||
builder: |p: &mut Self, tt, r| {
|
||||
p.inner
|
||||
.receivers
|
||||
.entry(tt)
|
||||
.or_insert_with(SmallVec::new)
|
||||
.push(r);
|
||||
},
|
||||
poller: |p: &mut Self, poller| p.inner.pollings.push(poller),
|
||||
receivers: HashMap::new(),
|
||||
pollers: Vec::new(),
|
||||
_m: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -395,26 +397,23 @@ impl BusBuilder {
|
||||
) -> RegisterEntry<
|
||||
UnsyncEntry,
|
||||
T,
|
||||
impl FnMut(
|
||||
&mut Self,
|
||||
(TypeTag, Receiver),
|
||||
Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>,
|
||||
Option<Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>>,
|
||||
),
|
||||
impl FnMut(&mut Self, TypeTag, Receiver),
|
||||
impl FnMut(&mut Self, Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>),
|
||||
Self,
|
||||
> {
|
||||
RegisterEntry {
|
||||
item: Arc::new(Mutex::new(item)) as Untyped,
|
||||
payload: self,
|
||||
builder: |p: &mut Self, val, poller, poller2| {
|
||||
p.inner.receivers.push(val);
|
||||
p.inner.pollings.push(poller);
|
||||
|
||||
if let Some(poller2) = poller2 {
|
||||
p.inner.pollings.push(poller2);
|
||||
}
|
||||
builder: |p: &mut Self, tt, r| {
|
||||
p.inner
|
||||
.receivers
|
||||
.entry(tt)
|
||||
.or_insert_with(SmallVec::new)
|
||||
.push(r);
|
||||
},
|
||||
poller: |p: &mut Self, poller| p.inner.pollings.push(poller),
|
||||
receivers: HashMap::new(),
|
||||
pollers: Vec::new(),
|
||||
_m: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -426,11 +425,19 @@ impl BusBuilder {
|
||||
}
|
||||
|
||||
pub fn build(self) -> (Bus, impl Future<Output = ()>) {
|
||||
let mut receivers = HashMap::new();
|
||||
|
||||
for (key, values) in self.inner.receivers {
|
||||
for v in values {
|
||||
receivers
|
||||
.entry(key.clone())
|
||||
.or_insert_with(SmallVec::new)
|
||||
.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
let bus = Bus {
|
||||
inner: Arc::new(BusInner::new(
|
||||
self.inner.receivers,
|
||||
self.inner.message_types,
|
||||
)),
|
||||
inner: Arc::new(BusInner::new(receivers, self.inner.message_types)),
|
||||
};
|
||||
|
||||
let mut futs = Vec::with_capacity(self.inner.pollings.len() * 2);
|
||||
|
@ -58,6 +58,19 @@ impl<T: TypeTagged> TypeTagged for Arc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TypeTagged> TypeTagged for Box<T> {
|
||||
fn type_tag_() -> TypeTag {
|
||||
T::type_tag_()
|
||||
}
|
||||
|
||||
fn type_tag(&self) -> TypeTag {
|
||||
T::type_tag(&*self)
|
||||
}
|
||||
fn type_name(&self) -> Cow<str> {
|
||||
T::type_name(&*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Message for () {
|
||||
fn as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
|
29
src/error.rs
29
src/error.rs
@ -9,26 +9,41 @@ use crate::{
|
||||
Message,
|
||||
};
|
||||
|
||||
pub trait DynError: TypeTagged {
|
||||
fn description(&self) -> String;
|
||||
}
|
||||
|
||||
pub trait StdSyncSendError: std::error::Error + TypeTagged + Send + Sync + Unpin + 'static {}
|
||||
impl<T: std::error::Error + TypeTagged + Send + Sync + Unpin + 'static> StdSyncSendError for T {}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum VoidError {}
|
||||
#[derive(Debug)]
|
||||
pub struct GenericError {
|
||||
pub type_tag: TypeTag,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
impl TypeTagged for VoidError {
|
||||
impl fmt::Display for GenericError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "GenericError({}): {}", self.type_tag, self.description)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for GenericError {}
|
||||
|
||||
impl TypeTagged for GenericError {
|
||||
fn type_name(&self) -> Cow<str> {
|
||||
type_name::<VoidError>().into()
|
||||
type_name::<GenericError>().into()
|
||||
}
|
||||
|
||||
fn type_tag(&self) -> TypeTag {
|
||||
type_name::<VoidError>().into()
|
||||
type_name::<GenericError>().into()
|
||||
}
|
||||
|
||||
fn type_tag_() -> TypeTag
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
type_name::<VoidError>().into()
|
||||
type_name::<GenericError>().into()
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +75,7 @@ impl<M: Message> SendError<M> {
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error<M: fmt::Debug + 'static = (), E: StdSyncSendError = VoidError> {
|
||||
pub enum Error<M: fmt::Debug + 'static = (), E: StdSyncSendError = GenericError> {
|
||||
#[error("Message Send Error: {0}")]
|
||||
SendError(#[from] SendError<M>),
|
||||
|
||||
|
43
src/lib.rs
43
src/lib.rs
@ -4,8 +4,8 @@ pub mod error;
|
||||
mod handler;
|
||||
mod receiver;
|
||||
pub mod receivers;
|
||||
mod trait_object;
|
||||
mod relay;
|
||||
mod trait_object;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
@ -22,6 +22,11 @@ pub use envelop::{IntoBoxedMessage, Message, MessageBounds, SharedMessage, TypeT
|
||||
use error::{Error, SendError, StdSyncSendError};
|
||||
pub use handler::*;
|
||||
use receiver::Receiver;
|
||||
pub use receiver::{
|
||||
Action, Event, ReciveTypedReceiver, ReciveUnypedReceiver, SendTypedReceiver,
|
||||
SendUntypedReceiver, TypeTagAccept,
|
||||
};
|
||||
pub use relay::Relay;
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
@ -57,19 +62,9 @@ pub struct BusInner {
|
||||
|
||||
impl BusInner {
|
||||
pub(crate) fn new(
|
||||
input: Vec<(TypeTag, Receiver)>,
|
||||
mt: Vec<(TypeTag, MessageTypeDescriptor)>,
|
||||
receivers: HashMap<TypeTag, SmallVec<[Receiver; 4]>>,
|
||||
message_types: HashMap<TypeTag, MessageTypeDescriptor>,
|
||||
) -> Self {
|
||||
let mut receivers = HashMap::new();
|
||||
let message_types: HashMap<TypeTag, MessageTypeDescriptor> = mt.into_iter().collect();
|
||||
|
||||
for (key, value) in input {
|
||||
receivers
|
||||
.entry(key)
|
||||
.or_insert_with(SmallVec::new)
|
||||
.push(value);
|
||||
}
|
||||
|
||||
Self {
|
||||
message_types,
|
||||
receivers,
|
||||
@ -220,6 +215,13 @@ impl BusInner {
|
||||
return Err(SendError::Closed(msg).into());
|
||||
}
|
||||
|
||||
for r in &self.receivers {
|
||||
println!("{:?}: ", r.0);
|
||||
for i in r.1 {
|
||||
println!(" {:?}: ", i.name());
|
||||
}
|
||||
}
|
||||
|
||||
let tt = msg.type_tag();
|
||||
let mid = ID_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
@ -332,7 +334,8 @@ impl BusInner {
|
||||
|
||||
let mut iter = self.select_receivers(&tid, options, Some(&rid), None);
|
||||
if let Some(rc) = iter.next() {
|
||||
let (mid, rx) = rc.add_response_waiter::<R>()
|
||||
let (mid, rx) = rc
|
||||
.add_response_waiter::<R>()
|
||||
.map_err(|x| x.specify::<M>())?;
|
||||
|
||||
let mid = mid | 1 << (u64::BITS - 1);
|
||||
@ -356,8 +359,10 @@ impl BusInner {
|
||||
|
||||
let mut iter = self.select_receivers(&tid, options, Some(&rid), Some(&eid));
|
||||
if let Some(rc) = iter.next() {
|
||||
let (mid, rx) = rc.add_response_waiter_we::<R, E>()
|
||||
.map_err(|x| x.map_err(|_| unimplemented!()).map_msg(|_| unimplemented!()))?;
|
||||
let (mid, rx) = rc.add_response_waiter_we::<R, E>().map_err(|x| {
|
||||
x.map_err(|_| unimplemented!())
|
||||
.map_msg(|_| unimplemented!())
|
||||
})?;
|
||||
|
||||
rc.send(mid | 1 << (u64::BITS - 1), req, rc.reserve().await)
|
||||
.map_err(|x| x.map_err(|_| unimplemented!()))?;
|
||||
@ -429,8 +434,10 @@ impl BusInner {
|
||||
|
||||
let mut iter = self.select_receivers(&tt, options, None, None);
|
||||
if let Some(rc) = iter.next() {
|
||||
let (mid, rx) = rc.add_response_waiter_boxed()
|
||||
.map_err(|x| x.map_err(|_| unimplemented!()).map_msg(|_| unimplemented!()))?;
|
||||
let (mid, rx) = rc.add_response_waiter_boxed().map_err(|x| {
|
||||
x.map_err(|_| unimplemented!())
|
||||
.map_msg(|_| unimplemented!())
|
||||
})?;
|
||||
|
||||
rc.send_boxed(mid | 1 << (usize::BITS - 1), req, rc.reserve().await)?;
|
||||
|
||||
|
189
src/receiver.rs
189
src/receiver.rs
@ -1,4 +1,10 @@
|
||||
use crate::{Bus, Error, Message, envelop::{IntoBoxedMessage, TypeTag}, error::{SendError, StdSyncSendError}, relay::TypeMap, trait_object::TraitObject};
|
||||
use crate::relay::RelayWrapper;
|
||||
use crate::{
|
||||
envelop::{IntoBoxedMessage, TypeTag},
|
||||
error::{GenericError, SendError, StdSyncSendError},
|
||||
trait_object::TraitObject,
|
||||
Bus, Error, Message, Relay,
|
||||
};
|
||||
use core::{
|
||||
any::TypeId,
|
||||
fmt,
|
||||
@ -7,8 +13,8 @@ use core::{
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use futures::{FutureExt, future::poll_fn};
|
||||
use futures::Future;
|
||||
use futures::{future::poll_fn, FutureExt};
|
||||
use std::{
|
||||
any::Any,
|
||||
borrow::Cow,
|
||||
@ -18,7 +24,6 @@ use std::{
|
||||
},
|
||||
};
|
||||
use tokio::sync::{oneshot, Notify};
|
||||
use crate::relay::RelayWrapper;
|
||||
struct SlabCfg;
|
||||
impl sharded_slab::Config for SlabCfg {
|
||||
const RESERVED_BITS: usize = 1;
|
||||
@ -28,7 +33,11 @@ type Slab<T> = sharded_slab::Slab<T, SlabCfg>;
|
||||
|
||||
pub trait SendUntypedReceiver: Send + Sync {
|
||||
fn send(&self, msg: Action) -> Result<(), SendError<Action>>;
|
||||
fn send_msg(&self, _mid: u64, _msg: Box<dyn Message>) -> Result<(), SendError<Box<dyn Message>>> {
|
||||
fn send_msg(
|
||||
&self,
|
||||
_mid: u64,
|
||||
_msg: Box<dyn Message>,
|
||||
) -> Result<(), SendError<Box<dyn Message>>> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
@ -45,6 +54,10 @@ where
|
||||
fn poll_events(&self, ctx: &mut Context<'_>) -> Poll<Event<M, E>>;
|
||||
}
|
||||
|
||||
pub trait ReciveUnypedReceiver: Sync {
|
||||
fn poll_events(&self, ctx: &mut Context<'_>) -> Poll<Event<Box<dyn Message>, GenericError>>;
|
||||
}
|
||||
|
||||
pub trait WrapperReturnTypeOnly<R: Message>: Send + Sync {
|
||||
fn add_response_listener(
|
||||
&self,
|
||||
@ -53,7 +66,9 @@ pub trait WrapperReturnTypeOnly<R: Message>: Send + Sync {
|
||||
}
|
||||
|
||||
pub trait WrapperReturnTypeAndError<R: Message, E: StdSyncSendError>: Send + Sync {
|
||||
fn start_polling_events(self: Arc<Self>) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>;
|
||||
fn start_polling_events(
|
||||
self: Arc<Self>,
|
||||
) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>;
|
||||
fn add_response_listener(
|
||||
&self,
|
||||
listener: oneshot::Sender<Result<R, Error<(), E>>>,
|
||||
@ -61,7 +76,12 @@ pub trait WrapperReturnTypeAndError<R: Message, E: StdSyncSendError>: Send + Syn
|
||||
fn response(&self, mid: u64, resp: Result<R, Error<(), E>>) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
pub trait ReceiverTrait: Send + Sync {
|
||||
pub trait TypeTagAccept {
|
||||
fn accept(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool;
|
||||
fn iter_types(&self, cb: &mut dyn FnMut(&TypeTag, &TypeTag, &TypeTag) -> bool);
|
||||
}
|
||||
|
||||
pub trait ReceiverTrait: TypeTagAccept + Send + Sync {
|
||||
fn name(&self) -> &str;
|
||||
fn typed(&self) -> Option<AnyReceiver<'_>>;
|
||||
fn wrapper(&self) -> Option<AnyWrapperRef<'_>>;
|
||||
@ -89,8 +109,9 @@ pub trait ReceiverTrait: Send + Sync {
|
||||
fn try_reserve(&self) -> Option<Permit>;
|
||||
fn reserve_notify(&self) -> &Notify;
|
||||
|
||||
fn accept(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool;
|
||||
fn start_polling(self: Arc<Self>) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>;
|
||||
fn start_polling(
|
||||
self: Arc<Self>,
|
||||
) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>;
|
||||
}
|
||||
|
||||
pub trait ReceiverPollerBuilder {
|
||||
@ -155,8 +176,9 @@ where
|
||||
E: StdSyncSendError,
|
||||
S: ReciveTypedReceiver<R, E> + Send + Sync + 'static,
|
||||
{
|
||||
|
||||
fn start_polling_events(self: Arc<Self>) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>> {
|
||||
fn start_polling_events(
|
||||
self: Arc<Self>,
|
||||
) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>> {
|
||||
Box::new(move |_| {
|
||||
Box::pin(async move {
|
||||
loop {
|
||||
@ -231,6 +253,34 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, R, E, S> TypeTagAccept for ReceiverWrapper<M, R, E, S>
|
||||
where
|
||||
M: Message,
|
||||
R: Message,
|
||||
E: StdSyncSendError,
|
||||
S: ReciveTypedReceiver<R, E> + Send + Sync + 'static,
|
||||
{
|
||||
fn iter_types(&self, cb: &mut dyn FnMut(&TypeTag, &TypeTag, &TypeTag) -> bool) {
|
||||
let _ = cb(&M::type_tag_(), &R::type_tag_(), &E::type_tag_());
|
||||
}
|
||||
|
||||
fn accept(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
if let Some(resp) = resp {
|
||||
if resp.as_ref() != R::type_tag_().as_ref() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(err) = err {
|
||||
if err.as_ref() != E::type_tag_().as_ref() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
msg.as_ref() == M::type_tag_().as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<M, R, E, S> ReceiverTrait for ReceiverWrapper<M, R, E, S>
|
||||
where
|
||||
M: Message,
|
||||
@ -339,23 +389,9 @@ where
|
||||
&self.context.response
|
||||
}
|
||||
|
||||
fn accept(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
if let Some(resp) = resp {
|
||||
if resp.as_ref() != R::type_tag_().as_ref() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(err) = err {
|
||||
if err.as_ref() != E::type_tag_().as_ref() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
msg.as_ref() == M::type_tag_().as_ref()
|
||||
}
|
||||
|
||||
fn start_polling(self: Arc<Self>) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>> {
|
||||
fn start_polling(
|
||||
self: Arc<Self>,
|
||||
) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>> {
|
||||
self.start_polling_events()
|
||||
}
|
||||
}
|
||||
@ -454,7 +490,7 @@ impl<'a> AnyWrapperRef<'a> {
|
||||
#[inline]
|
||||
pub fn cast_ret_only<R: Message>(&'a self) -> Option<&'a dyn WrapperReturnTypeOnly<R>> {
|
||||
if self.wrapper_r.0 != TypeId::of::<dyn WrapperReturnTypeOnly<R>>() {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(unsafe {
|
||||
@ -497,16 +533,18 @@ impl AnyWrapperArc {
|
||||
{
|
||||
let wrapper_re = Box::new(rcvr as Arc<dyn WrapperReturnTypeAndError<R, E>>);
|
||||
|
||||
Self {
|
||||
wrapper_re,
|
||||
}
|
||||
Self { wrapper_re }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cast_ret_and_error<R: Message, E: StdSyncSendError>(
|
||||
&self,
|
||||
) -> Option<Arc<dyn WrapperReturnTypeAndError<R, E>>> {
|
||||
Some(self.wrapper_re.downcast_ref::<Arc<dyn WrapperReturnTypeAndError<R, E>>>()?.clone())
|
||||
Some(
|
||||
self.wrapper_re
|
||||
.downcast_ref::<Arc<dyn WrapperReturnTypeAndError<R, E>>>()?
|
||||
.clone(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -557,6 +595,7 @@ enum Waiter<R: Message, E: StdSyncSendError> {
|
||||
Boxed(oneshot::Sender<Result<Box<dyn Message>, Error>>),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Receiver {
|
||||
inner: Arc<dyn ReceiverTrait>,
|
||||
}
|
||||
@ -604,15 +643,20 @@ impl Receiver {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn new_relay<S>(limit: u64, type_map: TypeMap, inner: S) -> Self
|
||||
pub(crate) fn new_relay<S>(limit: u64, inner: S) -> Self
|
||||
where
|
||||
S: SendUntypedReceiver + 'static,
|
||||
S: Relay + Send + Sync + 'static,
|
||||
{
|
||||
Self {
|
||||
inner: Arc::new(RelayWrapper::new(inner, type_map, limit)),
|
||||
inner: Arc::new(RelayWrapper::new(inner, limit)),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn name(&self) -> &str {
|
||||
self.inner.name()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn accept(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
self.inner.accept(msg, resp, err)
|
||||
@ -640,20 +684,18 @@ impl Receiver {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn send<M: Message>(
|
||||
&self,
|
||||
mid: u64,
|
||||
msg: M,
|
||||
mut permit: Permit,
|
||||
) -> Result<(), Error<M>> {
|
||||
pub fn send<M: Message>(&self, mid: u64, msg: M, mut permit: Permit) -> Result<(), Error<M>> {
|
||||
let res = if let Some(any_receiver) = self.inner.typed() {
|
||||
any_receiver.cast_send_typed::<M>().unwrap()
|
||||
any_receiver
|
||||
.cast_send_typed::<M>()
|
||||
.unwrap()
|
||||
.send(mid, msg)
|
||||
.map_err(Into::into)
|
||||
} else {
|
||||
self.inner.send_boxed(mid, msg.into_boxed())
|
||||
.map_err(|err| err.map_msg(|b|*b.as_any_boxed().downcast::<M>().unwrap()))
|
||||
.map(|_|())
|
||||
self.inner
|
||||
.send_boxed(mid, msg.into_boxed())
|
||||
.map_err(|err| err.map_msg(|b| *b.as_any_boxed().downcast::<M>().unwrap()))
|
||||
.map(|_| ())
|
||||
};
|
||||
|
||||
permit.fuse = true;
|
||||
@ -664,13 +706,16 @@ impl Receiver {
|
||||
#[inline]
|
||||
pub fn force_send<M: Message + Clone>(&self, mid: u64, msg: M) -> Result<(), Error<M>> {
|
||||
let res = if let Some(any_receiver) = self.inner.typed() {
|
||||
any_receiver.cast_send_typed::<M>().unwrap()
|
||||
any_receiver
|
||||
.cast_send_typed::<M>()
|
||||
.unwrap()
|
||||
.send(mid, msg)
|
||||
.map_err(Into::into)
|
||||
} else {
|
||||
self.inner.send_boxed(mid, msg.into_boxed())
|
||||
.map_err(|err| err.map_msg(|b|*b.as_any_boxed().downcast::<M>().unwrap()))
|
||||
.map(|_|())
|
||||
self.inner
|
||||
.send_boxed(mid, msg.into_boxed())
|
||||
.map_err(|err| err.map_msg(|b| *b.as_any_boxed().downcast::<M>().unwrap()))
|
||||
.map(|_| ())
|
||||
};
|
||||
|
||||
res
|
||||
@ -689,8 +734,10 @@ impl Receiver {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn start_polling(&self) -> Option<Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>>> {
|
||||
Some(self.inner.clone().start_polling())
|
||||
pub fn start_polling(
|
||||
&self,
|
||||
) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>> {
|
||||
self.inner.clone().start_polling()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -703,7 +750,7 @@ impl Receiver {
|
||||
Ok((mid, async move {
|
||||
match rx.await {
|
||||
Ok(x) => x,
|
||||
Err(err) => Err(Error::from(err))
|
||||
Err(err) => Err(Error::from(err)),
|
||||
}
|
||||
}))
|
||||
}
|
||||
@ -714,27 +761,36 @@ impl Receiver {
|
||||
) -> Result<(u64, impl Future<Output = Result<R, Error>>), Error> {
|
||||
if let Some(any_receiver) = self.inner.wrapper() {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let mid = any_receiver.cast_ret_only::<R>().unwrap()
|
||||
let mid = any_receiver
|
||||
.cast_ret_only::<R>()
|
||||
.unwrap()
|
||||
.add_response_listener(tx)?;
|
||||
|
||||
Ok((mid, async move {
|
||||
Ok((
|
||||
mid,
|
||||
async move {
|
||||
match rx.await {
|
||||
Ok(x) => x,
|
||||
Err(err) => Err(Error::from(err))
|
||||
Err(err) => Err(Error::from(err)),
|
||||
}
|
||||
}.left_future()))
|
||||
}
|
||||
.left_future(),
|
||||
))
|
||||
} else {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let mid = self.inner
|
||||
.add_response_listener(tx)?;
|
||||
let mid = self.inner.add_response_listener(tx)?;
|
||||
|
||||
Ok((mid, async move {
|
||||
Ok((
|
||||
mid,
|
||||
async move {
|
||||
match rx.await {
|
||||
Ok(Ok(x)) => Ok(*x.as_any_boxed().downcast::<R>().unwrap()),
|
||||
Ok(Err(x)) => Err(x),
|
||||
Err(err) => Err(Error::from(err))
|
||||
Err(err) => Err(Error::from(err)),
|
||||
}
|
||||
}.right_future()))
|
||||
}
|
||||
.right_future(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@ -744,13 +800,15 @@ impl Receiver {
|
||||
) -> Result<(u64, impl Future<Output = Result<R, Error<(), E>>>), Error> {
|
||||
if let Some(any_wrapper) = self.inner.wrapper() {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let mid = any_wrapper.cast_ret_and_error::<R, E>().unwrap()
|
||||
let mid = any_wrapper
|
||||
.cast_ret_and_error::<R, E>()
|
||||
.unwrap()
|
||||
.add_response_listener(tx)?;
|
||||
|
||||
Ok((mid, async move {
|
||||
match rx.await {
|
||||
Ok(x) => x,
|
||||
Err(err) => Err(Error::from(err))
|
||||
Err(err) => Err(Error::from(err)),
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
@ -790,4 +848,9 @@ impl Receiver {
|
||||
warn!("flush failed!");
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter_types(&self, cb: &mut dyn FnMut(&TypeTag, &TypeTag, &TypeTag) -> bool) {
|
||||
self.inner.iter_types(cb)
|
||||
}
|
||||
}
|
||||
|
281
src/relay.rs
281
src/relay.rs
@ -1,9 +1,23 @@
|
||||
use std::{collections::HashMap, pin::Pin, sync::{Arc, atomic::{AtomicBool, AtomicU64, Ordering}}};
|
||||
use futures::Future;
|
||||
use tokio::sync::{Notify, oneshot};
|
||||
use crate::{Bus, Message, Permit, TypeTag, TypeTagged, error::Error, receiver::{Action, AnyReceiver, AnyWrapperArc, AnyWrapperRef, PermitDrop, ReceiverTrait, SendUntypedReceiver, Stats}};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
receiver::{
|
||||
Action, AnyReceiver, AnyWrapperArc, AnyWrapperRef, PermitDrop, ReceiverTrait,
|
||||
SendUntypedReceiver, Stats, TypeTagAccept,
|
||||
},
|
||||
Bus, Event, Message, Permit, ReciveUnypedReceiver, TypeTag,
|
||||
};
|
||||
use futures::{future::poll_fn, Future};
|
||||
use std::{
|
||||
pin::Pin,
|
||||
sync::{
|
||||
atomic::{AtomicBool, AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
};
|
||||
use tokio::sync::{oneshot, Notify};
|
||||
|
||||
pub trait Relay: TypeTagAccept + SendUntypedReceiver + ReciveUnypedReceiver + 'static {}
|
||||
impl<T: TypeTagAccept + SendUntypedReceiver + ReciveUnypedReceiver + 'static> Relay for T {}
|
||||
|
||||
struct SlabCfg;
|
||||
impl sharded_slab::Config for SlabCfg {
|
||||
@ -12,140 +26,6 @@ impl sharded_slab::Config for SlabCfg {
|
||||
|
||||
type Slab<T> = sharded_slab::Slab<T, SlabCfg>;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! type_map {
|
||||
(inbound : $($tt:tt)*) => {{
|
||||
let mut type_map = TypeMap::new();
|
||||
type_map!(@inbound type_map, $($tt)*);
|
||||
type_map
|
||||
}};
|
||||
|
||||
(outbound : $($tt:tt)*) => {
|
||||
let mut type_map = TypeMap::new();
|
||||
type_map!(@outbound type_map, $($tt)*);
|
||||
type_map
|
||||
};
|
||||
|
||||
(@inbound $tm: ident, $msg:ty => $resp: ty, $($tt:tt)*) => {
|
||||
$tm.add_inbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), None);
|
||||
type_map!(@inbound $tm, $($tt)*)
|
||||
};
|
||||
|
||||
(@inbound $tm: ident, $msg:ty => ($resp:ty) throws $err: ty, $($tt:tt)*) => {
|
||||
$tm.add_inbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), Some(<$err as TypeTagged>::type_tag_()));
|
||||
type_map!(@inbound $tm, $($tt)*)
|
||||
};
|
||||
|
||||
(@inbound $tm: ident, $msg:ty => $resp: ty) => {
|
||||
$tm.add_inbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), None);
|
||||
};
|
||||
|
||||
(@inbound $tm: ident,) => {};
|
||||
|
||||
(@inbound $tm: ident, outbound : $($tt:tt)*) => {
|
||||
type_map!(@outbound $tm, $($tt)*)
|
||||
};
|
||||
|
||||
(@outbound $tm: ident, $msg:ty => ($resp:ty) throws $err: ty, $($tt:tt)*) => {
|
||||
$tm.add_outbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), Some(<$err as TypeTagged>::type_tag_()));
|
||||
type_map!(@outbound $tm, $($tt)*)
|
||||
};
|
||||
|
||||
(@outbound $tm: ident, $msg:ty => $resp: ty, $($tt:tt)*) => {
|
||||
$tm.add_outbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), None);
|
||||
type_map!(@outbound $tm, $($tt)*)
|
||||
};
|
||||
|
||||
(@outbound $tm: ident, $msg:ty => $resp: ty) => {
|
||||
$tm.add_outbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), None);
|
||||
};
|
||||
|
||||
(@outbound $tm: ident,) => {};
|
||||
|
||||
(@outbound $tm: ident, inbound : $($tt:tt)*) => {
|
||||
type_map!(@inbound $tm, $($tt)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TypeMap {
|
||||
inbound: HashMap<TypeTag, Vec<(TypeTag, Option<TypeTag>)>>,
|
||||
outbound: HashMap<TypeTag, Vec<(TypeTag, Option<TypeTag>)>>,
|
||||
}
|
||||
|
||||
impl TypeMap {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inbound: Default::default(),
|
||||
outbound: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_inbound(&mut self, msg: TypeTag, resp: TypeTag, err: Option<TypeTag>) -> &mut Self {
|
||||
let vec = self.inbound.entry(msg)
|
||||
.or_insert_with(Vec::new);
|
||||
|
||||
vec.push((resp, err));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_outbound(&mut self, msg: TypeTag, resp: TypeTag, err: Option<TypeTag>) -> &mut Self {
|
||||
let vec = self.outbound.entry(msg)
|
||||
.or_insert_with(Vec::new);
|
||||
|
||||
vec.push((resp, err));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn accept_inbound(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
if let Some(vec) = self.inbound.get(msg) {
|
||||
if let Some(rr) = resp {
|
||||
vec.iter().find(|(r, e)| {
|
||||
let ee = if let Some(e) = e {
|
||||
if let Some(te) = err {
|
||||
te.as_ref() == e.as_ref()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
err.is_none()
|
||||
};
|
||||
|
||||
r.as_ref() == rr.as_ref() && ee
|
||||
}).is_some()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn accept_outbound(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
if let Some(vec) = self.outbound.get(msg) {
|
||||
if let Some(rr) = resp {
|
||||
vec.iter().find(|(r, e)| {
|
||||
let ee = if let Some(e) = e {
|
||||
if let Some(te) = err {
|
||||
te.as_ref() == e.as_ref()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
err.is_none()
|
||||
};
|
||||
|
||||
r.as_ref() == rr.as_ref() && ee
|
||||
}).is_some()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RelayContext {
|
||||
limit: u64,
|
||||
processing: AtomicU64,
|
||||
@ -154,7 +34,6 @@ pub(crate) struct RelayContext {
|
||||
synchronized: Notify,
|
||||
closed: Notify,
|
||||
response: Notify,
|
||||
type_map: TypeMap,
|
||||
}
|
||||
|
||||
impl PermitDrop for RelayContext {
|
||||
@ -163,7 +42,6 @@ impl PermitDrop for RelayContext {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub(crate) struct RelayWrapper<S>
|
||||
where
|
||||
S: 'static,
|
||||
@ -173,7 +51,7 @@ where
|
||||
waiters: Slab<oneshot::Sender<Result<Box<dyn Message>, Error>>>,
|
||||
}
|
||||
impl<S> RelayWrapper<S> {
|
||||
pub fn new(inner: S, type_map: TypeMap, limit: u64) -> Self {
|
||||
pub fn new(inner: S, limit: u64) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
context: Arc::new(RelayContext {
|
||||
@ -184,23 +62,42 @@ impl<S> RelayWrapper<S> {
|
||||
synchronized: Notify::new(),
|
||||
closed: Notify::new(),
|
||||
response: Notify::new(),
|
||||
type_map,
|
||||
}),
|
||||
waiters: sharded_slab::Slab::new_with_config::<SlabCfg>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> TypeTagAccept for RelayWrapper<S>
|
||||
where
|
||||
S: Relay + Send + Sync + 'static,
|
||||
{
|
||||
fn iter_types(&self, cb: &mut dyn FnMut(&TypeTag, &TypeTag, &TypeTag) -> bool) {
|
||||
self.inner.iter_types(cb)
|
||||
}
|
||||
|
||||
fn accept(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
self.inner.accept(msg, resp, err)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> ReceiverTrait for RelayWrapper<S>
|
||||
where
|
||||
S: SendUntypedReceiver + 'static,
|
||||
S: Relay + Send + Sync + 'static,
|
||||
{
|
||||
fn name(&self) -> &str {
|
||||
std::any::type_name::<Self>()
|
||||
}
|
||||
|
||||
fn typed(&self) -> Option<AnyReceiver<'_>> { None }
|
||||
fn wrapper(&self) -> Option<AnyWrapperRef<'_>> { None }
|
||||
fn wrapper_arc(self: Arc<Self>) -> Option<AnyWrapperArc> { None }
|
||||
fn typed(&self) -> Option<AnyReceiver<'_>> {
|
||||
None
|
||||
}
|
||||
fn wrapper(&self) -> Option<AnyWrapperRef<'_>> {
|
||||
None
|
||||
}
|
||||
fn wrapper_arc(self: Arc<Self>) -> Option<AnyWrapperArc> {
|
||||
None
|
||||
}
|
||||
fn send_boxed(
|
||||
&self,
|
||||
mid: u64,
|
||||
@ -280,65 +177,39 @@ where
|
||||
&self.context.response
|
||||
}
|
||||
|
||||
fn accept(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
self.context.type_map.accept_inbound(msg, resp, err)
|
||||
fn start_polling(
|
||||
self: Arc<Self>,
|
||||
) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>> {
|
||||
Box::new(move |_| {
|
||||
Box::pin(async move {
|
||||
loop {
|
||||
let this = self.clone();
|
||||
let event = poll_fn(move |ctx| this.inner.poll_events(ctx)).await;
|
||||
|
||||
match event {
|
||||
Event::Exited => {
|
||||
self.context.closed.notify_waiters();
|
||||
break;
|
||||
}
|
||||
Event::Flushed => self.context.flushed.notify_waiters(),
|
||||
Event::Synchronized(_res) => self.context.synchronized.notify_waiters(),
|
||||
Event::Response(mid, resp) => {
|
||||
self.context.processing.fetch_sub(1, Ordering::SeqCst);
|
||||
self.context.response.notify_one();
|
||||
|
||||
if let Some(chan) = self.waiters.take(mid as _) {
|
||||
if let Err(err) = chan.send(resp) {
|
||||
error!("Response error for mid({}): {:?}", mid, err);
|
||||
}
|
||||
} else {
|
||||
warn!("No waiters for mid({})", mid);
|
||||
}
|
||||
}
|
||||
|
||||
fn start_polling(self: Arc<Self>) -> Box<dyn FnOnce(Bus) -> Pin<Box<dyn Future<Output = ()> + Send>>> {
|
||||
Box::new(move |_| Box::pin(async move {
|
||||
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate as messagebus;
|
||||
|
||||
use crate::derive::{ Message, Error };
|
||||
|
||||
#[derive(Debug, Message)]
|
||||
struct Test1;
|
||||
|
||||
#[derive(Debug, Message)]
|
||||
struct Test2;
|
||||
|
||||
#[derive(Debug, Message)]
|
||||
struct Test3;
|
||||
|
||||
#[derive(Debug, Message)]
|
||||
struct Test4;
|
||||
#[derive(Debug, Error)]
|
||||
struct Error1;
|
||||
#[derive(Debug, Error)]
|
||||
struct Error2;
|
||||
#[test]
|
||||
fn test_type_map() {
|
||||
let tm = type_map! {
|
||||
inbound:
|
||||
Test1 => (Test2) throws Error1,
|
||||
Test2 => (Test3) throws Error1,
|
||||
|
||||
outbound:
|
||||
Test3 => (Test4) throws Error2,
|
||||
};
|
||||
|
||||
assert!(tm.accept_inbound(&Test1::type_tag_(), None, None));
|
||||
assert!(tm.accept_inbound(&Test2::type_tag_(), None, None));
|
||||
assert!(!tm.accept_inbound(&Test3::type_tag_(), None, None));
|
||||
assert!(tm.accept_outbound(&Test3::type_tag_(), None, None));
|
||||
|
||||
assert!(tm.accept_inbound(&Test1::type_tag_(), Some(&Test2::type_tag_()), None));
|
||||
assert!(!tm.accept_inbound(&Test1::type_tag_(), Some(&Test3::type_tag_()), None));
|
||||
|
||||
assert!(!tm.accept_inbound(&Test2::type_tag_(), Some(&Test2::type_tag_()), None));
|
||||
assert!(tm.accept_inbound(&Test2::type_tag_(), Some(&Test3::type_tag_()), None));
|
||||
|
||||
assert!(tm.accept_inbound(&Test1::type_tag_(), Some(&Test2::type_tag_()), Some(&Error1::type_tag_())));
|
||||
assert!(!tm.accept_inbound(&Test1::type_tag_(), Some(&Test2::type_tag_()), Some(&Error2::type_tag_())));
|
||||
|
||||
assert!(tm.accept_outbound(&Test3::type_tag_(), Some(&Test4::type_tag_()), Some(&Error2::type_tag_())));
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
332
tests/test_relay.rs
Normal file
332
tests/test_relay.rs
Normal file
@ -0,0 +1,332 @@
|
||||
use std::task::{Context, Poll};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
derive::{Error as MbError, Message},
|
||||
error::{self, GenericError},
|
||||
receivers, Action, AsyncHandler, Bus, Event, Message, MessageBounds, ReciveUnypedReceiver,
|
||||
SendUntypedReceiver, TypeTagAccept, TypeTagged,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use thiserror::Error;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
// macro_rules! type_map {
|
||||
// (inbound : $($tt:tt)*) => {{
|
||||
// let mut type_map = TypeMap::new();
|
||||
// type_map!(@inbound type_map, $($tt)*);
|
||||
// type_map
|
||||
// }};
|
||||
|
||||
// (outbound : $($tt:tt)*) => {
|
||||
// let mut type_map = TypeMap::new();
|
||||
// type_map!(@outbound type_map, $($tt)*);
|
||||
// type_map
|
||||
// };
|
||||
|
||||
// (@inbound $tm: ident, $msg:ty => $resp: ty, $($tt:tt)*) => {
|
||||
// $tm.add_inbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), None);
|
||||
// type_map!(@inbound $tm, $($tt)*)
|
||||
// };
|
||||
|
||||
// (@inbound $tm: ident, $msg:ty => ($resp:ty) throws $err: ty, $($tt:tt)*) => {
|
||||
// $tm.add_inbound(<$msg as messagebus::TypeTagged>::type_tag_(), <$resp as messagebus:TypeTagged>::type_tag_(), Some(<$err as messagebus::TypeTagged>::type_tag_()));
|
||||
// type_map!(@inbound $tm, $($tt)*)
|
||||
// };
|
||||
|
||||
// (@inbound $tm: ident, $msg:ty => $resp: ty) => {
|
||||
// $tm.add_inbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), None);
|
||||
// };
|
||||
|
||||
// (@inbound $tm: ident, outbound : $($tt:tt)*) => {
|
||||
// type_map!(@outbound $tm, $($tt)*)
|
||||
// };
|
||||
|
||||
// (@inbound $tm: ident,) => {};
|
||||
|
||||
// (@outbound $tm: ident, $msg:ty => ($resp:ty) throws $err: ty, $($tt:tt)*) => {
|
||||
// $tm.add_outbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), Some(<$err as TypeTagged>::type_tag_()));
|
||||
// type_map!(@outbound $tm, $($tt)*)
|
||||
// };
|
||||
|
||||
// (@outbound $tm: ident, $msg:ty => $resp: ty, $($tt:tt)*) => {
|
||||
// $tm.add_outbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), None);
|
||||
// type_map!(@outbound $tm, $($tt)*)
|
||||
// };
|
||||
|
||||
// (@outbound $tm: ident, $msg:ty => $resp: ty) => {
|
||||
// $tm.add_outbound(<$msg as TypeTagged>::type_tag_(), <$resp as TypeTagged>::type_tag_(), None);
|
||||
// };
|
||||
|
||||
// (@outbound $tm: ident, inbound : $($tt:tt)*) => {
|
||||
// type_map!(@inbound $tm, $($tt)*)
|
||||
// };
|
||||
|
||||
// (@outbound $tm: ident,) => {};
|
||||
// }
|
||||
|
||||
// #[derive(Debug, Clone)]
|
||||
// pub struct TypeMap {
|
||||
// inbound: HashMap<TypeTag, Vec<(TypeTag, Option<TypeTag>)>>,
|
||||
// outbound: HashMap<TypeTag, Vec<(TypeTag, Option<TypeTag>)>>,
|
||||
// }
|
||||
|
||||
// impl TypeMap {
|
||||
// pub fn new() -> Self {
|
||||
// Self {
|
||||
// inbound: Default::default(),
|
||||
// outbound: Default::default(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn add_inbound(&mut self, msg: TypeTag, resp: TypeTag, err: Option<TypeTag>) -> &mut Self {
|
||||
// let vec = self.inbound.entry(msg)
|
||||
// .or_insert_with(Vec::new);
|
||||
|
||||
// vec.push((resp, err));
|
||||
// self
|
||||
// }
|
||||
|
||||
// pub fn add_outbound(&mut self, msg: TypeTag, resp: TypeTag, err: Option<TypeTag>) -> &mut Self {
|
||||
// let vec = self.outbound.entry(msg)
|
||||
// .or_insert_with(Vec::new);
|
||||
|
||||
// vec.push((resp, err));
|
||||
// self
|
||||
// }
|
||||
|
||||
// pub fn accept_inbound(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
// if let Some(vec) = self.inbound.get(msg) {
|
||||
// if let Some(rr) = resp {
|
||||
// vec.iter().find(|(r, e)| {
|
||||
// let ee = if let Some(e) = e {
|
||||
// if let Some(te) = err {
|
||||
// te.as_ref() == e.as_ref()
|
||||
// } else {
|
||||
// true
|
||||
// }
|
||||
// } else {
|
||||
// err.is_none()
|
||||
// };
|
||||
|
||||
// r.as_ref() == rr.as_ref() && ee
|
||||
// }).is_some()
|
||||
// } else {
|
||||
// true
|
||||
// }
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn accept_outbound(&self, msg: &TypeTag, resp: Option<&TypeTag>, err: Option<&TypeTag>) -> bool {
|
||||
// if let Some(vec) = self.outbound.get(msg) {
|
||||
// if let Some(rr) = resp {
|
||||
// vec.iter().find(|(r, e)| {
|
||||
// let ee = if let Some(e) = e {
|
||||
// if let Some(te) = err {
|
||||
// te.as_ref() == e.as_ref()
|
||||
// } else {
|
||||
// true
|
||||
// }
|
||||
// } else {
|
||||
// err.is_none()
|
||||
// };
|
||||
|
||||
// r.as_ref() == rr.as_ref() && ee
|
||||
// }).is_some()
|
||||
// } else {
|
||||
// true
|
||||
// }
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[inline]
|
||||
// pub fn inbound_iter(&self) -> impl Iterator<Item = (&TypeTag, &TypeTag, Option<&TypeTag>)> {
|
||||
// self.inbound.iter().map(|(k, v)| v.into_iter().map(move |(r, e)|(k, r, e.as_ref()))).flatten()
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Debug, Error, MbError)]
|
||||
enum Error {
|
||||
#[error("Error({0})")]
|
||||
Error(anyhow::Error),
|
||||
}
|
||||
|
||||
impl<M: Message> From<error::Error<M>> for Error {
|
||||
fn from(err: error::Error<M>) -> Self {
|
||||
Self::Error(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Message)]
|
||||
pub struct Msg<F: MessageBounds + Clone>(pub F);
|
||||
|
||||
struct TmpReceiver;
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<Msg<i32>> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, msg: Msg<i32>, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
println!("TmpReceiver::handle {:?}", msg);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn sync(&self, _bus: &Bus) -> Result<(), Self::Error> {
|
||||
println!("TmpReceiver::sync");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestRelay {
|
||||
stx: mpsc::UnboundedSender<Event<Box<dyn Message>, GenericError>>,
|
||||
srx: Mutex<mpsc::UnboundedReceiver<Event<Box<dyn Message>, GenericError>>>,
|
||||
}
|
||||
|
||||
impl TypeTagAccept for TestRelay {
|
||||
fn accept(
|
||||
&self,
|
||||
msg: &messagebus::TypeTag,
|
||||
resp: Option<&messagebus::TypeTag>,
|
||||
err: Option<&messagebus::TypeTag>,
|
||||
) -> bool {
|
||||
if msg.as_ref() == Msg::<i16>::type_tag_().as_ref() {
|
||||
if let Some(resp) = resp {
|
||||
if resp.as_ref() != Msg::<u8>::type_tag_().as_ref() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if msg.as_ref() == Msg::<i32>::type_tag_().as_ref() {
|
||||
if let Some(resp) = resp {
|
||||
if resp.as_ref() != Msg::<i64>::type_tag_().as_ref()
|
||||
&& resp.as_ref() != Msg::<()>::type_tag_().as_ref()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn iter_types(
|
||||
&self,
|
||||
cb: &mut dyn FnMut(
|
||||
&messagebus::TypeTag,
|
||||
&messagebus::TypeTag,
|
||||
&messagebus::TypeTag,
|
||||
) -> bool,
|
||||
) {
|
||||
if !cb(
|
||||
&Msg::<i16>::type_tag_(),
|
||||
&Msg::<u8>::type_tag_(),
|
||||
&Error::type_tag_(),
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if !cb(
|
||||
&Msg::<i32>::type_tag_(),
|
||||
&Msg::<()>::type_tag_(),
|
||||
&Error::type_tag_(),
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if !cb(
|
||||
&Msg::<i32>::type_tag_(),
|
||||
&Msg::<i64>::type_tag_(),
|
||||
&Error::type_tag_(),
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SendUntypedReceiver for TestRelay {
|
||||
fn send(&self, msg: Action) -> Result<(), error::SendError<Action>> {
|
||||
match msg {
|
||||
Action::Close => {
|
||||
self.stx.send(Event::Exited).unwrap();
|
||||
}
|
||||
Action::Flush => {
|
||||
self.stx.send(Event::Flushed).unwrap();
|
||||
}
|
||||
Action::Sync => {
|
||||
self.stx.send(Event::Synchronized(Ok(()))).unwrap();
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
|
||||
println!("TestRelay::send {:?}", msg);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_msg(
|
||||
&self,
|
||||
mid: u64,
|
||||
msg: Box<dyn Message>,
|
||||
) -> Result<(), error::SendError<Box<dyn Message>>> {
|
||||
println!("TestRelay::send_msg [{}] {:?}", mid, msg);
|
||||
if msg.type_tag().as_ref() == Msg::<i16>::type_tag_().as_ref() {
|
||||
self.stx
|
||||
.send(Event::Response(mid, Ok(Box::new(Msg(9u8)))))
|
||||
.unwrap();
|
||||
} else {
|
||||
self.stx
|
||||
.send(Event::Response(mid, Ok(Box::new(()))))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ReciveUnypedReceiver for TestRelay {
|
||||
fn poll_events(
|
||||
&self,
|
||||
ctx: &mut Context<'_>,
|
||||
) -> Poll<Event<Box<dyn Message>, error::GenericError>> {
|
||||
let poll = self.srx.lock().poll_recv(ctx);
|
||||
match poll {
|
||||
Poll::Pending => Poll::Pending,
|
||||
Poll::Ready(Some(event)) => Poll::Ready(event),
|
||||
Poll::Ready(None) => Poll::Ready(Event::Exited),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_relay() {
|
||||
let (stx, srx) = mpsc::unbounded_channel();
|
||||
let relay = TestRelay {
|
||||
stx,
|
||||
srx: Mutex::new(srx),
|
||||
};
|
||||
|
||||
let (b, poller) = Bus::build()
|
||||
.register_relay(relay, 1)
|
||||
.register(TmpReceiver)
|
||||
.subscribe_async::<Msg<i32>>(
|
||||
1,
|
||||
receivers::BufferUnorderedConfig {
|
||||
buffer_size: 1,
|
||||
max_parallel: 1,
|
||||
},
|
||||
)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
b.send(Msg(32i32)).await.unwrap();
|
||||
let res: Msg<u8> = b.request(Msg(12i16), Default::default()).await.unwrap();
|
||||
|
||||
assert_eq!(res.0, 9u8);
|
||||
|
||||
b.flush().await;
|
||||
b.close().await;
|
||||
poller.await;
|
||||
}
|
@ -1,4 +1,7 @@
|
||||
use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use messagebus::{
|
||||
@ -42,13 +45,16 @@ impl AsyncHandler<SharedMsg<f32>> for TmpReceiver {
|
||||
type Error = Error;
|
||||
type Response = ();
|
||||
|
||||
async fn handle(&self, _msg: SharedMsg<f32>, _bus: &Bus) -> Result<Self::Response, Self::Error> {
|
||||
async fn handle(
|
||||
&self,
|
||||
_msg: SharedMsg<f32>,
|
||||
_bus: &Bus,
|
||||
) -> Result<Self::Response, Self::Error> {
|
||||
self.ctx.sync1.store(true, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[async_trait]
|
||||
impl AsyncHandler<Msg> for TmpReceiver {
|
||||
type Error = Error;
|
||||
@ -60,7 +66,6 @@ impl AsyncHandler<Msg> for TmpReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_shared() {
|
||||
let ctx = Arc::new(TmpReceiverContext {
|
||||
|
Loading…
Reference in New Issue
Block a user