Skip to main content

cloud_sdk/
lib.rs

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}