AWS SDK

AWS SDK

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

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

@@ -0,1 +0,650 @@
           1  +
/*
           2  +
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
           3  +
 * SPDX-License-Identifier: Apache-2.0
           4  +
 */
           5  +
           6  +
//! String codec for HTTP bindings (headers, query params, URI labels).
           7  +
           8  +
use crate::serde::{ShapeDeserializer, ShapeSerializer};
           9  +
use crate::Schema;
          10  +
use aws_smithy_types::{BigDecimal, BigInteger, Blob, DateTime, Document};
          11  +
use std::error::Error;
          12  +
use std::fmt;
          13  +
          14  +
/// Error type for HTTP string serialization/deserialization.
          15  +
#[derive(Debug)]
          16  +
pub struct HttpStringCodecError {
          17  +
    message: String,
          18  +
}
          19  +
          20  +
impl HttpStringCodecError {
          21  +
    fn new(message: impl Into<String>) -> Self {
          22  +
        Self {
          23  +
            message: message.into(),
          24  +
        }
          25  +
    }
          26  +
}
          27  +
          28  +
impl fmt::Display for HttpStringCodecError {
          29  +
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
          30  +
        write!(f, "HTTP string codec error: {}", self.message)
          31  +
    }
          32  +
}
          33  +
          34  +
impl Error for HttpStringCodecError {}
          35  +
          36  +
/// Serializer for converting Smithy types to strings (for HTTP headers, query params, labels).
          37  +
pub struct HttpStringSerializer {
          38  +
    output: String,
          39  +
}
          40  +
          41  +
impl HttpStringSerializer {
          42  +
    /// Creates a new HTTP string serializer.
          43  +
    pub fn new() -> Self {
          44  +
        Self {
          45  +
            output: String::new(),
          46  +
        }
          47  +
    }
          48  +
}
          49  +
          50  +
impl Default for HttpStringSerializer {
          51  +
    fn default() -> Self {
          52  +
        Self::new()
          53  +
    }
          54  +
}
          55  +
          56  +
