camel_api/outcome_segment.rs
1//! Wrapper around `Box<dyn OutcomePipeline>`. Lives in camel-api (NOT
2//! camel-core) so EIP segment structs in camel-processor can type their
3//! fields as `camel_api::OutcomeSegment` (camel-processor depends on
4//! camel-api, not camel-core). See ADR-0025.
5
6use crate::exchange::Exchange;
7use crate::outcome_pipeline::OutcomePipeline;
8use crate::pipeline_outcome::PipelineOutcome;
9use std::future::Future;
10use std::pin::Pin;
11
12/// Wrapper around `Box<dyn OutcomePipeline>`. Constructed via
13/// `OutcomeSegment::new(...)` and run via `run(exchange)`.
14#[derive(Clone)]
15pub struct OutcomeSegment {
16 inner: Box<dyn OutcomePipeline>,
17}
18
19impl std::fmt::Debug for OutcomeSegment {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 f.debug_struct("OutcomeSegment").finish_non_exhaustive()
22 }
23}
24
25impl OutcomeSegment {
26 pub fn new(inner: Box<dyn OutcomePipeline>) -> Self {
27 Self { inner }
28 }
29
30 pub async fn run(&mut self, exchange: Exchange) -> PipelineOutcome {
31 self.inner.run(exchange).await
32 }
33}
34
35/// OutcomeSegment implements RetryableStep so it can participate in the
36/// retry path alongside BoxProcessor. Lives in camel-api (where both
37/// OutcomeSegment and RetryableStep are defined).
38impl crate::error_handler::RetryableStep for OutcomeSegment {
39 fn invoke<'a>(
40 &'a mut self,
41 exchange: Exchange,
42 ) -> Pin<Box<dyn Future<Output = PipelineOutcome> + Send + 'a>> {
43 Box::pin(async move { self.run(exchange).await })
44 }
45}
46
47/// OutcomeSegment implements OutcomePipeline by delegating to its inner
48/// `Box<dyn OutcomePipeline>`. `CompiledStep::Segment` can now produce
49/// `segment` directly as `Box<dyn OutcomePipeline>`.
50impl OutcomePipeline for OutcomeSegment {
51 fn clone_box(&self) -> Box<dyn OutcomePipeline> {
52 Box::new(self.clone())
53 }
54
55 fn run<'a>(
56 &'a mut self,
57 exchange: Exchange,
58 ) -> Pin<Box<dyn Future<Output = PipelineOutcome> + Send + 'a>> {
59 // Call the inherent async `run` method, NOT the trait method.
60 // `OutcomeSegment::run` is unambiguous: inherent methods shadow
61 // trait methods in Rust name resolution for plain method calls,
62 // and the qualified `OutcomeSegment::run(self, exchange)` syntax
63 // also selects the inherent fn.
64 Box::pin(OutcomeSegment::run(self, exchange))
65 }
66}