AWS SDK

AWS SDK

rev. 8da168d5fec7572c2f9dada1175b4c72d0140db8 (ignoring whitespace)

Files changed:

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-json/src/codec/serializer.rs

@@ -0,1 +0,440 @@
           1  +
/*
           2  +
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
           3  +
 * SPDX-License-Identifier: Apache-2.0
           4  +
 */
           5  +
           6  +
//! JSON serializer implementation.
           7  +
           8  +
use aws_smithy_schema::serde::ShapeSerializer;
           9  +
use aws_smithy_schema::{Schema, ShapeId};
          10  +
use aws_smithy_types::date_time::Format as TimestampFormat;
          11  +
use aws_smithy_types::{BigDecimal, BigInteger, Blob, DateTime, Document};
          12  +
use std::fmt;
          13  +
          14  +
use crate::codec::JsonCodecSettings;
          15  +
          16  +
/// Error type for JSON serialization.
          17  +
#[derive(Debug)]
          18  +
pub enum JsonSerializerError {
          19  +
    /// An error occurred during JSON writing.
          20  +
    WriteError(String),
          21  +
}
          22  +
          23  +
impl fmt::Display for JsonSerializerError {
          24  +
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
          25  +
        match self {
          26  +
            Self::WriteError(msg) => write!(f, "JSON write error: {}", msg),
          27  +
        }
          28  +
    }
          29  +
}
          30  +
          31  +
impl std::error::Error for JsonSerializerError {}
          32  +
          33  +
/// JSON serializer that implements the ShapeSerializer trait.
          34  +
pub struct JsonSerializer {
          35  +
    output: String,
          36  +
    settings: JsonCodecSettings,
          37  +
}
          38  +
          39  +
impl JsonSerializer {
          40  +
    /// Creates a new JSON serializer with the given settings.
          41  +
    pub fn new(settings: JsonCodecSettings) -> Self {
          42  +
        Self {
          43  +
            output: String::new(),
          44  +
            settings,
          45  +
        }
          46  +
    }
          47  +
          48  +
    /// Gets the timestamp format to use, respecting @timestampFormat trait.
          49  +
    fn get_timestamp_format(&self, schema: &dyn Schema) -> TimestampFormat {
          50  +
        let timestamp_format_trait_id = ShapeId::new("smithy.api#timestampFormat");
          51  +
        if let Some(trait_obj) = schema.traits().get(&timestamp_format_trait_id) {
          52  +
            if let Some(format_str) = trait_obj.as_any().downcast_ref::<String>() {
          53  +
                return match format_str.as_str() {
          54  +
                    "epoch-seconds" => TimestampFormat::EpochSeconds,
          55  +
                    "http-date" => TimestampFormat::HttpDate,
          56  +
                    "date-time" => TimestampFormat::DateTime,
          57  +
                    _ => self.settings.default_timestamp_format,
          58  +
                };
          59  +
            }
          60  +
        }
          61  +
        self.settings.default_timestamp_format
          62  +
    }
          63  +
          64  +
    fn write_json_value(&mut self, doc: &Document) {
          65  +
        use crate::serialize::JsonValueWriter;
          66  +
        let writer = JsonValueWriter::new(&mut self.output);
          67  +
        writer.document(doc);
          68  +
    }
          69  +
}
          70  +
          71  +
