Skip to main content

rama_core/matcher/service/
mod.rs

1use crate::std::sync::Arc;
2
3mod dynamic_dispatch;
4mod match_service_pair;
5mod tuples;
6
7pub use self::{
8    dynamic_dispatch::{BoxServiceMatcher, DynServiceMatcher},
9    match_service_pair::MatcherServicePair,
10};
11
12/// The result of attempting to select a service for an input.
13///
14/// The original input is always returned so that matcher-added extensions
15/// can continue through the pipeline even when no service matched.
16#[derive(Debug, Clone)]
17pub struct ServiceMatch<Input, Service> {
18    /// The input after matcher evaluation.
19    pub input: Input,
20    /// The selected service, if any matcher accepted the input.
21    pub service: Option<Service>,
22}
23
24/// Selects a concrete service for an input.
25///
26/// This is useful when the service decision itself depends on runtime input,
27/// while still preserving the selected value for later processing.
28pub trait ServiceMatcher<Input>: Send + Sync + 'static {
29    /// The value returned when a match succeeds.
30    type Service: Send + 'static;
31    /// The error that can happen while evaluating the matcher.
32    type Error: Send + 'static;
33    /// Input returned by matching functions,
34    /// it might be same as the original input but it can also be modified.
35    type ModifiedInput: Send + 'static;
36
37    /// Attempt to select a service for `input`.
38    fn match_service(
39        &self,
40        input: Input,
41    ) -> impl Future<Output = Result<ServiceMatch<Self::ModifiedInput, Self::Service>, Self::Error>>
42    + Send
43    + '_;
44
45    /// Attempt to select a service for `input`, consuming the matcher.
46    ///
47    /// Override this when the matcher stores services by value and can return
48    /// them without cloning.
49    fn into_match_service(
50        self,
51        input: Input,
52    ) -> impl Future<Output = Result<ServiceMatch<Self::ModifiedInput, Self::Service>, Self::Error>> + Send
53    where
54        Self: Sized,
55        Input: Send,
56    {
57        async move { self.match_service(input).await }
58    }
59
60    /// Box this matcher for dynamic dispatch.
61    fn boxed(self) -> BoxServiceMatcher<Input, Self::Service, Self::Error, Self::ModifiedInput>
62    where
63        Self: Sized,
64    {
65        BoxServiceMatcher::new(self)
66    }
67}
68
69impl<Input, M> ServiceMatcher<Input> for Arc<M>
70where
71    M: ServiceMatcher<Input>,
72{
73    type Service = M::Service;
74    type Error = M::Error;
75    type ModifiedInput = M::ModifiedInput;
76
77    fn match_service(
78        &self,
79        input: Input,
80    ) -> impl Future<Output = Result<ServiceMatch<Self::ModifiedInput, Self::Service>, Self::Error>>
81    + Send
82    + '_ {
83        (**self).match_service(input)
84    }
85
86    async fn into_match_service(
87        self,
88        input: Input,
89    ) -> Result<ServiceMatch<Self::ModifiedInput, Self::Service>, Self::Error>
90    where
91        Self: Sized,
92        Input: Send,
93    {
94        (*self).match_service(input).await
95    }
96}