impl ShapeSerializer for HttpStringSerializer {
          57  +
    type Output = String;
          58  +
    type Error = HttpStringCodecError;
          59  +
          60  +
    fn finish(self) -> Result<Self::Output, Self::Error> {
          61  +
        Ok(self.output)
          62  +
    }
          63  +
          64  +
    fn write_struct<F>(
          65  +
        &mut self,
          66  +
        _schema: &dyn Schema,
          67  +
        _write_members: F,
          68  +
    ) -> Result<(), Self::Error>
          69  +
    where
          70  +
        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
          71  +
    {
          72  +
        Err(HttpStringCodecError::new(
          73  +
            "structures cannot be serialized to strings",
          74  +
        ))
          75  +
    }
          76  +
          77  +
    fn write_list<F>(&mut self, _schema: &dyn Schema, write_elements: F) -> Result<(), Self::Error>
          78  +
    where
          79  +
        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
          80  +
    {
          81  +
        // Lists are serialized as comma-separated values
          82  +
        write_elements(self)
          83  +
    }
          84  +
          85  +
    fn write_map<F>(&mut self, _schema: &dyn Schema, _write_entries: F) -> Result<(), Self::Error>
          86  +
    where
          87  +
        F: FnOnce(&mut Self) -> Result<(), Self::Error>,
          88  +
    {
          89  +
        Err(HttpStringCodecError::new(
          90  +
            "maps cannot be serialized to strings",
          91  +
        ))
          92  +
    }
          93  +
          94  +
    fn write_boolean(&mut self, _schema: &dyn Schema, value: bool) -> Result<(), Self::Error> {
          95  +
        if !self.output.is_empty() {
          96  +
            self.output.push(',');
          97  +
        }
          98  +
        self.output.push_str(if value { "true" } else { "false" });
          99  +
        Ok(())
         100  +
    }
         101  +
         102  +
    fn write_byte(&mut self, _schema: &dyn Schema, value: i8) -> Result<(), Self::Error> {
         103  +
        if !self.output.is_empty() {
         104  +
            self.output.push(',');
         105  +
        }
         106  +
        self.output.push_str(&value.to_string());
         107  +
        Ok(())
         108  +
    }
         109  +
         110  +
    fn write_short(&mut self, _schema: &dyn Schema, value: i16) -> Result<(), Self::Error> {
         111  +
        if !self.output.is_empty() {
         112  +
            self.output.push(',');
         113  +
        }
         114  +
        self.output.push_str(&value.to_string());
         115  +
        Ok(())
         116  +
    }
         117  +
         118  +
    fn write_integer(&mut self, _schema: &dyn Schema, value: i32) -> Result<(), Self::Error> {
         119  +
        if !self.output.is_empty() {
         120  +
            self.output.push(',');
         121  +
        }
         122  +
        self.output.push_str(&value.to_string());
         123  +
        Ok(())
         124  +
    }
         125  +
         126  +
    fn write_long(&mut self, _schema: &dyn Schema, value: i64) -> Result<(), Self::Error> {
         127  +
        if !self.output.is_empty() {
         128  +
            self.output.push(',');
         129  +
        }
         130  +
        self.output.push_str(&value.to_string());
         131  +
        Ok(())
         132  +
    }
         133  +
         134  +
    fn write_float(&mut self, _schema: &dyn Schema, value: f32) -> Result<(), Self::Error> {
         135  +
        if !self.output.is_empty() {
         136  +
            self.output.push(',');
         137  +
        }
         138  +
        if value.is_nan() {
         139  +
            self.output.push_str("NaN");
         140  +
        } else if value.is_infinite() {
         141  +
            self.output.push_str(if value.is_sign_positive() {
         142  +
                "Infinity"
         143  +
            } else {
         144  +
                "-Infinity"
         145  +
            });
         146  +
        } else {
         147  +
            self.output.push_str(&value.to_string());
         148  +
        }
         149  +
        Ok(())
         150  +
    }
         151  +
         152  +
    fn write_double(&mut self, _schema: &dyn Schema, value: f64) -> Result<(), Self::Error> {
         153  +
        if !self.output.is_empty() {
         154  +
            self.output.push(',');
         155  +
        }
         156  +
        if value.is_nan() {
         157  +
            self.output.push_str("NaN");
         158  +
        } else if value.is_infinite() {
         159  +
            self.output.push_str(if value.is_sign_positive() {
         160  +
                "Infinity"
         161  +
            } else {
         162  +
                "-Infinity"
         163  +
            });
         164  +
        } else {
         165  +
            self.output.push_str(&value.to_string());
         166  +
        }
         167  +
        Ok(())
         168  +
    }
         169  +
         170  +
    fn write_big_integer(
         171  +
        &mut self,
         172  +
        _schema: &dyn Schema,
         173  +
        value: &BigInteger,
         174  +
    ) -> Result<(), Self::Error> {
         175  +
        if !self.output.is_empty() {
         176  +
            self.output.push(',');
         177  +
        }
         178  +
        self.output.push_str(value.as_ref());
         179  +
        Ok(())
         180  +
    }
         181  +
         182  +
    fn write_big_decimal(
         183  +
        &mut self,
         184  +
        _schema: &dyn Schema,
         185  +
        value: &BigDecimal,
         186  +
    ) -> Result<(), Self::Error> {
         187  +
        if !self.output.is_empty() {
         188  +
            self.output.push(',');
         189  +
        }
         190  +
        self.output.push_str(value.as_ref());
         191  +
        Ok(())
         192  +
    }
         193  +
         194  +
    fn write_string(&mut self, _schema: &dyn Schema, value: &str) -> Result<(), Self::Error> {
         195  +
        if !self.output.is_empty() {
         196  +
            self.output.push(',');
         197  +
        }
         198  +
        self.output.push_str(value);
         199  +
        Ok(())
         200  +
    }
         201  +
         202  +
    fn write_blob(&mut self, _schema: &dyn Schema, value: &Blob) -> Result<(), Self::Error> {
         203  +
        if !self.output.is_empty() {
         204  +
            self.output.push(',');
         205  +
        }
         206  +
        // Blobs are base64-encoded for string serialization
         207  +
        self.output
         208  +
            .push_str(&aws_smithy_types::base64::encode(value.as_ref()));
         209  +
        Ok(())
         210  +
    }
         211  +
         212  +
    fn write_timestamp(
         213  +
        &mut self,
         214  +
        _schema: &dyn Schema,
         215  +
        value: &DateTime,
         216  +
    ) -> Result<(), Self::Error> {
         217  +
        if !self.output.is_empty() {
         218  +
            self.output.push(',');
         219  +
        }
         220  +
        // Default to HTTP date format for string serialization
         221  +
        // TODO(schema): Check schema for timestampFormat trait
         222  +
        let formatted = value
         223  +
            .fmt(aws_smithy_types::date_time::Format::HttpDate)
         224  +
            .map_err(|e| HttpStringCodecError::new(format!("failed to format timestamp: {}", e)))?;
         225  +
        self.output.push_str(&formatted);
         226  +
        Ok(())
         227  +
    }
         228  +
         229  +
    fn write_document(
         230  +
        &mut self,
         231  +
        _schema: &dyn Schema,
         232  +
        _value: &Document,
         233  +
    ) -> Result<(), Self::Error> {
         234  +
        Err(HttpStringCodecError::new(
         235  +
            "documents cannot be serialized to strings",
         236  +
        ))
         237  +
    }
         238  +
         239  +
    fn write_null(&mut self, _schema: &dyn Schema) -> Result<(), Self::Error> {
         240  +
        Err(HttpStringCodecError::new(
         241  +
            "null cannot be serialized to strings",
         242  +
        ))
         243  +
    }
         244  +
}
         245  +
         246  +
