Skip to main content

prepared_request/
prepared_request.rs

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