impl ShapeSerializer for JsonSerializer {
          72  +
    type Output = Vec<u8>;
          73  +
    type Error = JsonSerializerError;
          74  +
          75  +
    fn finish(self) -> Result<Self::Output, Self::Error> {
          76  +
        Ok(self.output.into_bytes())
          77  +
    }
          78  +
          79  +
    fn write_struct<F>(&mut self, _schema: &dyn Schema, write_members: F) -> Result<(), Self::Error>
          80  +
    where
          81  +
        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
          82  +
    {
          83  +
        self.output.push('{');
          84  +
        write_members(self)?;
          85  +
        self.output.push('}');
          86  +
        Ok(())
          87  +
    }
          88  +
          89  +
    fn write_list<F>(&mut self, _schema: &dyn Schema, write_elements: F) -> Result<(), Self::Error>
          90  +
    where
          91  +
        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
          92  +
    {
          93  +
        self.output.push('[');
          94  +
        write_elements(self)?;
          95  +
        self.output.push(']');
          96  +
        Ok(())
          97  +
    }
          98  +
          99  +
    fn write_map<F>(&mut self, _schema: &dyn Schema, write_entries: F) -> Result<(), Self::Error>
         100  +
    where
         101  +
        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
         102  +
    {
         103  +
        self.output.push('{');
         104  +
        write_entries(self)?;
         105  +
        self.output.push('}');
         106  +
        Ok(())
         107  +
    }
         108  +
         109  +
    fn write_boolean(&mut self, _schema: &dyn Schema, value: bool) -> Result<(), Self::Error> {
         110  +
        self.output.push_str(if value { "true" } else { "false" });
         111  +
        Ok(())
         112  +
    }
         113  +
         114  +
    fn write_byte(&mut self, _schema: &dyn Schema, value: i8) -> Result<(), Self::Error> {
         115  +
        use std::fmt::Write;
         116  +
        write!(&mut self.output, "{}", value)
         117  +
            .map_err(|e| JsonSerializerError::WriteError(e.to_string()))
         118  +
    }
         119  +
         120  +
    fn write_short(&mut self, _schema: &dyn Schema, value: i16) -> Result<(), Self::Error> {
         121  +
        use std::fmt::Write;
         122  +
        write!(&mut self.output, "{}", value)
         123  +
            .map_err(|e| JsonSerializerError::WriteError(e.to_string()))
         124  +
    }
         125  +
         126  +
    fn write_integer(&mut self, _schema: &dyn Schema, value: i32) -> Result<(), Self::Error> {
         127  +
        use std::fmt::Write;
         128  +
        write!(&mut self.output, "{}", value)
         129  +
            .map_err(|e| JsonSerializerError::WriteError(e.to_string()))
         130  +
    }
         131  +
         132  +
    fn write_long(&mut self, _schema: &dyn Schema, value: i64) -> Result<(), Self::Error> {
         133  +
        use std::fmt::Write;
         134  +
        write!(&mut self.output, "{}", value)
         135  +
            .map_err(|e| JsonSerializerError::WriteError(e.to_string()))
         136  +
    }
         137  +
         138  +
    fn write_float(&mut self, _schema: &dyn Schema, value: f32) -> Result<(), Self::Error> {
         139  +
        use std::fmt::Write;
         140  +
        write!(&mut self.output, "{}", value)
         141  +
            .map_err(|e| JsonSerializerError::WriteError(e.to_string()))
         142  +
    }
         143  +
         144  +
    fn write_double(&mut self, _schema: &dyn Schema, value: f64) -> Result<(), Self::Error> {
         145  +
        use std::fmt::Write;
         146  +
        write!(&mut self.output, "{}", value)
         147  +
            .map_err(|e| JsonSerializerError::WriteError(e.to_string()))
         148  +
    }
         149  +
         150  +
    fn write_big_integer(
         151  +
        &mut self,
         152  +
        _schema: &dyn Schema,
         153  +
        value: &BigInteger,
         154  +
    ) -> Result<(), Self::Error> {
         155  +
        self.output.push_str(value.as_ref());
         156  +
        Ok(())
         157  +
    }
         158  +
         159  +
    fn write_big_decimal(
         160  +
        &mut self,
         161  +
        _schema: &dyn Schema,
         162  +
        value: &BigDecimal,
         163  +
    ) -> Result<(), Self::Error> {
         164  +
        self.output.push_str(value.as_ref());
         165  +
        Ok(())
         166  +
    }
         167  +
         168  +
    fn write_string(&mut self, _schema: &dyn Schema, value: &str) -> Result<(), Self::Error> {
         169  +
        use crate::escape::escape_string;
         170  +
        self.output.push('"');
         171  +
        self.output.push_str(&escape_string(value));
         172  +
        self.output.push('"');
         173  +
        Ok(())
         174  +
    }
         175  +
         176  +
    fn write_blob(&mut self, _schema: &dyn Schema, value: &Blob) -> Result<(), Self::Error> {
         177  +
        use aws_smithy_types::base64;
         178  +
        let encoded = base64::encode(value.as_ref());
         179  +
        self.output.push('"');
         180  +
        self.output.push_str(&encoded);
         181  +
        self.output.push('"');
         182  +
        Ok(())
         183  +
    }
         184  +
         185  +
    fn write_timestamp(
         186  +
        &mut self,
         187  +
        schema: &dyn Schema,
         188  +
        value: &DateTime,
         189  +
    ) -> Result<(), Self::Error> {
         190  +
        let format = self.get_timestamp_format(schema);
         191  +
        let formatted = value.fmt(format).map_err(|e| {
         192  +
            JsonSerializerError::WriteError(format!("Failed to format timestamp: {}", e))
         193  +
        })?;
         194  +
         195  +
        match format {
         196  +
            TimestampFormat::EpochSeconds => {
         197  +
                // Epoch seconds as number
         198  +
                self.output.push_str(&formatted);
         199  +
            }
         200  +
            _ => {
         201  +
                // Other formats as strings
         202  +
                self.output.push('"');
         203  +
                self.output.push_str(&formatted);
         204  +
                self.output.push('"');
         205  +
            }
         206  +
        }
         207  +
        Ok(())
         208  +
    }
         209  +
         210  +
    fn write_document(
         211  +
        &mut self,
         212  +
        _schema: &dyn Schema,
         213  +
        value: &Document,
         214  +
    ) -> Result<(), Self::Error> {
         215  +
        self.write_json_value(value);
         216  +
        Ok(())
         217  +
    }
         218  +
         219  +
    fn write_null(&mut self, _schema: &dyn Schema) -> Result<(), Self::Error> {
         220  +
        self.output.push_str("null");
         221  +
        Ok(())
         222  +
    }
         223  +
}
         224  +
         225  +
#[cfg(test)]
         226  +
