1#![no_std]
2#![doc = include_str!("../README.md")]
3
4#[cfg(feature = "std")]
5extern crate std;
6
7#[cfg(feature = "alloc")]
8extern crate alloc;
9
10macro_rules! impl_static_error {
11 ($error:ty, $($pattern:pat => $message:literal),+ $(,)?) => {
12 impl core::fmt::Display for $error {
13 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
14 formatter.write_str(match self {
15 $($pattern => $message,)+
16 })
17 }
18 }
19
20 impl core::error::Error for $error {}
21 };
22}
23
24pub mod action_polling;
25pub mod async_resource;
26pub mod authentication;
27pub mod buffer;
28pub mod client;
29pub mod diagnostics;
30mod identity;
31mod method;
32pub mod operation;
33pub mod pagination;
34pub mod rate_limit;
35pub mod retry;
36pub mod schema;
37pub mod transport;
38
39#[cfg(test)]
40mod test_sha256;
41
42pub use identity::{
43 IdentityError, MAX_PROVIDER_ID_BYTES, MAX_SERVICE_ID_BYTES, ProviderId, ProviderMarker,
44 ServiceId, ServiceMarker,
45};
46pub use method::{MAX_METHOD_BYTES, Method, MethodError};
47
48#[cfg(test)]
49mod tests {
50 use super::{Method, MethodError, ProviderId, ServiceId};
51 use crate::action_polling::{ActionObserveError, ActionPollError};
52 use crate::async_resource::AsyncResourceValidationError;
53 use crate::authentication::{
54 AuthenticationScopeError, CredentialAttemptError, CredentialGenerationError,
55 CredentialLifetimeError, ScopeValueError, SigningBuildError, SigningContextValueError,
56 SigningInputError, SigningOutputError, SigningValueError,
57 };
58 use crate::client::{
59 CheckedDecodeError, ClientExecutionError, WorkspaceAcquireError, WorkspacePoolError,
60 };
61 use crate::operation::{
62 AttemptBudgetError, CurrencyCodeError, ExecutionPermitError, OperationMetadataError,
63 PermitContextError, PermitExecutionError, PermitIdempotencyKeyError, PermitValidityError,
64 PlanCostError, PlanFingerprintBuildError, PreparedExecutionError, ResponsePolicyError,
65 ResponsePolicyValidationError,
66 };
67 use crate::pagination::{HeaderCursorExecutionError, PaginationError};
68 use crate::rate_limit::{
69 DelayDecisionError, QuotaError, QuotaExtensionError, RateLimitError, RetryAfterError,
70 };
71 use crate::retry::{
72 FingerprintBuildError, IdempotencyIntentError, MaxAttemptsError, RetryExecutionError,
73 RetryPermitError, RetryPolicyError,
74 };
75 use crate::schema::SchemaVersionError;
76 use crate::transport::{
77 AsyncExecutionError, ContentTypeError, EndpointIdentityError, EndpointPairPolicyError,
78 HeaderError, InformationalResponseError, RawResponsePolicyError, RequestPathError,
79 RequestTargetError, ResponseWriterError, StreamExecutionError, StreamLimitsError,
80 StreamPolicyError, StreamProgressError, StreamReplayError, StreamSourceIdError,
81 TransportFailure,
82 };
83 use core::fmt::{self, Write};
84
85 #[test]
86 fn exposes_provider_neutral_domains() {
87 assert_eq!(
88 ProviderId::new("example").map(ProviderId::as_str),
89 Ok("example")
90 );
91 assert_eq!(
92 ServiceId::new("compute").map(ServiceId::as_str),
93 Ok("compute")
94 );
95 assert_eq!(Method::Get, Method::Get);
96 assert_eq!(Method::Post.as_str(), "POST");
97 }
98
99 #[test]
100 fn public_errors_implement_payload_free_core_error() {
101 fn assert_error<E: core::error::Error>() {}
102
103 assert_error::<PaginationError>();
104 assert_error::<AsyncResourceValidationError>();
105 assert_error::<HeaderCursorExecutionError<core::convert::Infallible>>();
106 assert_error::<AuthenticationScopeError>();
107 assert_error::<CredentialAttemptError>();
108 assert_error::<CredentialGenerationError>();
109 assert_error::<CredentialLifetimeError>();
110 assert_error::<ScopeValueError>();
111 assert_error::<SigningValueError>();
112 assert_error::<SigningContextValueError>();
113 assert_error::<SigningInputError>();
114 assert_error::<SigningBuildError<core::convert::Infallible>>();
115 assert_error::<SigningOutputError<core::convert::Infallible>>();
116 assert_error::<RateLimitError>();
117 assert_error::<QuotaError>();
118 assert_error::<QuotaExtensionError>();
119 assert_error::<RetryAfterError>();
120 assert_error::<DelayDecisionError>();
121 assert_error::<FingerprintBuildError<core::convert::Infallible>>();
122 assert_error::<IdempotencyIntentError>();
123 assert_error::<MaxAttemptsError>();
124 assert_error::<RetryPolicyError>();
125 assert_error::<RetryPermitError>();
126 assert_error::<RetryExecutionError<()>>();
127 assert_error::<ContentTypeError>();
128 assert_error::<HeaderError>();
129 assert_error::<EndpointIdentityError>();
130 assert_error::<EndpointPairPolicyError>();
131 assert_error::<RequestTargetError>();
132 assert_error::<MethodError>();
133 assert_error::<ActionPollError>();
134 assert_error::<ActionObserveError<&'static str>>();
135 assert_error::<OperationMetadataError>();
136 assert_error::<ResponsePolicyError>();
137 assert_error::<ResponsePolicyValidationError>();
138 assert_error::<PreparedExecutionError<()>>();
139 assert_error::<AttemptBudgetError>();
140 assert_error::<CurrencyCodeError>();
141 assert_error::<ExecutionPermitError>();
142 assert_error::<PermitContextError>();
143 assert_error::<PermitExecutionError<()>>();
144 assert_error::<PermitIdempotencyKeyError>();
145 assert_error::<PermitValidityError>();
146 assert_error::<PlanCostError>();
147 assert_error::<PlanFingerprintBuildError<core::convert::Infallible>>();
148 assert_error::<ResponseWriterError>();
149 assert_error::<AsyncExecutionError<()>>();
150 assert_error::<RawResponsePolicyError>();
151 assert_error::<InformationalResponseError>();
152 assert_error::<StreamLimitsError>();
153 assert_error::<StreamPolicyError>();
154 assert_error::<StreamProgressError>();
155 assert_error::<StreamSourceIdError>();
156 assert_error::<StreamReplayError>();
157 assert_error::<StreamExecutionError<(), ()>>();
158 assert_error::<TransportFailure<()>>();
159 assert_error::<CheckedDecodeError<()>>();
160 assert_error::<ClientExecutionError<(), (), ()>>();
161 assert_error::<WorkspaceAcquireError>();
162 assert_error::<WorkspacePoolError>();
163 assert_error::<SchemaVersionError>();
164
165 assert_display(PaginationError::PageZero, "page number must be nonzero");
166 assert_display(RateLimitError::LimitZero, "rate limit must be nonzero");
167 assert_display(ContentTypeError::Empty, "content type is empty");
168 assert_display(HeaderError::DuplicateName, "HTTP header name is duplicated");
169 assert_display(
170 EndpointIdentityError::UnboundTransport,
171 "transport endpoint identity is unbound",
172 );
173 assert_display(
174 RequestTargetError::Path(RequestPathError::Empty),
175 "invalid request path: request path is empty",
176 );
177 assert_display(
178 MethodError::DeniedMethod,
179 "HTTP method is denied by the transport contract",
180 );
181 assert_display(
182 OperationMetadataError::NonIdempotentRetry,
183 "non-idempotent operation cannot be retry eligible",
184 );
185 assert_display(
186 ResponsePolicyError::UnexpectedContentType,
187 "response content type is not accepted",
188 );
189 assert_display(
190 ResponsePolicyError::InvalidContentType,
191 "response content type is invalid",
192 );
193 assert_display(
194 ResponsePolicyValidationError::MissingSuccessStatus,
195 "response policy has no success status",
196 );
197 assert_display(
198 PreparedExecutionError::<()>::Transport(()),
199 "prepared request transport failed",
200 );
201 assert_display(
202 PreparedExecutionError::<()>::AuthorizationRequired,
203 "state-changing request requires execution authority",
204 );
205 assert_display(
206 ResponseWriterError::AlreadyCommitted,
207 "response writer is already committed",
208 );
209 assert_display(
210 RawResponsePolicyError::UnsafeAdmittedHeader,
211 "an unsafe response header was admitted",
212 );
213 assert_display(
214 InformationalResponseError::SwitchingProtocols,
215 "switching protocols is forbidden",
216 );
217 assert_display(
218 TransportFailure::unknown("sentinel-secret"),
219 "transport failed with uncertain delivery",
220 );
221 assert_display(
222 ActionObserveError::Backoff("sentinel-secret"),
223 "action poll backoff policy failed",
224 );
225 }
226
227 fn assert_display(error: impl fmt::Display, expected: &str) {
228 let mut output = DisplayBuffer::new();
229 assert!(write!(&mut output, "{error}").is_ok());
230 assert_eq!(output.as_str(), expected);
231 }
232
233 struct DisplayBuffer {
234 bytes: [u8; 128],
235 len: usize,
236 }
237
238 impl DisplayBuffer {
239 const fn new() -> Self {
240 Self {
241 bytes: [0; 128],
242 len: 0,
243 }
244 }
245
246 fn as_str(&self) -> &str {
247 core::str::from_utf8(self.bytes.get(..self.len).unwrap_or_default()).unwrap_or_default()
248 }
249 }
250
251 impl Write for DisplayBuffer {
252 fn write_str(&mut self, value: &str) -> fmt::Result {
253 let end = self.len.checked_add(value.len()).ok_or(fmt::Error)?;
254 let target = self.bytes.get_mut(self.len..end).ok_or(fmt::Error)?;
255 target.copy_from_slice(value.as_bytes());
256 self.len = end;
257 Ok(())
258 }
259 }
260}