Skip to main content

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}