mod tests {
         227  +
    use super::*;
         228  +
    use aws_smithy_schema::prelude::*;
         229  +
         230  +
    #[test]
         231  +
    fn test_write_boolean() {
         232  +
        let mut ser = JsonSerializer::new(JsonCodecSettings::default());
         233  +
        ser.write_boolean(&BOOLEAN, true).unwrap();
         234  +
        let output = ser.finish().unwrap();
         235  +
        assert_eq!(String::from_utf8(output).unwrap(), "true");
         236  +
    }
         237  +
         238  +
    #[test]
         239  +
    fn test_write_string() {
         240  +
        let mut ser = JsonSerializer::new(JsonCodecSettings::default());
         241  +
        ser.write_string(&STRING, "hello").unwrap();
         242  +
        let output = ser.finish().unwrap();
         243  +
        assert_eq!(String::from_utf8(output).unwrap(), "\"hello\"");
         244  +
    }
         245  +
         246  +
    #[test]
         247  +
    fn test_write_integer() {
         248  +
        let mut ser = JsonSerializer::new(JsonCodecSettings::default());
         249  +
        ser.write_integer(&INTEGER, 42).unwrap();
         250  +
        let output = ser.finish().unwrap();
         251  +
        assert_eq!(String::from_utf8(output).unwrap(), "42");
         252  +
    }
         253  +
         254  +
    #[test]
         255  +
    fn test_write_null() {
         256  +
        let mut ser = JsonSerializer::new(JsonCodecSettings::default());
         257  +
        ser.write_null(&STRING).unwrap();
         258  +
        let output = ser.finish().unwrap();
         259  +
        assert_eq!(String::from_utf8(output).unwrap(), "null");
         260  +
    }
         261  +
         262  +
    #[test]
         263  +
    fn test_write_list() {
         264  +
        let mut ser = JsonSerializer::new(JsonCodecSettings::default());
         265  +
        // Create a simple list schema for testing
         266  +
        let list_schema = aws_smithy_schema::prelude::PreludeSchema::new(
         267  +
            aws_smithy_schema::ShapeId::new("test#List"),
         268  +
            aws_smithy_schema::ShapeType::List,
         269  +
        );
         270  +
        ser.write_list(&list_schema, |s| {
         271  +
            s.write_integer(&INTEGER, 1)?;
         272  +
            s.output.push(',');
         273  +
            s.write_integer(&INTEGER, 2)?;
         274  +
            s.output.push(',');
         275  +
            s.write_integer(&INTEGER, 3)?;
         276  +
            Ok(())
         277  +
        })
         278  +
        .unwrap();
         279  +
        let output = ser.finish().unwrap();
         280  +
        assert_eq!(String::from_utf8(output).unwrap(), "[1,2,3]");
         281  +
    }
         282  +
         283  +
    #[test]
         284  +
    fn test_write_full_object() {
         285  +
        let mut ser = JsonSerializer::new(JsonCodecSettings::default());
         286  +
        let struct_schema = aws_smithy_schema::prelude::PreludeSchema::new(
         287  +
            aws_smithy_schema::ShapeId::new("test#Struct"),
         288  +
            aws_smithy_schema::ShapeType::Structure,
         289  +
        );
         290  +
        let list_schema = aws_smithy_schema::prelude::PreludeSchema::new(
         291  +
            aws_smithy_schema::ShapeId::new("test#List"),
         292  +
            aws_smithy_schema::ShapeType::List,
         293  +
        );
         294  +
        ser.write_struct(&struct_schema, |s| {
         295  +
            s.output.push_str("\"active\":");
         296  +
            s.write_boolean(&BOOLEAN, true)?;
         297  +
            s.output.push(',');
         298  +
            s.output.push_str("\"name\":");
         299  +
            s.write_string(&STRING, "test")?;
         300  +
            s.output.push(',');
         301  +
            s.output.push_str("\"count\":");
         302  +
            s.write_integer(&INTEGER, 42)?;
         303  +
            s.output.push(',');
         304  +
            s.output.push_str("\"price\":");
         305  +
            s.write_float(&FLOAT, 3.14)?;
         306  +
            s.output.push(',');
         307  +
            s.output.push_str("\"items\":");
         308  +
            s.write_list(&list_schema, |ls| {
         309  +
                ls.write_integer(&INTEGER, 1)?;
         310  +
                ls.output.push(',');
         311  +
                ls.write_integer(&INTEGER, 2)?;
         312  +
                Ok(())
         313  +
            })?;
         314  +
            Ok(())
         315  +
        })
         316  +
        .unwrap();
         317  +
        let output = ser.finish().unwrap();
         318  +
        assert_eq!(
         319  +
            String::from_utf8(output).unwrap(),
         320  +
            "{\"active\":true,\"name\":\"test\",\"count\":42,\"price\":3.14,\"items\":[1,2]}"
         321  +
        );
         322  +
    }
         323  +
         324  +
    #[test]
         325  +
    fn test_nested_complex_serialization() {
         326  +
        let mut ser = JsonSerializer::new(JsonCodecSettings::default());
         327  +
        let struct_schema = aws_smithy_schema::prelude::PreludeSchema::new(
         328  +
            aws_smithy_schema::ShapeId::new("test#User"),
         329  +
            aws_smithy_schema::ShapeType::Structure,
         330  +
        );
         331  +
        let list_schema = aws_smithy_schema::prelude::PreludeSchema::new(
         332  +
            aws_smithy_schema::ShapeId::new("test#List"),
         333  +
            aws_smithy_schema::ShapeType::List,
         334  +
        );
         335  +
        let map_schema = aws_smithy_schema::prelude::PreludeSchema::new(
         336  +
            aws_smithy_schema::ShapeId::new("test#Map"),
         337  +
            aws_smithy_schema::ShapeType::Map,
         338  +
        );
         339  +
         340  +
        ser.write_struct(&struct_schema, |s| {
         341  +
            s.output.push_str("\"id\":");
         342  +
            s.write_long(&LONG, 12345)?;
         343  +
            s.output.push(',');
         344  +
            s.output.push_str("\"name\":");
         345  +
            s.write_string(&STRING, "John Doe")?;
         346  +
            s.output.push(',');
         347  +
            s.output.push_str("\"scores\":");
         348  +
            s.write_list(&list_schema, |ls| {
         349  +
                ls.write_double(&DOUBLE, 95.5)?;
         350  +
                ls.output.push(',');
         351  +
                ls.write_double(&DOUBLE, 87.3)?;
         352  +
                ls.output.push(',');
         353  +
                ls.write_double(&DOUBLE, 92.1)?;
         354  +
                Ok(())
         355  +
            })?;
         356  +
            s.output.push(',');
         357  +
            s.output.push_str("\"address\":");
         358  +
            s.write_struct(&struct_schema, |addr| {
         359  +
                addr.output.push_str("\"street\":");
         360  +
                addr.write_string(&STRING, "123 Main St")?;
         361  +
                addr.output.push(',');
         362  +
                addr.output.push_str("\"city\":");
         363  +
                addr.write_string(&STRING, "Seattle")?;
         364  +
                addr.output.push(',');
         365  +
                addr.output.push_str("\"zip\":");
         366  +
                addr.write_integer(&INTEGER, 98101)?;
         367  +
                Ok(())
         368  +
            })?;
         369  +
            s.output.push(',');
         370  +
            s.output.push_str("\"companies\":");
         371  +
            s.write_list(&list_schema, |ls| {
         372  +
                ls.write_struct(&struct_schema, |comp| {
         373  +
                    comp.output.push_str("\"name\":");
         374  +
                    comp.write_string(&STRING, "TechCorp")?;
         375  +
                    comp.output.push(',');
         376  +
                    comp.output.push_str("\"employees\":");
         377  +
                    comp.write_list(&list_schema, |emp| {
         378  +
                        emp.write_string(&STRING, "Alice")?;
         379  +
                        emp.output.push(',');
         380  +
                        emp.write_string(&STRING, "Bob")?;
         381  +
                        Ok(())
         382  +
                    })?;
         383  +
                    comp.output.push(',');
         384  +
                    comp.output.push_str("\"metadata\":");
         385  +
                    comp.write_map(&map_schema, |meta| {
         386  +
                        meta.output.push_str("\"founded\":");
         387  +
                        meta.write_integer(&INTEGER, 2010)?;
         388  +
                        meta.output.push(',');
         389  +
                        meta.output.push_str("\"size\":");
         390  +
                        meta.write_integer(&INTEGER, 500)?;
         391  +
                        Ok(())
         392  +
                    })?;
         393  +
                    comp.output.push(',');
         394  +
                    comp.output.push_str("\"active\":");
         395  +
                    comp.write_boolean(&BOOLEAN, true)?;
         396  +
                    Ok(())
         397  +
                })?;
         398  +
                ls.output.push(',');
         399  +
                ls.write_struct(&struct_schema, |comp| {
         400  +
                    comp.output.push_str("\"name\":");
         401  +
                    comp.write_string(&STRING, "StartupInc")?;
         402  +
                    comp.output.push(',');
         403  +
                    comp.output.push_str("\"employees\":");
         404  +
                    comp.write_list(&list_schema, |emp| {
         405  +
                        emp.write_string(&STRING, "Charlie")?;
         406  +
                        Ok(())
         407  +
                    })?;
         408  +
                    comp.output.push(',');
         409  +
                    comp.output.push_str("\"metadata\":");
         410  +
                    comp.write_map(&map_schema, |meta| {
         411  +
                        meta.output.push_str("\"founded\":");
         412  +
                        meta.write_integer(&INTEGER, 2020)?;
         413  +
                        Ok(())
         414  +
                    })?;
         415  +
                    comp.output.push(',');
         416  +
                    comp.output.push_str("\"active\":");
         417  +
                    comp.write_boolean(&BOOLEAN, false)?;
         418  +
                    Ok(())
         419  +
                })?;
         420  +
                Ok(())
         421  +
            })?;
         422  +
            s.output.push(',');
         423  +
            s.output.push_str("\"tags\":");
         424  +
            s.write_map(&map_schema, |tags| {
         425  +
                tags.output.push_str("\"role\":");
         426  +
                tags.write_string(&STRING, "admin")?;
         427  +
                tags.output.push(',');
         428  +
                tags.output.push_str("\"level\":");
         429  +
                tags.write_string(&STRING, "senior")?;
         430  +
                Ok(())
         431  +
            })?;
         432  +
            Ok(())
         433  +
        })
         434  +
        .unwrap();
         435  +
         436  +
        let output = String::from_utf8(ser.finish().unwrap()).unwrap();
         437  +
        let expected = r#"{"id":12345,"name":"John Doe","scores":[95.5,87.3,92.1],"address":{"street":"123 Main St","city":"Seattle","zip":98101},"companies":[{"name":"TechCorp","employees":["Alice","Bob"],"metadata":{"founded":2010,"size":500},"active":true},{"name":"StartupInc","employees":["Charlie"],"metadata":{"founded":2020},"active":false}],"tags":{"role":"admin","level":"senior"}}"#;
         438  +
        assert_eq!(output, expected);
         439  +
    }
         440  +
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-json/src/lib.rs

@@ -1,1 +22,23 @@
   10     10   
#![warn(
   11     11   
    // missing_docs,
   12     12   
    rustdoc::missing_crate_level_docs,
   13     13   
    unreachable_pub,
   14     14   
    // Enabling this requires fixing a macro but I don't understand how to do that.
   15     15   
    // rust_2018_idioms
   16     16   
)]
   17     17   
   18     18   