/// Deserializer for parsing Smithy types from strings.
         247  +
pub struct HttpStringDeserializer<'a> {
         248  +
    input: std::borrow::Cow<'a, str>,
         249  +
    position: usize,
         250  +
}
         251  +
         252  +
impl<'a> HttpStringDeserializer<'a> {
         253  +
    /// Creates a new HTTP string deserializer from the given input.
         254  +
    pub fn new(input: &'a str) -> Self {
         255  +
        Self {
         256  +
            input: std::borrow::Cow::Borrowed(input),
         257  +
            position: 0,
         258  +
        }
         259  +
    }
         260  +
         261  +
    fn next_value(&mut self) -> Option<&str> {
         262  +
        if self.position >= self.input.len() {
         263  +
            return None;
         264  +
        }
         265  +
         266  +
        let start = self.position;
         267  +
        if let Some(comma_pos) = self.input[start..].find(',') {
         268  +
            let end = start + comma_pos;
         269  +
            self.position = end + 1;
         270  +
            Some(&self.input[start..end])
         271  +
        } else {
         272  +
            self.position = self.input.len();
         273  +
            Some(&self.input[start..])
         274  +
        }
         275  +
    }
         276  +
         277  +
    fn current_value(&self) -> &str {
         278  +
        &self.input[self.position..]
         279  +
    }
         280  +
}
         281  +
         282  +
