aws_smithy_schema/schema/serde/serializer.rs
1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! Shape serialization interfaces for the Smithy data model.
7
8use super::error::SerdeError;
9use crate::Schema;
10use aws_smithy_types::{BigDecimal, BigInteger, Blob, DateTime, Document};
11
12/// Serializes Smithy shapes to a target format.
13///
14/// This trait provides a format-agnostic API for serializing the Smithy data model.
15/// Implementations serialize each data type to the corresponding encoding in their
16/// serial format (e.g., Smithy integers and floats to JSON numbers).
17///
18/// The serializer accepts a schema along with the value to provide additional
19/// information about how to serialize the value (e.g., timestamp format, JSON name).
20///
21/// This trait is object-safe so that generated `SerializableStruct` implementations
22/// can use `&mut dyn ShapeSerializer`, producing one compiled `serialize_members()`
23/// per shape regardless of how many codecs exist (`shapes + codecs` rather than
24/// `shapes * codecs` in binary size).
25///
26/// # Example
27///
28/// ```ignore
29/// let mut serializer = JsonSerializer::new();
30/// serializer.write_string(&STRING_SCHEMA, "hello")?;
31/// ```
32pub trait ShapeSerializer {
33 /// Writes a structure to the serializer.
34 ///
35 /// # Arguments
36 ///
37 /// * `schema` - The schema of the structure being serialized
38 /// * `value` - The structure to serialize
39 fn write_struct(
40 &mut self,
41 schema: &Schema,
42 value: &dyn SerializableStruct,
43 ) -> Result<(), SerdeError>;
44
45 /// Writes a list to the serializer.
46 ///
47 /// # Arguments
48 ///
49 /// * `schema` - The schema of the list being serialized
50 /// * `write_elements` - Callback that writes the list elements
51 fn write_list(
52 &mut self,
53 schema: &Schema,
54 write_elements: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
55 ) -> Result<(), SerdeError>;
56
57 /// Writes a map to the serializer.
58 ///
59 /// # Arguments
60 ///
61 /// * `schema` - The schema of the map being serialized
62 /// * `write_entries` - Callback that writes the map entries
63 fn write_map(
64 &mut self,
65 schema: &Schema,
66 write_entries: &dyn Fn(&mut dyn ShapeSerializer) -> Result<(), SerdeError>,
67 ) -> Result<(), SerdeError>;
68
69 /// Writes a boolean value.
70 fn write_boolean(&mut self, schema: &Schema, value: bool) -> Result<(), SerdeError>;
71
72 /// Writes a byte (i8) value.
73 fn write_byte(&mut self, schema: &Schema, value: i8) -> Result<(), SerdeError>;
74
75 /// Writes a short (i16) value.
76 fn write_short(&mut self, schema: &Schema, value: i16) -> Result<(), SerdeError>;
77
78 /// Writes an integer (i32) value.
79 fn write_integer(&mut self, schema: &Schema, value: i32) -> Result<(), SerdeError>;
80
81 /// Writes a long (i64) value.
82 fn write_long(&mut self, schema: &Schema, value: i64) -> Result<(), SerdeError>;
83
84 /// Writes a float (f32) value.
85 fn write_float(&mut self, schema: &Schema, value: f32) -> Result<(), SerdeError>;
86
87 /// Writes a double (f64) value.
88 fn write_double(&mut self, schema: &Schema, value: f64) -> Result<(), SerdeError>;
89
90 /// Writes a big integer value.
91 fn write_big_integer(&mut self, schema: &Schema, value: &BigInteger) -> Result<(), SerdeError>;
92
93 /// Writes a big decimal value.
94 fn write_big_decimal(&mut self, schema: &Schema, value: &BigDecimal) -> Result<(), SerdeError>;
95
96 /// Writes a string value.
97 fn write_string(&mut self, schema: &Schema, value: &str) -> Result<(), SerdeError>;
98
99 /// Writes a blob (byte array) value.
100 fn write_blob(&mut self, schema: &Schema, value: &Blob) -> Result<(), SerdeError>;
101
102 /// Writes a timestamp value.
103 fn write_timestamp(&mut self, schema: &Schema, value: &DateTime) -> Result<(), SerdeError>;
104
105 /// Writes a document value.
106 fn write_document(&mut self, schema: &Schema, value: &Document) -> Result<(), SerdeError>;
107
108 /// Writes a null value (for sparse collections).
109 fn write_null(&mut self, schema: &Schema) -> Result<(), SerdeError>;
110
111 // --- Collection helper methods ---
112 //
113 // This is a **closed set** of helpers for the most common AWS collection
114 // patterns. No additional helpers will be added. New collection patterns
115 // should use the generic `write_list`/`write_map` with closures.
116 //
117 // These exist for two reasons:
118 // 1. Code size: each helper replaces ~6-8 lines of closure boilerplate in
119 // generated code, yielding ~43% reduction for collection-heavy models.
120 // 2. Performance: the corresponding `ShapeDeserializer` helpers are
121 // overridden by codec implementations (e.g., `JsonDeserializer`) to
122 // avoid per-element vtable dispatch. Keeping them on the core trait
123 // (rather than an extension trait) is required because they are called
124 // through `&mut dyn ShapeSerializer`/`&mut dyn ShapeDeserializer` in
125 // generated `serialize_members`/`deserialize` methods.
126
127 /// Writes a list of strings.
128 fn write_string_list(&mut self, schema: &Schema, values: &[String]) -> Result<(), SerdeError> {
129 self.write_list(schema, &|ser| {
130 for item in values {
131 ser.write_string(&crate::prelude::STRING, item)?;
132 }
133 Ok(())
134 })
135 }
136
137 /// Writes a list of blobs.
138 fn write_blob_list(
139 &mut self,
140 schema: &Schema,
141 values: &[aws_smithy_types::Blob],
142 ) -> Result<(), SerdeError> {
143 self.write_list(schema, &|ser| {
144 for item in values {
145 ser.write_blob(&crate::prelude::BLOB, item)?;
146 }
147 Ok(())
148 })
149 }
150
151 /// Writes a list of integers.
152 fn write_integer_list(&mut self, schema: &Schema, values: &[i32]) -> Result<(), SerdeError> {
153 self.write_list(schema, &|ser| {
154 for item in values {
155 ser.write_integer(&crate::prelude::INTEGER, *item)?;
156 }
157 Ok(())
158 })
159 }
160
161 /// Writes a list of longs.
162 fn write_long_list(&mut self, schema: &Schema, values: &[i64]) -> Result<(), SerdeError> {
163 self.write_list(schema, &|ser| {
164 for item in values {
165 ser.write_long(&crate::prelude::LONG, *item)?;
166 }
167 Ok(())
168 })
169 }
170
171 /// Writes a map with string keys and string values.
172 fn write_string_string_map(
173 &mut self,
174 schema: &Schema,
175 values: &std::collections::HashMap<String, String>,
176 ) -> Result<(), SerdeError> {
177 self.write_map(schema, &|ser| {
178 for (key, value) in values {
179 ser.write_string(&crate::prelude::STRING, key)?;
180 ser.write_string(&crate::prelude::STRING, value)?;
181 }
182 Ok(())
183 })
184 }
185}
186
187/// Trait for structures that can be serialized via a schema.
188///
189/// Implemented by generated structure types. Because `ShapeSerializer` is object-safe,
190/// each struct gets one compiled `serialize_members()` that works with any serializer
191/// through dynamic dispatch.
192///
193/// # Example
194///
195/// ```ignore
196/// impl SerializableStruct for MyStruct {
197/// fn serialize_members(&self, serializer: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
198/// serializer.write_string(&NAME_SCHEMA, &self.name)?;
199/// serializer.write_integer(&AGE_SCHEMA, self.age)?;
200/// Ok(())
201/// }
202/// }
203/// ```
204pub trait SerializableStruct {
205 /// Serializes this structure's members using the provided serializer.
206 fn serialize_members(&self, serializer: &mut dyn ShapeSerializer) -> Result<(), SerdeError>;
207}
208
209impl<T: SerializableStruct + ?Sized> SerializableStruct for Box<T> {
210 fn serialize_members(&self, serializer: &mut dyn ShapeSerializer) -> Result<(), SerdeError> {
211 (**self).serialize_members(serializer)
212 }
213}