Skip to main content

pdk_classy/hl/
context.rs

1// Copyright (c) 2026, Salesforce, Inc.,
2// All rights reserved.
3// For full license text, see the LICENSE.txt file
4
5use std::{
6    cell::{Cell, RefCell},
7    rc::Rc,
8};
9
10use crate::{
11    context,
12    extract::{
13        context::FilterContext, extractability, AlreadyExtracted, Exclusive, FromContext,
14        FromContextOnce,
15    },
16    BoxFuture,
17};
18
19use super::{
20    dynamic_exchange::DynamicExchange, entity::EntityState, request::InvalidRequestState,
21    response::InvalidResponseState, IntoBodyState, RequestBodyState, RequestData,
22    RequestHeadersState, RequestState, ResponseBodyState, ResponseHeadersState, ResponseState,
23};
24
25use super::{IntoBodyStreamState, RequestBodyStreamState, ResponseBodyStreamState};
26
27pub struct RequestContext<S = ()> {
28    parent: Rc<FilterContext>,
29    exchange: Rc<RefCell<DynamicExchange>>,
30    state: Rc<S>,
31}
32
33impl<S> RequestContext<S> {
34    pub(super) fn new(
35        parent: Rc<FilterContext>,
36        exchange: Rc<RefCell<DynamicExchange>>,
37        state: Rc<S>,
38    ) -> Self {
39        Self {
40            parent,
41            exchange,
42            state,
43        }
44    }
45
46    pub(super) fn state(&self) -> &Rc<S> {
47        &self.state
48    }
49
50    fn parent(&self) -> &FilterContext {
51        &self.parent
52    }
53}
54
55context!(<S> RequestContext<S> => FilterContext {RequestContext::parent});
56
57impl<S> FromContextOnce<RequestContext<S>> for RequestState {
58    type Error = InvalidRequestState;
59
60    type Future<'c>
61        = BoxFuture<'c, Result<Self, Self::Error>>
62    where
63        S: 'c;
64
65    fn from_context_once(context: Exclusive<RequestContext<S>>) -> Self::Future<'_> {
66        Box::pin(RequestState::new(context.exchange.clone()))
67    }
68}
69
70impl<S> FromContextOnce<RequestContext<S>> for RequestHeadersState {
71    type Error = InvalidRequestState;
72
73    type Future<'c>
74        = BoxFuture<'c, Result<Self, Self::Error>>
75    where
76        S: 'c;
77
78    fn from_context_once(context: Exclusive<RequestContext<S>>) -> Self::Future<'_> {
79        Box::pin(async {
80            Ok(RequestState::from_context_once(context)
81                .await?
82                .into_headers_state()
83                .await)
84        })
85    }
86}
87
88impl<S> FromContextOnce<RequestContext<S>> for RequestBodyState {
89    type Error = InvalidRequestState;
90
91    type Future<'c>
92        = BoxFuture<'c, Result<Self, Self::Error>>
93    where
94        S: 'c;
95
96    fn from_context_once(context: Exclusive<RequestContext<S>>) -> Self::Future<'_> {
97        Box::pin(async {
98            Ok(RequestState::from_context_once(context)
99                .await?
100                .into_body_state()
101                .await)
102        })
103    }
104}
105
106impl<S> FromContextOnce<RequestContext<S>> for RequestBodyStreamState {
107    type Error = InvalidRequestState;
108
109    type Future<'c>
110        = BoxFuture<'c, Result<Self, Self::Error>>
111    where
112        S: 'c;
113
114    fn from_context_once(context: Exclusive<RequestContext<S>>) -> Self::Future<'_> {
115        Box::pin(async {
116            Ok(RequestState::from_context_once(context)
117                .await?
118                .into_body_stream_state()
119                .await)
120        })
121    }
122}
123
124pub struct ResponseContext<D, S = ()> {
125    parent: Rc<FilterContext>,
126    exchange: Rc<RefCell<DynamicExchange>>,
127    request_data: Cell<Option<RequestData<D>>>,
128    state: Rc<S>,
129}
130
131impl<D, S> ResponseContext<D, S> {
132    pub(super) fn new(
133        parent: Rc<FilterContext>,
134        exchange: Rc<RefCell<DynamicExchange>>,
135        request_data: RequestData<D>,
136        state: Rc<S>,
137    ) -> Self {
138        Self {
139            parent,
140            exchange,
141            request_data: Cell::new(Some(request_data)),
142            state,
143        }
144    }
145
146    pub(super) fn state(&self) -> &Rc<S> {
147        &self.state
148    }
149
150    fn parent(&self) -> &FilterContext {
151        &self.parent
152    }
153}
154
155context!(<D, S> ResponseContext<D, S> => FilterContext {ResponseContext::parent});
156
157impl<D, S> FromContextOnce<ResponseContext<D, S>> for ResponseState {
158    type Error = InvalidResponseState;
159
160    type Future<'c>
161        = BoxFuture<'c, Result<Self, Self::Error>>
162    where
163        D: 'c,
164        S: 'c;
165
166    fn from_context_once(context: Exclusive<ResponseContext<D, S>>) -> Self::Future<'_> {
167        Box::pin(ResponseState::new(context.exchange.clone()))
168    }
169}
170
171impl<D, S> FromContextOnce<ResponseContext<D, S>> for ResponseHeadersState {
172    type Error = InvalidResponseState;
173
174    type Future<'c>
175        = BoxFuture<'c, Result<Self, Self::Error>>
176    where
177        D: 'c,
178        S: 'c;
179
180    fn from_context_once(context: Exclusive<ResponseContext<D, S>>) -> Self::Future<'_> {
181        Box::pin(async {
182            Ok(ResponseState::from_context_once(context)
183                .await?
184                .into_headers_state()
185                .await)
186        })
187    }
188}
189
190impl<D, S> FromContextOnce<ResponseContext<D, S>> for ResponseBodyState {
191    type Error = InvalidResponseState;
192
193    type Future<'c>
194        = BoxFuture<'c, Result<Self, Self::Error>>
195    where
196        D: 'c,
197        S: 'c;
198
199    fn from_context_once(context: Exclusive<ResponseContext<D, S>>) -> Self::Future<'_> {
200        Box::pin(async {
201            Ok(ResponseState::from_context_once(context)
202                .await?
203                .into_body_state()
204                .await)
205        })
206    }
207}
208
209impl<D, S> FromContextOnce<ResponseContext<D, S>> for ResponseBodyStreamState {
210    type Error = InvalidResponseState;
211
212    type Future<'c>
213        = BoxFuture<'c, Result<Self, Self::Error>>
214    where
215        D: 'c,
216        S: 'c;
217
218    fn from_context_once(context: Exclusive<ResponseContext<D, S>>) -> Self::Future<'_> {
219        Box::pin(async {
220            Ok(ResponseState::from_context_once(context)
221                .await?
222                .into_body_stream_state()
223                .await)
224        })
225    }
226}
227
228impl<D, S> FromContext<ResponseContext<D, S>, extractability::Transitive> for RequestData<D>
229where
230    D: 'static,
231{
232    type Error = AlreadyExtracted<RequestData<D>>;
233
234    fn from_context(context: &ResponseContext<D, S>) -> Result<Self, Self::Error> {
235        context
236            .request_data
237            .take()
238            .ok_or_else(AlreadyExtracted::default)
239    }
240}