cloud_sdk/client/
response.rs1use core::fmt;
2
3use crate::diagnostics::{DiagnosticRequestId, DiagnosticResponse};
4use crate::operation::{CheckedResponse, PreparedRequest, ResponsePolicyError};
5use crate::transport::{
6 ResponseBuffer, ResponseDecodeWorkspace, ResponseWriterError, StatusCode, TransportResponse,
7};
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub enum ClientResponseKind {
12 Success,
14 Error,
16 Other,
18}
19
20pub enum CheckedDecodeError<E> {
22 ResponseWriter(ResponseWriterError),
24 ResponsePolicy(ResponsePolicyError),
26 ExpectedErrorStatus,
28 Decoder(E),
30}
31
32impl<E> fmt::Debug for CheckedDecodeError<E> {
33 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
34 formatter.write_str(match self {
35 Self::ResponseWriter(_) => "CheckedDecodeError::ResponseWriter",
36 Self::ResponsePolicy(_) => "CheckedDecodeError::ResponsePolicy",
37 Self::ExpectedErrorStatus => "CheckedDecodeError::ExpectedErrorStatus",
38 Self::Decoder(_) => "CheckedDecodeError::Decoder([redacted])",
39 })
40 }
41}
42
43impl<E> fmt::Display for CheckedDecodeError<E> {
44 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
45 formatter.write_str(match self {
46 Self::ResponseWriter(_) => "client response is not committed",
47 Self::ResponsePolicy(_) => "client response policy rejected the response",
48 Self::ExpectedErrorStatus => "client error decoder requires an error status",
49 Self::Decoder(_) => "provider response decoder failed",
50 })
51 }
52}
53
54impl<E> core::error::Error for CheckedDecodeError<E> {}
55
56pub struct ClientResponse<'request, 'buffer> {
62 prepared: PreparedRequest<'request>,
63 response: ResponseBuffer<'buffer>,
64}
65
66impl<'request, 'buffer> ClientResponse<'request, 'buffer> {
67 #[allow(clippy::large_types_passed_by_value)]
68 pub(crate) const fn new(
69 prepared: PreparedRequest<'request>,
70 response: ResponseBuffer<'buffer>,
71 ) -> Self {
72 Self { prepared, response }
73 }
74
75 pub fn status(&self) -> Result<StatusCode, ResponseWriterError> {
77 self.response.with_response(|response| response.status())
78 }
79
80 pub fn kind(&self) -> Result<ClientResponseKind, ResponseWriterError> {
82 self.status().map(|status| {
83 if status.is_success() {
84 ClientResponseKind::Success
85 } else if status.is_error() {
86 ClientResponseKind::Error
87 } else {
88 ClientResponseKind::Other
89 }
90 })
91 }
92
93 pub(crate) fn diagnostic_response(&self) -> Result<DiagnosticResponse, ResponseWriterError> {
94 let status = self.status()?;
95 let policy = self.prepared.metadata().request_id_policy();
96 let present = match policy {
97 crate::operation::RequestIdPolicy::Discard => false,
98 crate::operation::RequestIdPolicy::Protected
99 | crate::operation::RequestIdPolicy::Retain => self.response.has_request_id()?,
100 };
101 let request_id = DiagnosticRequestId::classify(policy, present);
102 Ok(DiagnosticResponse::new(status, request_id))
103 }
104
105 pub fn decode_success_owned<R, E>(
107 self,
108 decode: impl for<'response> FnOnce(
109 CheckedResponse<'response>,
110 &mut ResponseDecodeWorkspace,
111 ) -> Result<R, E>,
112 ) -> Result<R, CheckedDecodeError<E>> {
113 let checked = self
114 .prepared
115 .validate_response(self.response)
116 .map_err(CheckedDecodeError::ResponsePolicy)?;
117 checked
118 .decode_owned_with_workspace(decode)
119 .map_err(CheckedDecodeError::Decoder)
120 }
121
122 pub fn decode_error_owned<R, E>(
124 mut self,
125 decode: impl for<'response> FnOnce(
126 TransportResponse<'response, 'buffer>,
127 &mut ResponseDecodeWorkspace,
128 ) -> Result<R, E>,
129 ) -> Result<R, CheckedDecodeError<E>> {
130 let status = self.status().map_err(CheckedDecodeError::ResponseWriter)?;
131 if !status.is_error() {
132 return Err(CheckedDecodeError::ExpectedErrorStatus);
133 }
134 self.prepared
135 .apply_response_metadata_policy(&mut self.response)
136 .map_err(CheckedDecodeError::ResponsePolicy)?;
137 let mut workspace = ResponseDecodeWorkspace::new_for_provider();
138 self.response
139 .with_response(|response| decode(response, &mut workspace))
140 .map_err(CheckedDecodeError::ResponseWriter)?
141 .map_err(CheckedDecodeError::Decoder)
142 }
143}
144
145impl fmt::Debug for ClientResponse<'_, '_> {
146 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
147 formatter
148 .debug_struct("ClientResponse")
149 .field("prepared", &"[bound]")
150 .field("response", &"[redacted]")
151 .finish()
152 }
153}