1use std::{
2 collections::VecDeque,
3 fmt,
4 marker::PhantomData,
5 panic::{AssertUnwindSafe, catch_unwind},
6 sync::{
7 Arc, Condvar, Mutex, MutexGuard,
8 atomic::{AtomicBool, Ordering},
9 },
10 thread::{self, Thread, ThreadId},
11 time::{Duration, Instant},
12};
13
14use crate::{
15 context::FlowWithContext,
16 stream::{BoxStream, Flow, NotUsed, Sink, Source, StreamCompletion, StreamError, StreamResult},
17};
18
19use super::{
20 ASK_IDLE_YIELDS, ASK_MAX_PARK, ASK_READY_SPINS, ASK_TIME_REFRESH_ITERS, Actor, ActorFlow,
21 ActorRef, ActorResult, InFlightAsk, Message, ReplyPoll, ReplyPort, ReplyState,
22 block_on_ractor_runtime, panic_reason, recycle_reply_state, wait_for_ready_ask,
23};
24
25#[derive(Debug, Clone, PartialEq, Eq)]
30pub enum ActorStatus<T> {
31 Ok(T),
32 Err(StreamError),
33}
34
35impl<T> From<StreamResult<T>> for ActorStatus<T> {
36 fn from(value: StreamResult<T>) -> Self {
37 match value {
38 Ok(value) => Self::Ok(value),
39 Err(error) => Self::Err(error),
40 }
41 }
42}
43
44impl<T> ActorStatus<T> {
45 fn into_result(self) -> StreamResult<T> {
46 match self {
47 Self::Ok(value) => Ok(value),
48 Self::Err(error) => Err(error),
49 }
50 }
51}
52
53#[derive(Debug, Clone, PartialEq, Eq)]
56pub enum ActorSourceMessage<T> {
57 Element(T),
58 Complete,
59 Fail(String),
60}
61
62#[derive(Debug, Clone, PartialEq, Eq)]
64pub enum ActorSinkMessage<T> {
65 Element(T),
66 Complete,
67 Fail(StreamError),
68}
69
70#[derive(Debug)]
72pub enum ActorSinkBackpressureMessage<T, Ack> {
73 Init(ReplyPort<Ack>),
74 Element(T, ReplyPort<Ack>),
75 Complete,
76 Fail(StreamError),
77}
78
79#[derive(Debug, Clone, PartialEq, Eq)]
82pub struct WatchEvent {
83 reason: String,
84}
85
86impl WatchEvent {
87 #[must_use]
88 pub fn reason(&self) -> &str {
89 &self.reason
90 }
91
92 fn into_stream_error(self) -> StreamError {
93 StreamError::Failed(self.reason)
94 }
95}
96
97impl fmt::Display for WatchEvent {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 f.write_str(&self.reason)
100 }
101}
102
103pub struct ActorSource;
105
106pub struct ActorSink;
108
109pub struct ActorPubSub;
116
117impl ActorFlow {
118 #[must_use]
123 pub fn ask_with_status<In, Msg, Out, F>(
124 actor_ref: ActorRef<Msg>,
125 parallelism: usize,
126 timeout: Duration,
127 make_msg: F,
128 ) -> Flow<In, Out, NotUsed>
129 where
130 In: Send + 'static,
131 Msg: Message,
132 Out: Send + 'static,
133 F: Fn(In, ReplyPort<ActorStatus<Out>>) -> Msg + Send + Sync + 'static,
134 {
135 ask_flow_with_pending(
136 actor_ref,
137 parallelism,
138 timeout,
139 move |input, reply_to| (make_msg(input, reply_to), ()),
140 |(), reply| reply.into_result(),
141 )
142 }
143
144 #[must_use]
149 pub fn ask_with_context<In, Ctx, Msg, Out, F>(
150 actor_ref: ActorRef<Msg>,
151 parallelism: usize,
152 timeout: Duration,
153 make_msg: F,
154 ) -> FlowWithContext<In, Ctx, Out, Ctx, NotUsed>
155 where
156 In: Send + 'static,
157 Ctx: Send + 'static,
158 Msg: Message,
159 Out: Send + 'static,
160 F: Fn(In, ReplyPort<Out>) -> Msg + Send + Sync + 'static,
161 {
162 FlowWithContext::from_flow(ask_flow_with_pending(
163 actor_ref,
164 parallelism,
165 timeout,
166 move |(input, context), reply_to| (make_msg(input, reply_to), context),
167 |context, reply| Ok((reply, context)),
168 ))
169 }
170
171 #[must_use]
173 pub fn ask_with_status_and_context<In, Ctx, Msg, Out, F>(
174 actor_ref: ActorRef<Msg>,
175 parallelism: usize,
176 timeout: Duration,
177 make_msg: F,
178 ) -> FlowWithContext<In, Ctx, Out, Ctx, NotUsed>
179 where
180 In: Send + 'static,
181 Ctx: Send + 'static,
182 Msg: Message,
183 Out: Send + 'static,
184 F: Fn(In, ReplyPort<ActorStatus<Out>>) -> Msg + Send + Sync + 'static,
185 {
186 FlowWithContext::from_flow(ask_flow_with_pending(
187 actor_ref,
188 parallelism,
189 timeout,
190 move |(input, context), reply_to| (make_msg(input, reply_to), context),
191 |context, reply| reply.into_result().map(|reply| (reply, context)),
192 ))
193 }
194
195 #[must_use]
202 pub fn watch<T, Msg>(actor_ref: ActorRef<Msg>) -> Flow<T, T, NotUsed>
203 where
204 T: Send + 'static,
205 Msg: Message,
206 {
207 Flow::from_runtime_transform(move |input, materializer| {
208 let shared = Arc::new(WatchShared::default());
209 let (monitor_ref, _handle) =
210 spawn_watch_monitor(actor_ref.get_cell(), Arc::clone(&shared))?;
211 let producer_shared = Arc::clone(&shared);
212 let producer_completion = materializer.spawn_stream(move |cancelled| {
213 run_watch_upstream(input, producer_shared, cancelled)
214 });
215 Ok(Box::new(WatchStream {
216 shared,
217 monitor_ref: Some(monitor_ref),
218 producer_completion: Some(producer_completion),
219 terminated: false,
220 }) as BoxStream<T>)
221 })
222 }
223}
224
225impl ActorSource {
226 #[must_use]
236 pub fn actor_ref<T>() -> Source<T, ActorRef<ActorSourceMessage<T>>>
237 where
238 T: Send + 'static,
239 {
240 actor_source(None::<SourceBackpressure<ActorSourceMessage<T>>>)
241 }
242
243 #[must_use]
246 pub fn typed<T>() -> Source<T, ActorRef<ActorSourceMessage<T>>>
247 where
248 T: Send + 'static,
249 {
250 Self::actor_ref()
251 }
252
253 #[must_use]
259 pub fn actor_ref_with_backpressure<T, AckMsg>(
260 ack_to: ActorRef<AckMsg>,
261 ack_message: AckMsg,
262 ) -> Source<T, ActorRef<ActorSourceMessage<T>>>
263 where
264 T: Send + 'static,
265 AckMsg: Message + Clone + Sync,
266 {
267 actor_source(Some(SourceBackpressure {
268 ack_to,
269 make_ack: Arc::new(move || ack_message.clone()),
270 _marker: PhantomData,
271 }))
272 }
273}
274
275impl ActorSink {
276 #[must_use]
286 pub fn actor_ref<In, Msg, Elem, Complete, Failure>(
287 actor_ref: ActorRef<Msg>,
288 make_element_message: Elem,
289 on_complete_message: Complete,
290 on_failure_message: Failure,
291 ) -> Sink<In, StreamCompletion<NotUsed>>
292 where
293 In: Send + 'static,
294 Msg: Message,
295 Elem: Fn(In) -> Msg + Send + Sync + 'static,
296 Complete: Fn() -> Msg + Send + Sync + 'static,
297 Failure: Fn(StreamError) -> Msg + Send + Sync + 'static,
298 {
299 let make_element_message = Arc::new(make_element_message);
300 let on_complete_message = Arc::new(on_complete_message);
301 let on_failure_message = Arc::new(on_failure_message);
302 Sink::from_runner(move |mut input, materializer| {
303 let actor_ref = actor_ref.clone();
304 let make_element_message = Arc::clone(&make_element_message);
305 let on_complete_message = Arc::clone(&on_complete_message);
306 let on_failure_message = Arc::clone(&on_failure_message);
307 Ok(materializer.spawn_stream(move |cancelled| {
308 run_actor_ref_sink(
309 &mut input,
310 cancelled,
311 actor_ref,
312 make_element_message,
313 on_complete_message,
314 on_failure_message,
315 )
316 }))
317 })
318 }
319
320 #[must_use]
327 pub fn typed<In>(
328 actor_ref: ActorRef<ActorSinkMessage<In>>,
329 ) -> Sink<In, StreamCompletion<NotUsed>>
330 where
331 In: Send + 'static,
332 {
333 Self::actor_ref(
334 actor_ref,
335 ActorSinkMessage::Element,
336 || ActorSinkMessage::Complete,
337 ActorSinkMessage::Fail,
338 )
339 }
340
341 #[must_use]
348 pub fn actor_ref_with_backpressure<In, Msg, Ack, Init, Elem, Complete, Failure>(
349 actor_ref: ActorRef<Msg>,
350 timeout: Duration,
351 make_init_message: Init,
352 make_element_message: Elem,
353 on_complete_message: Complete,
354 on_failure_message: Failure,
355 ) -> Sink<In, StreamCompletion<NotUsed>>
356 where
357 In: Send + 'static,
358 Msg: Message,
359 Ack: Send + 'static,
360 Init: Fn(ReplyPort<Ack>) -> Msg + Send + Sync + 'static,
361 Elem: Fn(In, ReplyPort<Ack>) -> Msg + Send + Sync + 'static,
362 Complete: Fn() -> Msg + Send + Sync + 'static,
363 Failure: Fn(StreamError) -> Msg + Send + Sync + 'static,
364 {
365 let make_init_message = Arc::new(make_init_message);
366 let make_element_message = Arc::new(make_element_message);
367 let on_complete_message = Arc::new(on_complete_message);
368 let on_failure_message = Arc::new(on_failure_message);
369 Sink::from_runner(move |mut input, materializer| {
370 let actor_ref = actor_ref.clone();
371 let make_init_message = Arc::clone(&make_init_message);
372 let make_element_message = Arc::clone(&make_element_message);
373 let on_complete_message = Arc::clone(&on_complete_message);
374 let on_failure_message = Arc::clone(&on_failure_message);
375 Ok(materializer.spawn_stream(move |cancelled| {
376 send_and_wait_ack(&actor_ref, timeout, |reply_to| make_init_message(reply_to))?;
377 run_actor_ref_backpressure_sink(
378 &mut input,
379 cancelled,
380 actor_ref,
381 timeout,
382 make_element_message,
383 on_complete_message,
384 on_failure_message,
385 )
386 }))
387 })
388 }
389
390 #[must_use]
392 pub fn typed_with_backpressure<In, Ack>(
393 actor_ref: ActorRef<ActorSinkBackpressureMessage<In, Ack>>,
394 timeout: Duration,
395 ) -> Sink<In, StreamCompletion<NotUsed>>
396 where
397 In: Send + 'static,
398 Ack: Send + 'static,
399 {
400 Self::actor_ref_with_backpressure(
401 actor_ref,
402 timeout,
403 ActorSinkBackpressureMessage::Init,
404 ActorSinkBackpressureMessage::Element,
405 || ActorSinkBackpressureMessage::Complete,
406 ActorSinkBackpressureMessage::Fail,
407 )
408 }
409}
410
411impl ActorPubSub {
412 #[must_use]
417 pub fn source<T>(group: impl Into<String>) -> Source<T, ActorRef<ActorSourceMessage<T>>>
418 where
419 T: Send + 'static,
420 {
421 let group = group.into();
422 ActorSource::actor_ref().map_materialized_value(move |actor_ref| {
423 ractor::pg::join(group.clone(), vec![actor_ref.get_cell()]);
424 actor_ref
425 })
426 }
427
428 #[must_use]
435 pub fn sink<T>(group: impl Into<String>) -> Sink<T, StreamCompletion<NotUsed>>
436 where
437 T: Clone + Send + 'static,
438 {
439 let group = group.into();
440 Sink::from_runner(move |mut input, materializer| {
441 let group = group.clone();
442 Ok(materializer.spawn_stream(move |cancelled| {
443 loop {
444 if cancelled.load(Ordering::SeqCst) {
445 return Err(StreamError::Cancelled);
446 }
447 match input.next() {
448 Some(Ok(item)) => {
449 broadcast_to_group(&group, ActorSourceMessage::Element(item))?;
450 }
451 Some(Err(error)) => {
452 let _ = broadcast_to_group(
453 &group,
454 ActorSourceMessage::<T>::Fail(error.to_string()),
455 );
456 return Err(error);
457 }
458 None => {
459 broadcast_to_group(&group, ActorSourceMessage::<T>::Complete)?;
460 return Ok(NotUsed);
461 }
462 }
463 }
464 }))
465 })
466 }
467}
468
469fn ask_flow_with_pending<In, Msg, Reply, Out, Pending, Prepare, Finish>(
470 actor_ref: ActorRef<Msg>,
471 parallelism: usize,
472 timeout: Duration,
473 prepare: Prepare,
474 finish: Finish,
475) -> Flow<In, Out, NotUsed>
476where
477 In: Send + 'static,
478 Msg: Message,
479 Reply: Send + 'static,
480 Out: Send + 'static,
481 Pending: Send + 'static,
482 Prepare: Fn(In, ReplyPort<Reply>) -> (Msg, Pending) + Send + Sync + 'static,
483 Finish: Fn(Pending, Reply) -> StreamResult<Out> + Send + Sync + 'static,
484{
485 assert!(
486 parallelism > 0,
487 "ActorFlow ask parallelism must be greater than zero"
488 );
489 let prepare = Arc::new(prepare);
490 let finish = Arc::new(finish);
491 Flow::from_transform(move |input| {
492 ask_ractor_ordered_with_pending(
493 input,
494 actor_ref.clone(),
495 parallelism,
496 timeout,
497 Arc::clone(&prepare),
498 Arc::clone(&finish),
499 )
500 })
501}
502
503fn ask_ractor_ordered_with_pending<In, Msg, Reply, Out, Pending, Prepare, Finish>(
504 mut input: BoxStream<In>,
505 actor_ref: ActorRef<Msg>,
506 parallelism: usize,
507 timeout: Duration,
508 prepare: Arc<Prepare>,
509 finish: Arc<Finish>,
510) -> BoxStream<Out>
511where
512 In: Send + 'static,
513 Msg: Message,
514 Reply: Send + 'static,
515 Out: Send + 'static,
516 Pending: Send + 'static,
517 Prepare: Fn(In, ReplyPort<Reply>) -> (Msg, Pending) + Send + Sync + 'static,
518 Finish: Fn(Pending, Reply) -> StreamResult<Out> + Send + Sync + 'static,
519{
520 let mut in_flight = Vec::<InFlightAskWith<Reply, Pending>>::with_capacity(parallelism);
521 let mut next_index = 0_usize;
522 let mut next_to_emit = 0_usize;
523 let mut completed = Vec::with_capacity(parallelism);
524 let mut reply_pool = Vec::with_capacity(parallelism);
525 let mut input_done = false;
526
527 Box::new(std::iter::from_fn(move || {
528 loop {
529 if let Some(result) = take_completed_with_pending(&mut completed, next_to_emit) {
530 next_to_emit += 1;
531 return Some(result);
532 }
533
534 while in_flight.len() < parallelism && !input_done {
535 match input.next() {
536 Some(Ok(item)) => {
537 let index = next_index;
538 next_index += 1;
539 match start_ractor_ask_with_pending(
540 index,
541 actor_ref.clone(),
542 timeout,
543 item,
544 Arc::clone(&prepare),
545 &mut reply_pool,
546 ) {
547 Ok(ask) => in_flight.push(ask),
548 Err(error) => {
549 completed.push((index, Err(error)));
550 input_done = true;
551 }
552 }
553 }
554 Some(Err(error)) => {
555 completed.push((next_index, Err(error)));
556 next_index += 1;
557 input_done = true;
558 }
559 None => input_done = true,
560 }
561 }
562
563 if let Some(result) = take_completed_with_pending(&mut completed, next_to_emit) {
564 next_to_emit += 1;
565 return Some(result);
566 }
567
568 if in_flight.is_empty() {
569 return None;
570 }
571
572 let ask = wait_for_ready_ask_with_pending(&mut in_flight, timeout, finish.as_ref());
573 let index = ask.index;
574 let result = ask.result;
575 recycle_reply_state(ask.state, &mut reply_pool);
576 if index == next_to_emit {
577 next_to_emit += 1;
578 return Some(result);
579 }
580 completed.push((index, result));
581 }
582 }))
583}
584
585fn take_completed_with_pending<Out>(
586 completed: &mut Vec<(usize, StreamResult<Out>)>,
587 index: usize,
588) -> Option<StreamResult<Out>> {
589 let position = completed
590 .iter()
591 .position(|(completed_index, _)| *completed_index == index)?;
592 Some(completed.swap_remove(position).1)
593}
594
595struct InFlightAskWith<Reply, Pending> {
596 index: usize,
597 state: Option<Arc<ReplyState<Reply>>>,
598 pending: Option<Pending>,
599 deadline: Option<Instant>,
600}
601
602impl<Reply, Pending> InFlightAskWith<Reply, Pending> {
603 fn state(&self) -> &Arc<ReplyState<Reply>> {
604 self.state.as_ref().expect("in-flight ask has reply state")
605 }
606
607 fn into_parts(mut self) -> (Arc<ReplyState<Reply>>, Pending) {
608 let state = self.state.take().expect("in-flight ask has reply state");
609 let pending = self
610 .pending
611 .take()
612 .expect("in-flight ask has pending state");
613 (state, pending)
614 }
615}
616
617impl<Reply, Pending> Drop for InFlightAskWith<Reply, Pending> {
618 fn drop(&mut self) {
619 if let Some(state) = &self.state {
620 state.close_receiver();
621 }
622 }
623}
624
625struct CompletedAskWith<Reply, Out> {
626 index: usize,
627 result: StreamResult<Out>,
628 state: Arc<ReplyState<Reply>>,
629}
630
631fn start_ractor_ask_with_pending<In, Msg, Reply, Pending, Prepare>(
632 index: usize,
633 actor_ref: ActorRef<Msg>,
634 timeout: Duration,
635 input: In,
636 prepare: Arc<Prepare>,
637 reply_pool: &mut Vec<Arc<ReplyState<Reply>>>,
638) -> StreamResult<InFlightAskWith<Reply, Pending>>
639where
640 In: Send + 'static,
641 Msg: Message,
642 Reply: Send + 'static,
643 Pending: Send + 'static,
644 Prepare: Fn(In, ReplyPort<Reply>) -> (Msg, Pending) + Send + Sync + 'static,
645{
646 let reply_state = match reply_pool.pop() {
647 Some(state) => {
648 state.reset(timeout);
649 state
650 }
651 None => Arc::new(ReplyState::new(timeout)),
652 };
653 let reply_to = ReplyPort::new(Arc::clone(&reply_state));
654 let (message, pending) =
655 catch_unwind(AssertUnwindSafe(|| prepare(input, reply_to))).map_err(|panic| {
656 StreamError::ActorAskTaskFailed {
657 reason: panic_reason(panic),
658 }
659 })?;
660
661 send_actor_message(&actor_ref, message)?;
662
663 Ok(InFlightAskWith {
664 index,
665 state: Some(reply_state),
666 pending: Some(pending),
667 deadline: Instant::now().checked_add(timeout),
668 })
669}
670
671fn wait_for_ready_ask_with_pending<Reply, Pending, Out, Finish>(
672 in_flight: &mut Vec<InFlightAskWith<Reply, Pending>>,
673 timeout: Duration,
674 finish: &Finish,
675) -> CompletedAskWith<Reply, Out>
676where
677 Reply: Send + 'static,
678 Pending: Send + 'static,
679 Out: Send + 'static,
680 Finish: Fn(Pending, Reply) -> StreamResult<Out>,
681{
682 let mut idle_spins = 0;
683 let mut idle_yields = 0;
684 let mut time_refresh = 0_u32;
685 let mut now = Instant::now();
686 loop {
687 if time_refresh == 0 {
688 now = Instant::now();
689 }
690 time_refresh = (time_refresh + 1) % ASK_TIME_REFRESH_ITERS;
691 if let Some(ask) = take_ready_ask_with_pending(in_flight, timeout, now, finish) {
692 return ask;
693 }
694
695 if idle_spins < ASK_READY_SPINS {
696 idle_spins += 1;
697 std::hint::spin_loop();
698 } else if idle_yields < ASK_IDLE_YIELDS {
699 idle_yields += 1;
700 time_refresh = 0;
701 thread::yield_now();
702 } else {
703 idle_spins = 0;
704 idle_yields = 0;
705 time_refresh = 0;
706 let current = thread::current();
707 let registered = register_ask_waiters_with_pending(in_flight, ¤t);
708 now = Instant::now();
709 if let Some(ask) = take_ready_ask_with_pending(in_flight, timeout, now, finish) {
710 unregister_ask_waiters_with_pending(registered, current.id());
711 return ask;
712 }
713 thread::park_timeout(next_ask_park_with_pending(in_flight, now));
714 unregister_ask_waiters_with_pending(registered, current.id());
715 }
716 }
717}
718
719fn take_ready_ask_with_pending<Reply, Pending, Out, Finish>(
720 in_flight: &mut Vec<InFlightAskWith<Reply, Pending>>,
721 timeout: Duration,
722 now: Instant,
723 finish: &Finish,
724) -> Option<CompletedAskWith<Reply, Out>>
725where
726 Finish: Fn(Pending, Reply) -> StreamResult<Out>,
727{
728 let mut index = 0;
729 while index < in_flight.len() {
730 match in_flight[index].state().poll() {
731 ReplyPoll::Ready(reply) => {
732 let ask = in_flight.swap_remove(index);
733 let ask_index = ask.index;
734 let (state, pending) = ask.into_parts();
735 return Some(CompletedAskWith {
736 index: ask_index,
737 result: finish(pending, reply),
738 state,
739 });
740 }
741 ReplyPoll::Dropped => {
742 let ask = in_flight.swap_remove(index);
743 let ask_index = ask.index;
744 let (state, _pending) = ask.into_parts();
745 return Some(CompletedAskWith {
746 index: ask_index,
747 result: Err(StreamError::ActorAskResponseDropped),
748 state,
749 });
750 }
751 ReplyPoll::Pending => {
752 if in_flight[index]
753 .deadline
754 .is_some_and(|deadline| now >= deadline)
755 {
756 let outcome = in_flight[index].state().close_on_timeout();
757 let ask = in_flight.swap_remove(index);
758 let ask_index = ask.index;
759 let (state, pending) = ask.into_parts();
760 let result = match outcome {
761 ReplyPoll::Ready(reply) => finish(pending, reply),
762 ReplyPoll::Dropped => Err(StreamError::ActorAskResponseDropped),
763 ReplyPoll::Pending => Err(StreamError::ActorAskTimeout { timeout }),
764 };
765 return Some(CompletedAskWith {
766 index: ask_index,
767 result,
768 state,
769 });
770 }
771 index += 1;
772 }
773 }
774 }
775 None
776}
777
778fn register_ask_waiters_with_pending<Reply, Pending>(
779 in_flight: &[InFlightAskWith<Reply, Pending>],
780 current: &Thread,
781) -> Vec<Arc<ReplyState<Reply>>> {
782 let mut registered = Vec::with_capacity(in_flight.len());
783 for ask in in_flight {
784 ask.state().register_waiter(current.clone());
785 registered.push(Arc::clone(ask.state()));
786 }
787 registered
788}
789
790fn unregister_ask_waiters_with_pending<Reply>(
791 registered: Vec<Arc<ReplyState<Reply>>>,
792 current_id: ThreadId,
793) {
794 for state in registered {
795 state.unregister_waiter(current_id);
796 }
797}
798
799fn next_ask_park_with_pending<Reply, Pending>(
800 in_flight: &[InFlightAskWith<Reply, Pending>],
801 now: Instant,
802) -> Duration {
803 in_flight
804 .iter()
805 .filter_map(|ask| ask.deadline)
806 .map(|deadline| deadline.saturating_duration_since(now))
807 .min()
808 .unwrap_or(ASK_MAX_PARK)
809 .min(ASK_MAX_PARK)
810}
811
812struct SourceBackpressure<AckMsg> {
813 ack_to: ActorRef<AckMsg>,
814 make_ack: Arc<dyn Fn() -> AckMsg + Send + Sync>,
815 _marker: PhantomData<fn() -> AckMsg>,
816}
817
818impl<AckMsg> Clone for SourceBackpressure<AckMsg> {
819 fn clone(&self) -> Self {
820 Self {
821 ack_to: self.ack_to.clone(),
822 make_ack: Arc::clone(&self.make_ack),
823 _marker: PhantomData,
824 }
825 }
826}
827
828fn actor_source<T, AckMsg>(
829 backpressure: Option<SourceBackpressure<AckMsg>>,
830) -> Source<T, ActorRef<ActorSourceMessage<T>>>
831where
832 T: Send + 'static,
833 AckMsg: Message,
834{
835 Source::from_materialized_factory(move |_materializer| {
836 let shared = Arc::new(ActorSourceShared::new(backpressure.is_none()));
837 let actor = SourceActor {
838 shared: Arc::clone(&shared),
839 backpressure: backpressure.clone(),
840 };
841 let (actor_ref, _handle) =
842 block_on_ractor_runtime(Actor::spawn(None, actor, SourceActorState::default()))?
843 .map_err(|error| {
844 StreamError::Failed(format!("actor source failed to spawn: {error}"))
845 })?;
846 let stream = ActorSourceStream {
847 shared,
848 actor_ref: Some(actor_ref.clone()),
849 backpressure: backpressure.clone(),
850 terminated: false,
851 };
852 Ok((Box::new(stream) as BoxStream<T>, actor_ref))
853 })
854}
855
856struct ActorSourceShared<T> {
857 inner: Mutex<ActorSourceInner<T>>,
858 available: Condvar,
859}
860
861impl<T> ActorSourceShared<T> {
862 fn new(ready: bool) -> Self {
863 Self {
864 inner: Mutex::new(ActorSourceInner {
865 queue: VecDeque::new(),
866 completed: false,
867 ready,
868 }),
869 available: Condvar::new(),
870 }
871 }
872
873 fn lock(&self) -> MutexGuard<'_, ActorSourceInner<T>> {
874 self.inner
875 .lock()
876 .unwrap_or_else(|poison| poison.into_inner())
877 }
878
879 fn push(&self, item: T) {
880 let mut inner = self.lock();
881 if !inner.completed {
882 inner.queue.push_back(Ok(item));
883 }
884 drop(inner);
885 self.available.notify_all();
886 }
887
888 fn complete(&self) {
889 let mut inner = self.lock();
890 inner.completed = true;
891 drop(inner);
892 self.available.notify_all();
893 }
894
895 fn fail(&self, error: StreamError) {
896 let mut inner = self.lock();
897 inner.queue.clear();
898 inner.queue.push_back(Err(error));
899 inner.completed = true;
900 drop(inner);
901 self.available.notify_all();
902 }
903
904 fn mark_ready(&self) {
905 let mut inner = self.lock();
906 if !inner.completed {
907 inner.ready = true;
908 }
909 drop(inner);
910 self.available.notify_all();
911 }
912}
913
914struct ActorSourceInner<T> {
915 queue: VecDeque<StreamResult<T>>,
916 completed: bool,
917 ready: bool,
918}
919
920struct SourceActor<T, AckMsg> {
921 shared: Arc<ActorSourceShared<T>>,
922 backpressure: Option<SourceBackpressure<AckMsg>>,
923}
924
925#[derive(Default)]
926struct SourceActorState {
927 stopped_by_stream: bool,
928}
929
930impl<T, AckMsg> Actor for SourceActor<T, AckMsg>
931where
932 T: Send + 'static,
933 AckMsg: Message,
934{
935 type Msg = ActorSourceMessage<T>;
936 type State = SourceActorState;
937 type Arguments = SourceActorState;
938
939 async fn pre_start(
940 &self,
941 myself: ActorRef<Self::Msg>,
942 args: Self::Arguments,
943 ) -> ActorResult<Self::State> {
944 if let Some(backpressure) = &self.backpressure {
945 match send_source_ack(backpressure) {
946 Ok(()) => {
947 self.shared.mark_ready();
948 }
949 Err(error) => {
950 self.shared.fail(error);
951 myself.stop(None);
952 }
953 }
954 }
955 Ok(args)
956 }
957
958 async fn handle(
959 &self,
960 myself: ActorRef<Self::Msg>,
961 message: Self::Msg,
962 _state: &mut Self::State,
963 ) -> ActorResult {
964 match message {
965 ActorSourceMessage::Element(item) => {
966 if self.backpressure.is_some() {
967 let mut inner = self.shared.lock();
968 if !inner.ready {
969 inner.queue.clear();
970 inner.queue.push_back(Err(actor_interop_error(
971 "actor source backpressure protocol violation: element arrived before ack",
972 )));
973 inner.completed = true;
974 drop(inner);
975 self.shared.available.notify_all();
976 myself.stop(None);
977 return Ok(());
978 }
979 inner.ready = false;
980 drop(inner);
981 }
982 self.shared.push(item);
983 }
984 ActorSourceMessage::Complete => {
985 self.shared.complete();
986 myself.stop(None);
987 }
988 ActorSourceMessage::Fail(reason) => {
989 self.shared.fail(StreamError::Failed(reason));
990 myself.stop(None);
991 }
992 }
993 Ok(())
994 }
995
996 async fn post_stop(
997 &self,
998 _myself: ActorRef<Self::Msg>,
999 state: &mut Self::State,
1000 ) -> ActorResult {
1001 if !state.stopped_by_stream {
1002 self.shared.complete();
1003 }
1004 Ok(())
1005 }
1006}
1007
1008struct ActorSourceStream<T, AckMsg> {
1009 shared: Arc<ActorSourceShared<T>>,
1010 actor_ref: Option<ActorRef<ActorSourceMessage<T>>>,
1011 backpressure: Option<SourceBackpressure<AckMsg>>,
1012 terminated: bool,
1013}
1014
1015impl<T, AckMsg> Iterator for ActorSourceStream<T, AckMsg>
1016where
1017 T: Send + 'static,
1018 AckMsg: Message,
1019{
1020 type Item = StreamResult<T>;
1021
1022 fn next(&mut self) -> Option<Self::Item> {
1023 if self.terminated {
1024 return None;
1025 }
1026
1027 let next = {
1028 let mut inner = self.shared.lock();
1029 loop {
1030 if let Some(item) = inner.queue.pop_front() {
1031 break Some(item);
1032 }
1033 if inner.completed {
1034 self.terminated = true;
1035 break None;
1036 }
1037 inner = self
1038 .shared
1039 .available
1040 .wait(inner)
1041 .unwrap_or_else(|poison| poison.into_inner());
1042 }
1043 };
1044
1045 if let Some(Ok(_)) = &next
1046 && let Some(backpressure) = &self.backpressure
1047 {
1048 match send_source_ack(backpressure) {
1049 Ok(()) => self.shared.mark_ready(),
1050 Err(error) => {
1051 self.shared.fail(error.clone());
1052 return Some(Err(error));
1053 }
1054 }
1055 }
1056
1057 next
1058 }
1059}
1060
1061impl<T, AckMsg> Drop for ActorSourceStream<T, AckMsg> {
1062 fn drop(&mut self) {
1063 if let Some(actor_ref) = self.actor_ref.take() {
1064 actor_ref.stop(None);
1065 }
1066 }
1067}
1068
1069fn send_source_ack<AckMsg>(backpressure: &SourceBackpressure<AckMsg>) -> StreamResult<()>
1070where
1071 AckMsg: Message,
1072{
1073 let ack = catch_unwind(AssertUnwindSafe(|| (backpressure.make_ack)())).map_err(|panic| {
1074 StreamError::Failed(format!(
1075 "actor source ack builder failed: {}",
1076 panic_reason(panic)
1077 ))
1078 })?;
1079 send_actor_message(&backpressure.ack_to, ack)
1080}
1081
1082fn run_actor_ref_sink<In, Msg, Elem, Complete, Failure>(
1083 input: &mut BoxStream<In>,
1084 cancelled: Arc<AtomicBool>,
1085 actor_ref: ActorRef<Msg>,
1086 make_element_message: Arc<Elem>,
1087 on_complete_message: Arc<Complete>,
1088 on_failure_message: Arc<Failure>,
1089) -> StreamResult<NotUsed>
1090where
1091 Msg: Message,
1092 Elem: Fn(In) -> Msg,
1093 Complete: Fn() -> Msg,
1094 Failure: Fn(StreamError) -> Msg,
1095{
1096 loop {
1097 if cancelled.load(Ordering::SeqCst) {
1098 return Err(StreamError::Cancelled);
1099 }
1100 match input.next() {
1101 Some(Ok(item)) => {
1102 let message = catch_unwind(AssertUnwindSafe(|| make_element_message(item)))
1103 .map_err(actor_sink_panic)?;
1104 send_actor_message(&actor_ref, message)?;
1105 }
1106 Some(Err(error)) => {
1107 let message = catch_unwind(AssertUnwindSafe(|| on_failure_message(error.clone())))
1108 .map_err(actor_sink_panic)?;
1109 send_actor_message(&actor_ref, message)?;
1110 return Err(error);
1111 }
1112 None => {
1113 let message = catch_unwind(AssertUnwindSafe(|| on_complete_message()))
1114 .map_err(actor_sink_panic)?;
1115 send_actor_message(&actor_ref, message)?;
1116 return Ok(NotUsed);
1117 }
1118 }
1119 }
1120}
1121
1122fn run_actor_ref_backpressure_sink<In, Msg, Ack, Elem, Complete, Failure>(
1123 input: &mut BoxStream<In>,
1124 cancelled: Arc<AtomicBool>,
1125 actor_ref: ActorRef<Msg>,
1126 timeout: Duration,
1127 make_element_message: Arc<Elem>,
1128 on_complete_message: Arc<Complete>,
1129 on_failure_message: Arc<Failure>,
1130) -> StreamResult<NotUsed>
1131where
1132 Msg: Message,
1133 Ack: Send + 'static,
1134 Elem: Fn(In, ReplyPort<Ack>) -> Msg,
1135 Complete: Fn() -> Msg,
1136 Failure: Fn(StreamError) -> Msg,
1137{
1138 loop {
1139 if cancelled.load(Ordering::SeqCst) {
1140 return Err(StreamError::Cancelled);
1141 }
1142 match input.next() {
1143 Some(Ok(item)) => {
1144 send_and_wait_ack(&actor_ref, timeout, |reply_to| {
1145 make_element_message(item, reply_to)
1146 })?;
1147 }
1148 Some(Err(error)) => {
1149 let message = catch_unwind(AssertUnwindSafe(|| on_failure_message(error.clone())))
1150 .map_err(actor_sink_panic)?;
1151 send_actor_message(&actor_ref, message)?;
1152 return Err(error);
1153 }
1154 None => {
1155 let message = catch_unwind(AssertUnwindSafe(|| on_complete_message()))
1156 .map_err(actor_sink_panic)?;
1157 send_actor_message(&actor_ref, message)?;
1158 return Ok(NotUsed);
1159 }
1160 }
1161 }
1162}
1163
1164fn send_and_wait_ack<Msg, Ack, Build>(
1165 actor_ref: &ActorRef<Msg>,
1166 timeout: Duration,
1167 build: Build,
1168) -> StreamResult<()>
1169where
1170 Msg: Message,
1171 Ack: Send + 'static,
1172 Build: FnOnce(ReplyPort<Ack>) -> Msg,
1173{
1174 let reply_state = Arc::new(ReplyState::new(timeout));
1175 let reply_to = ReplyPort::new(Arc::clone(&reply_state));
1176 let message = catch_unwind(AssertUnwindSafe(|| build(reply_to))).map_err(actor_sink_panic)?;
1177 send_actor_message(actor_ref, message)?;
1178 let ask = InFlightAsk {
1179 index: 0,
1180 state: Some(reply_state),
1181 deadline: Instant::now().checked_add(timeout),
1182 };
1183 let mut in_flight = vec![ask];
1184 wait_for_ready_ask(&mut in_flight, timeout)
1185 .result
1186 .map(|_ack| ())
1187}
1188
1189fn actor_sink_panic(panic: Box<dyn std::any::Any + Send>) -> StreamError {
1190 StreamError::Failed(format!(
1191 "actor sink message builder failed: {}",
1192 panic_reason(panic)
1193 ))
1194}
1195
1196fn send_actor_message<Msg>(actor_ref: &ActorRef<Msg>, message: Msg) -> StreamResult<()>
1197where
1198 Msg: Message,
1199{
1200 match actor_ref.cast(message) {
1201 Ok(()) => Ok(()),
1202 Err(ractor::MessagingErr::SendErr(_)) | Err(ractor::MessagingErr::ChannelClosed) => {
1203 Err(StreamError::ActorTerminated)
1204 }
1205 Err(error) => Err(StreamError::ActorAskSendFailed {
1206 reason: error.to_string(),
1207 }),
1208 }
1209}
1210
1211fn broadcast_to_group<T>(group: &str, message: ActorSourceMessage<T>) -> StreamResult<()>
1212where
1213 T: Clone + Send + 'static,
1214{
1215 for member in ractor::pg::get_members(&group.to_owned()) {
1216 let actor_ref: ActorRef<ActorSourceMessage<T>> = member.into();
1217 match send_actor_message(&actor_ref, message.clone()) {
1218 Ok(()) | Err(StreamError::ActorTerminated) => {}
1219 Err(error) => return Err(error),
1220 }
1221 }
1222 Ok(())
1223}
1224
1225struct WatchShared<T> {
1226 inner: Mutex<WatchInner<T>>,
1227 available: Condvar,
1228}
1229
1230impl<T> Default for WatchShared<T> {
1231 fn default() -> Self {
1232 Self {
1233 inner: Mutex::new(WatchInner {
1234 queue: VecDeque::new(),
1235 event: None,
1236 upstream_done: false,
1237 }),
1238 available: Condvar::new(),
1239 }
1240 }
1241}
1242
1243impl<T> WatchShared<T> {
1244 fn lock(&self) -> MutexGuard<'_, WatchInner<T>> {
1245 self.inner
1246 .lock()
1247 .unwrap_or_else(|poison| poison.into_inner())
1248 }
1249
1250 fn push(&self, item: StreamResult<T>) -> bool {
1251 let mut inner = self.lock();
1252 if inner.event.is_some() || inner.upstream_done {
1253 return false;
1254 }
1255 inner.queue.push_back(item);
1256 drop(inner);
1257 self.available.notify_all();
1258 true
1259 }
1260
1261 fn complete(&self) {
1262 let mut inner = self.lock();
1263 inner.upstream_done = true;
1264 drop(inner);
1265 self.available.notify_all();
1266 }
1267
1268 fn fail(&self, event: WatchEvent) {
1269 let mut inner = self.lock();
1270 if inner.event.is_none() {
1271 inner.queue.clear();
1272 inner.event = Some(event);
1273 inner.upstream_done = true;
1274 }
1275 drop(inner);
1276 self.available.notify_all();
1277 }
1278}
1279
1280struct WatchInner<T> {
1281 queue: VecDeque<StreamResult<T>>,
1282 event: Option<WatchEvent>,
1283 upstream_done: bool,
1284}
1285
1286struct WatchMonitorActor<T> {
1287 watched: ractor::ActorCell,
1288 shared: Arc<WatchShared<T>>,
1289 ready: Mutex<Option<std::sync::mpsc::Sender<()>>>,
1290}
1291
1292impl<T> Actor for WatchMonitorActor<T>
1293where
1294 T: Send + 'static,
1295{
1296 type Msg = ();
1297 type State = ();
1298 type Arguments = ();
1299
1300 async fn pre_start(
1301 &self,
1302 myself: ActorRef<Self::Msg>,
1303 _args: Self::Arguments,
1304 ) -> ActorResult<Self::State> {
1305 myself.monitor(self.watched.clone());
1306 let ready = self
1307 .ready
1308 .lock()
1309 .unwrap_or_else(|poison| poison.into_inner())
1310 .take();
1311 if let Some(ready) = ready {
1312 let _ = ready.send(());
1313 }
1314 Ok(())
1315 }
1316
1317 async fn handle_supervisor_evt(
1318 &self,
1319 myself: ActorRef<Self::Msg>,
1320 event: ractor::SupervisionEvent,
1321 _state: &mut Self::State,
1322 ) -> ActorResult {
1323 match event {
1324 ractor::SupervisionEvent::ActorTerminated(who, _, reason)
1325 if who.get_id() == self.watched.get_id() =>
1326 {
1327 let detail = reason.unwrap_or_else(|| "terminated".to_owned());
1328 self.shared.fail(WatchEvent {
1329 reason: format!("watched actor terminated: {detail}"),
1330 });
1331 myself.stop(None);
1332 }
1333 ractor::SupervisionEvent::ActorFailed(who, error)
1334 if who.get_id() == self.watched.get_id() =>
1335 {
1336 self.shared.fail(WatchEvent {
1337 reason: format!("watched actor terminated: {error}"),
1338 });
1339 myself.stop(None);
1340 }
1341 _ => {}
1342 }
1343 Ok(())
1344 }
1345
1346 async fn post_stop(
1347 &self,
1348 myself: ActorRef<Self::Msg>,
1349 _state: &mut Self::State,
1350 ) -> ActorResult {
1351 myself.unmonitor(self.watched.clone());
1352 Ok(())
1353 }
1354}
1355
1356fn spawn_watch_monitor<T>(
1357 watched: ractor::ActorCell,
1358 shared: Arc<WatchShared<T>>,
1359) -> StreamResult<(ActorRef<()>, ractor::concurrency::JoinHandle<()>)>
1360where
1361 T: Send + 'static,
1362{
1363 let (ready_tx, ready_rx) = std::sync::mpsc::channel();
1364 block_on_ractor_runtime(Actor::spawn(
1365 None,
1366 WatchMonitorActor {
1367 watched,
1368 shared,
1369 ready: Mutex::new(Some(ready_tx)),
1370 },
1371 (),
1372 ))?
1373 .map_err(|error| StreamError::Failed(format!("watch monitor failed to spawn: {error}")))
1374 .and_then(|(monitor_ref, handle)| {
1375 ready_rx.recv_timeout(Duration::from_secs(1)).map_err(|_| {
1376 monitor_ref.stop(None);
1377 StreamError::Failed("watch monitor did not become ready".to_owned())
1378 })?;
1379 Ok((monitor_ref, handle))
1380 })
1381}
1382
1383struct WatchStream<T> {
1384 shared: Arc<WatchShared<T>>,
1385 monitor_ref: Option<ActorRef<()>>,
1386 producer_completion: Option<StreamCompletion<NotUsed>>,
1387 terminated: bool,
1388}
1389
1390impl<T> Iterator for WatchStream<T>
1391where
1392 T: Send + 'static,
1393{
1394 type Item = StreamResult<T>;
1395
1396 fn next(&mut self) -> Option<Self::Item> {
1397 if self.terminated {
1398 return None;
1399 }
1400
1401 let mut inner = self.shared.lock();
1402 loop {
1403 if let Some(event) = inner.event.take() {
1404 self.terminated = true;
1405 return Some(Err(event.into_stream_error()));
1406 }
1407 if let Some(item) = inner.queue.pop_front() {
1408 if item.is_err() {
1409 self.terminated = true;
1410 }
1411 return Some(item);
1412 }
1413 if inner.upstream_done {
1414 self.terminated = true;
1415 return None;
1416 }
1417 inner = self
1418 .shared
1419 .available
1420 .wait(inner)
1421 .unwrap_or_else(|poison| poison.into_inner());
1422 }
1423 }
1424}
1425
1426impl<T> Drop for WatchStream<T> {
1427 fn drop(&mut self) {
1428 if let Some(monitor_ref) = self.monitor_ref.take() {
1429 monitor_ref.stop(None);
1430 }
1431 drop(self.producer_completion.take());
1432 }
1433}
1434
1435fn run_watch_upstream<T>(
1436 mut input: BoxStream<T>,
1437 shared: Arc<WatchShared<T>>,
1438 cancelled: Arc<AtomicBool>,
1439) -> StreamResult<NotUsed>
1440where
1441 T: Send + 'static,
1442{
1443 loop {
1444 if cancelled.load(Ordering::SeqCst) {
1445 shared.complete();
1446 return Err(StreamError::Cancelled);
1447 }
1448 match input.next() {
1449 Some(Ok(item)) => {
1450 if !shared.push(Ok(item)) {
1451 return Err(StreamError::Cancelled);
1452 }
1453 }
1454 Some(Err(error)) => {
1455 let _ = shared.push(Err(error.clone()));
1456 shared.complete();
1457 return Err(error);
1458 }
1459 None => {
1460 shared.complete();
1461 return Ok(NotUsed);
1462 }
1463 }
1464 }
1465}
1466
1467fn actor_interop_error(reason: impl Into<String>) -> StreamError {
1468 StreamError::Failed(reason.into())
1469}
1470
1471#[cfg(test)]
1472mod tests {
1473 use super::*;
1474 use crate::stream::{Keep, Sink};
1475 use std::{
1476 sync::{
1477 Arc as StdArc, Mutex as StdMutex,
1478 atomic::{AtomicUsize, Ordering},
1479 mpsc,
1480 },
1481 time::{Duration as StdDuration, Instant as StdInstant},
1482 };
1483
1484 fn wait_until<F>(timeout: StdDuration, mut condition: F) -> bool
1485 where
1486 F: FnMut() -> bool,
1487 {
1488 let deadline = StdInstant::now() + timeout;
1489 while StdInstant::now() < deadline {
1490 if condition() {
1491 return true;
1492 }
1493 std::thread::park_timeout(StdDuration::from_millis(1));
1494 }
1495 condition()
1496 }
1497
1498 fn spawn_actor<A>(
1499 actor: A,
1500 args: A::Arguments,
1501 ) -> (ActorRef<A::Msg>, ractor::concurrency::JoinHandle<()>)
1502 where
1503 A: Actor,
1504 A::Msg: Message,
1505 A::Arguments: Send + 'static,
1506 {
1507 block_on_ractor_runtime(Actor::spawn(None, actor, args))
1508 .expect("ractor runtime runs")
1509 .expect("actor spawns")
1510 }
1511
1512 fn stop_actor<Msg>(actor_ref: ActorRef<Msg>, handle: ractor::concurrency::JoinHandle<()>)
1513 where
1514 Msg: Message,
1515 {
1516 actor_ref.stop(None);
1517 block_on_ractor_runtime(async move {
1518 handle.await.expect("actor task joins");
1519 })
1520 .expect("ractor runtime joins actor");
1521 }
1522
1523 enum AskInteropMsg {
1524 Status {
1525 input: u64,
1526 reply_to: ReplyPort<ActorStatus<u64>>,
1527 },
1528 Plain {
1529 input: u64,
1530 reply_to: ReplyPort<u64>,
1531 },
1532 }
1533
1534 struct AskInteropActor;
1535
1536 impl Actor for AskInteropActor {
1537 type Msg = AskInteropMsg;
1538 type State = ();
1539 type Arguments = ();
1540
1541 async fn pre_start(
1542 &self,
1543 _myself: ActorRef<Self::Msg>,
1544 _args: Self::Arguments,
1545 ) -> ActorResult<Self::State> {
1546 Ok(())
1547 }
1548
1549 async fn handle(
1550 &self,
1551 _myself: ActorRef<Self::Msg>,
1552 message: Self::Msg,
1553 _state: &mut Self::State,
1554 ) -> ActorResult {
1555 match message {
1556 AskInteropMsg::Status { input: 0, reply_to } => {
1557 let _ =
1558 reply_to.send(ActorStatus::Err(StreamError::Failed("bad status".into())));
1559 }
1560 AskInteropMsg::Status { input, reply_to } => {
1561 let _ = reply_to.send(ActorStatus::Ok(input + 10));
1562 }
1563 AskInteropMsg::Plain { input, reply_to } => {
1564 let _ = reply_to.send(input * 2);
1565 }
1566 }
1567 Ok(())
1568 }
1569 }
1570
1571 #[test]
1572 fn ask_with_status_unwraps_ok_and_fails_err() {
1573 let (actor_ref, handle) = spawn_actor(AskInteropActor, ());
1574
1575 let values = Source::from_iter([1_u64, 2])
1576 .via(ActorFlow::ask_with_status(
1577 actor_ref.clone(),
1578 2,
1579 Duration::from_secs(1),
1580 |input, reply_to| AskInteropMsg::Status { input, reply_to },
1581 ))
1582 .run_collect()
1583 .unwrap();
1584 assert_eq!(values, vec![11, 12]);
1585
1586 let failed = Source::single(0_u64)
1587 .via(ActorFlow::ask_with_status(
1588 actor_ref.clone(),
1589 1,
1590 Duration::from_secs(1),
1591 |input, reply_to| AskInteropMsg::Status { input, reply_to },
1592 ))
1593 .run_collect();
1594 assert_eq!(failed, Err(StreamError::Failed("bad status".into())));
1595
1596 stop_actor(actor_ref, handle);
1597 }
1598
1599 #[test]
1600 fn ask_with_context_preserves_context() {
1601 let (actor_ref, handle) = spawn_actor(AskInteropActor, ());
1602
1603 let values = Source::from_iter([1_u64, 2, 3])
1604 .as_source_with_context(|item| item + 100)
1605 .via(ActorFlow::ask_with_context(
1606 actor_ref.clone(),
1607 2,
1608 Duration::from_secs(1),
1609 |input, reply_to| AskInteropMsg::Plain { input, reply_to },
1610 ))
1611 .run_collect()
1612 .unwrap();
1613
1614 assert_eq!(values, vec![(2, 101), (4, 102), (6, 103)]);
1615 stop_actor(actor_ref, handle);
1616 }
1617
1618 #[test]
1619 fn ask_with_status_and_context_preserves_context_and_fails_status() {
1620 let (actor_ref, handle) = spawn_actor(AskInteropActor, ());
1621
1622 let values = Source::from_iter([1_u64, 2])
1623 .as_source_with_context(|item| item + 10)
1624 .via(ActorFlow::ask_with_status_and_context(
1625 actor_ref.clone(),
1626 2,
1627 Duration::from_secs(1),
1628 |input, reply_to| AskInteropMsg::Status { input, reply_to },
1629 ))
1630 .run_collect()
1631 .unwrap();
1632 assert_eq!(values, vec![(11, 11), (12, 12)]);
1633
1634 let failed = Source::single(0_u64)
1635 .as_source_with_context(|_| 99_u64)
1636 .via(ActorFlow::ask_with_status_and_context(
1637 actor_ref.clone(),
1638 1,
1639 Duration::from_secs(1),
1640 |input, reply_to| AskInteropMsg::Status { input, reply_to },
1641 ))
1642 .run_collect();
1643 assert_eq!(failed, Err(StreamError::Failed("bad status".into())));
1644
1645 stop_actor(actor_ref, handle);
1646 }
1647
1648 #[test]
1649 fn actor_source_actor_ref_emits_and_completes() {
1650 let (actor_ref, completion) = ActorSource::actor_ref::<u64>()
1651 .to_mat(Sink::collect(), Keep::both)
1652 .run()
1653 .unwrap();
1654
1655 actor_ref.cast(ActorSourceMessage::Element(1)).unwrap();
1656 actor_ref.cast(ActorSourceMessage::Element(2)).unwrap();
1657 actor_ref.cast(ActorSourceMessage::Complete).unwrap();
1658
1659 assert_eq!(completion.wait().unwrap(), vec![1, 2]);
1660 }
1661
1662 #[derive(Clone)]
1663 enum SourceAckMsg {
1664 Ack,
1665 }
1666
1667 struct SourceAckActor {
1668 count: StdArc<AtomicUsize>,
1669 }
1670
1671 impl Actor for SourceAckActor {
1672 type Msg = SourceAckMsg;
1673 type State = ();
1674 type Arguments = ();
1675
1676 async fn pre_start(
1677 &self,
1678 _myself: ActorRef<Self::Msg>,
1679 _args: Self::Arguments,
1680 ) -> ActorResult<Self::State> {
1681 Ok(())
1682 }
1683
1684 async fn handle(
1685 &self,
1686 _myself: ActorRef<Self::Msg>,
1687 _message: Self::Msg,
1688 _state: &mut Self::State,
1689 ) -> ActorResult {
1690 self.count.fetch_add(1, Ordering::SeqCst);
1691 Ok(())
1692 }
1693 }
1694
1695 #[test]
1696 fn actor_source_with_backpressure_acks_startup_and_each_element() {
1697 let ack_count = StdArc::new(AtomicUsize::new(0));
1698 let (ack_ref, ack_handle) = spawn_actor(
1699 SourceAckActor {
1700 count: StdArc::clone(&ack_count),
1701 },
1702 (),
1703 );
1704
1705 let (actor_ref, completion) =
1706 ActorSource::actor_ref_with_backpressure::<u64, SourceAckMsg>(
1707 ack_ref.clone(),
1708 SourceAckMsg::Ack,
1709 )
1710 .to_mat(Sink::collect(), Keep::both)
1711 .run()
1712 .unwrap();
1713
1714 assert!(wait_until(StdDuration::from_secs(1), || {
1715 ack_count.load(Ordering::SeqCst) >= 1
1716 }));
1717 actor_ref.cast(ActorSourceMessage::Element(1)).unwrap();
1718 assert!(wait_until(StdDuration::from_secs(1), || {
1719 ack_count.load(Ordering::SeqCst) >= 2
1720 }));
1721 actor_ref.cast(ActorSourceMessage::Element(2)).unwrap();
1722 assert!(wait_until(StdDuration::from_secs(1), || {
1723 ack_count.load(Ordering::SeqCst) >= 3
1724 }));
1725 actor_ref.cast(ActorSourceMessage::Complete).unwrap();
1726
1727 assert_eq!(completion.wait().unwrap(), vec![1, 2]);
1728 stop_actor(ack_ref, ack_handle);
1729 }
1730
1731 #[derive(Debug, Clone, PartialEq, Eq)]
1732 enum SinkEvent {
1733 Element(u64),
1734 Complete,
1735 Fail(String),
1736 }
1737
1738 struct EventActor {
1739 sender: mpsc::Sender<SinkEvent>,
1740 }
1741
1742 impl Actor for EventActor {
1743 type Msg = SinkEvent;
1744 type State = ();
1745 type Arguments = ();
1746
1747 async fn pre_start(
1748 &self,
1749 _myself: ActorRef<Self::Msg>,
1750 _args: Self::Arguments,
1751 ) -> ActorResult<Self::State> {
1752 Ok(())
1753 }
1754
1755 async fn handle(
1756 &self,
1757 _myself: ActorRef<Self::Msg>,
1758 message: Self::Msg,
1759 _state: &mut Self::State,
1760 ) -> ActorResult {
1761 self.sender
1762 .send(message)
1763 .expect("event receiver stays open");
1764 Ok(())
1765 }
1766 }
1767
1768 #[test]
1769 fn actor_sink_actor_ref_sends_elements_and_complete() {
1770 let (tx, rx) = mpsc::channel();
1771 let (actor_ref, handle) = spawn_actor(EventActor { sender: tx }, ());
1772
1773 Source::from_iter([1_u64, 2])
1774 .run_with(ActorSink::actor_ref(
1775 actor_ref.clone(),
1776 SinkEvent::Element,
1777 || SinkEvent::Complete,
1778 |error| SinkEvent::Fail(error.to_string()),
1779 ))
1780 .unwrap()
1781 .wait()
1782 .unwrap();
1783
1784 assert_eq!(
1785 [
1786 rx.recv_timeout(StdDuration::from_secs(1)).unwrap(),
1787 rx.recv_timeout(StdDuration::from_secs(1)).unwrap(),
1788 rx.recv_timeout(StdDuration::from_secs(1)).unwrap(),
1789 ],
1790 [
1791 SinkEvent::Element(1),
1792 SinkEvent::Element(2),
1793 SinkEvent::Complete,
1794 ]
1795 );
1796 stop_actor(actor_ref, handle);
1797 }
1798
1799 #[derive(Debug, Clone, PartialEq, Eq)]
1800 enum BackpressureEvent {
1801 Init,
1802 Element(u64),
1803 Complete,
1804 Fail(String),
1805 }
1806
1807 enum BackpressureSinkMsg {
1808 Init(ReplyPort<()>),
1809 Element(u64, ReplyPort<()>),
1810 Complete,
1811 Fail(String),
1812 }
1813
1814 struct BackpressureSinkActor {
1815 sender: mpsc::Sender<BackpressureEvent>,
1816 }
1817
1818 impl Actor for BackpressureSinkActor {
1819 type Msg = BackpressureSinkMsg;
1820 type State = ();
1821 type Arguments = ();
1822
1823 async fn pre_start(
1824 &self,
1825 _myself: ActorRef<Self::Msg>,
1826 _args: Self::Arguments,
1827 ) -> ActorResult<Self::State> {
1828 Ok(())
1829 }
1830
1831 async fn handle(
1832 &self,
1833 _myself: ActorRef<Self::Msg>,
1834 message: Self::Msg,
1835 _state: &mut Self::State,
1836 ) -> ActorResult {
1837 match message {
1838 BackpressureSinkMsg::Init(reply_to) => {
1839 self.sender.send(BackpressureEvent::Init).unwrap();
1840 let _ = reply_to.send(());
1841 }
1842 BackpressureSinkMsg::Element(item, reply_to) => {
1843 self.sender.send(BackpressureEvent::Element(item)).unwrap();
1844 let _ = reply_to.send(());
1845 }
1846 BackpressureSinkMsg::Complete => {
1847 self.sender.send(BackpressureEvent::Complete).unwrap();
1848 }
1849 BackpressureSinkMsg::Fail(error) => {
1850 self.sender.send(BackpressureEvent::Fail(error)).unwrap();
1851 }
1852 }
1853 Ok(())
1854 }
1855 }
1856
1857 #[test]
1858 fn actor_sink_with_backpressure_waits_for_init_and_element_acks() {
1859 let (tx, rx) = mpsc::channel();
1860 let (actor_ref, handle) = spawn_actor(BackpressureSinkActor { sender: tx }, ());
1861
1862 Source::from_iter([1_u64, 2])
1863 .run_with(ActorSink::actor_ref_with_backpressure(
1864 actor_ref.clone(),
1865 Duration::from_secs(1),
1866 BackpressureSinkMsg::Init,
1867 BackpressureSinkMsg::Element,
1868 || BackpressureSinkMsg::Complete,
1869 |error| BackpressureSinkMsg::Fail(error.to_string()),
1870 ))
1871 .unwrap()
1872 .wait()
1873 .unwrap();
1874
1875 assert_eq!(
1876 [
1877 rx.recv_timeout(StdDuration::from_secs(1)).unwrap(),
1878 rx.recv_timeout(StdDuration::from_secs(1)).unwrap(),
1879 rx.recv_timeout(StdDuration::from_secs(1)).unwrap(),
1880 rx.recv_timeout(StdDuration::from_secs(1)).unwrap(),
1881 ],
1882 [
1883 BackpressureEvent::Init,
1884 BackpressureEvent::Element(1),
1885 BackpressureEvent::Element(2),
1886 BackpressureEvent::Complete,
1887 ]
1888 );
1889 stop_actor(actor_ref, handle);
1890 }
1891
1892 enum WatchMsg {
1893 Stop,
1894 }
1895
1896 struct WatchActor;
1897
1898 impl Actor for WatchActor {
1899 type Msg = WatchMsg;
1900 type State = ();
1901 type Arguments = ();
1902
1903 async fn pre_start(
1904 &self,
1905 _myself: ActorRef<Self::Msg>,
1906 _args: Self::Arguments,
1907 ) -> ActorResult<Self::State> {
1908 Ok(())
1909 }
1910
1911 async fn handle(
1912 &self,
1913 myself: ActorRef<Self::Msg>,
1914 _message: Self::Msg,
1915 _state: &mut Self::State,
1916 ) -> ActorResult {
1917 myself.stop(Some("watched-stop".into()));
1918 Ok(())
1919 }
1920 }
1921
1922 #[test]
1923 fn watch_fails_idle_stream_when_actor_terminates() {
1924 let (watched_ref, watched_handle) = spawn_actor(WatchActor, ());
1925 let (source_ref, completion) = ActorSource::actor_ref::<u64>()
1926 .via(ActorFlow::watch(watched_ref.clone()))
1927 .to_mat(Sink::collect(), Keep::both)
1928 .run()
1929 .unwrap();
1930
1931 watched_ref.cast(WatchMsg::Stop).unwrap();
1932 assert!(wait_until(StdDuration::from_secs(1), || {
1933 watched_ref.get_status() == ractor::ActorStatus::Stopped
1934 }));
1935
1936 let result = completion.wait();
1937 let _ = source_ref.cast(ActorSourceMessage::Complete);
1938 assert!(
1939 matches!(result, Err(StreamError::Failed(reason)) if reason.contains("watched actor terminated"))
1940 );
1941 block_on_ractor_runtime(async move {
1942 watched_handle.await.expect("watched actor joins");
1943 })
1944 .expect("ractor runtime joins watched actor");
1945 }
1946
1947 static NEXT_GROUP: AtomicUsize = AtomicUsize::new(0);
1948
1949 #[test]
1950 fn pubsub_sink_broadcasts_to_pg_source() {
1951 let group = format!(
1952 "datum-test-pubsub-{}",
1953 NEXT_GROUP.fetch_add(1, Ordering::SeqCst)
1954 );
1955
1956 let (_source_ref, completion) = ActorPubSub::source::<u64>(group.clone())
1957 .to_mat(Sink::collect(), Keep::both)
1958 .run()
1959 .unwrap();
1960
1961 assert!(wait_until(StdDuration::from_secs(1), || {
1962 !ractor::pg::get_members(&group).is_empty()
1963 }));
1964
1965 Source::from_iter([1_u64, 2])
1966 .run_with(ActorPubSub::sink(group))
1967 .unwrap()
1968 .wait()
1969 .unwrap();
1970
1971 assert_eq!(completion.wait().unwrap(), vec![1, 2]);
1972 }
1973
1974 #[test]
1975 fn actor_source_fail_message_fails_stream() {
1976 let (actor_ref, completion) = ActorSource::typed::<u64>()
1977 .to_mat(Sink::collect(), Keep::both)
1978 .run()
1979 .unwrap();
1980
1981 actor_ref
1982 .cast(ActorSourceMessage::Fail("source failed".into()))
1983 .unwrap();
1984
1985 assert_eq!(
1986 completion.wait(),
1987 Err(StreamError::Failed("source failed".into()))
1988 );
1989 }
1990
1991 #[test]
1992 fn actor_sink_typed_sends_protocol_messages() {
1993 let received = StdArc::new(StdMutex::new(Vec::<String>::new()));
1994
1995 struct TypedSinkActor {
1996 received: StdArc<StdMutex<Vec<String>>>,
1997 }
1998
1999 impl Actor for TypedSinkActor {
2000 type Msg = ActorSinkMessage<u64>;
2001 type State = ();
2002 type Arguments = ();
2003
2004 async fn pre_start(
2005 &self,
2006 _myself: ActorRef<Self::Msg>,
2007 _args: Self::Arguments,
2008 ) -> ActorResult<Self::State> {
2009 Ok(())
2010 }
2011
2012 async fn handle(
2013 &self,
2014 _myself: ActorRef<Self::Msg>,
2015 message: Self::Msg,
2016 _state: &mut Self::State,
2017 ) -> ActorResult {
2018 let label = match message {
2019 ActorSinkMessage::Element(item) => format!("element:{item}"),
2020 ActorSinkMessage::Complete => "complete".to_owned(),
2021 ActorSinkMessage::Fail(error) => format!("fail:{error}"),
2022 };
2023 self.received.lock().unwrap().push(label);
2024 Ok(())
2025 }
2026 }
2027
2028 let (actor_ref, handle) = spawn_actor(
2029 TypedSinkActor {
2030 received: StdArc::clone(&received),
2031 },
2032 (),
2033 );
2034
2035 Source::from_iter([7_u64])
2036 .run_with(ActorSink::typed(actor_ref.clone()))
2037 .unwrap()
2038 .wait()
2039 .unwrap();
2040
2041 assert!(wait_until(StdDuration::from_secs(1), || {
2042 received.lock().unwrap().len() == 2
2043 }));
2044 assert_eq!(
2045 *received.lock().unwrap(),
2046 vec!["element:7".to_owned(), "complete".to_owned()]
2047 );
2048 stop_actor(actor_ref, handle);
2049 }
2050}