Skip to main content

cloud_sdk/operation/prepared/
error.rs

1//! Redacted prepared-request construction and execution failures.
2
3use core::fmt;
4
5use crate::operation::{ExecutionPermitError, ResponsePolicyError};
6use crate::transport::{EndpointIdentityError, ResponseWriterError, StatusCode};
7
8/// Incoherent policy supplied while constructing a prepared request.
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub enum PreparedRequestPolicyError {
11    /// Protected or retainable request IDs were not admitted by raw transport.
12    MissingRequestIdHeader,
13    /// Read-only metadata was paired with a method that can change state.
14    ReadOnlyMethodMismatch,
15    /// A closed read-only POST approval did not match the complete operation.
16    ReadOnlyPostQueryMismatch,
17}
18
19impl fmt::Display for PreparedRequestPolicyError {
20    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
21        formatter.write_str(match self {
22            Self::MissingRequestIdHeader => {
23                "prepared request ID policy requires raw x-request-id admission"
24            }
25            Self::ReadOnlyMethodMismatch => "read-only operation metadata requires GET or HEAD",
26            Self::ReadOnlyPostQueryMismatch => {
27                "read-only POST query differs from its closed registry approval"
28            }
29        })
30    }
31}
32
33impl core::error::Error for PreparedRequestPolicyError {}
34
35/// Prepared execution failure with transport details redacted from diagnostics.
36#[derive(Clone, Copy, Eq, PartialEq)]
37pub enum PreparedExecutionError<E> {
38    /// A state-changing request was executed without plan-confirm authority.
39    AuthorizationRequired,
40    /// Plan-confirm authority became invalid before transport dispatch.
41    AuthorizationInvalid(ExecutionPermitError),
42    /// The bound transport returned invalid endpoint identity.
43    EndpointIdentity(EndpointIdentityError),
44    /// The bound endpoint differs from the prepared provider service.
45    EndpointMismatch,
46    /// The concrete transport failed.
47    Transport(E),
48    /// The SDK-owned response transaction failed.
49    ResponseWriter(ResponseWriterError),
50    /// A committed response used a status outside the operation success set.
51    UnexpectedStatus(StatusCode),
52    /// The response failed provider-neutral policy.
53    ResponsePolicy(ResponsePolicyError),
54}
55
56impl<E> fmt::Debug for PreparedExecutionError<E> {
57    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
58        match self {
59            Self::AuthorizationRequired => formatter.write_str("AuthorizationRequired"),
60            Self::AuthorizationInvalid(error) => formatter
61                .debug_tuple("AuthorizationInvalid")
62                .field(error)
63                .finish(),
64            Self::EndpointIdentity(error) => formatter
65                .debug_tuple("EndpointIdentity")
66                .field(error)
67                .finish(),
68            Self::EndpointMismatch => formatter.write_str("EndpointMismatch"),
69            Self::Transport(_) => formatter.write_str("Transport([redacted])"),
70            Self::ResponseWriter(error) => formatter
71                .debug_tuple("ResponseWriter")
72                .field(error)
73                .finish(),
74            Self::UnexpectedStatus(status) => formatter
75                .debug_tuple("UnexpectedStatus")
76                .field(status)
77                .finish(),
78            Self::ResponsePolicy(error) => formatter
79                .debug_tuple("ResponsePolicy")
80                .field(error)
81                .finish(),
82        }
83    }
84}
85
86impl<E> fmt::Display for PreparedExecutionError<E> {
87    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
88        formatter.write_str(match self {
89            Self::AuthorizationRequired => "state-changing request requires execution authority",
90            Self::AuthorizationInvalid(_) => "execution authority is no longer valid",
91            Self::EndpointIdentity(_) => "transport endpoint identity is invalid",
92            Self::EndpointMismatch => "transport endpoint differs from prepared service",
93            Self::Transport(_) => "prepared request transport failed",
94            Self::ResponseWriter(_) => "prepared response transaction failed",
95            Self::UnexpectedStatus(_) => "prepared response status is unexpected",
96            Self::ResponsePolicy(_) => "prepared response policy failed",
97        })
98    }
99}
100
101impl<E> core::error::Error for PreparedExecutionError<E> {}
102
103impl<E: crate::transport::DeliveryClassified> crate::transport::DeliveryClassified
104    for PreparedExecutionError<E>
105{
106    fn delivery_phase(&self) -> crate::transport::DeliveryPhase {
107        use crate::transport::DeliveryPhase;
108        match self {
109            Self::AuthorizationRequired
110            | Self::AuthorizationInvalid(_)
111            | Self::EndpointIdentity(_)
112            | Self::EndpointMismatch => DeliveryPhase::NotSent,
113            Self::Transport(error) => error.delivery_phase(),
114            Self::ResponseWriter(_) => DeliveryPhase::PossiblySent,
115            Self::UnexpectedStatus(_) | Self::ResponsePolicy(_) => DeliveryPhase::ResponseStarted,
116        }
117    }
118}
119
120pub(super) enum EndpointCheckError {
121    Invalid(EndpointIdentityError),
122    Mismatch,
123}
124
125pub(super) fn map_endpoint_error<E>(error: EndpointCheckError) -> PreparedExecutionError<E> {
126    match error {
127        EndpointCheckError::Invalid(error) => PreparedExecutionError::EndpointIdentity(error),
128        EndpointCheckError::Mismatch => PreparedExecutionError::EndpointMismatch,
129    }
130}