aws_smithy_schema/schema/
codec.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! Codec trait for creating shape serializers and deserializers.
7//!
8//! A codec represents a specific serialization format (e.g., JSON, XML, CBOR)
9//! and provides methods to create serializers and deserializers for that format.
10
11pub mod http_string;
12
13use crate::serde::{ShapeDeserializer, ShapeSerializer};
14
15/// Trait for serializers that can produce a final byte output.
16///
17/// This is separate from [`ShapeSerializer`] to preserve object safety on
18/// [`ShapeSerializer`] (which is used as `&mut dyn ShapeSerializer` in generated code).
19///
20/// # Why isn't `FinishSerializer` itself object-safe?
21///
22/// [`FinishSerializer::finish`] takes `self` by value so it can consume and tear down the
23/// serializer (e.g., return an owned `Vec<u8>` without a leftover borrow on the serializer's
24/// internal buffer). Methods that receive `self` by value are not dispatchable through a
25/// trait object: `dyn FinishSerializer` doesn't know the concrete size of `Self`, so it
26/// cannot move it. This is the standard Rust object-safety restriction.
27///
28/// The consequence is that `FinishSerializer` can only be used with a statically-known
29/// serializer type, which is fine for generated code that knows the concrete [`Codec`].
30/// For call sites that need dynamic dispatch (e.g., event stream marshallers that receive
31/// a `Box<dyn PayloadSerializer>` from `ClientProtocol::payload_codec`), use
32/// [`PayloadSerializer::finish_boxed`] instead — it takes `self: Box<Self>`, which *is*
33/// object-safe because the `Box` owns the value and knows how to drop it.
34pub trait FinishSerializer {
35    /// Consumes the serializer and returns the serialized bytes.
36    fn finish(self) -> Vec<u8>;
37}
38
39/// A codec for a specific serialization format.
40///
41/// Codecs are responsible for creating [`ShapeSerializer`] and [`ShapeDeserializer`]
42/// instances that can serialize and deserialize shapes to and from a specific format.
43///
44/// # Examples
45///
46/// Implementing a custom codec:
47///
48/// ```ignore
49/// use aws_smithy_schema::codec::Codec;
50/// use aws_smithy_schema::serde::{ShapeSerializer, ShapeDeserializer};
51///
52/// struct MyCodec {
53///     // codec configuration
54/// }
55///
56/// impl Codec for MyCodec {
57///     type Serializer = MySerializer;
58///     type Deserializer = MyDeserializer;
59///
60///     fn create_serializer(&self) -> Self::Serializer {
61///         MySerializer::new()
62///     }
63///
64///     fn create_deserializer(&self, input: &[u8]) -> Self::Deserializer {
65///         MyDeserializer::new(input)
66///     }
67/// }
68/// ```
69pub trait Codec {
70    /// The serializer type for this codec.
71    type Serializer: ShapeSerializer + FinishSerializer;
72
73    /// The deserializer type for this codec.
74    type Deserializer<'a>: ShapeDeserializer + 'a;
75
76    /// Creates a new serializer for this codec.
77    fn create_serializer(&self) -> Self::Serializer;
78
79    /// Creates a new deserializer for this codec from the given input bytes.
80    fn create_deserializer<'a>(&self, input: &'a [u8]) -> Self::Deserializer<'a>;
81}
82
83/// Object-safe view of a codec's serializer.
84///
85/// Combines [`ShapeSerializer`] with an object-safe finish operation. [`FinishSerializer::finish`]
86/// takes `self` by value, which cannot be called through `&mut dyn ShapeSerializer` — so this
87/// trait exposes `finish(self: Box<Self>)` instead, which is object-safe.
88///
89/// A blanket impl is provided for every `ShapeSerializer + FinishSerializer`, so every concrete
90/// codec serializer (e.g., `JsonSerializer`) is automatically usable through `Box<dyn PayloadSerializer>`
91/// without requiring codec authors to write extra impls.
92pub trait PayloadSerializer: ShapeSerializer {
93    /// Consumes this boxed serializer and returns the serialized bytes.
94    fn finish_boxed(self: Box<Self>) -> Vec<u8>;
95}
96
97impl<S> PayloadSerializer for S
98where
99    S: ShapeSerializer + FinishSerializer,
100{
101    fn finish_boxed(self: Box<Self>) -> Vec<u8> {
102        <S as FinishSerializer>::finish(*self)
103    }
104}
105
106/// Object-safe sibling of [`Codec`] exposing dynamic deserializer creation.
107///
108/// # Why a sibling trait?
109///
110/// [`Codec`] uses associated types (`Serializer`, `Deserializer<'a>`) and
111/// returns them by value from its methods. This gives codec consumers
112/// zero-cost static dispatch — the compiler can inline and monomorphize
113/// serializer/deserializer creation at call sites that know the concrete
114/// codec type. That is the right choice for the common case (generated code
115/// that knows the protocol statically).
116///
117/// However, some features require accessing a codec through a trait object.
118/// The SEP-specified `ClientProtocol::payload_codec()` method returns "the
119/// codec" in a context where the `ClientProtocol` itself is accessed via
120/// `dyn ClientProtocol` (see [`SharedClientProtocol`](crate::protocol::SharedClientProtocol),
121/// which stores `Arc<dyn ClientProtocol>` for runtime protocol swapping).
122/// Returning a [`Codec`] through `dyn` is not possible in Rust because
123/// associated types and by-value returns are not object-safe.
124///
125/// `DynCodec` is the minimal object-safe view that covers the operations
126/// needed through a trait object. It exists purely as a Rust adaptation of
127/// the SEP's object-oriented `Codec` design; it is not additional user-facing
128/// API. A blanket `impl<C: Codec> DynCodec for C` makes every concrete codec
129/// automatically usable through `&dyn DynCodec` without any extra work from
130/// codec authors.
131///
132/// Both deserializer and serializer creation are exposed through this trait
133/// to support event-stream marshalling (input streams) and unmarshalling
134/// (output streams) through `dyn ClientProtocol`.
135///
136/// # Returning (de)serializers as boxed trait objects
137///
138/// [`ShapeDeserializer`] implementations typically hold cursor state over an
139/// input byte slice (e.g., `JsonDeserializer` holds `input: &'a [u8]` and a
140/// `position: usize`). Producing a fresh deserializer positioned at the start
141/// of the input is the standard way to read independent messages — as is
142/// required for event-stream frames, where each frame is an independent
143/// serialized payload. The returned `Box<dyn ShapeDeserializer + 'a>`
144/// borrows from `input`, so the caller retains ownership of the bytes for
145/// the duration of deserialization. Similarly each event frame requires a
146/// fresh serializer.
147pub trait DynCodec: Send + Sync + std::fmt::Debug {
148    /// Creates a new deserializer over the given input bytes.
149    fn create_deserializer<'a>(&self, input: &'a [u8]) -> Box<dyn ShapeDeserializer + 'a>;
150
151    /// Creates a new serializer. Use [`PayloadSerializer::finish_boxed`] to
152    /// consume the serializer and obtain the serialized bytes.
153    fn create_serializer(&self) -> Box<dyn PayloadSerializer + '_>;
154}
155
156// Blanket implementation: any statically-dispatched `Codec` is automatically
157// available as a `DynCodec`. The boxed (de)serializer here incurs one heap
158// allocation per call, which is acceptable for the per-event-frame use case.
159// Callers using `Codec` directly pay no such cost.
160impl<C> DynCodec for C
161where
162    C: Codec + Send + Sync + std::fmt::Debug,
163{
164    fn create_deserializer<'a>(&self, input: &'a [u8]) -> Box<dyn ShapeDeserializer + 'a> {
165        Box::new(<C as Codec>::create_deserializer(self, input))
166    }
167
168    fn create_serializer(&self) -> Box<dyn PayloadSerializer + '_> {
169        Box::new(<C as Codec>::create_serializer(self))
170    }
171}
172
173#[cfg(test)]
174mod test {
175    use super::*;
176    use crate::serde::{SerdeError, SerializableStruct, ShapeDeserializer, ShapeSerializer};
177    use crate::{prelude::*, Schema};
178
179    // Mock serializer
180    struct MockSerializer {
181        output: Vec<u8>,
182    }
183
184    impl MockSerializer {
185        fn finish(self) -> Vec<u8> {
186            self.output
187        }
188    }
189
190    impl FinishSerializer for MockSerializer {
191        fn finish(self) -> Vec<u8> {
192            self.output
193        }
194    }
195
196    impl ShapeSerializer for MockSerializer {
197        fn write_struct(
198            &mut self,
199            _schema: &Schema,
200            _value: &dyn SerializableStruct,
201        ) -> Result<(), SerdeError> {
202            Ok(())
203        }
204
205        fn write_list(
206            &mut self,
207            _schema: &Schema,
208            _write_elements: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
209        ) -> Result<(), SerdeError> {
210            Ok(())
211        }
212
213        fn write_map(
214            &mut self,
215            _schema: &Schema,
216            _write_entries: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
217        ) -> Result<(), SerdeError> {
218            Ok(())
219        }
220
221        fn write_boolean(&mut self, _schema: &Schema, _value: bool) -> Result<(), SerdeError> {
222            Ok(())
223        }
224
225        fn write_byte(&mut self, _schema: &Schema, _value: i8) -> Result<(), SerdeError> {
226            Ok(())
227        }
228
229        fn write_short(&mut self, _schema: &Schema, _value: i16) -> Result<(), SerdeError> {
230            Ok(())
231        }
232
233        fn write_integer(&mut self, _schema: &Schema, _value: i32) -> Result<(), SerdeError> {
234            Ok(())
235        }
236
237        fn write_long(&mut self, _schema: &Schema, _value: i64) -> Result<(), SerdeError> {
238            Ok(())
239        }
240
241        fn write_float(&mut self, _schema: &Schema, _value: f32) -> Result<(), SerdeError> {
242            Ok(())
243        }
244
245        fn write_double(&mut self, _schema: &Schema, _value: f64) -> Result<(), SerdeError> {
246            Ok(())
247        }
248
249        fn write_big_integer(
250            &mut self,
251            _schema: &Schema,
252            _value: &aws_smithy_types::BigInteger,
253        ) -> Result<(), SerdeError> {
254            Ok(())
255        }
256
257        fn write_big_decimal(
258            &mut self,
259            _schema: &Schema,
260            _value: &aws_smithy_types::BigDecimal,
261        ) -> Result<(), SerdeError> {
262            Ok(())
263        }
264
265        fn write_string(&mut self, _schema: &Schema, _value: &str) -> Result<(), SerdeError> {
266            Ok(())
267        }
268
269        fn write_blob(
270            &mut self,
271            _schema: &Schema,
272            _value: &aws_smithy_types::Blob,
273        ) -> Result<(), SerdeError> {
274            Ok(())
275        }
276
277        fn write_timestamp(
278            &mut self,
279            _schema: &Schema,
280            _value: &aws_smithy_types::DateTime,
281        ) -> Result<(), SerdeError> {
282            Ok(())
283        }
284
285        fn write_document(
286            &mut self,
287            _schema: &Schema,
288            _value: &aws_smithy_types::Document,
289        ) -> Result<(), SerdeError> {
290            Ok(())
291        }
292
293        fn write_null(&mut self, _schema: &Schema) -> Result<(), SerdeError> {
294            Ok(())
295        }
296    }
297
298    // Mock deserializer
299    struct MockDeserializer<'a> {
300        #[allow(dead_code)]
301        input: &'a [u8],
302    }
303
304    impl<'a> ShapeDeserializer for MockDeserializer<'a> {
305        fn read_struct(
306            &mut self,
307            _schema: &Schema,
308            _consumer: &mut dyn FnMut(
309                &Schema,
310                &mut dyn ShapeDeserializer,
311            ) -> Result<(), SerdeError>,
312        ) -> Result<(), SerdeError> {
313            Ok(())
314        }
315
316        fn read_list(
317            &mut self,
318            _schema: &Schema,
319            _consumer: &mut dyn FnMut(&mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
320        ) -> Result<(), SerdeError> {
321            Ok(())
322        }
323
324        fn read_map(
325            &mut self,
326            _schema: &Schema,
327            _consumer: &mut dyn FnMut(String, &mut dyn ShapeDeserializer) -> Result<(), SerdeError>,
328        ) -> Result<(), SerdeError> {
329            Ok(())
330        }
331
332        fn read_boolean(&mut self, _schema: &Schema) -> Result<bool, SerdeError> {
333            Ok(false)
334        }
335
336        fn read_byte(&mut self, _schema: &Schema) -> Result<i8, SerdeError> {
337            Ok(0)
338        }
339
340        fn read_short(&mut self, _schema: &Schema) -> Result<i16, SerdeError> {
341            Ok(0)
342        }
343
344        fn read_integer(&mut self, _schema: &Schema) -> Result<i32, SerdeError> {
345            Ok(0)
346        }
347
348        fn read_long(&mut self, _schema: &Schema) -> Result<i64, SerdeError> {
349            Ok(0)
350        }
351
352        fn read_float(&mut self, _schema: &Schema) -> Result<f32, SerdeError> {
353            Ok(0.0)
354        }
355
356        fn read_double(&mut self, _schema: &Schema) -> Result<f64, SerdeError> {
357            Ok(0.0)
358        }
359
360        fn read_big_integer(
361            &mut self,
362            _schema: &Schema,
363        ) -> Result<aws_smithy_types::BigInteger, SerdeError> {
364            use std::str::FromStr;
365            Ok(aws_smithy_types::BigInteger::from_str("0").unwrap())
366        }
367
368        fn read_big_decimal(
369            &mut self,
370            _schema: &Schema,
371        ) -> Result<aws_smithy_types::BigDecimal, SerdeError> {
372            use std::str::FromStr;
373            Ok(aws_smithy_types::BigDecimal::from_str("0").unwrap())
374        }
375
376        fn read_string(&mut self, _schema: &Schema) -> Result<String, SerdeError> {
377            Ok(String::new())
378        }
379
380        fn read_blob(&mut self, _schema: &Schema) -> Result<aws_smithy_types::Blob, SerdeError> {
381            Ok(aws_smithy_types::Blob::new(Vec::new()))
382        }
383
384        fn read_timestamp(
385            &mut self,
386            _schema: &Schema,
387        ) -> Result<aws_smithy_types::DateTime, SerdeError> {
388            Ok(aws_smithy_types::DateTime::from_secs(0))
389        }
390
391        fn read_document(
392            &mut self,
393            _schema: &Schema,
394        ) -> Result<aws_smithy_types::Document, SerdeError> {
395            Ok(aws_smithy_types::Document::Null)
396        }
397
398        fn is_null(&self) -> bool {
399            false
400        }
401
402        fn container_size(&self) -> Option<usize> {
403            None
404        }
405    }
406
407    // Mock codec
408    struct MockCodec;
409
410    impl Codec for MockCodec {
411        type Serializer = MockSerializer;
412        type Deserializer<'a> = MockDeserializer<'a>;
413
414        fn create_serializer(&self) -> Self::Serializer {
415            MockSerializer { output: Vec::new() }
416        }
417
418        fn create_deserializer<'a>(&self, input: &'a [u8]) -> Self::Deserializer<'a> {
419            MockDeserializer { input }
420        }
421    }
422
423    #[test]
424    fn test_codec_create_serializer() {
425        let codec = MockCodec;
426        let mut serializer = codec.create_serializer();
427
428        // Test that we can use the serializer
429        serializer.write_string(&STRING, "test").unwrap();
430        let output = serializer.finish();
431        assert_eq!(output, Vec::<u8>::new());
432    }
433
434    #[test]
435    fn test_codec_create_deserializer() {
436        let codec = MockCodec;
437        let input = b"test data";
438        let mut deserializer = codec.create_deserializer(input);
439
440        // Test that we can use the deserializer
441        let result = deserializer.read_string(&STRING).unwrap();
442        assert_eq!(result, "");
443    }
444
445    #[test]
446    fn test_codec_roundtrip() {
447        let codec = MockCodec;
448
449        // Serialize
450        let mut serializer = codec.create_serializer();
451        serializer.write_integer(&INTEGER, 42).unwrap();
452        let bytes = serializer.finish();
453
454        // Deserialize
455        let mut deserializer = codec.create_deserializer(&bytes);
456        let value = deserializer.read_integer(&INTEGER).unwrap();
457        assert_eq!(value, 0); // Mock deserializer always returns 0
458    }
459}