//! JSON Abstractions for Smithy
   19     19   
          20  +
pub mod codec;
   20     21   
pub mod deserialize;
   21     22   
mod escape;
   22     23   
pub mod serialize;

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-schema/src/lib.rs

@@ -1,1 +111,116 @@
   11     11   
//!
   12     12   
//! This module provides the core types for representing Smithy schemas at runtime,
   13     13   
//! enabling protocol-agnostic serialization and deserialization.
   14     14   
   15     15   
mod schema {
   16     16   
    pub mod shape_id;
   17     17   
    pub mod shape_type;
   18     18   
    pub mod trait_map;
   19     19   
    pub mod trait_type;
   20     20   
          21  +
    pub mod codec;
   21     22   
    pub mod prelude;
   22     23   
    pub mod serde;
   23     24   
}
   24     25   
   25     26   
pub use schema::shape_id::ShapeId;
   26     27   
pub use schema::shape_type::ShapeType;
   27     28   
pub use schema::trait_map::TraitMap;
   28     29   
pub use schema::trait_type::Trait;
   29     30   
   30     31   
pub mod prelude {
   31     32   
    pub use crate::schema::prelude::*;
   32     33   
}
   33     34   
   34     35   
pub mod serde {
   35     36   
    pub use crate::schema::serde::*;
   36     37   
}
   37     38   
          39  +
pub mod codec {
          40  +
    pub use crate::schema::codec::*;
          41  +
}
          42  +
   38     43   
/// Core trait representing a Smithy schema at runtime.
   39     44   
///
   40     45   
/// A schema is a lightweight runtime representation of a Smithy shape,
   41     46   
/// containing the shape's ID, type, traits, and references to member schemas.
   42     47   