impl<'a> ShapeDeserializer for HttpStringDeserializer<'a> {
         283  +
    type Error = HttpStringCodecError;
         284  +
         285  +
    fn read_struct<T, F>(
         286  +
        &mut self,
         287  +
        _schema: &dyn Schema,
         288  +
        _state: T,
         289  +
        _consumer: F,
         290  +
    ) -> Result<T, Self::Error>
         291  +
    where
         292  +
        F: FnMut(T, &dyn Schema, &mut Self) -> Result<T, Self::Error>,
         293  +
    {
         294  +
        Err(HttpStringCodecError::new(
         295  +
            "structures cannot be deserialized from strings",
         296  +
        ))
         297  +
    }
         298  +
         299  +
    fn read_list<T, F>(
         300  +
        &mut self,
         301  +
        _schema: &dyn Schema,
         302  +
        state: T,
         303  +
        _consumer: F,
         304  +
    ) -> Result<T, Self::Error>
         305  +
    where
         306  +
        F: FnMut(T, &mut Self) -> Result<T, Self::Error>,
         307  +
    {
         308  +
        // Lists are comma-separated values
         309  +
        // The consumer will call read methods for each element
         310  +
        Ok(state)
         311  +
    }
         312  +
         313  +
    fn read_map<T, F>(
         314  +
        &mut self,
         315  +
        _schema: &dyn Schema,
         316  +
        _state: T,
         317  +
        _consumer: F,
         318  +
    ) -> Result<T, Self::Error>
         319  +
    where
         320  +
        F: FnMut(T, String, &mut Self) -> Result<T, Self::Error>,
         321  +
    {
         322  +
        Err(HttpStringCodecError::new(
         323  +
            "maps cannot be deserialized from strings",
         324  +
        ))
         325  +
    }
         326  +
         327  +
    fn read_boolean(&mut self, _schema: &dyn Schema) -> Result<bool, Self::Error> {
         328  +
        let value = self
         329  +
            .next_value()
         330  +
            .ok_or_else(|| HttpStringCodecError::new("expected boolean value"))?;
         331  +
        value
         332  +
            .parse()
         333  +
            .map_err(|_| HttpStringCodecError::new(format!("invalid boolean: {}", value)))
         334  +
    }
         335  +
         336  +
    fn read_byte(&mut self, _schema: &dyn Schema) -> Result<i8, Self::Error> {
         337  +
        let value = self
         338  +
            .next_value()
         339  +
            .ok_or_else(|| HttpStringCodecError::new("expected byte value"))?;
         340  +
        value
         341  +
            .parse()
         342  +
            .map_err(|_| HttpStringCodecError::new(format!("invalid byte: {}", value)))
         343  +
    }
         344  +
         345  +
    fn read_short(&mut self, _schema: &dyn Schema) -> Result<i16, Self::Error> {
         346  +
        let value = self
         347  +
            .next_value()
         348  +
            .ok_or_else(|| HttpStringCodecError::new("expected short value"))?;
         349  +
        value
         350  +
            .parse()
         351  +
            .map_err(|_| HttpStringCodecError::new(format!("invalid short: {}", value)))
         352  +
    }
         353  +
         354  +
    fn read_integer(&mut self, _schema: &dyn Schema) -> Result<i32, Self::Error> {
         355  +
        let value = self
         356  +
            .next_value()
         357  +
            .ok_or_else(|| HttpStringCodecError::new("expected integer value"))?;
         358  +
        value
         359  +
            .parse()
         360  +
            .map_err(|_| HttpStringCodecError::new(format!("invalid integer: {}", value)))
         361  +
    }
         362  +
         363  +
    fn read_long(&mut self, _schema: &dyn Schema) -> Result<i64, Self::Error> {
         364  +
        let value = self
         365  +
            .next_value()
         366  +
            .ok_or_else(|| HttpStringCodecError::new("expected long value"))?;
         367  +
        value
         368  +
            .parse()
         369  +
            .map_err(|_| HttpStringCodecError::new(format!("invalid long: {}", value)))
         370  +
    }
         371  +
         372  +
    fn read_float(&mut self, _schema: &dyn Schema) -> Result<f32, Self::Error> {
         373  +
        let value = self
         374  +
            .next_value()
         375  +
            .ok_or_else(|| HttpStringCodecError::new("expected float value"))?;
         376  +
        match value {
         377  +
            "NaN" => Ok(f32::NAN),
         378  +
            "Infinity" => Ok(f32::INFINITY),
         379  +
            "-Infinity" => Ok(f32::NEG_INFINITY),
         380  +
            _ => value
         381  +
                .parse()
         382  +
                .map_err(|_| HttpStringCodecError::new(format!("invalid float: {}", value))),
         383  +
        }
         384  +
    }
         385  +
         386  +
    fn read_double(&mut self, _schema: &dyn Schema) -> Result<f64, Self::Error> {
         387  +
        let value = self
         388  +
            .next_value()
         389  +
            .ok_or_else(|| HttpStringCodecError::new("expected double value"))?;
         390  +
        match value {
         391  +
            "NaN" => Ok(f64::NAN),
         392  +
            "Infinity" => Ok(f64::INFINITY),
         393  +
            "-Infinity" => Ok(f64::NEG_INFINITY),
         394  +
            _ => value
         395  +
                .parse()
         396  +
                .map_err(|_| HttpStringCodecError::new(format!("invalid double: {}", value))),
         397  +
        }
         398  +
    }
         399  +
         400  +
    fn read_big_integer(&mut self, _schema: &dyn Schema) -> Result<BigInteger, Self::Error> {
         401  +
        let value = self
         402  +
            .next_value()
         403  +
            .ok_or_else(|| HttpStringCodecError::new("expected big integer value"))?;
         404  +
        use std::str::FromStr;
         405  +
        BigInteger::from_str(value)
         406  +
            .map_err(|_| HttpStringCodecError::new(format!("invalid big integer: {}", value)))
         407  +
    }
         408  +
         409  +
    fn read_big_decimal(&mut self, _schema: &dyn Schema) -> Result<BigDecimal, Self::Error> {
         410  +
        let value = self
         411  +
            .next_value()
         412  +
            .ok_or_else(|| HttpStringCodecError::new("expected big decimal value"))?;
         413  +
        use std::str::FromStr;
         414  +
        BigDecimal::from_str(value)
         415  +
            .map_err(|_| HttpStringCodecError::new(format!("invalid big decimal: {}", value)))
         416  +
    }
         417  +
         418  +
    fn read_string(&mut self, _schema: &dyn Schema) -> Result<String, Self::Error> {
         419  +
        self.next_value()
         420  +
            .ok_or_else(|| HttpStringCodecError::new("expected string value"))
         421  +
            .map(|s| s.to_string())
         422  +
    }
         423  +
         424  +
    fn read_blob(&mut self, _schema: &dyn Schema) -> Result<Blob, Self::Error> {
         425  +
        let value = self
         426  +
            .next_value()
         427  +
            .ok_or_else(|| HttpStringCodecError::new("expected blob value"))?;
         428  +
        let decoded = aws_smithy_types::base64::decode(value)
         429  +
            .map_err(|e| HttpStringCodecError::new(format!("invalid base64: {}", e)))?;
         430  +
        Ok(Blob::new(decoded))
         431  +
    }
         432  +
         433  +
    fn read_timestamp(&mut self, _schema: &dyn Schema) -> Result<DateTime, Self::Error> {
         434  +
        let value = self
         435  +
            .next_value()
         436  +
            .ok_or_else(|| HttpStringCodecError::new("expected timestamp value"))?;
         437  +
        // Try HTTP date format first, then fall back to other formats
         438  +
        // TODO(schema): Check schema for timestampFormat trait
         439  +
        DateTime::from_str(value, aws_smithy_types::date_time::Format::HttpDate)
         440  +
            .or_else(|_| DateTime::from_str(value, aws_smithy_types::date_time::Format::DateTime))
         441  +
            .map_err(|e| HttpStringCodecError::new(format!("invalid timestamp: {}", e)))
         442  +
    }
         443  +
         444  +
    fn read_document(&mut self, _schema: &dyn Schema) -> Result<Document, Self::Error> {
         445  +
        Err(HttpStringCodecError::new(
         446  +
            "documents cannot be deserialized from strings",
         447  +
        ))
         448  +
    }
         449  +
         450  +
    fn is_null(&self) -> bool {
         451  +
        self.current_value().is_empty()
         452  +
    }
         453  +
         454  +
    fn container_size(&self) -> Option<usize> {
         455  +
        // Count commas + 1 for list size estimation
         456  +
        Some(self.input.matches(',').count() + 1)
         457  +
    }
         458  +
}
         459  +
         460  +
