aws_smithy_runtime_api/client/
ser_de.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! Serialization/deserialization for the orchestrator.
7
8use crate::box_error::BoxError;
9use crate::client::interceptors::context::{Error, Input, Output};
10use crate::client::orchestrator::{HttpRequest, HttpResponse, OrchestratorError};
11use crate::impl_shared_conversions;
12use aws_smithy_types::config_bag::{ConfigBag, Storable, StoreReplace};
13use std::fmt;
14use std::sync::Arc;
15
16/// Serialization implementation that converts an [`Input`] into an [`HttpRequest`].
17pub trait SerializeRequest: Send + Sync + fmt::Debug {
18    /// Serializes the input into an HTTP request.
19    ///
20    /// The type of the [`Input`] must be known ahead of time by the request serializer
21    /// implementation, and must be downcasted to get access to the information necessary
22    /// for serialization.
23    ///
24    /// The request serializer is generally added to the [`ConfigBag`] by the operation's
25    /// code generated runtime plugin, which is aware of the correct input/output/error types.
26    fn serialize_input(&self, input: Input, cfg: &mut ConfigBag) -> Result<HttpRequest, BoxError>;
27}
28
29/// A shared request serializer.
30///
31/// This is a simple shared ownership wrapper type for the [`SerializeRequest`] trait.
32#[derive(Clone, Debug)]
33pub struct SharedRequestSerializer(Arc<dyn SerializeRequest>);
34
35impl SharedRequestSerializer {
36    /// Creates a new shared request serializer.
37    pub fn new(serializer: impl SerializeRequest + 'static) -> Self {
38        Self(Arc::new(serializer))
39    }
40}
41
42impl SerializeRequest for SharedRequestSerializer {
43    fn serialize_input(&self, input: Input, cfg: &mut ConfigBag) -> Result<HttpRequest, BoxError> {
44        self.0.serialize_input(input, cfg)
45    }
46}
47
48impl Storable for SharedRequestSerializer {
49    type Storer = StoreReplace<Self>;
50}
51
52impl_shared_conversions!(convert SharedRequestSerializer from SerializeRequest using SharedRequestSerializer::new);
53
54/// Deserialization implementation that converts an [`HttpResponse`] into an [`Output`] or [`Error`].
55///
56/// This trait uses a backward-compatible versioning pattern for methods that need
57/// access to [`ConfigBag`]. Each method has a `_with_config` variant:
58///
59/// - **Legacy implementations** override the original method (without config).
60///   The default `_with_config` variant delegates to it, ignoring the config.
61/// - **New implementations** override the `_with_config` variant.
62///   The default original method delegates to it with an empty config bag.
63///
64/// The orchestrator always calls the `_with_config` variants.
65pub trait DeserializeResponse: Send + Sync + fmt::Debug {
66    /// For streaming requests, deserializes the response headers.
67    ///
68    /// The orchestrator will call [`deserialize_streaming_with_config`](Self::deserialize_streaming_with_config)
69    /// first, and if it returns `None`, then it will continue onto
70    /// [`deserialize_nonstreaming_with_config`](Self::deserialize_nonstreaming_with_config).
71    ///
72    /// Override this or [`deserialize_streaming_with_config`](Self::deserialize_streaming_with_config),
73    /// but not both.
74    #[deprecated(
75        note = "Implement `deserialize_streaming_with_config` instead. This method will be removed in a future release."
76    )]
77    fn deserialize_streaming(
78        &self,
79        response: &mut HttpResponse,
80    ) -> Option<Result<Output, OrchestratorError<Error>>> {
81        let _ = response;
82        None
83    }
84
85    /// For streaming requests, deserializes the response headers with access to the config bag.
86    ///
87    /// This is the method called by the orchestrator. The default implementation
88    /// delegates to [`deserialize_streaming`](Self::deserialize_streaming), ignoring the config.
89    fn deserialize_streaming_with_config(
90        &self,
91        response: &mut HttpResponse,
92        _cfg: &ConfigBag,
93    ) -> Option<Result<Output, OrchestratorError<Error>>> {
94        #[allow(deprecated)]
95        self.deserialize_streaming(response)
96    }
97
98    /// Deserialize the entire response including its body into an output or error.
99    ///
100    /// Override this or [`deserialize_nonstreaming_with_config`](Self::deserialize_nonstreaming_with_config),
101    /// but not both.
102    #[deprecated(
103        note = "Implement `deserialize_nonstreaming_with_config` instead. This method will be removed in a future release."
104    )]
105    fn deserialize_nonstreaming(
106        &self,
107        response: &HttpResponse,
108    ) -> Result<Output, OrchestratorError<Error>> {
109        self.deserialize_nonstreaming_with_config(response, &ConfigBag::base())
110    }
111
112    /// Deserialize the entire response including its body into an output or error,
113    /// with access to the config bag.
114    ///
115    /// This is the method called by the orchestrator. The default implementation
116    /// delegates to [`deserialize_nonstreaming`](Self::deserialize_nonstreaming),
117    /// ignoring the config bag.
118    fn deserialize_nonstreaming_with_config(
119        &self,
120        response: &HttpResponse,
121        _cfg: &ConfigBag,
122    ) -> Result<Output, OrchestratorError<Error>> {
123        #[allow(deprecated)]
124        self.deserialize_nonstreaming(response)
125    }
126}
127
128/// Shared response deserializer.
129///
130/// This is a simple shared ownership wrapper type for the [`DeserializeResponse`] trait.
131#[derive(Debug)]
132pub struct SharedResponseDeserializer(Arc<dyn DeserializeResponse>);
133
134impl SharedResponseDeserializer {
135    /// Creates a new [`SharedResponseDeserializer`].
136    pub fn new(serializer: impl DeserializeResponse + 'static) -> Self {
137        Self(Arc::new(serializer))
138    }
139}
140
141#[allow(deprecated)]
142impl DeserializeResponse for SharedResponseDeserializer {
143    fn deserialize_nonstreaming(
144        &self,
145        response: &HttpResponse,
146    ) -> Result<Output, OrchestratorError<Error>> {
147        self.0.deserialize_nonstreaming(response)
148    }
149
150    fn deserialize_nonstreaming_with_config(
151        &self,
152        response: &HttpResponse,
153        cfg: &ConfigBag,
154    ) -> Result<Output, OrchestratorError<Error>> {
155        self.0.deserialize_nonstreaming_with_config(response, cfg)
156    }
157
158    fn deserialize_streaming(
159        &self,
160        response: &mut HttpResponse,
161    ) -> Option<Result<Output, OrchestratorError<Error>>> {
162        self.0.deserialize_streaming(response)
163    }
164
165    fn deserialize_streaming_with_config(
166        &self,
167        response: &mut HttpResponse,
168        cfg: &ConfigBag,
169    ) -> Option<Result<Output, OrchestratorError<Error>>> {
170        self.0.deserialize_streaming_with_config(response, cfg)
171    }
172}
173
174impl Storable for SharedResponseDeserializer {
175    type Storer = StoreReplace<Self>;
176}
177
178impl_shared_conversions!(convert SharedResponseDeserializer from DeserializeResponse using SharedResponseDeserializer::new);