Skip to main content

prepared_request/
prepared_request.rs

1//! Prepares a complete provider-neutral operation without performing I/O.
2
3use cloud_sdk::operation::{
4    ContentTypePolicy, CostIntent, OperationImpact, OperationMetadata, PreparationStorage,
5    PrepareOperation, PreparedRequest, ProviderService, RequestSemantics, ResponseBodyPolicy,
6    ResponsePolicy, RetryEligibility,
7};
8use cloud_sdk::transport::{
9    EndpointIdentity, EndpointPolicy, EndpointScheme, MediaType, RequestTarget, StatusCode,
10};
11use cloud_sdk::transport::{MAX_REQUEST_TARGET_BYTES, TransportRequest};
12use cloud_sdk::{
13    Method, ProviderId, ProviderMarker, ServiceId, ServiceMarker, provider_id, service_id,
14};
15
16static OK_STATUS: [StatusCode; 1] = [StatusCode::OK];
17static JSON_MEDIA: [MediaType<'static>; 1] = [MediaType::JSON];
18
19enum ExampleProvider {}
20
21impl ProviderMarker for ExampleProvider {
22    const ID: ProviderId = provider_id!("example");
23}
24
25enum ComputeService {}
26
27impl ServiceMarker for ComputeService {
28    type Provider = ExampleProvider;
29    const ID: ServiceId = service_id!("compute");
30}
31
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33enum PrepareError {
34    TargetBuffer,
35    InvalidTarget,
36    InvalidMetadata,
37    InvalidResponsePolicy,
38    InvalidEndpoint,
39}
40
41struct ListResources;
42
43impl PrepareOperation for ListResources {
44    type Error = PrepareError;
45
46    fn prepare<'storage>(
47        &self,
48        storage: PreparationStorage<'storage>,
49    ) -> Result<PreparedRequest<'storage>, Self::Error> {
50        let (target_storage, _body_storage) = storage.into_parts();
51        let target = target_storage
52            .get_mut(..17)
53            .ok_or(PrepareError::TargetBuffer)?;
54        target.copy_from_slice(b"/resources?page=1");
55        let target = core::str::from_utf8(target).map_err(|_| PrepareError::InvalidTarget)?;
56        let target = RequestTarget::new(target).map_err(|_| PrepareError::InvalidTarget)?;
57        let request = TransportRequest::new(Method::Get, target);
58        let metadata = OperationMetadata::new(
59            OperationImpact::ReadOnly,
60            RequestSemantics::Safe,
61            RetryEligibility::ExplicitPolicy,
62            CostIntent::NoKnownCost,
63        )
64        .map_err(|_| PrepareError::InvalidMetadata)?;
65        let response_policy = ResponsePolicy::new(
66            &OK_STATUS,
67            ContentTypePolicy::Required(&JSON_MEDIA),
68            ResponseBodyPolicy::Required,
69            65_536,
70        )
71        .map_err(|_| PrepareError::InvalidResponsePolicy)?;
72        let endpoint =
73            EndpointIdentity::new(EndpointScheme::Https, "api.example.invalid", 443, "/v1")
74                .map_err(|_| PrepareError::InvalidEndpoint)?;
75        Ok(PreparedRequest::new(
76            request,
77            ProviderService::from_marker::<ComputeService>(EndpointPolicy::fixed(endpoint)),
78            metadata,
79            response_policy,
80        ))
81    }
82}
83
84fn main() {
85    let mut target = [0_u8; MAX_REQUEST_TARGET_BYTES];
86    let mut body = [0_u8; 1];
87    let prepared = ListResources.prepare(PreparationStorage::new(&mut target, &mut body));
88    let Ok(prepared) = prepared else { return };
89
90    assert_eq!(prepared.transport_request().method(), Method::Get);
91    assert_eq!(prepared.metadata().impact(), OperationImpact::ReadOnly);
92    assert_eq!(prepared.response_policy().max_body_bytes(), 65_536);
93}