pub trait Schema: Send + Sync {
   43     48   
    /// Returns the Shape ID of this schema.
   44     49   
    fn shape_id(&self) -> &ShapeId;
   45     50   
   46     51   
    /// Returns the shape type.
   47     52   
    fn shape_type(&self) -> ShapeType;
   48     53   
   49     54   
    /// Returns the traits associated with this schema.
   50     55   
    fn traits(&self) -> &TraitMap;
   51     56   
   52     57   
    /// Returns the member name if this is a member schema.
   53     58   
    fn member_name(&self) -> Option<&str> {
   54     59   
        None
   55     60   
    }
   56     61   
   57     62   
    /// Returns the member schema by name (for structures and unions).
   58     63   
    fn member_schema(&self, _name: &str) -> Option<&dyn Schema> {
   59     64   
        None
   60     65   
    }
   61     66   
   62         -
    /// Returns the member schema by position index (for structures and unions).
          67  +
    /// Returns the member name and schema by position index (for structures and unions).
   63     68   
    ///
   64     69   
    /// This is an optimization for generated code to avoid string lookups.
   65     70   
    /// Consumer code should not rely on specific position values as they may change.
   66         -
    fn member_schema_by_index(&self, _index: usize) -> Option<&dyn Schema> {
          71  +
    fn member_schema_by_index(&self, _index: usize) -> Option<(&str, &dyn Schema)> {
   67     72   
        None
   68     73   
    }
   69     74   
   70     75   
    /// Returns the member schema for collections (list member or map value).
   71     76   
    fn member(&self) -> Option<&dyn Schema> {
   72     77   
        None
   73     78   
    }
   74     79   
   75     80   
    /// Returns the key schema for maps.
   76     81   
    fn key(&self) -> Option<&dyn Schema> {
   77     82   
        None
   78     83   
    }
   79     84   
   80         -
    /// Returns an iterator over member schemas (for structures and unions).
   81         -
    fn members(&self) -> Box<dyn Iterator<Item = &dyn Schema> + '_> {
          85  +
    /// Returns an iterator over member names and schemas (for structures and unions).
          86  +
    fn members(&self) -> Box<dyn Iterator<Item = (&str, &dyn Schema)> + '_> {
   82     87   
        Box::new(std::iter::empty())
   83     88   
    }
   84     89   
   85     90   
    /// Returns the member index for member schemas.
   86     91   
    ///
   87     92   
    /// This is used internally by generated code for efficient member lookup.
   88     93   
    /// Returns None if not applicable or not a member schema.
   89     94   
    fn member_index(&self) -> Option<usize> {
   90     95   
        None
   91     96   
    }

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-schema/src/schema/codec.rs

@@ -0,1 +0,376 @@
           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  +
          11  +
use crate::serde::{ShapeDeserializer, ShapeSerializer};
          12  +
          13  +
/// A codec for a specific serialization format.
          14  +
///
          15  +
/// Codecs are responsible for creating [`ShapeSerializer`] and [`ShapeDeserializer`]
          16  +
/// instances that can serialize and deserialize shapes to and from a specific format.
          17  +
///
          18  +
/// # Examples
          19  +
///
          20  +
/// Implementing a custom codec:
          21  +
///
          22  +
/// ```ignore
          23  +
/// use aws_smithy_schema::codec::Codec;
          24  +
/// use aws_smithy_schema::serde::{ShapeSerializer, ShapeDeserializer};
          25  +
///
          26  +
/// struct MyCodec {
          27  +
///     // codec configuration
          28  +
/// }
          29  +
///
          30  +
/// impl Codec for MyCodec {
          31  +
///     type Serializer = MySerializer;
          32  +
///     type Deserializer = MyDeserializer;
          33  +
///
          34  +
///     fn create_serializer(&self) -> Self::Serializer {
          35  +
///         MySerializer::new()
          36  +
///     }
          37  +
///
          38  +
///     fn create_deserializer(&self, input: &[u8]) -> Self::Deserializer {
          39  +
///         MyDeserializer::new(input)
          40  +
///     }
          41  +
/// }
          42  +
/// ```
          43  +
pub trait Codec {
          44  +
    /// The serializer type for this codec.
          45  +
    type Serializer: ShapeSerializer;
          46  +
          47  +
    /// The deserializer type for this codec.
          48  +
    type Deserializer: ShapeDeserializer;
          49  +
          50  +
    /// Creates a new serializer for this codec.
          51  +
    fn create_serializer(&self) -> Self::Serializer;
          52  +
          53  +
    /// Creates a new deserializer for this codec from the given input bytes.
          54  +
    fn create_deserializer(&self, input: &[u8]) -> Self::Deserializer;
          55  +
}
          56  +
          57  +
#[cfg(test)]
          58  +
mod test {
          59  +
    use super::*;
          60  +
    use crate::serde::{ShapeDeserializer, ShapeSerializer};
          61  +
    use crate::{prelude::*, Schema};
          62  +
    use std::fmt;
          63  +
          64  +
    // Mock error type
          65  +
    #[derive(Debug)]
          66  +
    struct MockError;
          67  +
          68  +
    impl fmt::Display for MockError {
          69  +
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
          70  +
            write!(f, "mock error")
          71  +
        }
          72  +
    }
          73  +
          74  +
    impl std::error::Error for MockError {}
          75  +
          76  +
    // Mock serializer
          77  +
    struct MockSerializer {
          78  +
        output: Vec<u8>,
          79  +
    }
          80  +
          81  +
    impl ShapeSerializer for MockSerializer {
          82  +
        type Output = Vec<u8>;
          83  +
        type Error = MockError;
          84  +
          85  +
        fn finish(self) -> Result<Self::Output, Self::Error> {
          86  +
            Ok(self.output)
          87  +
        }
          88  +
          89  +
        fn write_struct<F>(
          90  +
            &mut self,
          91  +
            _schema: &dyn Schema,
          92  +
            _write_members: F,
          93  +
        ) -> Result<(), Self::Error>
          94  +
        where
          95  +
            F: FnOnce(&mut Self) -> Result<(), Self::Error>,
          96  +
        {
          97  +
            Ok(())
          98  +
        }
          99  +
         100  +
        fn write_list<F>(
         101  +
            &mut self,
         102  +
            _schema: &dyn Schema,
         103  +
            _write_elements: F,
         104  +
        ) -> Result<(), Self::Error>
         105  +
        where
         106  +
            F: FnOnce(&mut Self) -> Result<(), Self::Error>,
         107  +
        {
         108  +
            Ok(())
         109  +
        }
         110  +
         111  +
        fn write_map<F>(
         112  +
            &mut self,
         113  +
            _schema: &dyn Schema,
         114  +
            _write_entries: F,
         115  +
        ) -> Result<(), Self::Error>
         116  +
        where
         117  +
            F: FnOnce(&mut Self) -> Result<(), Self::Error>,
         118  +
        {
         119  +
            Ok(())
         120  +
        }
         121  +
         122  +
        fn write_boolean(&mut self, _schema: &dyn Schema, _value: bool) -> Result<(), Self::Error> {
         123  +
            Ok(())
         124  +
        }
         125  +
         126  +
        fn write_byte(&mut self, _schema: &dyn Schema, _value: i8) -> Result<(), Self::Error> {
         127  +
            Ok(())
         128  +
        }
         129  +
         130  +
        fn write_short(&mut self, _schema: &dyn Schema, _value: i16) -> Result<(), Self::Error> {
         131  +
            Ok(())
         132  +
        }
         133  +
         134  +
        fn write_integer(&mut self, _schema: &dyn Schema, _value: i32) -> Result<(), Self::Error> {
         135  +
            Ok(())
         136  +
        }
         137  +
         138  +
        fn write_long(&mut self, _schema: &dyn Schema, _value: i64) -> Result<(), Self::Error> {
         139  +
            Ok(())
         140  +
        }
         141  +
         142  +
        fn write_float(&mut self, _schema: &dyn Schema, _value: f32) -> Result<(), Self::Error> {
         143  +
            Ok(())
         144  +
        }
         145  +
         146  +
        fn write_double(&mut self, _schema: &dyn Schema, _value: f64) -> Result<(), Self::Error> {
         147  +
            Ok(())
         148  +
        }
         149  +
         150  +
        fn write_big_integer(
         151  +
            &mut self,
         152  +
            _schema: &dyn Schema,
         153  +
            _value: &aws_smithy_types::BigInteger,
         154  +
        ) -> Result<(), Self::Error> {
         155  +
            Ok(())
         156  +
        }
         157  +
         158  +
        fn write_big_decimal(
         159  +
            &mut self,
         160  +
            _schema: &dyn Schema,
         161  +
            _value: &aws_smithy_types::BigDecimal,
         162  +
        ) -> Result<(), Self::Error> {
         163  +
            Ok(())
         164  +
        }
         165  +
         166  +
        fn write_string(&mut self, _schema: &dyn Schema, _value: &str) -> Result<(), Self::Error> {
         167  +
            Ok(())
         168  +
        }
         169  +
         170  +
        fn write_blob(
         171  +
            &mut self,
         172  +
            _schema: &dyn Schema,
         173  +
            _value: &aws_smithy_types::Blob,
         174  +
        ) -> Result<(), Self::Error> {
         175  +
            Ok(())
         176  +
        }
         177  +
         178  +
        fn write_timestamp(
         179  +
            &mut self,
         180  +
            _schema: &dyn Schema,
         181  +
            _value: &aws_smithy_types::DateTime,
         182  +
        ) -> Result<(), Self::Error> {
         183  +
            Ok(())
         184  +
        }
         185  +
         186  +
        fn write_document(
         187  +
            &mut self,
         188  +
            _schema: &dyn Schema,
         189  +
            _value: &aws_smithy_types::Document,
         190  +
        ) -> Result<(), Self::Error> {
         191  +
            Ok(())
         192  +
        }
         193  +
         194  +
        fn write_null(&mut self, _schema: &dyn Schema) -> Result<(), Self::Error> {
         195  +
            Ok(())
         196  +
        }
         197  +
    }
         198  +
         199  +
    // Mock deserializer
         200  +
    struct MockDeserializer {
         201  +
        #[allow(dead_code)]
         202  +
        input: Vec<u8>,
         203  +
    }
         204  +
         205  +
    impl ShapeDeserializer for MockDeserializer {
         206  +
        type Error = MockError;
         207  +
         208  +
        fn read_struct<T, F>(
         209  +
            &mut self,
         210  +
            _schema: &dyn Schema,
         211  +
            state: T,
         212  +
            _consumer: F,
         213  +
        ) -> Result<T, Self::Error>
         214  +
        where
         215  +
            F: FnMut(T, &dyn Schema, &mut Self) -> Result<T, Self::Error>,
         216  +
        {
         217  +
            Ok(state)
         218  +
        }
         219  +
         220  +
        fn read_list<T, F>(
         221  +
            &mut self,
         222  +
            _schema: &dyn Schema,
         223  +
            state: T,
         224  +
            _consumer: F,
         225  +
        ) -> Result<T, Self::Error>
         226  +
        where
         227  +
            F: FnMut(T, &mut Self) -> Result<T, Self::Error>,
         228  +
        {
         229  +
            Ok(state)
         230  +
        }
         231  +
         232  +
        fn read_map<T, F>(
         233  +
            &mut self,
         234  +
            _schema: &dyn Schema,
         235  +
            state: T,
         236  +
            _consumer: F,
         237  +
        ) -> Result<T, Self::Error>
         238  +
        where
         239  +
            F: FnMut(T, String, &mut Self) -> Result<T, Self::Error>,
         240  +
        {
         241  +
            Ok(state)
         242  +
        }
         243  +
         244  +
        fn read_boolean(&mut self, _schema: &dyn Schema) -> Result<bool, Self::Error> {
         245  +
            Ok(false)
         246  +
        }
         247  +
         248  +
        fn read_byte(&mut self, _schema: &dyn Schema) -> Result<i8, Self::Error> {
         249  +
            Ok(0)
         250  +
        }
         251  +
         252  +
        fn read_short(&mut self, _schema: &dyn Schema) -> Result<i16, Self::Error> {
         253  +
            Ok(0)
         254  +
        }
         255  +
         256  +
        fn read_integer(&mut self, _schema: &dyn Schema) -> Result<i32, Self::Error> {
         257  +
            Ok(0)
         258  +
        }
         259  +
         260  +
        fn read_long(&mut self, _schema: &dyn Schema) -> Result<i64, Self::Error> {
         261  +
            Ok(0)
         262  +
        }
         263  +
         264  +
        fn read_float(&mut self, _schema: &dyn Schema) -> Result<f32, Self::Error> {
         265  +
            Ok(0.0)
         266  +
        }
         267  +
         268  +
        fn read_double(&mut self, _schema: &dyn Schema) -> Result<f64, Self::Error> {
         269  +
            Ok(0.0)
         270  +
        }
         271  +
         272  +
        fn read_big_integer(
         273  +
            &mut self,
         274  +
            _schema: &dyn Schema,
         275  +
        ) -> Result<aws_smithy_types::BigInteger, Self::Error> {
         276  +
            use std::str::FromStr;
         277  +
            Ok(aws_smithy_types::BigInteger::from_str("0").unwrap())
         278  +
        }
         279  +
         280  +
        fn read_big_decimal(
         281  +
            &mut self,
         282  +
            _schema: &dyn Schema,
         283  +
        ) -> Result<aws_smithy_types::BigDecimal, Self::Error> {
         284  +
            use std::str::FromStr;
         285  +
            Ok(aws_smithy_types::BigDecimal::from_str("0").unwrap())
         286  +
        }
         287  +
         288  +
        fn read_string(&mut self, _schema: &dyn Schema) -> Result<String, Self::Error> {
         289  +
            Ok(String::new())
         290  +
        }
         291  +
         292  +
        fn read_blob(
         293  +
            &mut self,
         294  +
            _schema: &dyn Schema,
         295  +
        ) -> Result<aws_smithy_types::Blob, Self::Error> {
         296  +
            Ok(aws_smithy_types::Blob::new(Vec::new()))
         297  +
        }
         298  +
         299  +
        fn read_timestamp(
         300  +
            &mut self,
         301  +
            _schema: &dyn Schema,
         302  +
        ) -> Result<aws_smithy_types::DateTime, Self::Error> {
         303  +
            Ok(aws_smithy_types::DateTime::from_secs(0))
         304  +
        }
         305  +
         306  +
        fn read_document(
         307  +
            &mut self,
         308  +
            _schema: &dyn Schema,
         309  +
        ) -> Result<aws_smithy_types::Document, Self::Error> {
         310  +
            Ok(aws_smithy_types::Document::Null)
         311  +
        }
         312  +
         313  +
        fn is_null(&self) -> bool {
         314  +
            false
         315  +
        }
         316  +
         317  +
        fn container_size(&self) -> Option<usize> {
         318  +
            None
         319  +
        }
         320  +
    }
         321  +
         322  +
    // Mock codec
         323  +
    struct MockCodec;
         324  +
         325  +
    impl Codec for MockCodec {
         326  +
        type Serializer = MockSerializer;
         327  +
        type Deserializer = MockDeserializer;
         328  +
         329  +
        fn create_serializer(&self) -> Self::Serializer {
         330  +
            MockSerializer { output: Vec::new() }
         331  +
        }
         332  +
         333  +
        fn create_deserializer(&self, input: &[u8]) -> Self::Deserializer {
         334  +
            MockDeserializer {
         335  +
                input: input.to_vec(),
         336  +
            }
         337  +
        }
         338  +
    }
         339  +
         340  +
    #[test]
         341  +
    fn test_codec_create_serializer() {
         342  +
        let codec = MockCodec;
         343  +
        let mut serializer = codec.create_serializer();
         344  +
         345  +
        // Test that we can use the serializer
         346  +
        serializer.write_string(&STRING, "test").unwrap();
         347  +
        let output = serializer.finish().unwrap();
         348  +
        assert_eq!(output, Vec::<u8>::new());
         349  +
    }
         350  +
         351  +
    #[test]
         352  +
    fn test_codec_create_deserializer() {
         353  +
        let codec = MockCodec;
         354  +
        let input = b"test data";
         355  +
        let mut deserializer = codec.create_deserializer(input);
         356  +
         357  +
        // Test that we can use the deserializer
         358  +
        let result = deserializer.read_string(&STRING).unwrap();
         359  +
        assert_eq!(result, "");
         360  +
    }
         361  +
         362  +
    #[test]
         363  +
    fn test_codec_roundtrip() {
         364  +
        let codec = MockCodec;
         365  +
         366  +
        // Serialize
         367  +
        let mut serializer = codec.create_serializer();
         368  +
        serializer.write_integer(&INTEGER, 42).unwrap();
         369  +
        let bytes = serializer.finish().unwrap();
         370  +
         371  +
        // Deserialize
         372  +
        let mut deserializer = codec.create_deserializer(&bytes);
         373  +
        let value = deserializer.read_integer(&INTEGER).unwrap();
         374  +
        assert_eq!(value, 0); // Mock deserializer always returns 0
         375  +
    }
         376  +
}

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-schema/src/schema/prelude.rs

