1use std::{
11 sync::{Arc, Mutex},
12 task::Poll,
13};
14
15use futures::{StreamExt, channel::oneshot};
16
17use crate::{
18 effect::{EffectId, EffectKind, HandlerDescriptor, Outcome},
19 error::{ErrorKind, ErrorReport},
20 streaming::{Item, Relayed, StreamEvent, StreamEvents},
21 wasm_compat::{WasmBoxedFuture, WasmCompatSend, WasmCompatSync},
22};
23
24#[cfg(test)]
25mod tests;
26
27pub type HandlerFuture<'a> = WasmBoxedFuture<'a, Reply>;
29
30pub trait Serve: WasmCompatSend + WasmCompatSync {
74 type Family: crate::effect::Served;
76
77 fn descriptor(&self) -> HandlerDescriptor;
80
81 fn serve(
83 &self,
84 kind: EffectKind,
85 dispatch: Dispatch,
86 ) -> impl Future<Output = Reply> + WasmCompatSend + use<'_, Self>;
87}
88
89pub(crate) trait Handler: WasmCompatSend + WasmCompatSync {
91 fn descriptor(&self) -> HandlerDescriptor;
92 fn handle(&self, kind: EffectKind, dispatch: Dispatch) -> HandlerFuture<'_>;
93}
94
95#[diagnostic::do_not_recommend]
98impl<T: Serve> Handler for T {
99 fn descriptor(&self) -> HandlerDescriptor {
100 Serve::descriptor(self)
101 }
102
103 fn handle(&self, kind: EffectKind, dispatch: Dispatch) -> HandlerFuture<'_> {
104 let observer = dispatch.observer.clone();
105 let folded = dispatch.folded.clone();
106 let streaming = dispatch.is_stream();
107 Box::pin(async move {
108 let reply = self.serve(kind, dispatch).await;
109 let seen = observer.and_then(|slot| lock(&slot).take());
110 reply.observed(streaming, seen, folded)
111 })
112 }
113}
114
115impl<H: Serve + ?Sized> Serve for Arc<H> {
118 type Family = H::Family;
119
120 fn descriptor(&self) -> HandlerDescriptor {
121 (**self).descriptor()
122 }
123
124 async fn serve(&self, kind: EffectKind, dispatch: Dispatch) -> Reply {
125 (**self).serve(kind, dispatch).await
126 }
127}
128
129#[derive(Clone)]
132pub struct ErasedHandler(ErasedInner);
133
134#[cfg(not(target_family = "wasm"))]
135type ErasedInner = Arc<dyn Handler + Send + Sync>;
136#[cfg(target_family = "wasm")]
137type ErasedInner = Arc<dyn Handler>;
138
139impl ErasedHandler {
140 pub fn new(handler: impl Serve + 'static) -> Self {
142 Self(Arc::new(handler))
143 }
144
145 pub fn layered(self, intercept: impl super::Intercept) -> Self {
149 Self::new(super::Layer::new(self, intercept))
150 }
151
152 pub fn descriptor(&self) -> HandlerDescriptor {
154 self.0.descriptor()
155 }
156
157 pub fn handle(&self, kind: EffectKind, dispatch: Dispatch) -> HandlerFuture<'_> {
159 self.0.handle(kind, dispatch)
160 }
161
162 pub fn ptr_eq(&self, other: &Self) -> bool {
164 Arc::ptr_eq(&self.0, &other.0)
165 }
166}
167
168impl std::fmt::Debug for ErasedHandler {
169 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170 f.debug_struct("ErasedHandler")
171 .field("key", &self.0.descriptor().key)
172 .finish_non_exhaustive()
173 }
174}
175
176impl Serve for ErasedHandler {
178 type Family = crate::effect::family::Dynamic;
179
180 fn descriptor(&self) -> HandlerDescriptor {
181 self.0.descriptor()
182 }
183
184 async fn serve(&self, kind: EffectKind, dispatch: Dispatch) -> Reply {
185 self.handle(kind, dispatch).await
186 }
187}
188
189pub trait Observe: Send + Sync {
190 fn adapter_context(&self) -> Option<crate::observe::AdapterContext> {
192 None
193 }
194
195 fn outcome(&mut self, outcome: &Result<Outcome, ErrorReport>);
199 fn keep_events(&self) -> bool;
201 fn event(&mut self, item: &Item<StreamEvent>);
204 fn stream_error(&mut self, _error: &ErrorReport) {}
206 fn origin(&mut self, origin: &crate::message::Origin);
210 fn stream_item(
214 &mut self,
215 item: &Result<Relayed, ErrorReport>,
216 outcome: Option<&Result<Outcome, ErrorReport>>,
217 ) {
218 if self.keep_events() {
219 match item {
220 Ok(Relayed::Origin(origin)) => self.origin(origin),
221 Ok(Relayed::Item(item)) => self.event(item),
222 Ok(Relayed::Done(_)) => {}
223 Err(error) => self.stream_error(error),
224 }
225 }
226 if let Some(outcome) = outcome {
227 self.outcome(outcome);
228 }
229 }
230 fn discard(&mut self, layer: &str);
233 fn patch(&mut self, kind: &EffectKind);
237}
238
239#[derive(Default)]
243pub struct StreamTap {
244 finished: bool,
246}
247
248impl StreamTap {
249 pub fn new() -> Self {
251 Self::default()
252 }
253
254 pub fn observe(
257 &mut self,
258 item: &Result<Relayed, ErrorReport>,
259 ) -> Option<Result<Outcome, ErrorReport>> {
260 if self.finished {
261 return None;
262 }
263 let outcome = match item {
264 Ok(Relayed::Origin(_) | Relayed::Item(_)) => None,
265 Ok(Relayed::Done(response)) => Some(Ok(Outcome::Completion((**response).clone()))),
266 Err(report) => Some(Err(report.clone())),
267 };
268 self.finished = outcome.is_some();
269 outcome
270 }
271}
272
273pub fn stream_truncated() -> ErrorReport {
277 ErrorReport::from(&crate::error::ProviderError::Truncated)
278}
279
280pub enum Reply {
282 Outcome(Result<Outcome, ErrorReport>),
284 Stream(StreamEvents),
286}
287
288impl Reply {
289 pub async fn into_outcome(self) -> Result<Outcome, ErrorReport> {
291 self.folded_outcome(None).await
292 }
293
294 pub(crate) async fn folded_outcome(
295 self,
296 folded: Option<Folded>,
297 ) -> Result<Outcome, ErrorReport> {
298 match self {
299 Self::Outcome(outcome) => outcome,
300 Self::Stream(mut stream) => {
301 let mut fold = StreamTap::new();
302 while let Some(item) = stream.next().await {
303 let outcome = match &folded {
304 Some(folded) => lock(folded).take(),
305 None => fold.observe(&item),
306 };
307 if let Some(outcome) = outcome {
308 return outcome;
309 }
310 }
311 Err(stream_truncated())
312 }
313 }
314 }
315
316 pub fn into_stream(self) -> StreamEvents {
319 match self {
320 Self::Stream(stream) => stream,
321 Self::Outcome(outcome) => Box::pin(futures::stream::iter(match outcome {
322 Ok(Outcome::Completion(response)) => {
323 match crate::operation::completion::events_of(&response) {
324 Ok(items) => std::iter::once(Ok(Relayed::Origin(response.origin.clone())))
325 .chain(items.into_iter().map(|item| Ok(Relayed::Item(item))))
326 .chain(std::iter::once(Ok(Relayed::Done(Box::new(response)))))
327 .collect(),
328 Err(error) => vec![Err(ErrorReport::from(&error))],
329 }
330 }
331 Ok(other) => vec![Err(wrong_stream_answer(&other))],
332 Err(report) => vec![Err(report)],
333 })),
334 }
335 }
336
337 fn observed(self, streaming: bool, mut seen: Option<Observed>, folded: Option<Folded>) -> Self {
338 if !streaming && let Self::Outcome(outcome) = self {
339 if let Some(seen) = &mut seen {
340 seen.outcome(&outcome);
341 }
342 return Self::Outcome(outcome);
343 }
344 if seen.is_none() && folded.is_none() {
345 return if streaming {
346 Self::Stream(self.into_stream())
347 } else {
348 self
349 };
350 }
351 let original = match &self {
352 Self::Outcome(Ok(Outcome::Completion(response))) => {
353 Some(Ok(Outcome::Completion(response.clone())))
354 }
355 _ => None,
356 };
357 let mut stream = self.into_stream();
358 let mut fold = StreamTap::new();
359 let mut finished = false;
360 Self::Stream(Box::pin(futures::stream::poll_fn(move |cx| {
361 let item = match stream.as_mut().poll_next(cx) {
362 Poll::Pending => return Poll::Pending,
363 Poll::Ready(item) => item,
364 };
365 if let Some(item) = &item {
366 let outcome = if finished { None } else { fold.observe(item) };
367 if let Some(seen) = &mut seen {
368 let recorded = outcome.as_ref().map(|outcome| {
369 if matches!(item, Ok(Relayed::Done(_))) {
370 original.as_ref().unwrap_or(outcome)
371 } else {
372 outcome
373 }
374 });
375 if streaming {
376 seen.item(item, recorded);
377 } else if let Some(recorded) = recorded {
378 seen.outcome(recorded);
379 }
380 }
381 if let Some(outcome) = outcome {
382 finished = true;
383 if let Some(folded) = &folded {
384 *lock(folded) = Some(outcome);
385 }
386 }
387 } else if !finished {
388 finished = true;
389 let outcome = Err(stream_truncated());
390 if let Some(seen) = &mut seen {
391 seen.outcome(&outcome);
392 }
393 if let Some(folded) = &folded {
394 *lock(folded) = Some(outcome);
395 }
396 }
397 Poll::Ready(item)
398 })))
399 }
400}
401
402pub(crate) type Folded = Arc<Mutex<Option<Result<Outcome, ErrorReport>>>>;
405
406fn lock<T>(value: &Mutex<T>) -> std::sync::MutexGuard<'_, T> {
407 value
408 .lock()
409 .unwrap_or_else(std::sync::PoisonError::into_inner)
410}
411
412pub struct Dispatch {
415 adapter_context: Option<crate::observe::AdapterContext>,
416 adapter_context_explicit: bool,
417 id: EffectId,
418 streaming: bool,
419 scopes: Vec<Arc<dyn std::any::Any + Send + Sync>>,
420 observer: Option<Arc<Mutex<Option<Observed>>>>,
421 replaced_by: Arc<Mutex<Option<String>>>,
425 folded: Option<Folded>,
426}
427
428#[derive(Clone)]
431pub(crate) struct Attribution(Arc<Mutex<Option<String>>>);
432
433impl Attribution {
434 pub(crate) fn replaced(&self, layer: &str) {
437 *lock(&self.0) = Some(layer.to_owned());
438 }
439}
440
441impl Dispatch {
442 pub fn new(id: EffectId, streaming: bool) -> Self {
444 Self {
445 id,
446 streaming,
447 adapter_context: None,
448 adapter_context_explicit: false,
449 scopes: Vec::new(),
450 observer: None,
451 replaced_by: Arc::new(Mutex::new(None)),
452 folded: None,
453 }
454 }
455
456 pub fn replaced_by(&self) -> Arc<Mutex<Option<String>>> {
462 self.replaced_by.clone()
463 }
464
465 pub const fn id(&self) -> EffectId {
467 self.id
468 }
469
470 pub const fn is_stream(&self) -> bool {
472 self.streaming
473 }
474
475 pub fn with_scope(mut self, scope: Arc<dyn std::any::Any + Send + Sync>) -> Self {
477 self.scopes.push(scope);
478 self
479 }
480
481 pub fn scope<T: std::any::Any + Send + Sync>(&self) -> Option<Arc<T>> {
483 self.scopes
484 .iter()
485 .find_map(|scope| Arc::downcast::<T>(scope.clone()).ok())
486 }
487
488 pub fn scopes(&self) -> Vec<Arc<dyn std::any::Any + Send + Sync>> {
490 self.scopes.clone()
491 }
492
493 pub fn with_observer(mut self, observer: Box<dyn Observe>) -> Self {
495 if !self.adapter_context_explicit {
496 self.adapter_context = observer.adapter_context();
497 }
498 self.observer = Some(Arc::new(Mutex::new(Some(Observed {
499 observer,
500 told: false,
501 }))));
502 self
503 }
504
505 pub fn with_adapter_context(mut self, context: crate::observe::AdapterContext) -> Self {
511 self.adapter_context = Some(context);
512 self.adapter_context_explicit = true;
513 self
514 }
515
516 pub fn adapter_context(&self) -> Option<crate::observe::AdapterContext> {
518 self.adapter_context.clone()
519 }
520
521 pub(crate) fn patched(&mut self, kind: &EffectKind) {
522 if let Some(slot) = &self.observer
523 && let Some(seen) = lock(slot).as_mut()
524 {
525 seen.observer.patch(kind);
526 }
527 }
528
529 pub(crate) fn discard(&mut self, layer: &str) {
530 if let Some(slot) = &self.observer
531 && let Some(mut seen) = lock(slot).take()
532 {
533 seen.told = true;
534 seen.observer.discard(layer);
535 }
536 }
537
538 pub(crate) fn attribution(&self) -> Attribution {
542 Attribution(self.replaced_by.clone())
543 }
544
545 pub(crate) fn inner(&mut self, folded: Option<Folded>) -> Self {
546 let observer = self.observer.as_ref().and_then(|slot| lock(slot).take());
547 Self {
548 id: self.id,
549 streaming: self.streaming,
550 adapter_context: self.adapter_context.clone(),
551 adapter_context_explicit: self.adapter_context_explicit,
552 scopes: self.scopes.clone(),
553 observer: observer.map(|seen| Arc::new(Mutex::new(Some(seen)))),
554 replaced_by: self.replaced_by.clone(),
555 folded,
556 }
557 }
558}
559
560struct Observed {
561 observer: Box<dyn Observe>,
562 told: bool,
563}
564
565impl Observed {
566 fn outcome(&mut self, outcome: &Result<Outcome, ErrorReport>) {
567 if !self.told {
568 self.told = true;
569 self.observer.outcome(outcome);
570 }
571 }
572
573 fn item(
574 &mut self,
575 item: &Result<Relayed, ErrorReport>,
576 outcome: Option<&Result<Outcome, ErrorReport>>,
577 ) {
578 let outcome = outcome.filter(|_| !self.told);
579 self.told |= outcome.is_some();
580 self.observer.stream_item(item, outcome);
581 }
582}
583
584impl Drop for Observed {
585 fn drop(&mut self) {
586 self.outcome(&Err(cancelled()));
587 }
588}
589
590fn wrong_stream_answer(other: &Outcome) -> ErrorReport {
591 ErrorReport::new(
592 ErrorKind::Internal,
593 format!(
594 "a streaming dispatch was answered with a {} outcome",
595 other.family()
596 ),
597 )
598}
599
600pub fn cancelled() -> ErrorReport {
602 ErrorReport::new(
603 ErrorKind::Cancelled,
604 "the consumer cancelled the dispatch before it was answered",
605 )
606 .with_retryable(false)
607}
608
609#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
611#[error("the dispatch's consumer is gone")]
612pub struct SinkClosed;
613
614pub struct Resolver(oneshot::Sender<Result<Outcome, ErrorReport>>);
616
617pub fn deferred() -> (
621 Resolver,
622 impl Future<Output = Result<Outcome, ErrorReport>> + Send + 'static,
623) {
624 let (sender, receiver) = oneshot::channel();
625 (Resolver(sender), async move {
626 receiver.await.unwrap_or_else(|_| {
627 Err(ErrorReport::new(
628 ErrorKind::Internal,
629 "the handler dropped its outcome sink without answering",
630 ))
631 })
632 })
633}
634
635impl Resolver {
636 pub fn resolve(self, outcome: Result<Outcome, ErrorReport>) -> Result<(), SinkClosed> {
638 self.0.send(outcome).map_err(|_| SinkClosed)
639 }
640
641 pub fn is_closed(&self) -> bool {
643 self.0.is_canceled()
644 }
645}
646
647pub async fn serve_inline(
649 handler: &ErasedHandler,
650 kind: EffectKind,
651) -> Result<Outcome, ErrorReport> {
652 serve_inline_with(handler, kind, Vec::new()).await
653}
654
655pub async fn serve_inline_with(
657 handler: &ErasedHandler,
658 kind: EffectKind,
659 scopes: Vec<Arc<dyn std::any::Any + Send + Sync>>,
660) -> Result<Outcome, ErrorReport> {
661 let mut dispatch = Dispatch::new(EffectId::from_raw(0), false);
662 for scope in scopes {
663 dispatch = dispatch.with_scope(scope);
664 }
665 handler.handle(kind, dispatch).await.into_outcome().await
666}