1mod asynchronous;
4mod content_type;
5mod endpoint;
6mod request_target;
7
8pub use asynchronous::AsyncTransport;
9pub use content_type::{
10 ContentType, ContentTypeError, MAX_CONTENT_TYPE_BYTES, MediaType, ResponseContentType,
11};
12pub use endpoint::{
13 AcknowledgedCustomEndpoint, BoundTransport, CustomEndpointAcknowledgement, EndpointIdentity,
14 EndpointIdentityError, EndpointPolicy, EndpointPolicyError, EndpointPolicyKind, EndpointScheme,
15 MAX_ENDPOINT_BASE_PATH_BYTES, MAX_ENDPOINT_HOST_BYTES, MAX_ENDPOINT_REGION_BYTES,
16 MAX_OFFICIAL_ENDPOINTS, RegionEndpoint,
17};
18pub use request_target::{
19 CanonicalQuery, FormQuery, MAX_REQUEST_TARGET_BYTES, QueryPair, QueryPairs, RequestPath,
20 RequestPathError, RequestQuery, RequestTarget, RequestTargetError, StructuredQueryError,
21};
22
23use core::fmt;
24
25use crate::Method;
26use crate::rate_limit::RateLimit;
27
28pub trait ResponseStorageSanitizer {
37 fn sanitize_response_storage(&self, response_storage: &mut [u8]);
39}
40
41#[derive(Clone, Copy)]
43pub struct TransportRequest<'a> {
44 method: Method,
45 target: RequestTarget<'a>,
46 body: &'a [u8],
47 content_type: Option<ContentType<'a>>,
48}
49
50impl<'a> TransportRequest<'a> {
51 #[must_use]
53 pub const fn new(method: Method, target: RequestTarget<'a>) -> Self {
54 Self {
55 method,
56 target,
57 body: &[],
58 content_type: None,
59 }
60 }
61
62 #[must_use]
64 pub const fn with_body(mut self, body: &'a [u8]) -> Self {
65 self.body = body;
66 self
67 }
68
69 #[must_use]
71 pub const fn with_content_type(mut self, content_type: ContentType<'a>) -> Self {
72 self.content_type = Some(content_type);
73 self
74 }
75
76 #[must_use]
78 pub const fn method(self) -> Method {
79 self.method
80 }
81
82 #[must_use]
84 pub const fn target(self) -> RequestTarget<'a> {
85 self.target
86 }
87
88 #[must_use]
90 pub const fn body(self) -> &'a [u8] {
91 self.body
92 }
93
94 #[must_use]
96 pub const fn content_type(self) -> Option<ContentType<'a>> {
97 self.content_type
98 }
99}
100
101impl fmt::Debug for TransportRequest<'_> {
102 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
103 formatter
104 .debug_struct("TransportRequest")
105 .field("method", &self.method)
106 .field("target", &self.target)
107 .field("body", &"[redacted]")
108 .field("content_type", &self.content_type)
109 .finish()
110 }
111}
112
113#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
115pub struct StatusCode(u16);
116
117impl StatusCode {
118 pub const OK: Self = Self(200);
120 pub const CREATED: Self = Self(201);
122 pub const ACCEPTED: Self = Self(202);
124 pub const NO_CONTENT: Self = Self(204);
126 pub const TOO_MANY_REQUESTS: Self = Self(429);
128
129 #[must_use]
131 pub const fn new(value: u16) -> Option<Self> {
132 if value < 100 || value > 599 {
133 return None;
134 }
135 Some(Self(value))
136 }
137
138 #[must_use]
140 pub const fn get(self) -> u16 {
141 self.0
142 }
143
144 #[must_use]
146 pub const fn is_success(self) -> bool {
147 self.0 >= 200 && self.0 <= 299
148 }
149
150 #[must_use]
152 pub const fn is_error(self) -> bool {
153 self.0 >= 400
154 }
155}
156
157#[derive(Clone, Copy, Eq, PartialEq)]
169pub struct TransportResponse<'buffer> {
170 status: StatusCode,
171 body: &'buffer [u8],
172 content_type: Option<ResponseContentType>,
173 rate_limit: Option<RateLimit>,
174}
175
176impl<'buffer> TransportResponse<'buffer> {
177 #[must_use]
179 pub const fn new(status: StatusCode, body: &'buffer [u8]) -> Self {
180 Self {
181 status,
182 body,
183 content_type: None,
184 rate_limit: None,
185 }
186 }
187
188 #[must_use]
190 pub const fn with_content_type(mut self, content_type: ResponseContentType) -> Self {
191 self.content_type = Some(content_type);
192 self
193 }
194
195 #[must_use]
197 pub const fn with_rate_limit(mut self, rate_limit: RateLimit) -> Self {
198 self.rate_limit = Some(rate_limit);
199 self
200 }
201
202 #[must_use]
204 pub const fn status(&self) -> StatusCode {
205 self.status
206 }
207
208 #[must_use]
210 pub const fn body(&self) -> &'buffer [u8] {
211 self.body
212 }
213
214 #[must_use]
216 pub const fn content_type(&self) -> Option<ResponseContentType> {
217 self.content_type
218 }
219
220 #[must_use]
222 pub const fn rate_limit(&self) -> Option<RateLimit> {
223 self.rate_limit
224 }
225}
226
227impl fmt::Debug for TransportResponse<'_> {
228 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
229 formatter
230 .debug_struct("TransportResponse")
231 .field("status", &self.status)
232 .field("body_len", &self.body.len())
233 .field("body", &"[redacted]")
234 .field("content_type", &self.content_type)
235 .field("rate_limit", &self.rate_limit)
236 .finish()
237 }
238}
239
240pub trait BlockingTransport {
249 type Error;
251
252 fn send<'buffer>(
254 &self,
255 request: TransportRequest<'_>,
256 response_body: &'buffer mut [u8],
257 ) -> Result<TransportResponse<'buffer>, Self::Error>;
258}
259
260#[cfg(test)]
261mod tests;