1use crate::*;
2use futures::future::BoxFuture;
3use std::{any::TypeId, future::Future, marker::PhantomData, sync::Arc};
4use type_sets::SubsetOf;
5
6pub trait PolyBox: DynPolyBox + Clone {
8 type Set: Members;
10
11 fn into_dyn_unchecked<T>(self) -> DynInbox<T>;
19}
20
21pub trait PolyboxExt: PolyBox {
23 fn into_dyn_subset<T>(self) -> DynInbox<T>
27 where
28 T: SubsetOf<Self::Set>,
29 {
30 self.into_dyn_unchecked()
31 }
32
33 fn into_dyn(self) -> DynInbox<Self::Set> {
35 self.into_dyn_unchecked()
36 }
37
38 fn into_dyn_checked<T: Members>(self) -> Result<DynInbox<T>, Self> {
40 if self.accepts_msgs(&T::members()) {
41 Ok(self.into_dyn_unchecked())
42 } else {
43 Err(self)
44 }
45 }
46
47 #[must_use]
49 fn accepts_msg(&self, id: TypeId) -> bool {
50 <Self::Set as Members>::members().contains(&id)
51 }
52
53 #[must_use]
55 fn accepts_msgs(&self, ids: &[TypeId]) -> bool {
56 ids.iter()
57 .all(|id| <Self::Set as Members>::members().contains(id))
58 }
59
60 fn send_checked<T: Message>(
62 &self,
63 msg: T,
64 ) -> impl Future<Output = Result<Output<T>, SendCheckedError<T>>> + Send {
65 async {
66 let (payload, output) = T::build_payload(msg);
67 let payload = BoxedPayload::new::<T>(payload);
68
69 match self._send_boxed_payload_checked(payload).await {
70 Ok(()) => Ok(output),
71 Err(SendCheckedError::Closed(payload)) => {
72 let payload = payload
73 .downcast::<T>()
74 .expect("Failed to convert payload back");
75
76 Err(SendCheckedError::Closed(T::destroy_payload(payload)))
77 }
78 Err(SendCheckedError::NotAccepted(payload)) => {
79 Err(SendCheckedError::NotAccepted(T::destroy_payload(
80 payload
81 .downcast::<T>()
82 .expect("Failed to convert payload back"),
83 )))
84 }
85 }
86 }
87 }
88
89 fn send_checked_blocking<T: Message>(&self, msg: T) -> Result<Output<T>, SendCheckedError<T>> {
91 let (payload, output) = T::build_payload(msg);
92 let payload = BoxedPayload::new::<T>(payload);
93
94 match self._send_boxed_payload_checked_blocking(payload) {
95 Ok(()) => Ok(output),
96 Err(SendCheckedError::Closed(payload)) => {
97 let payload = payload
98 .downcast::<T>()
99 .expect("Failed to convert payload back");
100
101 Err(SendCheckedError::Closed(T::destroy_payload(payload)))
102 }
103 Err(SendCheckedError::NotAccepted(payload)) => {
104 Err(SendCheckedError::NotAccepted(T::destroy_payload(
105 payload
106 .downcast::<T>()
107 .expect("Failed to convert payload back"),
108 )))
109 }
110 }
111 }
112}
113impl<T: PolyBox> PolyboxExt for T {}
114
115pub trait DynPolyBox: Send + Sync {
117 fn _send_boxed_payload_checked(
119 &self,
120 msg: BoxedPayload,
121 ) -> BoxFuture<'_, Result<(), SendCheckedError<BoxedPayload>>>;
122
123 fn _send_boxed_payload_checked_blocking(
125 &self,
126 msg: BoxedPayload,
127 ) -> Result<(), SendCheckedError<BoxedPayload>> {
128 futures::executor::block_on(self._send_boxed_payload_checked(msg))
129 }
130}
131
132pub struct DynInbox<T> {
140 inbox: Arc<dyn DynPolyBox>,
141 _t: PhantomData<fn() -> T>,
142}
143
144impl<T> Clone for DynInbox<T> {
145 fn clone(&self) -> Self {
146 Self {
147 inbox: self.inbox.clone(),
148 _t: PhantomData,
149 }
150 }
151}
152
153impl<T> DynInbox<T> {
154 pub fn new_unchecked(inbox: Arc<dyn DynPolyBox>) -> Self {
155 Self {
156 inbox,
157 _t: PhantomData,
158 }
159 }
160
161 pub fn new<R>(inbox: R) -> Self
162 where
163 R: DynPolyBox + PolyBox + 'static,
164 T: SubsetOf<R::Set>,
165 {
166 Self {
167 inbox: Arc::new(inbox),
168 _t: PhantomData,
169 }
170 }
171}
172
173impl<T: Members> PolyBox for DynInbox<T> {
174 type Set = T;
175
176 fn into_dyn_unchecked<R>(self) -> DynInbox<R> {
177 DynInbox::new_unchecked(self.inbox)
178 }
179}
180
181impl<T, R> Sends<T> for DynInbox<R>
182where
183 T: Message<Kind: MessageSpecifier<T, Output: Send, Payload: Send>>,
184 R: Members + Contains<T>,
185{
186 async fn send(&self, msg: T) -> Result<Output<T>, SendError<T>> {
187 self.send_checked(msg).await.map_err(|e| match e {
188 SendCheckedError::Closed(msg) => SendError(msg),
189 SendCheckedError::NotAccepted(_msg) => {
190 panic!(
191 "Payload was not accepted, this should not happen if the type system is used correctly"
192 )
193 }
194 })
195 }
196}
197
198impl<T> DynPolyBox for DynInbox<T> {
199 fn _send_boxed_payload_checked(
200 &self,
201 msg: BoxedPayload,
202 ) -> BoxFuture<'_, Result<(), SendCheckedError<BoxedPayload>>> {
203 self.inbox._send_boxed_payload_checked(msg)
204 }
205}