/// HTTP string codec for serializing/deserializing to/from strings.
         461  +
pub struct HttpStringCodec;
         462  +
         463  +
impl crate::codec::Codec for HttpStringCodec {
         464  +
    type Serializer = HttpStringSerializer;
         465  +
    type Deserializer = HttpStringDeserializer<'static>;
         466  +
         467  +
    fn create_serializer(&self) -> Self::Serializer {
         468  +
        HttpStringSerializer::new()
         469  +
    }
         470  +
         471  +
    fn create_deserializer(&self, input: &[u8]) -> Self::Deserializer {
         472  +
        let input_str = std::str::from_utf8(input).unwrap_or("").to_string();
         473  +
        HttpStringDeserializer {
         474  +
            input: std::borrow::Cow::Owned(input_str),
         475  +
            position: 0,
         476  +
        }
         477  +
    }
         478  +
}
         479  +
         480  +
#[cfg(test)]
         481  +
mod tests {
         482  +
    use super::*;
         483  +
    use crate::prelude::*;
         484  +
         485  +
    #[test]
         486  +
    fn test_serialize_boolean() {
         487  +
        let mut ser = HttpStringSerializer::new();
         488  +
        ser.write_boolean(&BOOLEAN, true).unwrap();
         489  +
        assert_eq!(ser.finish().unwrap(), "true");
         490  +
         491  +
        let mut ser = HttpStringSerializer::new();
         492  +
        ser.write_boolean(&BOOLEAN, false).unwrap();
         493  +
        assert_eq!(ser.finish().unwrap(), "false");
         494  +
    }
         495  +
         496  +
    #[test]
         497  +
    fn test_serialize_integers() {
         498  +
        let mut ser = HttpStringSerializer::new();
         499  +
        ser.write_byte(&BYTE, 42).unwrap();
         500  +
        assert_eq!(ser.finish().unwrap(), "42");
         501  +
         502  +
        let mut ser = HttpStringSerializer::new();
         503  +
        ser.write_integer(&INTEGER, -123).unwrap();
         504  +
        assert_eq!(ser.finish().unwrap(), "-123");
         505  +
         506  +
        let mut ser = HttpStringSerializer::new();
         507  +
        ser.write_long(&LONG, 9876543210).unwrap();
         508  +
        assert_eq!(ser.finish().unwrap(), "9876543210");
         509  +
    }
         510  +
         511  +
    #[test]
         512  +
    fn test_serialize_floats() {
         513  +
        let mut ser = HttpStringSerializer::new();
         514  +
        ser.write_float(&FLOAT, 3.14).unwrap();
         515  +
        assert_eq!(ser.finish().unwrap(), "3.14");
         516  +
         517  +
        let mut ser = HttpStringSerializer::new();
         518  +
        ser.write_float(&FLOAT, f32::NAN).unwrap();
         519  +
        assert_eq!(ser.finish().unwrap(), "NaN");
         520  +
         521  +
        let mut ser = HttpStringSerializer::new();
         522  +
        ser.write_float(&FLOAT, f32::INFINITY).unwrap();
         523  +
        assert_eq!(ser.finish().unwrap(), "Infinity");
         524  +
    }
         525  +
         526  +
    #[test]
         527  +
    fn test_serialize_string() {
         528  +
        let mut ser = HttpStringSerializer::new();
         529  +
        ser.write_string(&STRING, "hello world").unwrap();
         530  +
        assert_eq!(ser.finish().unwrap(), "hello world");
         531  +
    }
         532  +
         533  +
    #[test]
         534  +
    fn test_serialize_list() {
         535  +
        let mut ser = HttpStringSerializer::new();
         536  +
        ser.write_list(&STRING, |s| {
         537  +
            s.write_string(&STRING, "a")?;
         538  +
            s.write_string(&STRING, "b")?;
         539  +
            s.write_string(&STRING, "c")?;
         540  +
            Ok(())
         541  +
        })
         542  +
        .unwrap();
         543  +
        assert_eq!(ser.finish().unwrap(), "a,b,c");
         544  +
    }
         545  +
         546  +
    #[test]
         547  +
    fn test_serialize_blob() {
         548  +
        let mut ser = HttpStringSerializer::new();
         549  +
        let blob = Blob::new(vec![1, 2, 3, 4]);
         550  +
        ser.write_blob(&BLOB, &blob).unwrap();
         551  +
        // Base64 encoding of [1, 2, 3, 4]
         552  +
        assert_eq!(ser.finish().unwrap(), "AQIDBA==");
         553  +
    }
         554  +
         555  +
    #[test]
         556  +
    fn test_deserialize_boolean() {
         557  +
        let mut deser = HttpStringDeserializer::new("true");
         558  +
        assert_eq!(deser.read_boolean(&BOOLEAN).unwrap(), true);
         559  +
         560  +
        let mut deser = HttpStringDeserializer::new("false");
         561  +
        assert_eq!(deser.read_boolean(&BOOLEAN).unwrap(), false);
         562  +
    }
         563  +
         564  +
    #[test]
         565  +
    fn test_deserialize_integers() {
         566  +
        let mut deser = HttpStringDeserializer::new("42");
         567  +
        assert_eq!(deser.read_byte(&BYTE).unwrap(), 42);
         568  +
         569  +
        let mut deser = HttpStringDeserializer::new("-123");
         570  +
        assert_eq!(deser.read_integer(&INTEGER).unwrap(), -123);
         571  +
         572  +
        let mut deser = HttpStringDeserializer::new("9876543210");
         573  +
        assert_eq!(deser.read_long(&LONG).unwrap(), 9876543210);
         574  +
    }
         575  +
         576  +
    #[test]
         577  +
    fn test_deserialize_floats() {
         578  +
        let mut deser = HttpStringDeserializer::new("3.14");
         579  +
        assert!((deser.read_float(&FLOAT).unwrap() - 3.14).abs() < 0.01);
         580  +
         581  +
        let mut deser = HttpStringDeserializer::new("NaN");
         582  +
        assert!(deser.read_float(&FLOAT).unwrap().is_nan());
         583  +
         584  +
        let mut deser = HttpStringDeserializer::new("Infinity");
         585  +
        assert_eq!(deser.read_float(&FLOAT).unwrap(), f32::INFINITY);
         586  +
    }
         587  +
         588  +
    #[test]
         589  +
    fn test_deserialize_string() {
         590  +
        let mut deser = HttpStringDeserializer::new("hello world");
         591  +
        assert_eq!(deser.read_string(&STRING).unwrap(), "hello world");
         592  +
    }
         593  +
         594  +
    #[test]
         595  +
    fn test_deserialize_list() {
         596  +
        let mut deser = HttpStringDeserializer::new("a,b,c");
         597  +
        let mut values = Vec::new();
         598  +
         599  +
        // Manually read list elements
         600  +
        values.push(deser.read_string(&STRING).unwrap());
         601  +
        values.push(deser.read_string(&STRING).unwrap());
         602  +
        values.push(deser.read_string(&STRING).unwrap());
         603  +
         604  +
        assert_eq!(values, vec!["a", "b", "c"]);
         605  +
    }
         606  +
         607  +
    #[test]
         608  +
    fn test_deserialize_blob() {
         609  +
        let mut deser = HttpStringDeserializer::new("AQIDBA==");
         610  +
        let blob = deser.read_blob(&BLOB).unwrap();
         611  +
        assert_eq!(blob.as_ref(), &[1, 2, 3, 4]);
         612  +
    }
         613  +
         614  +
    #[test]
         615  +
    fn test_container_size() {
         616  +
        let deser = HttpStringDeserializer::new("a,b,c");
         617  +
        assert_eq!(deser.container_size(), Some(3));
         618  +
         619  +
        let deser = HttpStringDeserializer::new("single");
         620  +
        assert_eq!(deser.container_size(), Some(1));
         621  +
    }
         622  +
         623  +
    #[test]
         624  +
    fn test_is_null() {
         625  +
        let deser = HttpStringDeserializer::new("");
         626  +
        assert!(deser.is_null());
         627  +
         628  +
        let deser = HttpStringDeserializer::new("value");
         629  +
        assert!(!deser.is_null());
         630  +
    }
         631  +
         632  +
    #[test]
         633  +
    fn test_codec_trait() {
         634  +
        use crate::codec::Codec;
         635  +
         636  +
        let codec = HttpStringCodec;
         637  +
         638  +
        // Test serialization through codec
         639  +
        let mut ser = codec.create_serializer();
         640  +
        ser.write_string(&STRING, "test").unwrap();
         641  +
        let output = ser.finish().unwrap();
         642  +
        assert_eq!(output, "test");
         643  +
         644  +
        // Test deserialization through codec
         645  +
        let input = b"hello";
         646  +
        let mut deser = codec.create_deserializer(input);
         647  +
        let result = deser.read_string(&STRING).unwrap();
         648  +
        assert_eq!(result, "hello");
         649  +
    }
         650  +
}