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, ResponseStorageSanitizer, 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, 'sanitizer, S>(
189 self,
190 response: ResponseBuffer<'buffer, 'sanitizer, S>,
191 ) -> Result<CheckedResponseGuard<'buffer, 'sanitizer, S>, ResponsePolicyError>
192 where
193 S: ResponseStorageSanitizer + ?Sized,
194 {
195 self.response_policy.validate(response)
196 }
197
198 pub fn execute_blocking<'transport, 'buffer, T>(
200 self,
201 transport: &'transport T,
202 response_storage: &'buffer mut [u8],
203 ) -> Result<CheckedResponseGuard<'buffer, 'transport, T>, PreparedExecutionError<T::Error>>
204 where
205 T: BlockingTransport + BoundTransport + ResponseStorageSanitizer,
206 {
207 let mut response = ResponseBuffer::new(
208 response_storage,
209 self.response_policy.max_body_bytes(),
210 transport,
211 );
212 self.verify_endpoint(transport)
213 .map_err(map_endpoint_error)?;
214 transport
215 .send(self.request, response.writer())
216 .map_err(PreparedExecutionError::Transport)?;
217 self.response_policy
218 .validate(response)
219 .map_err(PreparedExecutionError::ResponsePolicy)
220 }
221
222 pub async fn execute_async<'transport, 'buffer, T>(
224 &'transport self,
225 transport: &'transport T,
226 response_storage: &'buffer mut [u8],
227 ) -> Result<CheckedResponseGuard<'buffer, 'transport, T>, PreparedExecutionError<T::Error>>
228 where
229 T: AsyncTransport + BoundTransport + ResponseStorageSanitizer,
230 'request: 'transport,
231 {
232 let mut response = ResponseBuffer::new(
233 response_storage,
234 self.response_policy.max_body_bytes(),
235 transport,
236 );
237 self.verify_endpoint(transport)
238 .map_err(map_endpoint_error)?;
239 transport
240 .send(self.request, response.writer())
241 .await
242 .map_err(PreparedExecutionError::Transport)?;
243 self.response_policy
244 .validate(response)
245 .map_err(PreparedExecutionError::ResponsePolicy)
246 }
247
248 fn verify_endpoint<T>(self, transport: &T) -> Result<(), EndpointCheckError>
249 where
250 T: BoundTransport,
251 {
252 let actual = transport
253 .endpoint_identity()
254 .map_err(EndpointCheckError::Invalid)?;
255 self.service
256 .endpoint_policy
257 .verify(actual)
258 .map_err(|_| EndpointCheckError::Mismatch)
259 }
260}
261
262impl fmt::Debug for PreparedRequest<'_> {
263 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
264 formatter
265 .debug_struct("PreparedRequest")
266 .field("request", &self.request)
267 .field("service", &self.service)
268 .field("metadata", &self.metadata)
269 .field("response_policy", &self.response_policy)
270 .field("operation_id", &self.operation_id)
271 .finish()
272 }
273}
274
275#[derive(Clone, Copy, Eq, PartialEq)]
277pub enum PreparedExecutionError<E> {
278 EndpointIdentity(EndpointIdentityError),
280 EndpointMismatch,
282 Transport(E),
284 ResponsePolicy(ResponsePolicyError),
286}
287
288impl<E> fmt::Debug for PreparedExecutionError<E> {
289 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
290 match self {
291 Self::EndpointIdentity(error) => formatter
292 .debug_tuple("EndpointIdentity")
293 .field(error)
294 .finish(),
295 Self::EndpointMismatch => formatter.write_str("EndpointMismatch"),
296 Self::Transport(_) => formatter.write_str("Transport([redacted])"),
297 Self::ResponsePolicy(error) => formatter
298 .debug_tuple("ResponsePolicy")
299 .field(error)
300 .finish(),
301 }
302 }
303}
304
305impl<E> fmt::Display for PreparedExecutionError<E> {
306 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
307 formatter.write_str(match self {
308 Self::EndpointIdentity(_) => "transport endpoint identity is invalid",
309 Self::EndpointMismatch => "transport endpoint differs from prepared service",
310 Self::Transport(_) => "prepared request transport failed",
311 Self::ResponsePolicy(_) => "prepared response policy failed",
312 })
313 }
314}
315
316impl<E: fmt::Debug> core::error::Error for PreparedExecutionError<E> {}
317
318enum EndpointCheckError {
319 Invalid(EndpointIdentityError),
320 Mismatch,
321}
322
323fn map_endpoint_error<E>(error: EndpointCheckError) -> PreparedExecutionError<E> {
324 match error {
325 EndpointCheckError::Invalid(error) => PreparedExecutionError::EndpointIdentity(error),
326 EndpointCheckError::Mismatch => PreparedExecutionError::EndpointMismatch,
327 }
328}