1use core::fmt;
4
5use crate::operation::{
6 CheckedResponseGuard, OperationId, OperationMetadata, ResponsePolicy, ResponsePolicyError,
7};
8use crate::transport::{
9 AsyncTransport, BlockingTransport, BoundTransport, EndpointIdentityError, EndpointPolicy,
10 ResponseBuffer, TransportRequest,
11};
12use crate::{ProviderId, ProviderMarker, ServiceId, ServiceMarker};
13
14pub struct PreparationStorage<'storage> {
16 target: &'storage mut [u8],
17 body: &'storage mut [u8],
18}
19
20impl<'storage> PreparationStorage<'storage> {
21 #[must_use]
33 pub const fn new(target: &'storage mut [u8], body: &'storage mut [u8]) -> Self {
34 Self { target, body }
35 }
36
37 #[must_use]
39 pub fn into_parts(self) -> (&'storage mut [u8], &'storage mut [u8]) {
40 (self.target, self.body)
41 }
42}
43
44impl fmt::Debug for PreparationStorage<'_> {
45 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
46 formatter
47 .debug_struct("PreparationStorage")
48 .field("target_capacity", &self.target.len())
49 .field("body_capacity", &self.body.len())
50 .finish()
51 }
52}
53
54pub trait PrepareOperation {
64 type Error;
66
67 fn prepare<'storage>(
69 &self,
70 storage: PreparationStorage<'storage>,
71 ) -> Result<PreparedRequest<'storage>, Self::Error>;
72}
73
74#[derive(Clone, Copy, Debug, Eq, PartialEq)]
76pub struct ProviderService<'endpoint> {
77 provider_id: ProviderId,
78 service_id: ServiceId,
79 endpoint_policy: EndpointPolicy<'endpoint>,
80}
81
82impl<'endpoint> ProviderService<'endpoint> {
83 #[must_use]
85 pub const fn new(
86 provider_id: ProviderId,
87 service_id: ServiceId,
88 endpoint_policy: EndpointPolicy<'endpoint>,
89 ) -> Self {
90 Self {
91 provider_id,
92 service_id,
93 endpoint_policy,
94 }
95 }
96
97 #[must_use]
99 pub const fn from_marker<S: ServiceMarker>(endpoint_policy: EndpointPolicy<'endpoint>) -> Self {
100 Self::new(<S::Provider as ProviderMarker>::ID, S::ID, endpoint_policy)
101 }
102
103 #[must_use]
105 pub const fn provider_id(self) -> ProviderId {
106 self.provider_id
107 }
108
109 #[must_use]
111 pub const fn service_id(self) -> ServiceId {
112 self.service_id
113 }
114
115 #[must_use]
117 pub const fn endpoint_policy(self) -> EndpointPolicy<'endpoint> {
118 self.endpoint_policy
119 }
120}
121
122#[derive(Clone, Copy)]
124pub struct PreparedRequest<'request> {
125 request: TransportRequest<'request>,
126 service: ProviderService<'request>,
127 metadata: OperationMetadata,
128 response_policy: ResponsePolicy,
129 operation_id: Option<OperationId>,
130}
131
132impl<'request> PreparedRequest<'request> {
133 #[must_use]
135 pub const fn new(
136 request: TransportRequest<'request>,
137 service: ProviderService<'request>,
138 metadata: OperationMetadata,
139 response_policy: ResponsePolicy,
140 ) -> Self {
141 Self {
142 request,
143 service,
144 metadata,
145 response_policy,
146 operation_id: None,
147 }
148 }
149
150 #[must_use]
152 pub const fn with_operation_id(mut self, operation_id: OperationId) -> Self {
153 self.operation_id = Some(operation_id);
154 self
155 }
156
157 #[must_use]
159 pub const fn transport_request(self) -> TransportRequest<'request> {
160 self.request
161 }
162
163 #[must_use]
165 pub const fn service(self) -> ProviderService<'request> {
166 self.service
167 }
168
169 #[must_use]
171 pub const fn metadata(self) -> OperationMetadata {
172 self.metadata
173 }
174
175 #[must_use]
177 pub const fn response_policy(self) -> ResponsePolicy {
178 self.response_policy
179 }
180
181 #[must_use]
183 pub const fn operation_id(self) -> Option<OperationId> {
184 self.operation_id
185 }
186
187 pub fn validate_response<'buffer>(
189 self,
190 response: ResponseBuffer<'buffer>,
191 ) -> Result<CheckedResponseGuard<'buffer>, ResponsePolicyError> {
192 self.response_policy
193 .validate(response, self.metadata.request_id_policy())
194 }
195
196 pub fn apply_response_metadata_policy(
202 self,
203 response: &mut ResponseBuffer<'_>,
204 ) -> Result<(), ResponsePolicyError> {
205 super::policy::apply_request_id_policy(response, self.metadata.request_id_policy())
206 }
207
208 pub fn execute_blocking<'buffer, T>(
210 self,
211 transport: &T,
212 response_storage: &'buffer mut [u8],
213 response_header_storage: &'buffer mut [u8],
214 ) -> Result<CheckedResponseGuard<'buffer>, PreparedExecutionError<T::Error>>
215 where
216 T: BlockingTransport + BoundTransport,
217 {
218 let mut response = ResponseBuffer::new(
219 response_storage,
220 self.response_policy.max_body_bytes(),
221 response_header_storage,
222 );
223 self.verify_endpoint(transport)
224 .map_err(map_endpoint_error)?;
225 transport
226 .send(self.request, response.writer())
227 .map_err(PreparedExecutionError::Transport)?;
228 self.response_policy
229 .validate(response, self.metadata.request_id_policy())
230 .map_err(PreparedExecutionError::ResponsePolicy)
231 }
232
233 pub async fn execute_async<'transport, 'buffer, T>(
235 &'transport self,
236 transport: &'transport T,
237 response_storage: &'buffer mut [u8],
238 response_header_storage: &'buffer mut [u8],
239 ) -> Result<CheckedResponseGuard<'buffer>, PreparedExecutionError<T::Error>>
240 where
241 T: AsyncTransport + BoundTransport,
242 'request: 'transport,
243 {
244 let mut response = ResponseBuffer::new(
245 response_storage,
246 self.response_policy.max_body_bytes(),
247 response_header_storage,
248 );
249 self.verify_endpoint(transport)
250 .map_err(map_endpoint_error)?;
251 transport
252 .send(self.request, response.writer())
253 .await
254 .map_err(PreparedExecutionError::Transport)?;
255 self.response_policy
256 .validate(response, self.metadata.request_id_policy())
257 .map_err(PreparedExecutionError::ResponsePolicy)
258 }
259
260 fn verify_endpoint<T>(self, transport: &T) -> Result<(), EndpointCheckError>
261 where
262 T: BoundTransport,
263 {
264 let actual = transport
265 .endpoint_identity()
266 .map_err(EndpointCheckError::Invalid)?;
267 self.service
268 .endpoint_policy
269 .verify(actual)
270 .map_err(|_| EndpointCheckError::Mismatch)
271 }
272}
273
274impl fmt::Debug for PreparedRequest<'_> {
275 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
276 formatter
277 .debug_struct("PreparedRequest")
278 .field("request", &self.request)
279 .field("service", &self.service)
280 .field("metadata", &self.metadata)
281 .field("response_policy", &self.response_policy)
282 .field("operation_id", &self.operation_id)
283 .finish()
284 }
285}
286
287#[derive(Clone, Copy, Eq, PartialEq)]
289pub enum PreparedExecutionError<E> {
290 EndpointIdentity(EndpointIdentityError),
292 EndpointMismatch,
294 Transport(E),
296 ResponsePolicy(ResponsePolicyError),
298}
299
300impl<E> fmt::Debug for PreparedExecutionError<E> {
301 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
302 match self {
303 Self::EndpointIdentity(error) => formatter
304 .debug_tuple("EndpointIdentity")
305 .field(error)
306 .finish(),
307 Self::EndpointMismatch => formatter.write_str("EndpointMismatch"),
308 Self::Transport(_) => formatter.write_str("Transport([redacted])"),
309 Self::ResponsePolicy(error) => formatter
310 .debug_tuple("ResponsePolicy")
311 .field(error)
312 .finish(),
313 }
314 }
315}
316
317impl<E> fmt::Display for PreparedExecutionError<E> {
318 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
319 formatter.write_str(match self {
320 Self::EndpointIdentity(_) => "transport endpoint identity is invalid",
321 Self::EndpointMismatch => "transport endpoint differs from prepared service",
322 Self::Transport(_) => "prepared request transport failed",
323 Self::ResponsePolicy(_) => "prepared response policy failed",
324 })
325 }
326}
327
328impl<E: fmt::Debug> core::error::Error for PreparedExecutionError<E> {}
329
330enum EndpointCheckError {
331 Invalid(EndpointIdentityError),
332 Mismatch,
333}
334
335fn map_endpoint_error<E>(error: EndpointCheckError) -> PreparedExecutionError<E> {
336 match error {
337 EndpointCheckError::Invalid(error) => PreparedExecutionError::EndpointIdentity(error),
338 EndpointCheckError::Mismatch => PreparedExecutionError::EndpointMismatch,
339 }
340}