Skip to main content

apigate_core/
pipeline.rs

1use std::future::Future;
2use std::pin::Pin;
3
4use axum::body::Body;
5use http::Extensions;
6
7use crate::PartsCtx;
8use crate::error::ApigateError;
9
10// ---------------------------------------------------------------------------
11// RequestScope
12// ---------------------------------------------------------------------------
13
14/// Owns the request body and extracted data for a single pipeline invocation.
15///
16/// App-level state lives in a shared `Arc<Extensions>` (zero-copy per request).
17/// Per-request data (path params, hook insertions) goes into a local `Extensions`
18/// that starts empty and allocates only on first `insert`.
19pub struct RequestScope<'a> {
20    shared: &'a Extensions,
21    local: Extensions,
22    body: Option<Body>,
23    body_limit: usize,
24}
25
26impl<'a> RequestScope<'a> {
27    pub fn new(shared: &'a Extensions, body: Body, body_limit: usize) -> Self {
28        Self {
29            shared,
30            local: Extensions::new(),
31            body: Some(body),
32            body_limit,
33        }
34    }
35
36    pub fn take_body(&mut self) -> Option<Body> {
37        self.body.take()
38    }
39
40    pub fn body_limit(&self) -> usize {
41        self.body_limit
42    }
43
44    /// Returns a shared reference to `T`.
45    /// Checks local (per-request) extensions first, then shared (app) state.
46    pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
47        self.local.get::<T>().or_else(|| self.shared.get::<T>())
48    }
49
50    /// Returns a mutable reference to `T` from local (per-request) extensions only.
51    pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
52        self.local.get_mut::<T>()
53    }
54
55    /// Inserts a value into per-request (local) extensions.
56    pub fn insert<T: Clone + Send + Sync + 'static>(&mut self, val: T) {
57        self.local.insert(val);
58    }
59
60    /// Takes a value from local extensions first; if absent, clones from shared state.
61    pub fn take<T: Clone + Send + Sync + 'static>(&mut self) -> Option<T> {
62        self.local
63            .remove::<T>()
64            .or_else(|| self.shared.get::<T>().cloned())
65    }
66}
67
68// ---------------------------------------------------------------------------
69// Pipeline types
70// ---------------------------------------------------------------------------
71
72/// Single function that orchestrates all request processing:
73/// parse path params → before hooks → validate/parse body → map → return body.
74pub type PipelineFn = for<'a> fn(PartsCtx<'a>, RequestScope<'a>) -> PipelineFuture<'a>;
75pub type PipelineFuture<'a> = Pin<Box<dyn Future<Output = PipelineResult> + Send + 'a>>;
76pub type PipelineResult = Result<Body, ApigateError>;
77
78pub type HookResult = Result<(), ApigateError>;
79pub type MapResult<T> = Result<T, ApigateError>;