1use core::fmt;
4
5use crate::authentication::{
6 AsyncAuthenticatedTransport, AuthenticatedRequest, AuthenticationScopePolicy,
7 BlockingAuthenticatedTransport,
8};
9use crate::operation::{
10 CheckedResponseGuard, OperationId, OperationMetadata, RequestIdPolicy, ResponsePolicy,
11 ResponsePolicyError,
12};
13use crate::transport::{
14 BoundTransport, EndpointIdentityError, EndpointPolicy, RawResponsePolicy, ResponseBuffer,
15 TransportRequest,
16};
17use crate::{ProviderId, ProviderMarker, ServiceId, ServiceMarker};
18
19pub struct PreparationStorage<'storage> {
21 target: &'storage mut [u8],
22 body: &'storage mut [u8],
23}
24
25impl<'storage> PreparationStorage<'storage> {
26 #[must_use]
38 pub const fn new(target: &'storage mut [u8], body: &'storage mut [u8]) -> Self {
39 Self { target, body }
40 }
41
42 #[must_use]
44 pub fn into_parts(self) -> (&'storage mut [u8], &'storage mut [u8]) {
45 (self.target, self.body)
46 }
47}
48
49impl fmt::Debug for PreparationStorage<'_> {
50 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
51 formatter
52 .debug_struct("PreparationStorage")
53 .field("target_capacity", &self.target.len())
54 .field("body_capacity", &self.body.len())
55 .finish()
56 }
57}
58
59pub trait PrepareOperation {
69 type Error;
71
72 fn prepare<'storage>(
74 &self,
75 storage: PreparationStorage<'storage>,
76 ) -> Result<PreparedRequest<'storage>, Self::Error>;
77}
78
79#[derive(Clone, Copy, Debug, Eq, PartialEq)]
81pub struct ProviderService<'endpoint> {
82 provider_id: ProviderId,
83 service_id: ServiceId,
84 endpoint_policy: EndpointPolicy<'endpoint>,
85}
86
87impl<'endpoint> ProviderService<'endpoint> {
88 #[must_use]
90 pub const fn new(
91 provider_id: ProviderId,
92 service_id: ServiceId,
93 endpoint_policy: EndpointPolicy<'endpoint>,
94 ) -> Self {
95 Self {
96 provider_id,
97 service_id,
98 endpoint_policy,
99 }
100 }
101
102 #[must_use]
104 pub const fn from_marker<S: ServiceMarker>(endpoint_policy: EndpointPolicy<'endpoint>) -> Self {
105 Self::new(<S::Provider as ProviderMarker>::ID, S::ID, endpoint_policy)
106 }
107
108 #[must_use]
110 pub const fn provider_id(self) -> ProviderId {
111 self.provider_id
112 }
113
114 #[must_use]
116 pub const fn service_id(self) -> ServiceId {
117 self.service_id
118 }
119
120 #[must_use]
122 pub const fn endpoint_policy(self) -> EndpointPolicy<'endpoint> {
123 self.endpoint_policy
124 }
125}
126
127#[derive(Clone, Copy)]
129pub struct PreparedRequest<'request> {
130 request: TransportRequest<'request>,
131 service: ProviderService<'request>,
132 metadata: OperationMetadata,
133 response_policy: ResponsePolicy,
134 authentication_policy: AuthenticationScopePolicy<'request>,
135 raw_response_policy: RawResponsePolicy<'request>,
136 operation_id: Option<OperationId>,
137}
138
139#[derive(Clone, Copy, Debug, Eq, PartialEq)]
141pub enum PreparedRequestPolicyError {
142 MissingRequestIdHeader,
144}
145
146impl fmt::Display for PreparedRequestPolicyError {
147 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
148 formatter.write_str(match self {
149 Self::MissingRequestIdHeader => {
150 "prepared request ID policy requires raw x-request-id admission"
151 }
152 })
153 }
154}
155
156impl core::error::Error for PreparedRequestPolicyError {}
157
158impl<'request> PreparedRequest<'request> {
159 pub fn new(
167 request: TransportRequest<'request>,
168 service: ProviderService<'request>,
169 metadata: OperationMetadata,
170 response_policy: ResponsePolicy,
171 authentication_policy: AuthenticationScopePolicy<'request>,
172 raw_response_policy: RawResponsePolicy<'request>,
173 ) -> Result<Self, PreparedRequestPolicyError> {
174 if metadata.request_id_policy() != RequestIdPolicy::Discard
175 && !raw_response_policy.admits_header("x-request-id")
176 {
177 return Err(PreparedRequestPolicyError::MissingRequestIdHeader);
178 }
179 Ok(Self {
180 request,
181 service,
182 metadata,
183 response_policy,
184 authentication_policy,
185 raw_response_policy,
186 operation_id: None,
187 })
188 }
189
190 #[must_use]
192 pub const fn with_operation_id(mut self, operation_id: OperationId) -> Self {
193 self.operation_id = Some(operation_id);
194 self
195 }
196
197 #[must_use]
199 pub const fn transport_request(self) -> TransportRequest<'request> {
200 self.request
201 }
202
203 #[must_use]
205 pub const fn service(self) -> ProviderService<'request> {
206 self.service
207 }
208
209 #[must_use]
211 pub const fn metadata(self) -> OperationMetadata {
212 self.metadata
213 }
214
215 #[must_use]
217 pub const fn response_policy(self) -> ResponsePolicy {
218 self.response_policy
219 }
220
221 #[must_use]
223 pub const fn authentication_policy(self) -> AuthenticationScopePolicy<'request> {
224 self.authentication_policy
225 }
226
227 #[must_use]
229 pub const fn raw_response_policy(self) -> RawResponsePolicy<'request> {
230 self.raw_response_policy
231 }
232
233 #[must_use]
235 pub const fn authenticated_request(self) -> AuthenticatedRequest<'request, 'request> {
236 AuthenticatedRequest::new(
237 self.request,
238 self.authentication_policy,
239 self.raw_response_policy,
240 )
241 }
242
243 #[must_use]
245 pub const fn operation_id(self) -> Option<OperationId> {
246 self.operation_id
247 }
248
249 pub fn validate_response<'buffer>(
251 self,
252 response: ResponseBuffer<'buffer>,
253 ) -> Result<CheckedResponseGuard<'buffer>, ResponsePolicyError> {
254 self.response_policy
255 .validate(response, self.metadata.request_id_policy())
256 }
257
258 pub fn apply_response_metadata_policy(
264 self,
265 response: &mut ResponseBuffer<'_>,
266 ) -> Result<(), ResponsePolicyError> {
267 super::policy::apply_request_id_policy(response, self.metadata.request_id_policy())
268 }
269
270 pub fn execute_blocking<'buffer, T>(
272 self,
273 transport: &T,
274 response_storage: &'buffer mut [u8],
275 response_header_storage: &'buffer mut [u8],
276 ) -> Result<CheckedResponseGuard<'buffer>, PreparedExecutionError<T::Error>>
277 where
278 T: BlockingAuthenticatedTransport + BoundTransport,
279 {
280 let mut response = ResponseBuffer::new(
281 response_storage,
282 self.raw_response_policy.max_body_bytes(),
283 response_header_storage,
284 );
285 self.verify_endpoint(transport)
286 .map_err(map_endpoint_error)?;
287 transport
288 .send_authenticated(self.authenticated_request(), response.writer())
289 .map_err(PreparedExecutionError::Transport)?;
290 self.response_policy
291 .validate(response, self.metadata.request_id_policy())
292 .map_err(PreparedExecutionError::ResponsePolicy)
293 }
294
295 pub async fn execute_async<'transport, 'buffer, T>(
297 &'transport self,
298 transport: &'transport T,
299 response_storage: &'buffer mut [u8],
300 response_header_storage: &'buffer mut [u8],
301 ) -> Result<CheckedResponseGuard<'buffer>, PreparedExecutionError<T::Error>>
302 where
303 T: AsyncAuthenticatedTransport + BoundTransport,
304 'request: 'transport,
305 {
306 let mut response = ResponseBuffer::new(
307 response_storage,
308 self.raw_response_policy.max_body_bytes(),
309 response_header_storage,
310 );
311 self.verify_endpoint(transport)
312 .map_err(map_endpoint_error)?;
313 transport
314 .send_authenticated(self.authenticated_request(), response.writer())
315 .await
316 .map_err(PreparedExecutionError::Transport)?;
317 self.response_policy
318 .validate(response, self.metadata.request_id_policy())
319 .map_err(PreparedExecutionError::ResponsePolicy)
320 }
321
322 fn verify_endpoint<T>(self, transport: &T) -> Result<(), EndpointCheckError>
323 where
324 T: BoundTransport,
325 {
326 let actual = transport
327 .endpoint_identity()
328 .map_err(EndpointCheckError::Invalid)?;
329 self.service
330 .endpoint_policy
331 .verify(actual)
332 .map_err(|_| EndpointCheckError::Mismatch)
333 }
334}
335
336impl fmt::Debug for PreparedRequest<'_> {
337 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
338 formatter
339 .debug_struct("PreparedRequest")
340 .field("request", &self.request)
341 .field("service", &self.service)
342 .field("metadata", &self.metadata)
343 .field("response_policy", &self.response_policy)
344 .field("authentication_policy", &self.authentication_policy)
345 .field("raw_response_policy", &self.raw_response_policy)
346 .field("operation_id", &self.operation_id)
347 .finish()
348 }
349}
350
351#[derive(Clone, Copy, Eq, PartialEq)]
353pub enum PreparedExecutionError<E> {
354 EndpointIdentity(EndpointIdentityError),
356 EndpointMismatch,
358 Transport(E),
360 ResponsePolicy(ResponsePolicyError),
362}
363
364impl<E> fmt::Debug for PreparedExecutionError<E> {
365 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
366 match self {
367 Self::EndpointIdentity(error) => formatter
368 .debug_tuple("EndpointIdentity")
369 .field(error)
370 .finish(),
371 Self::EndpointMismatch => formatter.write_str("EndpointMismatch"),
372 Self::Transport(_) => formatter.write_str("Transport([redacted])"),
373 Self::ResponsePolicy(error) => formatter
374 .debug_tuple("ResponsePolicy")
375 .field(error)
376 .finish(),
377 }
378 }
379}
380
381impl<E> fmt::Display for PreparedExecutionError<E> {
382 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
383 formatter.write_str(match self {
384 Self::EndpointIdentity(_) => "transport endpoint identity is invalid",
385 Self::EndpointMismatch => "transport endpoint differs from prepared service",
386 Self::Transport(_) => "prepared request transport failed",
387 Self::ResponsePolicy(_) => "prepared response policy failed",
388 })
389 }
390}
391
392impl<E: fmt::Debug> core::error::Error for PreparedExecutionError<E> {}
393
394enum EndpointCheckError {
395 Invalid(EndpointIdentityError),
396 Mismatch,
397}
398
399fn map_endpoint_error<E>(error: EndpointCheckError) -> PreparedExecutionError<E> {
400 match error {
401 EndpointCheckError::Invalid(error) => PreparedExecutionError::EndpointIdentity(error),
402 EndpointCheckError::Mismatch => PreparedExecutionError::EndpointMismatch,
403 }
404}