@@ -15,15 +151,150 @@
   35     35   
        self.shape_type
   36     36   
    }
   37     37   
   38     38   
    fn traits(&self) -> &TraitMap {
   39     39   
        static MAP: LazyLock<TraitMap> = LazyLock::new(TraitMap::empty);
   40     40   
   41     41   
        &MAP
   42     42   
    }
   43     43   
}
   44     44   
   45         -
// TODO(schema): We should probably test with these as `pub static` too since that could
   46         -
// theoretically cut down on binary size (at the expense of some runtime performance)
          45  +
// Static schemas for prelude types to allow static lifetime references
   47     46   
   48     47   
/// Schema for `smithy.api#String`
   49         -
pub const STRING: PreludeSchema = PreludeSchema::new(
          48  +
pub static STRING: PreludeSchema = PreludeSchema::new(
   50     49   
    ShapeId::from_static("smithy.api#String", "smithy.api", "String"),
   51     50   
    ShapeType::String,
   52     51   
);
   53     52   
   54     53   
/// Schema for `smithy.api#Boolean`
   55         -
pub const BOOLEAN: PreludeSchema = PreludeSchema::new(
          54  +
pub static BOOLEAN: PreludeSchema = PreludeSchema::new(
   56     55   
    ShapeId::from_static("smithy.api#Boolean", "smithy.api", "Boolean"),
   57     56   
    ShapeType::Boolean,
   58     57   
);
   59     58   
   60     59   
/// Schema for `smithy.api#Byte`
   61         -
pub const BYTE: PreludeSchema = PreludeSchema::new(
          60  +
pub static BYTE: PreludeSchema = PreludeSchema::new(
   62     61   
    ShapeId::from_static("smithy.api#Byte", "smithy.api", "Byte"),
   63     62   
    ShapeType::Byte,
   64     63   
);
   65     64   
   66     65   
/// Schema for `smithy.api#Short`
   67         -
pub const SHORT: PreludeSchema = PreludeSchema::new(
          66  +
pub static SHORT: PreludeSchema = PreludeSchema::new(
   68     67   
    ShapeId::from_static("smithy.api#Short", "smithy.api", "Short"),
   69     68   
    ShapeType::Short,
   70     69   
);
   71     70   
   72     71   
/// Schema for `smithy.api#Integer`
   73         -
pub const INTEGER: PreludeSchema = PreludeSchema::new(
          72  +
pub static INTEGER: PreludeSchema = PreludeSchema::new(
   74     73   
    ShapeId::from_static("smithy.api#Integer", "smithy.api", "Integer"),
   75     74   
    ShapeType::Integer,
   76     75   
);
   77     76   
   78     77   
/// Schema for `smithy.api#Long`
   79         -
pub const LONG: PreludeSchema = PreludeSchema::new(
          78  +
pub static LONG: PreludeSchema = PreludeSchema::new(
   80     79   
    ShapeId::from_static("smithy.api#Long", "smithy.api", "Long"),
   81     80   
    ShapeType::Long,
   82     81   
);
   83     82   
   84     83   
/// Schema for `smithy.api#Float`
   85         -
pub const FLOAT: PreludeSchema = PreludeSchema::new(
          84  +
pub static FLOAT: PreludeSchema = PreludeSchema::new(
   86     85   
    ShapeId::from_static("smithy.api#Float", "smithy.api", "Float"),
   87     86   
    ShapeType::Float,
   88     87   
);
   89     88   
   90     89   
/// Schema for `smithy.api#Double`
   91         -
pub const DOUBLE: PreludeSchema = PreludeSchema::new(
          90  +
pub static DOUBLE: PreludeSchema = PreludeSchema::new(
   92     91   
    ShapeId::from_static("smithy.api#Double", "smithy.api", "Double"),
   93     92   
    ShapeType::Double,
   94     93   
);
   95     94   
   96     95   
/// Schema for `smithy.api#BigInteger`
   97         -
pub const BIG_INTEGER: PreludeSchema = PreludeSchema::new(
          96  +
pub static BIG_INTEGER: PreludeSchema = PreludeSchema::new(
   98     97   
    ShapeId::from_static("smithy.api#BigInteger", "smithy.api", "BigInteger"),
   99     98   
    ShapeType::BigInteger,
  100     99   
);
  101    100   
  102    101   
/// Schema for `smithy.api#BigDecimal`
  103         -
pub const BIG_DECIMAL: PreludeSchema = PreludeSchema::new(
         102  +
pub static BIG_DECIMAL: PreludeSchema = PreludeSchema::new(
  104    103   
    ShapeId::from_static("smithy.api#BigDecimal", "smithy.api", "BigDecimal"),
  105    104   
    ShapeType::BigDecimal,
  106    105   
);
  107    106   
  108    107   
/// Schema for `smithy.api#Blob`
  109         -
pub const BLOB: PreludeSchema = PreludeSchema::new(
         108  +
pub static BLOB: PreludeSchema = PreludeSchema::new(
  110    109   
    ShapeId::from_static("smithy.api#Blob", "smithy.api", "Blob"),
  111    110   
    ShapeType::Blob,
  112    111   
);
  113    112   
  114    113   
/// Schema for `smithy.api#Timestamp`
  115         -
pub const TIMESTAMP: PreludeSchema = PreludeSchema::new(
         114  +
pub static TIMESTAMP: PreludeSchema = PreludeSchema::new(
  116    115   
    ShapeId::from_static("smithy.api#Timestamp", "smithy.api", "Timestamp"),
  117    116   
    ShapeType::Timestamp,
  118    117   
);
  119    118   
  120    119   
/// Schema for `smithy.api#Document`
  121         -
pub const DOCUMENT: PreludeSchema = PreludeSchema::new(
         120  +
pub static DOCUMENT: PreludeSchema = PreludeSchema::new(
  122    121   
    ShapeId::from_static("smithy.api#Document", "smithy.api", "Document"),
  123    122   
    ShapeType::Document,
  124    123   
);
  125    124   
  126    125   
#[cfg(test)]
  127    126   
mod tests {
  128    127   
    use super::*;
  129    128   
    use crate::SchemaExt;
  130    129   
  131    130   
    #[test]