From bc55504b8741bedbf2bac2e214dc7796cf5b9a85 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 20 Apr 2023 19:56:01 +0000 Subject: [PATCH 001/312] add serde support on meta data --- rust-runtime/aws-smithy-types/src/error/metadata.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/error/metadata.rs b/rust-runtime/aws-smithy-types/src/error/metadata.rs index 06925e13f9c..9036dc94ec8 100644 --- a/rust-runtime/aws-smithy-types/src/error/metadata.rs +++ b/rust-runtime/aws-smithy-types/src/error/metadata.rs @@ -6,6 +6,7 @@ //! Error metadata use crate::retry::{ErrorKind, ProvideErrorKind}; +use std::borrow::Cow; use std::collections::HashMap; use std::fmt; @@ -39,11 +40,19 @@ pub const EMPTY_ERROR_METADATA: ErrorMetadata = ErrorMetadata { /// For many services, Errors are modeled. However, many services only partially model errors or don't /// model errors at all. In these cases, the SDK will return this generic error type to expose the /// `code`, `message` and `request_id`. +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-serialize"), + derive(serde::Serialize) +)] +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-deserialize"), + derive(serde::Deserialize) +)] #[derive(Debug, Eq, PartialEq, Default, Clone)] pub struct ErrorMetadata { code: Option, message: Option, - extras: Option>, + extras: Option, String>>, } /// Builder for [`ErrorMetadata`]. @@ -98,7 +107,7 @@ impl Builder { .extras .as_mut() .unwrap() - .insert(key, value.into()); + .insert(Cow::Borrowed(key), value.into()); self } From 931a23e9d450dee61b913be48b1b47c736b66df0 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 20 Apr 2023 19:56:01 +0000 Subject: [PATCH 002/312] add serde support to - blob - document - datetime - number number, blob and document moves to another file --- rust-runtime/aws-smithy-types/Cargo.toml | 5 + rust-runtime/aws-smithy-types/src/blob.rs | 160 ++++++ .../aws-smithy-types/src/date_time/mod.rs | 51 ++ rust-runtime/aws-smithy-types/src/document.rs | 145 +++++ rust-runtime/aws-smithy-types/src/lib.rs | 543 +----------------- rust-runtime/aws-smithy-types/src/number.rs | 494 ++++++++++++++++ 6 files changed, 859 insertions(+), 539 deletions(-) create mode 100644 rust-runtime/aws-smithy-types/src/blob.rs create mode 100644 rust-runtime/aws-smithy-types/src/document.rs create mode 100644 rust-runtime/aws-smithy-types/src/number.rs diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 7ebd3ece231..a0a62f4bf4b 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -14,6 +14,11 @@ ryu = "1.0.5" time = { version = "0.3.4", features = ["parsing"] } base64-simd = "0.8" + +[target."cfg(aws_sdk_unstable)".dependencies.serde] +version = "1" +features = ["derive"] + [dev-dependencies] base64 = "0.13.0" lazy_static = "1.4" diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs new file mode 100644 index 00000000000..0364727d4f0 --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -0,0 +1,160 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#[cfg(all( + aws_sdk_unstable, + any(feature = "serde-deserialize", feature = "serde-serialize") +))] +use crate::base64; +#[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] +use serde::Serialize; +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +use serde::{de::Visitor, Deserialize}; +/// Binary Blob Type +/// +/// Blobs represent protocol-agnostic binary content. +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +pub struct Blob { + inner: Vec, +} + +impl Blob { + /// Creates a new blob from the given `input`. + pub fn new>>(input: T) -> Self { + Blob { + inner: input.into(), + } + } + + /// Consumes the `Blob` and returns a `Vec` with its contents. + pub fn into_inner(self) -> Vec { + self.inner + } +} + +impl AsRef<[u8]> for Blob { + fn as_ref(&self) -> &[u8] { + &self.inner + } +} + +#[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] +impl Serialize for Blob { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + if serializer.is_human_readable() { + serializer.serialize_str(&crate::base64::encode(&self.inner)) + } else { + serializer.serialize_bytes(&self.inner) + } + } +} + +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +struct HumanReadableBlobVisitor; + +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +impl<'de> Visitor<'de> for HumanReadableBlobVisitor { + type Value = Blob; + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("expected base64 encoded string") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + match base64::decode(v) { + Ok(inner) => Ok(Blob { inner }), + Err(e) => Err(serde::de::Error::custom(e)), + } + } +} + +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +struct NotHumanReadableBlobVisitor; + +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +impl<'de> Visitor<'de> for NotHumanReadableBlobVisitor { + type Value = Blob; + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("expected base64 encoded string") + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: serde::de::Error, + { + Ok(Blob { inner: v }) + } +} + +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +impl<'de> Deserialize<'de> for Blob { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + if deserializer.is_human_readable() { + deserializer.deserialize_str(HumanReadableBlobVisitor) + } else { + deserializer.deserialize_byte_buf(NotHumanReadableBlobVisitor) + } + } +} + +#[cfg(test)] +#[cfg(all( + aws_sdk_unstable, + feature = "serde-serialize", + feature = "serde-deserialize" +))] +mod test { + use crate::Blob; + use serde::{Deserialize, Serialize}; + use std::collections::HashMap; + + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct ForTest { + blob: Blob, + } + + #[test] + fn human_readable_blob() { + let aws_in_base64 = r#"{"blob":"QVdT"}"#; + let for_test = ForTest { + blob: Blob { + inner: vec![b'A', b'W', b'S'], + }, + }; + assert_eq!(for_test, serde_json::from_str(aws_in_base64).unwrap()); + assert_eq!(serde_json::to_string(&for_test).unwrap(), aws_in_base64); + } + + #[test] + fn not_human_readable_blob() { + use std::ffi::CString; + + let for_test = ForTest { + blob: Blob { + inner: vec![b'A', b'W', b'S'], + }, + }; + let mut buf = vec![]; + let res = ciborium::ser::into_writer(&for_test, &mut buf); + assert!(res.is_ok()); + + // checks whether the bytes are deserialiezd properly + let n: HashMap = + ciborium::de::from_reader(std::io::Cursor::new(buf.clone())).unwrap(); + assert!(n.get("blob").is_some()); + assert!(n.get("blob") == CString::new([65, 87, 83]).ok().as_ref()); + + let de: ForTest = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); + assert_eq!(for_test, de); + } +} diff --git a/rust-runtime/aws-smithy-types/src/date_time/mod.rs b/rust-runtime/aws-smithy-types/src/date_time/mod.rs index 0459619998e..9739bce0f2d 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/mod.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/mod.rs @@ -16,7 +16,12 @@ use std::time::Duration; use std::time::SystemTime; use std::time::UNIX_EPOCH; +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +mod de; mod format; +#[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] +mod ser; + pub use self::format::DateTimeFormatError; pub use self::format::DateTimeParseError; @@ -552,4 +557,50 @@ mod test { SystemTime::try_from(date_time).unwrap() ); } + + #[cfg(all( + test, + aws_sdk_unstable, + feature = "serde-deserialize", + feature = "serde-serialize" + ))] + #[test] + fn human_readable_datetime() { + use serde::{Deserialize, Serialize}; + + let datetime = DateTime::from_secs(1576540098); + #[derive(Serialize, Deserialize, PartialEq)] + struct Test { + datetime: DateTime, + } + let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; + assert!(serde_json::to_string(&Test { datetime }).ok() == Some(datetime_json.to_string())); + + let test = serde_json::from_str::(&datetime_json).ok(); + assert!(test.is_some()); + assert!(test.unwrap().datetime == datetime); + } + + /// checks that they are serialized into tuples + #[cfg(all( + test, + aws_sdk_unstable, + feature = "serde-deserialize", + feature = "serde-serialize" + ))] + #[test] + fn not_human_readable_datetime() { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(1576540098i64.into()), + ciborium::value::Value::Integer(0u32.into()), + ]); + let datetime = DateTime::from_secs(1576540098); + + let mut buf1 = vec![]; + let mut buf2 = vec![]; + let res1 = ciborium::ser::into_writer(&datetime, &mut buf1); + let res2 = ciborium::ser::into_writer(&cbor, &mut buf2); + assert!(res1.is_ok() && res2.is_ok()); + assert!(buf1 == buf2, "{:#?}", (buf1, buf2)); + } } diff --git a/rust-runtime/aws-smithy-types/src/document.rs b/rust-runtime/aws-smithy-types/src/document.rs new file mode 100644 index 00000000000..8cbae5b3800 --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/document.rs @@ -0,0 +1,145 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::Number; +use std::collections::HashMap; + +/* ANCHOR: document */ + +/// Document Type +/// +/// Document types represents protocol-agnostic open content that is accessed like JSON data. +/// Open content is useful for modeling unstructured data that has no schema, data that can't be +/// modeled using rigid types, or data that has a schema that evolves outside of the purview of a model. +/// The serialization format of a document is an implementation detail of a protocol. +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-serialize"), + derive(serde::Serialize) +)] +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-deserialize"), + derive(serde::Deserialize) +)] +#[cfg_attr( + any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") + ), + serde(untagged) +)] +pub enum Document { + /// JSON object + Object(HashMap), + /// JSON array + Array(Vec), + /// JSON number + Number(Number), + /// JSON string + String(String), + /// JSON boolean + Bool(bool), + /// JSON null + Null, +} + +impl From for Document { + fn from(value: bool) -> Self { + Document::Bool(value) + } +} + +impl From for Document { + fn from(value: String) -> Self { + Document::String(value) + } +} + +impl From> for Document { + fn from(values: Vec) -> Self { + Document::Array(values) + } +} + +impl From> for Document { + fn from(values: HashMap) -> Self { + Document::Object(values) + } +} + +impl From for Document { + fn from(value: u64) -> Self { + Document::Number(Number::PosInt(value)) + } +} + +impl From for Document { + fn from(value: i64) -> Self { + Document::Number(Number::NegInt(value)) + } +} + +impl From for Document { + fn from(value: i32) -> Self { + Document::Number(Number::NegInt(value as i64)) + } +} + +/* ANCHOR END: document */ + +#[cfg(test)] +mod test { + /// checks if a) serialization of json suceeds and b) it is compatible with serde_json + #[test] + #[cfg(all( + aws_sdk_unstable, + feature = "serde-serialize", + feature = "serde-deserialize" + ))] + fn serialize_json() { + use crate::Document; + use crate::Number; + use std::collections::HashMap; + let mut map: HashMap = HashMap::new(); + // string + map.insert("hello".into(), "world".to_string().into()); + // numbers + map.insert("pos_int".into(), Document::Number(Number::PosInt(1).into())); + map.insert( + "neg_int".into(), + Document::Number(Number::NegInt(-1).into()), + ); + map.insert( + "float".into(), + Document::Number(Number::Float(0.1 + 0.2).into()), + ); + // booleans + map.insert("true".into(), true.into()); + map.insert("false".into(), false.into()); + // check if array with different datatypes would succeed + map.insert( + "array".into(), + vec![ + map.clone().into(), + "hello-world".to_string().into(), + true.into(), + false.into(), + ] + .into(), + ); + // map + map.insert("map".into(), map.clone().into()); + // null + map.insert("null".into(), Document::Null); + let obj = Document::Object(map); + // comparing string isnt going to work since there is no gurantee for the ordering of the keys + let target_file = include_str!("../test_data/serialize_document.json"); + let json: Result = serde_json::from_str(target_file); + // serializer + assert_eq!(serde_json::to_value(&obj).unwrap(), json.unwrap()); + let doc: Result = serde_json::from_str(target_file); + assert_eq!(obj, doc.unwrap()); + } +} diff --git a/rust-runtime/aws-smithy-types/src/lib.rs b/rust-runtime/aws-smithy-types/src/lib.rs index 2634ff7f390..3bfd3033191 100644 --- a/rust-runtime/aws-smithy-types/src/lib.rs +++ b/rust-runtime/aws-smithy-types/src/lib.rs @@ -25,543 +25,8 @@ pub mod primitive; pub mod retry; pub mod timeout; -pub use crate::date_time::DateTime; - -// TODO(deprecated): Remove deprecated re-export -/// Use [error::ErrorMetadata] instead. -#[deprecated( - note = "`aws_smithy_types::Error` has been renamed to `aws_smithy_types::error::ErrorMetadata`" -)] +pub use blob::Blob; +pub use date_time::DateTime; +pub use document::Document; pub use error::ErrorMetadata as Error; - -/// Binary Blob Type -/// -/// Blobs represent protocol-agnostic binary content. -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub struct Blob { - inner: Vec, -} - -impl Blob { - /// Creates a new blob from the given `input`. - pub fn new>>(input: T) -> Self { - Blob { - inner: input.into(), - } - } - - /// Consumes the `Blob` and returns a `Vec` with its contents. - pub fn into_inner(self) -> Vec { - self.inner - } -} - -impl AsRef<[u8]> for Blob { - fn as_ref(&self) -> &[u8] { - &self.inner - } -} - -/* ANCHOR: document */ - -/// Document Type -/// -/// Document types represents protocol-agnostic open content that is accessed like JSON data. -/// Open content is useful for modeling unstructured data that has no schema, data that can't be -/// modeled using rigid types, or data that has a schema that evolves outside of the purview of a model. -/// The serialization format of a document is an implementation detail of a protocol. -#[derive(Debug, Clone, PartialEq)] -pub enum Document { - /// JSON object - Object(HashMap), - /// JSON array - Array(Vec), - /// JSON number - Number(Number), - /// JSON string - String(String), - /// JSON boolean - Bool(bool), - /// JSON null - Null, -} - -impl From for Document { - fn from(value: bool) -> Self { - Document::Bool(value) - } -} - -impl From for Document { - fn from(value: String) -> Self { - Document::String(value) - } -} - -impl From> for Document { - fn from(values: Vec) -> Self { - Document::Array(values) - } -} - -impl From> for Document { - fn from(values: HashMap) -> Self { - Document::Object(values) - } -} - -impl From for Document { - fn from(value: u64) -> Self { - Document::Number(Number::PosInt(value)) - } -} - -impl From for Document { - fn from(value: i64) -> Self { - Document::Number(Number::NegInt(value)) - } -} - -impl From for Document { - fn from(value: i32) -> Self { - Document::Number(Number::NegInt(value as i64)) - } -} - -/// A number type that implements Javascript / JSON semantics, modeled on serde_json: -/// -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum Number { - /// Unsigned 64-bit integer value. - PosInt(u64), - /// Signed 64-bit integer value. The wrapped value is _always_ negative. - NegInt(i64), - /// 64-bit floating-point value. - Float(f64), -} - -/* ANCHOR_END: document */ - -impl Number { - /// Converts to an `f64` lossily. - /// Use `Number::try_from` to make the conversion only if it is not lossy. - pub fn to_f64_lossy(self) -> f64 { - match self { - Number::PosInt(v) => v as f64, - Number::NegInt(v) => v as f64, - Number::Float(v) => v, - } - } - - /// Converts to an `f32` lossily. - /// Use `Number::try_from` to make the conversion only if it is not lossy. - pub fn to_f32_lossy(self) -> f32 { - match self { - Number::PosInt(v) => v as f32, - Number::NegInt(v) => v as f32, - Number::Float(v) => v as f32, - } - } -} - -macro_rules! to_unsigned_integer_converter { - ($typ:ident, $styp:expr) => { - #[doc = "Converts to a `"] - #[doc = $styp] - #[doc = "`. This conversion fails if it is lossy."] - impl TryFrom for $typ { - type Error = TryFromNumberError; - - fn try_from(value: Number) -> Result { - match value { - Number::PosInt(v) => Ok(Self::try_from(v)?), - Number::NegInt(v) => { - Err(TryFromNumberErrorKind::NegativeToUnsignedLossyConversion(v).into()) - } - Number::Float(v) => { - Err(TryFromNumberErrorKind::FloatToIntegerLossyConversion(v).into()) - } - } - } - } - }; - - ($typ:ident) => { - to_unsigned_integer_converter!($typ, stringify!($typ)); - }; -} - -macro_rules! to_signed_integer_converter { - ($typ:ident, $styp:expr) => { - #[doc = "Converts to a `"] - #[doc = $styp] - #[doc = "`. This conversion fails if it is lossy."] - impl TryFrom for $typ { - type Error = TryFromNumberError; - - fn try_from(value: Number) -> Result { - match value { - Number::PosInt(v) => Ok(Self::try_from(v)?), - Number::NegInt(v) => Ok(Self::try_from(v)?), - Number::Float(v) => { - Err(TryFromNumberErrorKind::FloatToIntegerLossyConversion(v).into()) - } - } - } - } - }; - - ($typ:ident) => { - to_signed_integer_converter!($typ, stringify!($typ)); - }; -} - -/// Converts to a `u64`. The conversion fails if it is lossy. -impl TryFrom for u64 { - type Error = TryFromNumberError; - - fn try_from(value: Number) -> Result { - match value { - Number::PosInt(v) => Ok(v), - Number::NegInt(v) => { - Err(TryFromNumberErrorKind::NegativeToUnsignedLossyConversion(v).into()) - } - Number::Float(v) => { - Err(TryFromNumberErrorKind::FloatToIntegerLossyConversion(v).into()) - } - } - } -} -to_unsigned_integer_converter!(u32); -to_unsigned_integer_converter!(u16); -to_unsigned_integer_converter!(u8); - -impl TryFrom for i64 { - type Error = TryFromNumberError; - - fn try_from(value: Number) -> Result { - match value { - Number::PosInt(v) => Ok(Self::try_from(v)?), - Number::NegInt(v) => Ok(v), - Number::Float(v) => { - Err(TryFromNumberErrorKind::FloatToIntegerLossyConversion(v).into()) - } - } - } -} -to_signed_integer_converter!(i32); -to_signed_integer_converter!(i16); -to_signed_integer_converter!(i8); - -/// Converts to an `f64`. The conversion fails if it is lossy. -impl TryFrom for f64 { - type Error = TryFromNumberError; - - fn try_from(value: Number) -> Result { - match value { - // Integers can only be represented with full precision in a float if they fit in the - // significand, which is 24 bits in `f32` and 53 bits in `f64`. - // https://github.com/rust-lang/rust/blob/58f11791af4f97572e7afd83f11cffe04bbbd12f/library/core/src/convert/num.rs#L151-L153 - Number::PosInt(v) => { - if v <= (1 << 53) { - Ok(v as Self) - } else { - Err(TryFromNumberErrorKind::U64ToFloatLossyConversion(v).into()) - } - } - Number::NegInt(v) => { - if (-(1 << 53)..=(1 << 53)).contains(&v) { - Ok(v as Self) - } else { - Err(TryFromNumberErrorKind::I64ToFloatLossyConversion(v).into()) - } - } - Number::Float(v) => Ok(v), - } - } -} - -/// Converts to an `f64`. The conversion fails if it is lossy. -impl TryFrom for f32 { - type Error = TryFromNumberError; - - fn try_from(value: Number) -> Result { - match value { - Number::PosInt(v) => { - if v <= (1 << 24) { - Ok(v as Self) - } else { - Err(TryFromNumberErrorKind::U64ToFloatLossyConversion(v).into()) - } - } - Number::NegInt(v) => { - if (-(1 << 24)..=(1 << 24)).contains(&v) { - Ok(v as Self) - } else { - Err(TryFromNumberErrorKind::I64ToFloatLossyConversion(v).into()) - } - } - Number::Float(v) => Err(TryFromNumberErrorKind::F64ToF32LossyConversion(v).into()), - } - } -} - -#[cfg(test)] -mod number { - use super::*; - use crate::error::{TryFromNumberError, TryFromNumberErrorKind}; - - macro_rules! to_unsigned_converter_tests { - ($typ:ident) => { - assert_eq!($typ::try_from(Number::PosInt(69u64)).unwrap(), 69); - - assert!(matches!( - $typ::try_from(Number::PosInt(($typ::MAX as u64) + 1u64)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::OutsideIntegerRange(..) - } - )); - - assert!(matches!( - $typ::try_from(Number::NegInt(-1i64)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::NegativeToUnsignedLossyConversion(..) - } - )); - - for val in [69.69f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY] { - assert!(matches!( - $typ::try_from(Number::Float(val)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::FloatToIntegerLossyConversion(..) - } - )); - } - }; - } - - #[test] - fn to_u64() { - assert_eq!(u64::try_from(Number::PosInt(69u64)).unwrap(), 69u64); - - assert!(matches!( - u64::try_from(Number::NegInt(-1i64)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::NegativeToUnsignedLossyConversion(..) - } - )); - - for val in [69.69f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY] { - assert!(matches!( - u64::try_from(Number::Float(val)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::FloatToIntegerLossyConversion(..) - } - )); - } - } - - #[test] - fn to_u32() { - to_unsigned_converter_tests!(u32); - } - - #[test] - fn to_u16() { - to_unsigned_converter_tests!(u16); - } - - #[test] - fn to_u8() { - to_unsigned_converter_tests!(u8); - } - - macro_rules! to_signed_converter_tests { - ($typ:ident) => { - assert_eq!($typ::try_from(Number::PosInt(69u64)).unwrap(), 69); - assert_eq!($typ::try_from(Number::NegInt(-69i64)).unwrap(), -69); - - assert!(matches!( - $typ::try_from(Number::PosInt(($typ::MAX as u64) + 1u64)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::OutsideIntegerRange(..) - } - )); - - assert!(matches!( - $typ::try_from(Number::NegInt(($typ::MIN as i64) - 1i64)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::OutsideIntegerRange(..) - } - )); - - for val in [69.69f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY] { - assert!(matches!( - u64::try_from(Number::Float(val)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::FloatToIntegerLossyConversion(..) - } - )); - } - }; - } - - #[test] - fn to_i64() { - assert_eq!(i64::try_from(Number::PosInt(69u64)).unwrap(), 69); - assert_eq!(i64::try_from(Number::NegInt(-69i64)).unwrap(), -69); - - for val in [69.69f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY] { - assert!(matches!( - u64::try_from(Number::Float(val)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::FloatToIntegerLossyConversion(..) - } - )); - } - } - - #[test] - fn to_i32() { - to_signed_converter_tests!(i32); - } - - #[test] - fn to_i16() { - to_signed_converter_tests!(i16); - } - - #[test] - fn to_i8() { - to_signed_converter_tests!(i8); - } - - #[test] - fn to_f64() { - assert_eq!(f64::try_from(Number::PosInt(69u64)).unwrap(), 69f64); - assert_eq!(f64::try_from(Number::NegInt(-69i64)).unwrap(), -69f64); - assert_eq!(f64::try_from(Number::Float(-69f64)).unwrap(), -69f64); - assert!(f64::try_from(Number::Float(f64::NAN)).unwrap().is_nan()); - assert_eq!( - f64::try_from(Number::Float(f64::INFINITY)).unwrap(), - f64::INFINITY - ); - assert_eq!( - f64::try_from(Number::Float(f64::NEG_INFINITY)).unwrap(), - f64::NEG_INFINITY - ); - - let significand_max_u64: u64 = 1 << 53; - let significand_max_i64: i64 = 1 << 53; - - assert_eq!( - f64::try_from(Number::PosInt(significand_max_u64)).unwrap(), - 9007199254740992f64 - ); - - assert_eq!( - f64::try_from(Number::NegInt(significand_max_i64)).unwrap(), - 9007199254740992f64 - ); - assert_eq!( - f64::try_from(Number::NegInt(-significand_max_i64)).unwrap(), - -9007199254740992f64 - ); - - assert!(matches!( - f64::try_from(Number::PosInt(significand_max_u64 + 1)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::U64ToFloatLossyConversion(..) - } - )); - - assert!(matches!( - f64::try_from(Number::NegInt(significand_max_i64 + 1)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::I64ToFloatLossyConversion(..) - } - )); - assert!(matches!( - f64::try_from(Number::NegInt(-significand_max_i64 - 1)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::I64ToFloatLossyConversion(..) - } - )); - } - - #[test] - fn to_f32() { - assert_eq!(f32::try_from(Number::PosInt(69u64)).unwrap(), 69f32); - assert_eq!(f32::try_from(Number::NegInt(-69i64)).unwrap(), -69f32); - - let significand_max_u64: u64 = 1 << 24; - let significand_max_i64: i64 = 1 << 24; - - assert_eq!( - f32::try_from(Number::PosInt(significand_max_u64)).unwrap(), - 16777216f32 - ); - - assert_eq!( - f32::try_from(Number::NegInt(significand_max_i64)).unwrap(), - 16777216f32 - ); - assert_eq!( - f32::try_from(Number::NegInt(-significand_max_i64)).unwrap(), - -16777216f32 - ); - - assert!(matches!( - f32::try_from(Number::PosInt(significand_max_u64 + 1)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::U64ToFloatLossyConversion(..) - } - )); - - assert!(matches!( - f32::try_from(Number::NegInt(significand_max_i64 + 1)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::I64ToFloatLossyConversion(..) - } - )); - assert!(matches!( - f32::try_from(Number::NegInt(-significand_max_i64 - 1)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::I64ToFloatLossyConversion(..) - } - )); - - for val in [69f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY] { - assert!(matches!( - f32::try_from(Number::Float(val)).unwrap_err(), - TryFromNumberError { - kind: TryFromNumberErrorKind::F64ToF32LossyConversion(..) - } - )); - } - } - - #[test] - fn to_f64_lossy() { - assert_eq!(Number::PosInt(69u64).to_f64_lossy(), 69f64); - assert_eq!( - Number::PosInt((1 << 53) + 1).to_f64_lossy(), - 9007199254740992f64 - ); - assert_eq!( - Number::NegInt(-(1 << 53) - 1).to_f64_lossy(), - -9007199254740992f64 - ); - } - - #[test] - fn to_f32_lossy() { - assert_eq!(Number::PosInt(69u64).to_f32_lossy(), 69f32); - assert_eq!(Number::PosInt((1 << 24) + 1).to_f32_lossy(), 16777216f32); - assert_eq!(Number::NegInt(-(1 << 24) - 1).to_f32_lossy(), -16777216f32); - assert_eq!( - Number::Float(1452089033.7674935).to_f32_lossy(), - 1452089100f32 - ); - } -} +pub use number::Number; diff --git a/rust-runtime/aws-smithy-types/src/number.rs b/rust-runtime/aws-smithy-types/src/number.rs new file mode 100644 index 00000000000..80527cfc104 --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/number.rs @@ -0,0 +1,494 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! A number type that implements Javascript / JSON semantics, modeled on serde_json: +//! + +use crate::error::{TryFromNumberError, TryFromNumberErrorKind}; +#[cfg(all( + aws_sdk_unstable, + any(feature = "serde-serialize", feature = "serde-deserialize") +))] +use serde; + +/// A number type that implements Javascript / JSON semantics, modeled on serde_json: +/// +#[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-deserialize"), + derive(serde::Deserialize) +)] +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-serialize"), + derive(serde::Serialize) +)] +#[cfg_attr( + any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") + ), + serde(untagged) +)] +pub enum Number { + /// Unsigned 64-bit integer value. + PosInt(u64), + /// Signed 64-bit integer value. The wrapped value is _always_ negative. + NegInt(i64), + /// 64-bit floating-point value. + Float(f64), +} + +/* ANCHOR_END: document */ + +impl Number { + /// Converts to an `f64` lossily. + /// Use `Number::try_from` to make the conversion only if it is not lossy. + pub fn to_f64_lossy(self) -> f64 { + match self { + Number::PosInt(v) => v as f64, + Number::NegInt(v) => v as f64, + Number::Float(v) => v, + } + } + + /// Converts to an `f32` lossily. + /// Use `Number::try_from` to make the conversion only if it is not lossy. + pub fn to_f32_lossy(self) -> f32 { + match self { + Number::PosInt(v) => v as f32, + Number::NegInt(v) => v as f32, + Number::Float(v) => v as f32, + } + } +} + +macro_rules! to_unsigned_integer_converter { + ($typ:ident, $styp:expr) => { + #[doc = "Converts to a `"] + #[doc = $styp] + #[doc = "`. This conversion fails if it is lossy."] + impl TryFrom for $typ { + type Error = TryFromNumberError; + + fn try_from(value: Number) -> Result { + match value { + Number::PosInt(v) => Ok(Self::try_from(v)?), + Number::NegInt(v) => { + Err(TryFromNumberErrorKind::NegativeToUnsignedLossyConversion(v).into()) + } + Number::Float(v) => { + Err(TryFromNumberErrorKind::FloatToIntegerLossyConversion(v).into()) + } + } + } + } + }; + + ($typ:ident) => { + to_unsigned_integer_converter!($typ, stringify!($typ)); + }; +} + +macro_rules! to_signed_integer_converter { + ($typ:ident, $styp:expr) => { + #[doc = "Converts to a `"] + #[doc = $styp] + #[doc = "`. This conversion fails if it is lossy."] + impl TryFrom for $typ { + type Error = TryFromNumberError; + + fn try_from(value: Number) -> Result { + match value { + Number::PosInt(v) => Ok(Self::try_from(v)?), + Number::NegInt(v) => Ok(Self::try_from(v)?), + Number::Float(v) => { + Err(TryFromNumberErrorKind::FloatToIntegerLossyConversion(v).into()) + } + } + } + } + }; + + ($typ:ident) => { + to_signed_integer_converter!($typ, stringify!($typ)); + }; +} + +/// Converts to a `u64`. The conversion fails if it is lossy. +impl TryFrom for u64 { + type Error = TryFromNumberError; + + fn try_from(value: Number) -> Result { + match value { + Number::PosInt(v) => Ok(v), + Number::NegInt(v) => { + Err(TryFromNumberErrorKind::NegativeToUnsignedLossyConversion(v).into()) + } + Number::Float(v) => { + Err(TryFromNumberErrorKind::FloatToIntegerLossyConversion(v).into()) + } + } + } +} +to_unsigned_integer_converter!(u32); +to_unsigned_integer_converter!(u16); +to_unsigned_integer_converter!(u8); + +impl TryFrom for i64 { + type Error = TryFromNumberError; + + fn try_from(value: Number) -> Result { + match value { + Number::PosInt(v) => Ok(Self::try_from(v)?), + Number::NegInt(v) => Ok(v), + Number::Float(v) => { + Err(TryFromNumberErrorKind::FloatToIntegerLossyConversion(v).into()) + } + } + } +} +to_signed_integer_converter!(i32); +to_signed_integer_converter!(i16); +to_signed_integer_converter!(i8); + +/// Converts to an `f64`. The conversion fails if it is lossy. +impl TryFrom for f64 { + type Error = TryFromNumberError; + + fn try_from(value: Number) -> Result { + match value { + // Integers can only be represented with full precision in a float if they fit in the + // significand, which is 24 bits in `f32` and 53 bits in `f64`. + // https://github.com/rust-lang/rust/blob/58f11791af4f97572e7afd83f11cffe04bbbd12f/library/core/src/convert/num.rs#L151-L153 + Number::PosInt(v) => { + if v <= (1 << 53) { + Ok(v as Self) + } else { + Err(TryFromNumberErrorKind::U64ToFloatLossyConversion(v).into()) + } + } + Number::NegInt(v) => { + if (-(1 << 53)..=(1 << 53)).contains(&v) { + Ok(v as Self) + } else { + Err(TryFromNumberErrorKind::I64ToFloatLossyConversion(v).into()) + } + } + Number::Float(v) => Ok(v), + } + } +} + +/// Converts to an `f64`. The conversion fails if it is lossy. +impl TryFrom for f32 { + type Error = TryFromNumberError; + + fn try_from(value: Number) -> Result { + match value { + Number::PosInt(v) => { + if v <= (1 << 24) { + Ok(v as Self) + } else { + Err(TryFromNumberErrorKind::U64ToFloatLossyConversion(v).into()) + } + } + Number::NegInt(v) => { + if (-(1 << 24)..=(1 << 24)).contains(&v) { + Ok(v as Self) + } else { + Err(TryFromNumberErrorKind::I64ToFloatLossyConversion(v).into()) + } + } + Number::Float(v) => Err(TryFromNumberErrorKind::F64ToF32LossyConversion(v).into()), + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::error::{TryFromNumberError, TryFromNumberErrorKind}; + + macro_rules! to_unsigned_converter_tests { + ($typ:ident) => { + assert_eq!($typ::try_from(Number::PosInt(69u64)).unwrap(), 69); + + assert!(matches!( + $typ::try_from(Number::PosInt(($typ::MAX as u64) + 1u64)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::OutsideIntegerRange(..) + } + )); + + assert!(matches!( + $typ::try_from(Number::NegInt(-1i64)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::NegativeToUnsignedLossyConversion(..) + } + )); + + for val in [69.69f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY] { + assert!(matches!( + $typ::try_from(Number::Float(val)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::FloatToIntegerLossyConversion(..) + } + )); + } + }; + } + + #[test] + fn to_u64() { + assert_eq!(u64::try_from(Number::PosInt(69u64)).unwrap(), 69u64); + + assert!(matches!( + u64::try_from(Number::NegInt(-1i64)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::NegativeToUnsignedLossyConversion(..) + } + )); + + for val in [69.69f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY] { + assert!(matches!( + u64::try_from(Number::Float(val)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::FloatToIntegerLossyConversion(..) + } + )); + } + } + + #[test] + fn to_u32() { + to_unsigned_converter_tests!(u32); + } + + #[test] + fn to_u16() { + to_unsigned_converter_tests!(u16); + } + + #[test] + fn to_u8() { + to_unsigned_converter_tests!(u8); + } + + macro_rules! to_signed_converter_tests { + ($typ:ident) => { + assert_eq!($typ::try_from(Number::PosInt(69u64)).unwrap(), 69); + assert_eq!($typ::try_from(Number::NegInt(-69i64)).unwrap(), -69); + + assert!(matches!( + $typ::try_from(Number::PosInt(($typ::MAX as u64) + 1u64)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::OutsideIntegerRange(..) + } + )); + + assert!(matches!( + $typ::try_from(Number::NegInt(($typ::MIN as i64) - 1i64)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::OutsideIntegerRange(..) + } + )); + + for val in [69.69f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY] { + assert!(matches!( + u64::try_from(Number::Float(val)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::FloatToIntegerLossyConversion(..) + } + )); + } + }; + } + + #[test] + fn to_i64() { + assert_eq!(i64::try_from(Number::PosInt(69u64)).unwrap(), 69); + assert_eq!(i64::try_from(Number::NegInt(-69i64)).unwrap(), -69); + + for val in [69.69f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY] { + assert!(matches!( + u64::try_from(Number::Float(val)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::FloatToIntegerLossyConversion(..) + } + )); + } + } + + #[test] + fn to_i32() { + to_signed_converter_tests!(i32); + } + + #[test] + fn to_i16() { + to_signed_converter_tests!(i16); + } + + #[test] + fn to_i8() { + to_signed_converter_tests!(i8); + } + + #[test] + fn to_f64() { + assert_eq!(f64::try_from(Number::PosInt(69u64)).unwrap(), 69f64); + assert_eq!(f64::try_from(Number::NegInt(-69i64)).unwrap(), -69f64); + assert_eq!(f64::try_from(Number::Float(-69f64)).unwrap(), -69f64); + assert!(f64::try_from(Number::Float(f64::NAN)).unwrap().is_nan()); + assert_eq!( + f64::try_from(Number::Float(f64::INFINITY)).unwrap(), + f64::INFINITY + ); + assert_eq!( + f64::try_from(Number::Float(f64::NEG_INFINITY)).unwrap(), + f64::NEG_INFINITY + ); + + let significand_max_u64: u64 = 1 << 53; + let significand_max_i64: i64 = 1 << 53; + + assert_eq!( + f64::try_from(Number::PosInt(significand_max_u64)).unwrap(), + 9007199254740992f64 + ); + + assert_eq!( + f64::try_from(Number::NegInt(significand_max_i64)).unwrap(), + 9007199254740992f64 + ); + assert_eq!( + f64::try_from(Number::NegInt(-significand_max_i64)).unwrap(), + -9007199254740992f64 + ); + + assert!(matches!( + f64::try_from(Number::PosInt(significand_max_u64 + 1)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::U64ToFloatLossyConversion(..) + } + )); + + assert!(matches!( + f64::try_from(Number::NegInt(significand_max_i64 + 1)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::I64ToFloatLossyConversion(..) + } + )); + assert!(matches!( + f64::try_from(Number::NegInt(-significand_max_i64 - 1)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::I64ToFloatLossyConversion(..) + } + )); + } + + #[test] + fn to_f32() { + assert_eq!(f32::try_from(Number::PosInt(69u64)).unwrap(), 69f32); + assert_eq!(f32::try_from(Number::NegInt(-69i64)).unwrap(), -69f32); + + let significand_max_u64: u64 = 1 << 24; + let significand_max_i64: i64 = 1 << 24; + + assert_eq!( + f32::try_from(Number::PosInt(significand_max_u64)).unwrap(), + 16777216f32 + ); + + assert_eq!( + f32::try_from(Number::NegInt(significand_max_i64)).unwrap(), + 16777216f32 + ); + assert_eq!( + f32::try_from(Number::NegInt(-significand_max_i64)).unwrap(), + -16777216f32 + ); + + assert!(matches!( + f32::try_from(Number::PosInt(significand_max_u64 + 1)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::U64ToFloatLossyConversion(..) + } + )); + + assert!(matches!( + f32::try_from(Number::NegInt(significand_max_i64 + 1)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::I64ToFloatLossyConversion(..) + } + )); + assert!(matches!( + f32::try_from(Number::NegInt(-significand_max_i64 - 1)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::I64ToFloatLossyConversion(..) + } + )); + + for val in [69f64, f64::NAN, f64::INFINITY, f64::NEG_INFINITY] { + assert!(matches!( + f32::try_from(Number::Float(val)).unwrap_err(), + TryFromNumberError { + kind: TryFromNumberErrorKind::F64ToF32LossyConversion(..) + } + )); + } + } + + #[test] + fn to_f64_lossy() { + assert_eq!(Number::PosInt(69u64).to_f64_lossy(), 69f64); + assert_eq!( + Number::PosInt((1 << 53) + 1).to_f64_lossy(), + 9007199254740992f64 + ); + assert_eq!( + Number::NegInt(-(1 << 53) - 1).to_f64_lossy(), + -9007199254740992f64 + ); + } + + #[test] + fn to_f32_lossy() { + assert_eq!(Number::PosInt(69u64).to_f32_lossy(), 69f32); + assert_eq!(Number::PosInt((1 << 24) + 1).to_f32_lossy(), 16777216f32); + assert_eq!(Number::NegInt(-(1 << 24) - 1).to_f32_lossy(), -16777216f32); + assert_eq!( + Number::Float(1452089033.7674935).to_f32_lossy(), + 1452089100f32 + ); + } + + #[test] + #[cfg(all( + test, + aws_sdk_unstable, + feature = "serde-deserialize", + feature = "serde-serialize" + ))] + /// ensures that numbers are deserialized as expected + /// 0 <= PosInt + /// 0 > NegInt + /// non integer values == Float + fn number_serde() { + let n: Number = serde_json::from_str("1.1").unwrap(); + assert_eq!(n, Number::Float(1.1)); + let n: Number = serde_json::from_str("1").unwrap(); + assert_eq!(n, Number::PosInt(1)); + let n: Number = serde_json::from_str("0").unwrap(); + assert_eq!(n, Number::PosInt(0)); + let n: Number = serde_json::from_str("-1").unwrap(); + assert_eq!(n, Number::NegInt(-1)); + + assert_eq!("1.1", serde_json::to_string(&Number::Float(1.1)).unwrap()); + assert_eq!("1", serde_json::to_string(&Number::PosInt(1)).unwrap()); + assert_eq!("0", serde_json::to_string(&Number::PosInt(0)).unwrap()); + assert_eq!("-1", serde_json::to_string(&Number::NegInt(-1)).unwrap()); + } +} From f7715fbffd056f5688dfd3970a94dfbeb0c78df1 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 20 Apr 2023 23:07:46 +0000 Subject: [PATCH 003/312] update lib.rs --- rust-runtime/aws-smithy-types/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rust-runtime/aws-smithy-types/src/lib.rs b/rust-runtime/aws-smithy-types/src/lib.rs index 3bfd3033191..d7ec6337d39 100644 --- a/rust-runtime/aws-smithy-types/src/lib.rs +++ b/rust-runtime/aws-smithy-types/src/lib.rs @@ -28,5 +28,10 @@ pub mod timeout; pub use blob::Blob; pub use date_time::DateTime; pub use document::Document; +// TODO(deprecated): Remove deprecated re-export +/// Use [error::ErrorMetadata] instead. +#[deprecated( + note = "`aws_smithy_types::Error` has been renamed to `aws_smithy_types::error::ErrorMetadata`" +)] pub use error::ErrorMetadata as Error; pub use number::Number; From 8cf5e3ce573364cd0ab05020c682daf9d744f714 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 20 Apr 2023 23:08:07 +0000 Subject: [PATCH 004/312] remove unused imports --- rust-runtime/aws-smithy-types/src/lib.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/lib.rs b/rust-runtime/aws-smithy-types/src/lib.rs index d7ec6337d39..eba2a3a3aca 100644 --- a/rust-runtime/aws-smithy-types/src/lib.rs +++ b/rust-runtime/aws-smithy-types/src/lib.rs @@ -13,10 +13,6 @@ rust_2018_idioms, unreachable_pub )] - -use crate::error::{TryFromNumberError, TryFromNumberErrorKind}; -use std::collections::HashMap; - pub mod base64; pub mod date_time; pub mod endpoint; From eef5b35a22c4f3c70a7e2387c2cf129da637ef3f Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 21 Apr 2023 00:15:58 +0000 Subject: [PATCH 005/312] - add RUSTFLAGS --- buildSrc/src/main/kotlin/CodegenTestCommon.kt | 4 ++++ buildSrc/src/main/kotlin/RustBuildTool.kt | 1 + 2 files changed, 5 insertions(+) diff --git a/buildSrc/src/main/kotlin/CodegenTestCommon.kt b/buildSrc/src/main/kotlin/CodegenTestCommon.kt index 2173c237a64..e42d7e5ed2a 100644 --- a/buildSrc/src/main/kotlin/CodegenTestCommon.kt +++ b/buildSrc/src/main/kotlin/CodegenTestCommon.kt @@ -244,12 +244,14 @@ fun Project.registerCargoCommandsTasks( this.tasks.register(Cargo.CHECK.toString) { dependsOn(dependentTasks) workingDir(outputDir) + environment("RUSTFLAGS", "--cfg aws_sdk_unstable") commandLine("cargo", "check", "--lib", "--tests", "--benches", "--all-features") } this.tasks.register(Cargo.TEST.toString) { dependsOn(dependentTasks) workingDir(outputDir) + environment("RUSTFLAGS", "--cfg aws_sdk_unstable") commandLine("cargo", "test", "--all-features") } @@ -257,12 +259,14 @@ fun Project.registerCargoCommandsTasks( dependsOn(dependentTasks) workingDir(outputDir) environment("RUSTDOCFLAGS", defaultRustDocFlags) + environment("RUSTFLAGS", "--cfg aws_sdk_unstable") commandLine("cargo", "doc", "--no-deps", "--document-private-items") } this.tasks.register(Cargo.CLIPPY.toString) { dependsOn(dependentTasks) workingDir(outputDir) + environment("RUSTFLAGS", "--cfg aws_sdk_unstable") commandLine("cargo", "clippy") } } diff --git a/buildSrc/src/main/kotlin/RustBuildTool.kt b/buildSrc/src/main/kotlin/RustBuildTool.kt index 1e679956487..b8a1a15fb15 100644 --- a/buildSrc/src/main/kotlin/RustBuildTool.kt +++ b/buildSrc/src/main/kotlin/RustBuildTool.kt @@ -28,6 +28,7 @@ private fun runCli( } } .copyTo(action) + action.environment("RUSTFLAGS", "--cfg aws_sdk_unstable") action.execute() } } From 75269b35e0fcf9b7bbe49358934b350a162930b2 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 21 Apr 2023 00:38:04 +0000 Subject: [PATCH 006/312] merge codegen core code for RFC30 --- .../codegen/core/rustlang/CargoDependency.kt | 4 ++ .../rust/codegen/core/rustlang/RustType.kt | 20 ++++++++ .../rust/codegen/core/smithy/RuntimeType.kt | 5 ++ .../smithy/generators/BuilderGenerator.kt | 8 ++- .../smithy/generators/CargoTomlGenerator.kt | 11 +++- .../core/smithy/generators/EnumGenerator.kt | 5 +- .../smithy/generators/RenderSerdeAttribute.kt | 51 +++++++++++++++++++ .../smithy/generators/SensitiveWarning.kt | 20 ++++++++ .../smithy/generators/StructureGenerator.kt | 6 ++- .../core/smithy/generators/UnionGenerator.kt | 3 +- 10 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt create mode 100644 codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/SensitiveWarning.kt diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt index 2e372b49894..0ead4d6e7b7 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt @@ -16,6 +16,7 @@ import java.nio.file.Path sealed class DependencyScope { object Dev : DependencyScope() object Compile : DependencyScope() + object CfgUnstable : DependencyScope() object Build : DependencyScope() } @@ -277,5 +278,8 @@ data class CargoDependency( fun smithyRuntimeApi(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-runtime-api") fun smithyTypes(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-types") fun smithyXml(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-xml") + + // behind feature-gate + val Serde = CargoDependency("serde", CratesIo("1.0"), features = setOf("derive"), scope = DependencyScope.CfgUnstable) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index e4d27fe4516..e5bc8a6cb12 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -473,6 +473,23 @@ class Attribute(val inner: Writable) { } } + // These were supposed to be a part of companion object but we decided to move it out to here to avoid NPE + // You can find the discussion here. + // https://github.com/awslabs/smithy-rs/discussions/2248 + public fun SerdeSerialize(): Attribute { + return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-serialize")), derive(RuntimeType.SerdeSerialize))) + } + public fun SerdeDeserialize(): Attribute { + return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-deserialize")), derive(RuntimeType.SerdeDeserialize))) + } + public fun SerdeSkip(): Attribute { + return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))), serde("skip"))) + } + + public fun SerdeSerializeOrDeserialize(): Attribute { + return Attribute(cfg(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))))) + } + companion object { val AllowClippyBoxedLocal = Attribute(allow("clippy::boxed_local")) val AllowClippyLetAndReturn = Attribute(allow("clippy::let_and_return")) @@ -501,6 +518,7 @@ class Attribute(val inner: Writable) { val Test = Attribute("test") val TokioTest = Attribute(RuntimeType.Tokio.resolve("test").writable) + val AwsSdkUnstableAttribute = Attribute(cfg("aws_sdk_unstable")) /** * [non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute) @@ -529,10 +547,12 @@ class Attribute(val inner: Writable) { } fun all(vararg attrMacros: Writable): Writable = macroWithArgs("all", *attrMacros) + fun cfgAttr(vararg attrMacros: Writable): Writable = macroWithArgs("cfg_attr", *attrMacros) fun allow(lints: Collection): Writable = macroWithArgs("allow", *lints.toTypedArray()) fun allow(vararg lints: String): Writable = macroWithArgs("allow", *lints) fun deny(vararg lints: String): Writable = macroWithArgs("deny", *lints) + fun serde(vararg lints: String): Writable = macroWithArgs("serde", *lints) fun any(vararg attrMacros: Writable): Writable = macroWithArgs("any", *attrMacros) fun cfg(vararg attrMacros: Writable): Writable = macroWithArgs("cfg", *attrMacros) fun cfg(vararg attrMacros: String): Writable = macroWithArgs("cfg", *attrMacros) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt index b74fbf2b9a5..0d46d30bc23 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt @@ -247,6 +247,11 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) val ConstrainedTrait = RuntimeType("crate::constrained::Constrained", InlineDependency.constrained()) val MaybeConstrained = RuntimeType("crate::constrained::MaybeConstrained", InlineDependency.constrained()) + // serde types. Gated behind `CfgUnstable`. + val Serde = CargoDependency.Serde.toType() + val SerdeSerialize = Serde.resolve("Serialize") + val SerdeDeserialize = Serde.resolve("Deserialize") + // smithy runtime types fun smithyAsync(runtimeConfig: RuntimeConfig) = CargoDependency.smithyAsync(runtimeConfig).toType() fun smithyChecksums(runtimeConfig: RuntimeConfig) = CargoDependency.smithyChecksums(runtimeConfig).toType() diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt index 16cb28b8032..743536c5133 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt @@ -4,7 +4,6 @@ */ package software.amazon.smithy.rust.codegen.core.smithy.generators - import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.codegen.core.SymbolProvider import software.amazon.smithy.model.Model @@ -24,6 +23,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.documentShape import software.amazon.smithy.rust.codegen.core.rustlang.render import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock +import software.amazon.smithy.rust.codegen.core.rustlang.rustInline import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.stripOuter import software.amazon.smithy.rust.codegen.core.rustlang.withBlock @@ -41,6 +41,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.expectRustMetadata import software.amazon.smithy.rust.codegen.core.smithy.isOptional import software.amazon.smithy.rust.codegen.core.smithy.makeOptional import software.amazon.smithy.rust.codegen.core.smithy.rustType +import software.amazon.smithy.rust.codegen.core.smithy.shape import software.amazon.smithy.rust.codegen.core.smithy.traits.SyntheticInputTrait import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.hasTrait @@ -213,11 +214,16 @@ class BuilderGenerator( writer.docs("A builder for #D.", structureSymbol) metadata.additionalAttributes.render(writer) Attribute(derive(builderDerives)).render(writer) + RenderSerdeAttribute.forBuilders(writer, shape, model) + SensitiveWarning.addDoc(writer, shape) writer.rustBlock("pub struct $builderName") { + // add serde for (member in members) { val memberName = symbolProvider.toMemberName(member) // All fields in the builder are optional. val memberSymbol = symbolProvider.toSymbol(member).makeOptional() + SensitiveWarning.addDoc(writer, member) + RenderSerdeAttribute.skipIfStream(writer, member, model) renderBuilderMember(this, memberName, memberSymbol) } writeCustomizations(customizations, BuilderSection.AdditionalFields(shape)) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/CargoTomlGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/CargoTomlGenerator.kt index 86c76c521a0..fec774facfa 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/CargoTomlGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/CargoTomlGenerator.kt @@ -76,9 +76,18 @@ class CargoTomlGenerator( .associate { it.name to it.toMap() }, "dev-dependencies" to dependencies.filter { it.scope == DependencyScope.Dev } .associate { it.name to it.toMap() }, + "target.'cfg(aws_sdk_unstable)'.dependencies" to dependencies.filter { + it.scope == DependencyScope.CfgUnstable + } + .associate { it.name to it.toMap() }, "features" to cargoFeatures.toMap(), ).deepMergeWith(manifestCustomizations) - writer.writeWithNoFormatting(TomlWriter().write(cargoToml)) + // NOTE: without this it will produce ["target.'cfg(aws_sdk_unstable)'.dependencies"] + // In JSON, this is an equivalent of: {"target.'cfg(aws_sdk_unstable)'.dependencies" : ...} + // To make it work, it has to be: {"target": {'cfg(aws_sdk_unstable)': {"dependencies": ...}}} + // This piece of code fixes it. + var tomlString = TomlWriter().write(cargoToml).replace("\"target.'cfg(aws_sdk_unstable)'.dependencies\"", "target.'cfg(aws_sdk_unstable)'.dependencies") + writer.writeWithNoFormatting(tomlString) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt index 379a6982da5..4ca9cd26003 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt @@ -4,7 +4,6 @@ */ package software.amazon.smithy.rust.codegen.core.smithy.generators - import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.MemberShape @@ -222,6 +221,8 @@ open class EnumGenerator( private fun RustWriter.renderUnnamedEnum() { documentShape(shape, model) deprecatedShape(shape) + RenderSerdeAttribute.writeAttributes(this) + SensitiveWarning.addDoc(this, shape) context.enumMeta.render(this) rust("struct ${context.enumName}(String);") implBlock( @@ -257,6 +258,8 @@ open class EnumGenerator( ) deprecatedShape(shape) + RenderSerdeAttribute.writeAttributes(this) + SensitiveWarning.addDoc(this, shape) context.enumMeta.render(this) rustBlock("enum ${context.enumName}") { context.sortedMembers.forEach { member -> member.render(this) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt new file mode 100644 index 00000000000..8d5ec34be4f --- /dev/null +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -0,0 +1,51 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.core.smithy.generators + +import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.MemberShape +import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute +import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.core.rustlang.raw +import software.amazon.smithy.rust.codegen.core.util.isEventStream +import software.amazon.smithy.rust.codegen.core.util.isStreaming + +// Part of RFC30 +public object RenderSerdeAttribute { + public fun forStructureShape(writer: RustWriter, shape: StructureShape, model: Model) { + if (shape.members().none { it.isEventStream(model) }) { + writeAttributes(writer) + } + } + + public fun forBuilders(writer: RustWriter, shape: StructureShape, model: Model) { + if (shape.members().none { it.isEventStream(model) }) { + writeAttributes(writer) + } + } + + public fun skipIfStream(writer: RustWriter, member: MemberShape, model: Model) { + if (member.isEventStream(model)) { + return + } + if (member.isStreaming(model)) { + Attribute("").SerdeSkip().render(writer) + } + } + + public fun importSerde(writer: RustWriter) { + // we need this for skip serde to work + Attribute.AllowUnusedImports.render(writer) + Attribute("").SerdeSerializeOrDeserialize().render(writer) + writer.raw("use serde;") + } + + public fun writeAttributes(writer: RustWriter) { + Attribute("").SerdeSerialize().render(writer) + Attribute("").SerdeDeserialize().render(writer) + } +} diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/SensitiveWarning.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/SensitiveWarning.kt new file mode 100644 index 00000000000..59483329b88 --- /dev/null +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/SensitiveWarning.kt @@ -0,0 +1,20 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.core.smithy.generators + +import software.amazon.smithy.model.shapes.Shape +import software.amazon.smithy.model.traits.SensitiveTrait +import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.core.util.hasTrait + +object SensitiveWarning { + private const val warningMessage = "/// This data may contain sensitive information; It will not be obscured when serialized.\n" + fun addDoc(writer: RustWriter, shape: T) { + if (shape.hasTrait()) { + writer.writeInline(warningMessage) + } + } +} diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt index 80d89e341ff..e1896a7b947 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt @@ -4,7 +4,6 @@ */ package software.amazon.smithy.rust.codegen.core.smithy.generators - import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.MemberShape @@ -161,14 +160,19 @@ open class StructureGenerator( } open fun renderStructure() { + RenderSerdeAttribute.importSerde(writer) val symbol = symbolProvider.toSymbol(shape) val containerMeta = symbol.expectRustMetadata() writer.documentShape(shape, model) writer.deprecatedShape(shape) + RenderSerdeAttribute.forStructureShape(writer, shape, model) + SensitiveWarning.addDoc(writer, shape) containerMeta.render(writer) writer.rustBlock("struct $name ${lifetimeDeclaration()}") { writer.forEachMember(members) { member, memberName, memberSymbol -> + SensitiveWarning.addDoc(writer, shape) + RenderSerdeAttribute.skipIfStream(writer, member, model) renderStructureMember(writer, member, memberName, memberSymbol) } writeCustomizations(customizations, StructureSection.AdditionalFields(shape)) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt index 39b191ba965..170729db53d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt @@ -4,7 +4,6 @@ */ package software.amazon.smithy.rust.codegen.core.smithy.generators - import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.codegen.core.SymbolProvider import software.amazon.smithy.model.Model @@ -63,7 +62,7 @@ open class UnionGenerator( open fun render() { writer.documentShape(shape, model) writer.deprecatedShape(shape) - + RenderSerdeAttribute.writeAttributes(writer) val containerMeta = unionSymbol.expectRustMetadata() containerMeta.render(writer) From f30828eb0c77c10634fbb577f40ff8745b5908b5 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 21 Apr 2023 00:21:24 +0000 Subject: [PATCH 007/312] RFC30 update --- .../client/smithy/RustClientCodegenPlugin.kt | 2 + .../client/smithy/customize/SerdeDecorator.kt | 28 +++++++++++++ .../smithy/generators/ClientEnumGenerator.kt | 3 ++ .../client/FluentClientGenerator.kt | 39 +++++++++++++++++++ .../smithy/generators/BuilderGenerator.kt | 1 - 5 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt index f8852a700d5..5f900a8e71a 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt @@ -15,6 +15,7 @@ import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegen import software.amazon.smithy.rust.codegen.client.smithy.customize.CombinedClientCodegenDecorator import software.amazon.smithy.rust.codegen.client.smithy.customize.NoOpEventStreamSigningDecorator import software.amazon.smithy.rust.codegen.client.smithy.customize.RequiredCustomizations +import software.amazon.smithy.rust.codegen.client.smithy.customize.SerdeDecorator import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointsDecorator import software.amazon.smithy.rust.codegen.client.smithy.generators.client.FluentClientDecorator import software.amazon.smithy.rust.codegen.client.testutil.ClientDecoratableBuildPlugin @@ -54,6 +55,7 @@ class RustClientCodegenPlugin : ClientDecoratableBuildPlugin() { val codegenDecorator = CombinedClientCodegenDecorator.fromClasspath( context, + SerdeDecorator(), ClientCustomizations(), RequiredCustomizations(), FluentClientDecorator(), diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt new file mode 100644 index 00000000000..56a777b4708 --- /dev/null +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -0,0 +1,28 @@ +/* +* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +* SPDX-License-Identifier: Apache-2.0 +*/ + +package software.amazon.smithy.rust.codegen.client.smithy.customize + +import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext +import software.amazon.smithy.rust.codegen.core.rustlang.Feature +import software.amazon.smithy.rust.codegen.core.smithy.RustCrate + +/** + * This class, + * - Adds serde as a dependency + * + */ +class SerdeDecorator : ClientCodegenDecorator { + override val name: String = "SerdeDecorator" + override val order: Byte = -1 + + override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + fun _feature(feature_name: String, crate_name: String): Feature { + return Feature(feature_name, false, listOf(crate_name + "/" + feature_name)) + } + rustCrate.mergeFeature(_feature("serde-serialize", "aws-smithy-types")) + rustCrate.mergeFeature(_feature("serde-deserialize", "aws-smithy-types")) + } +} diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt index d1b87591cb4..b107955915b 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt @@ -21,6 +21,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.EnumGenerator import software.amazon.smithy.rust.codegen.core.smithy.generators.EnumGeneratorContext import software.amazon.smithy.rust.codegen.core.smithy.generators.EnumMemberModel import software.amazon.smithy.rust.codegen.core.smithy.generators.EnumType +import software.amazon.smithy.rust.codegen.core.smithy.generators.RenderSerdeAttribute import software.amazon.smithy.rust.codegen.core.util.dq /** Infallible enums have an `Unknown` variant and can't fail to parse */ @@ -97,6 +98,8 @@ data class InfallibleEnumType( part of the enums that are public interface. """.trimIndent(), ) + + RenderSerdeAttribute.writeAttributes(this) context.enumMeta.render(this) rust("struct $UnknownVariantValue(pub(crate) String);") rustBlock("impl $UnknownVariantValue") { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 6669ee04f1a..572faa75495 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -262,6 +262,8 @@ class FluentClientGenerator( ) { val outputType = symbolProvider.toSymbol(operation.outputShape(model)) val errorType = symbolProvider.symbolForOperationError(operation) + val inputBuilderType = symbolProvider.symbolForBuilder(input) + val fnName = clientOperationFnName(operation, symbolProvider) // Have to use fully-qualified result here or else it could conflict with an op named Result rustTemplate( @@ -301,6 +303,7 @@ class FluentClientGenerator( .map_err(#{SdkError}::construction_failure)?; self.handle.client.call(op).await } + """, "CustomizableOperation" to ClientRustModule.Client.customize.toType() .resolve("CustomizableOperation"), @@ -317,6 +320,42 @@ class FluentClientGenerator( ), ) if (codegenContext.settings.codegenConfig.enableNewSmithyRuntime) { + // this fixes this error + // error[E0592]: duplicate definitions with name `set_fields` + // --> sdk/connectcases/src/operation/update_case/builders.rs:115:5 + // | + // 78 | / pub fn set_fields( + // 79 | | mut self, + // 80 | | data: crate::operation::update_case::builders::UpdateCaseInputBuilder, + // 81 | | ) -> Self { + // | |_____________- other definition for `set_fields` + // ... + // 115 | / pub fn set_fields( + // 116 | | mut self, + // 117 | | input: std::option::Option>, + // 118 | | ) -> Self { + // | |_____________^ duplicate definitions for `set_fields` + if (inputBuilderType.toString().endsWith("Builder")) { + rustTemplate( + """ + ##[#{AwsSdkUnstableAttribute}] + /// This function replaces the parameter with new one. + /// It is useful when you want to replace the existing data with de-serialized data. + /// ```compile_fail + /// let result_future = async { + /// let deserialized_parameters: $inputBuilderType = serde_json::from_str(&json_string).unwrap(); + /// client.$fnName().set_fields(&deserialized_parameters).send().await + /// }; + /// ``` + pub fn set_fields(mut self, data: $inputBuilderType) -> Self { + self.inner = data; + self + } + """, + "AwsSdkUnstableAttribute" to Attribute.AwsSdkUnstableAttribute.inner, + ) + } + rustTemplate( """ // TODO(enableNewSmithyRuntime): Replace `send` with `send_v2` diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt index 743536c5133..5f82bb8a589 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt @@ -23,7 +23,6 @@ import software.amazon.smithy.rust.codegen.core.rustlang.documentShape import software.amazon.smithy.rust.codegen.core.rustlang.render import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock -import software.amazon.smithy.rust.codegen.core.rustlang.rustInline import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.stripOuter import software.amazon.smithy.rust.codegen.core.rustlang.withBlock From c203d2e3eed2b989281346455757a467329fbfa2 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 21 Apr 2023 01:40:07 +0000 Subject: [PATCH 008/312] FIX --- rust-runtime/aws-smithy-types/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rust-runtime/aws-smithy-types/src/lib.rs b/rust-runtime/aws-smithy-types/src/lib.rs index eba2a3a3aca..5042988f603 100644 --- a/rust-runtime/aws-smithy-types/src/lib.rs +++ b/rust-runtime/aws-smithy-types/src/lib.rs @@ -21,6 +21,10 @@ pub mod primitive; pub mod retry; pub mod timeout; +mod blob; +mod number; +mod document; + pub use blob::Blob; pub use date_time::DateTime; pub use document::Document; From 70fa84f3b94e3e6b7129915d53c87fe252e676bf Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 21 Apr 2023 01:58:34 +0000 Subject: [PATCH 009/312] apply pre-commit add features to aws-smithy-types --- .../client/FluentClientGenerator.kt | 28 +++++++++---------- rust-runtime/aws-smithy-types/Cargo.toml | 5 ++++ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index a30c31ef32e..95288e07012 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -358,20 +358,20 @@ class FluentClientGenerator( if (inputBuilderType.toString().endsWith("Builder")) { rustTemplate( """ - ##[#{AwsSdkUnstableAttribute}] - /// This function replaces the parameter with new one. - /// It is useful when you want to replace the existing data with de-serialized data. - /// ```compile_fail - /// let result_future = async { - /// let deserialized_parameters: $inputBuilderType = serde_json::from_str(&json_string).unwrap(); - /// client.$fnName().set_fields(&deserialized_parameters).send().await - /// }; - /// ``` - pub fn set_fields(mut self, data: $inputBuilderType) -> Self { - self.inner = data; - self - } - """, + ##[#{AwsSdkUnstableAttribute}] + /// This function replaces the parameter with new one. + /// It is useful when you want to replace the existing data with de-serialized data. + /// ```compile_fail + /// let result_future = async { + /// let deserialized_parameters: $inputBuilderType = serde_json::from_str(&json_string).unwrap(); + /// client.$fnName().set_fields(&deserialized_parameters).send().await + /// }; + /// ``` + pub fn set_fields(mut self, data: $inputBuilderType) -> Self { + self.inner = data; + self + } + """, "AwsSdkUnstableAttribute" to Attribute.AwsSdkUnstableAttribute.inner, ) } diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index a0a62f4bf4b..e160a1837ff 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -18,6 +18,7 @@ base64-simd = "0.8" [target."cfg(aws_sdk_unstable)".dependencies.serde] version = "1" features = ["derive"] +optional = true [dev-dependencies] base64 = "0.13.0" @@ -37,3 +38,7 @@ rustdoc-args = ["--cfg", "docsrs"] [[bench]] name = "base64" harness = false + +[features] +serde-serialize = [] +serde-deserialize = [] \ No newline at end of file From 7acc75e6c83ef2e08c6c50c0bd5dc69ad13b0281 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 21 Apr 2023 02:10:05 +0000 Subject: [PATCH 010/312] add de/ser to date time --- rust-runtime/aws-smithy-types/Cargo.toml | 2 +- .../aws-smithy-types/src/date_time/de.rs | 110 ++++++++++++++++++ .../aws-smithy-types/src/date_time/ser.rs | 26 +++++ rust-runtime/aws-smithy-types/src/lib.rs | 2 +- 4 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 rust-runtime/aws-smithy-types/src/date_time/de.rs create mode 100644 rust-runtime/aws-smithy-types/src/date_time/ser.rs diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index e160a1837ff..8c694fbefd9 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -41,4 +41,4 @@ harness = false [features] serde-serialize = [] -serde-deserialize = [] \ No newline at end of file +serde-deserialize = [] diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs new file mode 100644 index 00000000000..6f346ea8dee --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -0,0 +1,110 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use super::*; +use serde::de::Visitor; +use serde::Deserialize; + +struct DateTimeVisitor; + +enum VisitorState { + Second, + SubsecondNanos, + Unexpected, +} + +impl VisitorState { + const UNEXPECTED_VISITOR_STATE: &'static str = "Unexpected state. This happens when visitor tries to parse something after finished parsing the `subsec_nanos`."; +} + +struct NonHumanReadableDateTimeVisitor { + state: VisitorState, + seconds: i64, + subsecond_nanos: u32, +} + +fn fail(err_message: M) -> Result +where + M: std::fmt::Display, + E: serde::de::Error, +{ + Err(E::custom(err_message)) +} + +impl<'de> Visitor<'de> for DateTimeVisitor { + type Value = DateTime; + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("expected RFC-3339 Date Time") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + match DateTime::from_str(v, Format::DateTime) { + Ok(e) => Ok(e), + Err(e) => fail(e), + } + } +} + +impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { + type Value = Self; + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("expected (i64, u32)") + } + + fn visit_i64(mut self, v: i64) -> Result + where + E: serde::de::Error, + { + match self.state { + VisitorState::Unexpected => fail(VisitorState::UNEXPECTED_VISITOR_STATE), + VisitorState::Second => { + self.seconds = v; + self.state = VisitorState::SubsecondNanos; + Ok(self) + } + _ => fail("`seconds` value must be i64"), + } + } + + fn visit_u32(mut self, v: u32) -> Result + where + E: serde::de::Error, + { + match self.state { + VisitorState::Unexpected => fail(VisitorState::UNEXPECTED_VISITOR_STATE), + VisitorState::SubsecondNanos => { + self.subsecond_nanos = v; + self.state = VisitorState::Unexpected; + Ok(self) + } + _ => fail("`subsecond_nanos` value must be u32"), + } + } +} + +impl<'de> Deserialize<'de> for DateTime { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + if deserializer.is_human_readable() { + deserializer.deserialize_str(DateTimeVisitor) + } else { + let visitor = NonHumanReadableDateTimeVisitor { + state: VisitorState::Second, + seconds: 0, + subsecond_nanos: 0, + }; + let visitor = deserializer.deserialize_tuple(2, visitor)?; + Ok(DateTime { + seconds: visitor.seconds, + subsecond_nanos: visitor.subsecond_nanos, + }) + } + } +} diff --git a/rust-runtime/aws-smithy-types/src/date_time/ser.rs b/rust-runtime/aws-smithy-types/src/date_time/ser.rs new file mode 100644 index 00000000000..4dc39292ec0 --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/date_time/ser.rs @@ -0,0 +1,26 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use super::*; +use serde::ser::SerializeTuple; + +impl serde::Serialize for DateTime { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + if serializer.is_human_readable() { + match self.fmt(Format::DateTime) { + Ok(val) => serializer.serialize_str(&val), + Err(e) => Err(serde::ser::Error::custom(e)), + } + } else { + let mut tup_ser = serializer.serialize_tuple(2)?; + tup_ser.serialize_element(&self.seconds)?; + tup_ser.serialize_element(&self.subsecond_nanos)?; + tup_ser.end() + } + } +} diff --git a/rust-runtime/aws-smithy-types/src/lib.rs b/rust-runtime/aws-smithy-types/src/lib.rs index 5042988f603..ffa1c86ea58 100644 --- a/rust-runtime/aws-smithy-types/src/lib.rs +++ b/rust-runtime/aws-smithy-types/src/lib.rs @@ -22,8 +22,8 @@ pub mod retry; pub mod timeout; mod blob; -mod number; mod document; +mod number; pub use blob::Blob; pub use date_time::DateTime; From d371781522d40e8c2337bae3191f9ec472e4147e Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 21 Apr 2023 02:29:06 +0000 Subject: [PATCH 011/312] add serialize_document.json --- .../test_data/serialize_document.json | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 rust-runtime/aws-smithy-types/test_data/serialize_document.json diff --git a/rust-runtime/aws-smithy-types/test_data/serialize_document.json b/rust-runtime/aws-smithy-types/test_data/serialize_document.json new file mode 100644 index 00000000000..315acc50f6e --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/serialize_document.json @@ -0,0 +1,43 @@ +{ + "null": null, + "true": true, + "pos_int": 1, + "false": false, + "map": { + "array": [ + { + "pos_int": 1, + "float": 0.30000000000000004, + "neg_int": -1, + "hello": "world", + "false": false, + "true": true + }, + "hello-world", + true, + false + ], + "pos_int": 1, + "float": 0.30000000000000004, + "neg_int": -1, + "hello": "world", + "false": false, + "true": true + }, + "float": 0.30000000000000004, + "neg_int": -1, + "hello": "world", + "array": [ + { + "pos_int": 1, + "float": 0.30000000000000004, + "neg_int": -1, + "hello": "world", + "false": false, + "true": true + }, + "hello-world", + true, + false + ] +} \ No newline at end of file From 2546bf5523600837b5217060020bb410988f33ca Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 21 Apr 2023 02:39:33 +0000 Subject: [PATCH 012/312] update CHANGELOG.next.toml --- CHANGELOG.next.toml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index b9ca3ff1be1..1672dc09624 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -144,3 +144,41 @@ message = "Add a sensitive method to `ParseHttpResponse`. When this returns true author = "rcoh" references = ["smithy-rs#2603"] meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client" } + +[[smithy-rs]] +message = """ +List of changes: + +- rust runtime + - Implements serde support to `number`, `blob`, `document`, `date time` and `error type`. + - `&'static str` on Error type is replaced with `Cow` to allow `serde` support. No breaking changes are introduced. + +- buildSrc + - add rustflag to enable feature gated features + +- Core codegen code + - Add sensitive warning + - Add `serde` attributes + - Import `serde` crate to enable `serde(skip)` on some namespaces + - Add `serde` crate behind unstable feature gate on `Cargo.toml` + +- Client codegen code + - add `serde` as dependency behind feature gate +""" +author = "thomas-k-cameron" +references = ["smithy-rs#2615"] +meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client" } + +[[aws-sdk-rust]] +message = """ +- SDK + - Implements `serde` support as described in RFC 30 + +- rust runtime + - Implements serde support to `number`, `blob`, `document`, `date time` and `error type`. + - `&'static str` on Error type is replaced with `Cow` to allow `serde` support. No breaking changes are introduced. + +""" +author = "thomas-k-cameron" +references = ["smithy-rs#2615"] +meta = { "breaking" = false, "tada" = false, "bug" = false } From 924cec22b28d3d665a721320aef951989c7dc755 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 21 Apr 2023 02:42:15 +0000 Subject: [PATCH 013/312] FIX: import serde --- .../core/smithy/generators/RenderSerdeAttribute.kt | 1 + rust-runtime/aws-smithy-types/Cargo.toml | 2 +- rust-runtime/aws-smithy-types/src/blob.rs | 2 +- rust-runtime/aws-smithy-types/src/date_time/ser.rs | 3 ++- rust-runtime/aws-smithy-types/src/document.rs | 8 +++++++- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index 8d5ec34be4f..354e509e00d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -18,6 +18,7 @@ import software.amazon.smithy.rust.codegen.core.util.isStreaming public object RenderSerdeAttribute { public fun forStructureShape(writer: RustWriter, shape: StructureShape, model: Model) { if (shape.members().none { it.isEventStream(model) }) { + importSerde(writer) writeAttributes(writer) } } diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 8c694fbefd9..b2992210abd 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -18,7 +18,6 @@ base64-simd = "0.8" [target."cfg(aws_sdk_unstable)".dependencies.serde] version = "1" features = ["derive"] -optional = true [dev-dependencies] base64 = "0.13.0" @@ -28,6 +27,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" criterion = "0.4" rand = "0.8.4" +ciborium = "0.2.0" [package.metadata.docs.rs] all-features = true diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 0364727d4f0..f4f1da94d8d 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -70,7 +70,7 @@ impl<'de> Visitor<'de> for HumanReadableBlobVisitor { { match base64::decode(v) { Ok(inner) => Ok(Blob { inner }), - Err(e) => Err(serde::de::Error::custom(e)), + Err(e) => Err(E::custom(e)), } } } diff --git a/rust-runtime/aws-smithy-types/src/date_time/ser.rs b/rust-runtime/aws-smithy-types/src/date_time/ser.rs index 4dc39292ec0..bd8ed29a049 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/ser.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/ser.rs @@ -11,10 +11,11 @@ impl serde::Serialize for DateTime { where S: serde::Serializer, { + use serde::ser::Error; if serializer.is_human_readable() { match self.fmt(Format::DateTime) { Ok(val) => serializer.serialize_str(&val), - Err(e) => Err(serde::ser::Error::custom(e)), + Err(e) => Err(Error::custom(e)), } } else { let mut tup_ser = serializer.serialize_tuple(2)?; diff --git a/rust-runtime/aws-smithy-types/src/document.rs b/rust-runtime/aws-smithy-types/src/document.rs index 8cbae5b3800..c414af20f01 100644 --- a/rust-runtime/aws-smithy-types/src/document.rs +++ b/rust-runtime/aws-smithy-types/src/document.rs @@ -5,7 +5,13 @@ use crate::Number; use std::collections::HashMap; - +#[cfg( + any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") + ) +)] +use serde; /* ANCHOR: document */ /// Document Type From c12e9affff1b4bf3b188f6a05b1d227c6782f843 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 21 Apr 2023 03:04:31 +0000 Subject: [PATCH 014/312] pre-commit --- CHANGELOG.next.toml | 4 ++-- rust-runtime/aws-smithy-types/src/document.rs | 12 +++++------- .../test_data/serialize_document.json | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 1672dc09624..85454148c1e 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -158,7 +158,7 @@ List of changes: - Core codegen code - Add sensitive warning - - Add `serde` attributes + - Add `serde` attributes - Import `serde` crate to enable `serde(skip)` on some namespaces - Add `serde` crate behind unstable feature gate on `Cargo.toml` @@ -173,7 +173,7 @@ meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client" message = """ - SDK - Implements `serde` support as described in RFC 30 - + - rust runtime - Implements serde support to `number`, `blob`, `document`, `date time` and `error type`. - `&'static str` on Error type is replaced with `Cow` to allow `serde` support. No breaking changes are introduced. diff --git a/rust-runtime/aws-smithy-types/src/document.rs b/rust-runtime/aws-smithy-types/src/document.rs index c414af20f01..9515d26c2d1 100644 --- a/rust-runtime/aws-smithy-types/src/document.rs +++ b/rust-runtime/aws-smithy-types/src/document.rs @@ -4,14 +4,12 @@ */ use crate::Number; -use std::collections::HashMap; -#[cfg( - any( - all(aws_sdk_unstable, feature = "serde-deserialize"), - all(aws_sdk_unstable, feature = "serde-serialize") - ) -)] +#[cfg(any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") +))] use serde; +use std::collections::HashMap; /* ANCHOR: document */ /// Document Type diff --git a/rust-runtime/aws-smithy-types/test_data/serialize_document.json b/rust-runtime/aws-smithy-types/test_data/serialize_document.json index 315acc50f6e..dcbac2986ac 100644 --- a/rust-runtime/aws-smithy-types/test_data/serialize_document.json +++ b/rust-runtime/aws-smithy-types/test_data/serialize_document.json @@ -40,4 +40,4 @@ true, false ] -} \ No newline at end of file +} From fd740293653570f73408352dbe1f07ea153d244a Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 21 Apr 2023 03:14:18 +0000 Subject: [PATCH 015/312] serde import FIX --- .../rust/codegen/core/smithy/generators/StructureGenerator.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt index e1896a7b947..dbde047d51c 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt @@ -160,7 +160,6 @@ open class StructureGenerator( } open fun renderStructure() { - RenderSerdeAttribute.importSerde(writer) val symbol = symbolProvider.toSymbol(shape) val containerMeta = symbol.expectRustMetadata() writer.documentShape(shape, model) From 42ba8c705fd8b4fc89f21e3cd216ab9da7c81ce3 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 21 Apr 2023 03:48:13 +0000 Subject: [PATCH 016/312] FIX missing docs error --- .../rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt | 1 - .../rust/codegen/core/smithy/generators/StructureGenerator.kt | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index 354e509e00d..8d5ec34be4f 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -18,7 +18,6 @@ import software.amazon.smithy.rust.codegen.core.util.isStreaming public object RenderSerdeAttribute { public fun forStructureShape(writer: RustWriter, shape: StructureShape, model: Model) { if (shape.members().none { it.isEventStream(model) }) { - importSerde(writer) writeAttributes(writer) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt index dbde047d51c..987cd04078a 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt @@ -160,6 +160,8 @@ open class StructureGenerator( } open fun renderStructure() { + RenderSerdeAttribute.importSerde(writer) + val symbol = symbolProvider.toSymbol(shape) val containerMeta = symbol.expectRustMetadata() writer.documentShape(shape, model) From 6c4e380a375ec16ed9b5b4aa6f388ff7d0b1ca8d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 21 Apr 2023 05:32:05 +0000 Subject: [PATCH 017/312] trying to fix pyo3 error... --- .../rust/codegen/core/smithy/generators/BuilderGenerator.kt | 2 +- .../rust/codegen/core/smithy/generators/StructureGenerator.kt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt index 5f82bb8a589..0be116db0a8 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt @@ -221,8 +221,8 @@ class BuilderGenerator( val memberName = symbolProvider.toMemberName(member) // All fields in the builder are optional. val memberSymbol = symbolProvider.toSymbol(member).makeOptional() - SensitiveWarning.addDoc(writer, member) RenderSerdeAttribute.skipIfStream(writer, member, model) + SensitiveWarning.addDoc(writer, member) renderBuilderMember(this, memberName, memberSymbol) } writeCustomizations(customizations, BuilderSection.AdditionalFields(shape)) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt index 987cd04078a..5e3e0a2491f 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt @@ -160,8 +160,6 @@ open class StructureGenerator( } open fun renderStructure() { - RenderSerdeAttribute.importSerde(writer) - val symbol = symbolProvider.toSymbol(shape) val containerMeta = symbol.expectRustMetadata() writer.documentShape(shape, model) @@ -179,6 +177,7 @@ open class StructureGenerator( writeCustomizations(customizations, StructureSection.AdditionalFields(shape)) } + RenderSerdeAttribute.importSerde(writer) renderStructureImpl() if (!containerMeta.hasDebugDerive()) { renderDebugImpl() From e274f1b36276ca3c9b5687d1ae4ee28071dd6748 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 21 Apr 2023 06:38:26 +0000 Subject: [PATCH 018/312] fix unicode parse error --- aws/rust-runtime/aws-credential-types/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/rust-runtime/aws-credential-types/Cargo.toml b/aws/rust-runtime/aws-credential-types/Cargo.toml index 8fad933c2aa..3783cdcc984 100644 --- a/aws/rust-runtime/aws-credential-types/Cargo.toml +++ b/aws/rust-runtime/aws-credential-types/Cargo.toml @@ -14,6 +14,7 @@ test-util = [] [dependencies] aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async" } aws-smithy-types = { path = "../../../rust-runtime/aws-smithy-types" } +regex = { version = "1", features = ["unicode-case"] } fastrand = "1.4.0" tokio = { version = "1.23.1", features = ["sync"] } tracing = "0.1" From 10d9c9a31e877619f12105944e889fa2c7a4da1f Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 21 Apr 2023 08:16:58 +0000 Subject: [PATCH 019/312] fix udeps error --- aws/rust-runtime/aws-credential-types/Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aws/rust-runtime/aws-credential-types/Cargo.toml b/aws/rust-runtime/aws-credential-types/Cargo.toml index 3783cdcc984..66689bb8b19 100644 --- a/aws/rust-runtime/aws-credential-types/Cargo.toml +++ b/aws/rust-runtime/aws-credential-types/Cargo.toml @@ -6,7 +6,8 @@ description = "Types for AWS SDK credentials." edition = "2021" license = "Apache-2.0" repository = "https://github.com/awslabs/smithy-rs" - +[package.metadata.cargo-udeps] +ignore = true [features] hardcoded-credentials = [] test-util = [] From 31780e79aa567a1cefd924869363e03db785641a Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 21 Apr 2023 08:39:10 +0000 Subject: [PATCH 020/312] meta data serde test --- .../aws-credential-types/Cargo.toml | 6 ++- .../aws-smithy-types/src/error/metadata.rs | 48 +++++++++++++++++++ .../test_data/error_meta_data.json | 7 +++ .../test_data/error_meta_data_empty.json | 5 ++ 4 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 rust-runtime/aws-smithy-types/test_data/error_meta_data.json create mode 100644 rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json diff --git a/aws/rust-runtime/aws-credential-types/Cargo.toml b/aws/rust-runtime/aws-credential-types/Cargo.toml index 66689bb8b19..2568a59fd17 100644 --- a/aws/rust-runtime/aws-credential-types/Cargo.toml +++ b/aws/rust-runtime/aws-credential-types/Cargo.toml @@ -6,8 +6,10 @@ description = "Types for AWS SDK credentials." edition = "2021" license = "Apache-2.0" repository = "https://github.com/awslabs/smithy-rs" -[package.metadata.cargo-udeps] -ignore = true +[package.metadata.cargo-udeps.ignore] +normal = ["regex"] +development = ["regex"] +build = ["regex"] [features] hardcoded-credentials = [] test-util = [] diff --git a/rust-runtime/aws-smithy-types/src/error/metadata.rs b/rust-runtime/aws-smithy-types/src/error/metadata.rs index 9036dc94ec8..004b7ee81ac 100644 --- a/rust-runtime/aws-smithy-types/src/error/metadata.rs +++ b/rust-runtime/aws-smithy-types/src/error/metadata.rs @@ -56,8 +56,23 @@ pub struct ErrorMetadata { } /// Builder for [`ErrorMetadata`]. +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-serialize"), + derive(serde::Serialize) +)] +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-deserialize"), + derive(serde::Deserialize) +)] #[derive(Debug, Default)] pub struct Builder { + #[cfg_attr( + any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") + ), + serde(flatten) + )] inner: ErrorMetadata, } @@ -173,3 +188,36 @@ impl fmt::Display for ErrorMetadata { } impl std::error::Error for ErrorMetadata {} + +#[cfg(all( + test, + any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") + ) +))] +mod test { + use super::*; + + #[test] + /// tests de/ser on ErrorMetaData. + fn test_error_meta_data() { + let mut data = Builder::default() + .code("code") + .message("message") + .custom("hello", "world"); + let ok = serde_json::to_string_pretty(&EMPTY_ERROR_METADATA).unwrap(); + assert_eq!( + &ok, + include_str!("../../test-data/error_meta_data_empty.json") + ); + assert_eq!( + serde_json::from_str(include_str!("../../test-data/error_meta_data.json")).unwrap(), + &data + ); + assert_eq!( + serde_json::from_str(include_str!("../../test-data/error_meta_data.json")).unwrap(), + data.build() + ); + } +} diff --git a/rust-runtime/aws-smithy-types/test_data/error_meta_data.json b/rust-runtime/aws-smithy-types/test_data/error_meta_data.json new file mode 100644 index 00000000000..db7067d86e4 --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/error_meta_data.json @@ -0,0 +1,7 @@ +{ + "code": "code", + "message": "message", + "extras": { + "hello": "world" + } +} diff --git a/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json b/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json new file mode 100644 index 00000000000..41165f4a49c --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json @@ -0,0 +1,5 @@ +{ + "code": null, + "message": null, + "extras": null +} From b8bc71dbb354fc0362b9b45c74f2ddd388c06e1f Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 21 Apr 2023 10:08:32 +0000 Subject: [PATCH 021/312] add description on changelog --- CHANGELOG.next.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 85454148c1e..a1831ecd604 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -147,8 +147,6 @@ meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client" [[smithy-rs]] message = """ -List of changes: - - rust runtime - Implements serde support to `number`, `blob`, `document`, `date time` and `error type`. - `&'static str` on Error type is replaced with `Cow` to allow `serde` support. No breaking changes are introduced. @@ -178,6 +176,9 @@ message = """ - Implements serde support to `number`, `blob`, `document`, `date time` and `error type`. - `&'static str` on Error type is replaced with `Cow` to allow `serde` support. No breaking changes are introduced. +- aws-credential-types/Cargo.toml + - tracing-subscriber 0.3.16 requires regex to enable feature = unicode-case. Without it it fails. + - regex is added to package.metadata.cargo-udeps.ignore to work with check-aws-sdk-smoketest-docs-clippy-udeps """ author = "thomas-k-cameron" references = ["smithy-rs#2615"] From 58512c2be1b61f1bef705bf60a144588bd2ab6b1 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 21 Apr 2023 10:16:20 +0000 Subject: [PATCH 022/312] - add python packages for compiletime benchmark - add scripts --- tools/ci-build/Dockerfile | 2 ++ tools/ci-scripts/compiletime-benchmark | 30 +++++++++++++++++++++ tools/compiletime-benchmark/format.py | 36 ++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 tools/ci-scripts/compiletime-benchmark create mode 100644 tools/compiletime-benchmark/format.py diff --git a/tools/ci-build/Dockerfile b/tools/ci-build/Dockerfile index 0e64f746a9f..1db1677d142 100644 --- a/tools/ci-build/Dockerfile +++ b/tools/ci-build/Dockerfile @@ -198,6 +198,8 @@ ENV PATH=/opt/cargo/bin:$PATH \ # they will assume the tools are on the PATH, but if outside of the image, they will `cargo run` the tools. ENV SMITHY_RS_DOCKER_BUILD_IMAGE=1 RUN pip3 install --no-cache-dir mypy==0.991 +# We are adding this for compile time benchmark +RUN pip3 install pandas polars pyarrow WORKDIR /home/build COPY sanity-test /home/build/sanity-test RUN /home/build/sanity-test diff --git a/tools/ci-scripts/compiletime-benchmark b/tools/ci-scripts/compiletime-benchmark new file mode 100644 index 00000000000..50f99ccdff3 --- /dev/null +++ b/tools/ci-scripts/compiletime-benchmark @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# +set -eux + +export TIMEFORMAT=%R +function compile() { + cd $1 && + export CARGORUSTFLAG="" && + cargo build &> /dev/null && cargo clean && + time cargo build &> /dev/null && cargo clean && + time cargo build --release &> /dev/null && cargo clean && + export CARGORUSTFLAG="--cfg aws_sdk_unstable" && + time cargo build --all-features &> /dev/null && cargo clean && + time cargo build --all-features --release &> /dev/null && cargo clean +} + +./gradlew :aws:sdk:assemble +DIR=$PWD +for variable in $(dir "aws/sdk/build/aws-sdk/sdk"); do + echo "$DIR/aws/sdk/build/aws-sdk/sdk/$variable"; + if [[ $variable != *"aws-"* ]]; then + echo "$variable" &>> /tmp/compiletime-benchmark.txt + compile "$DIR/aws/sdk/build/aws-sdk/sdk/$variable" &>> /tmp/compiletime-benchmark.txt + fi +done + +python3 tools/compiletime-benchmark/format.py diff --git a/tools/compiletime-benchmark/format.py b/tools/compiletime-benchmark/format.py new file mode 100644 index 00000000000..a4b1262a0cd --- /dev/null +++ b/tools/compiletime-benchmark/format.py @@ -0,0 +1,36 @@ +# +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# + +import polars as pl + +def main(): + file = open("/tmp/compiletime-benchmark.txt", "r").read() + stack = [] + idx = 0 + hashmap = {} + for i in file.split("\n"): + if idx > 4: + idx = 0 + + if idx == 0: + hashmap["sdk"] = i + elif idx == 1: + hashmap["dev"] = i + elif idx == 2: + hashmap["release"] = i + elif idx == 3: + hashmap["dev-w-all-features"] = i + elif idx == 4: + hashmap["release-w-all-features"] = i + + idx+=1 + + df = pl.DataFrame(stack).sort("sdk").select(pl.all().exclude("sdk").cast(pl.Float64)) + dev = df.filter(pl.col("sdk") == "s3").to_dicts()[0]["dev"] + df = df.with_columns(pl.col(pl.Float64)/dev) + print(df) + df.to_pandas().to_markdown("./benchmark.md") + +main() From 1d9cd835febea8577556d18e68aafe3eeb4b0da6 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 21 Apr 2023 11:55:28 +0000 Subject: [PATCH 023/312] remove polars --- tools/ci-build/Dockerfile | 2 -- tools/compiletime-benchmark/format.py | 42 +++++++++++++++++---------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/tools/ci-build/Dockerfile b/tools/ci-build/Dockerfile index 1db1677d142..0e64f746a9f 100644 --- a/tools/ci-build/Dockerfile +++ b/tools/ci-build/Dockerfile @@ -198,8 +198,6 @@ ENV PATH=/opt/cargo/bin:$PATH \ # they will assume the tools are on the PATH, but if outside of the image, they will `cargo run` the tools. ENV SMITHY_RS_DOCKER_BUILD_IMAGE=1 RUN pip3 install --no-cache-dir mypy==0.991 -# We are adding this for compile time benchmark -RUN pip3 install pandas polars pyarrow WORKDIR /home/build COPY sanity-test /home/build/sanity-test RUN /home/build/sanity-test diff --git a/tools/compiletime-benchmark/format.py b/tools/compiletime-benchmark/format.py index a4b1262a0cd..74401e906fe 100644 --- a/tools/compiletime-benchmark/format.py +++ b/tools/compiletime-benchmark/format.py @@ -2,35 +2,45 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 # - -import polars as pl - def main(): file = open("/tmp/compiletime-benchmark.txt", "r").read() stack = [] idx = 0 hashmap = {} for i in file.split("\n"): - if idx > 4: - idx = 0 + idx += 1 + if idx > 5: + idx = 1 - if idx == 0: + if idx == 1: hashmap["sdk"] = i - elif idx == 1: + continue + + i = float(i) + if idx == 2: hashmap["dev"] = i - elif idx == 2: - hashmap["release"] = i elif idx == 3: - hashmap["dev-w-all-features"] = i + hashmap["release"] = i elif idx == 4: + hashmap["dev-w-all-features"] = i + elif idx == 5: hashmap["release-w-all-features"] = i + stack.append(hashmap) + hashmap = {} - idx+=1 + header = "|".join(stack[0].keys()) + header = f"|{header}|" + table = [header] + for hashmap in stack: + row = [] + for i in hashmap.keys(): + row.append(str(hashmap[i])) + inner = "|".join(row) + inner = f"|{inner}|" + table.append(inner) - df = pl.DataFrame(stack).sort("sdk").select(pl.all().exclude("sdk").cast(pl.Float64)) - dev = df.filter(pl.col("sdk") == "s3").to_dicts()[0]["dev"] - df = df.with_columns(pl.col(pl.Float64)/dev) - print(df) - df.to_pandas().to_markdown("./benchmark.md") + markdown = "\n".join(table) + print(markdown) + # send markdown to somewhere main() From 72cbd5dafebf40f4ae8e7b860a6199d92662c0ab Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 21 Apr 2023 12:10:31 +0000 Subject: [PATCH 024/312] update action --- .github/workflows/benchmark.yml | 18 ++++++++++++++++++ .github/workflows/ci.yml | 2 -- 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/benchmark.yml diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 00000000000..a9f268eb659 --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,18 @@ +name: compiletime benchmark +run-name: compile time benchmark +on: + push: + branches: + - main +jobs: + compiletime-benchmark: + name: Compile time benchmark + runs-on: ${{ matrix.test.runner }} + + steps: + - uses: actions/checkout@v3 + with: + path: smithy-rs + ref: ${{ inputs.git_ref }} + - name: compiletime-benchmark + run: bash tools/ci-scripts/compiletime-benchmark \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c36d5ba08ca..941298298d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -159,8 +159,6 @@ jobs: with: action: ${{ matrix.test.action }} - - test-rust-windows: name: Rust Tests on Windows runs-on: windows-latest From c97dfee4d87074fdaeab0db68b0c302c80ae6803 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Sat, 22 Apr 2023 08:18:08 +0900 Subject: [PATCH 025/312] Update ci.yml --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 336f02b6552..54ccda52ff9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -159,6 +159,8 @@ jobs: with: action: ${{ matrix.test.action }} + + test-rust-windows: name: Rust Tests on Windows runs-on: windows-latest From 12dfc86564e8dd116d6c013dec8b9fb36d5f5215 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Sat, 22 Apr 2023 15:56:02 +0900 Subject: [PATCH 026/312] Update Cargo.toml --- aws/rust-runtime/aws-credential-types/Cargo.toml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/aws/rust-runtime/aws-credential-types/Cargo.toml b/aws/rust-runtime/aws-credential-types/Cargo.toml index 3cd832ecd12..4a0b8a93907 100644 --- a/aws/rust-runtime/aws-credential-types/Cargo.toml +++ b/aws/rust-runtime/aws-credential-types/Cargo.toml @@ -6,10 +6,7 @@ description = "Types for AWS SDK credentials." edition = "2021" license = "Apache-2.0" repository = "https://github.com/awslabs/smithy-rs" -[package.metadata.cargo-udeps.ignore] -normal = ["regex"] -development = ["regex"] -build = ["regex"] + [features] hardcoded-credentials = [] test-util = [] @@ -17,7 +14,6 @@ test-util = [] [dependencies] aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async" } aws-smithy-types = { path = "../../../rust-runtime/aws-smithy-types" } -regex = { version = "1", features = ["unicode-case"] } fastrand = "1.4.0" tokio = { version = "1.23.1", features = ["sync"] } tracing = "0.1" From 17ab7ffa0306c78c40c0b6ac963d5666eef2ca26 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 21 Apr 2023 08:39:10 +0000 Subject: [PATCH 027/312] serde support for error metadata --- .../aws-smithy-types/src/error/metadata.rs | 56 +++++++++++++++++++ .../test_data/error_meta_data.json | 7 +++ .../test_data/error_meta_data_empty.json | 5 ++ 3 files changed, 68 insertions(+) create mode 100644 rust-runtime/aws-smithy-types/test_data/error_meta_data.json create mode 100644 rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json diff --git a/rust-runtime/aws-smithy-types/src/error/metadata.rs b/rust-runtime/aws-smithy-types/src/error/metadata.rs index 06925e13f9c..70fdc999d7c 100644 --- a/rust-runtime/aws-smithy-types/src/error/metadata.rs +++ b/rust-runtime/aws-smithy-types/src/error/metadata.rs @@ -39,6 +39,14 @@ pub const EMPTY_ERROR_METADATA: ErrorMetadata = ErrorMetadata { /// For many services, Errors are modeled. However, many services only partially model errors or don't /// model errors at all. In these cases, the SDK will return this generic error type to expose the /// `code`, `message` and `request_id`. +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-serialize"), + derive(serde::Serialize) +)] +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-deserialize"), + derive(serde::Deserialize) +)] #[derive(Debug, Eq, PartialEq, Default, Clone)] pub struct ErrorMetadata { code: Option, @@ -47,8 +55,23 @@ pub struct ErrorMetadata { } /// Builder for [`ErrorMetadata`]. +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-serialize"), + derive(serde::Serialize) +)] +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-deserialize"), + derive(serde::Deserialize) +)] #[derive(Debug, Default)] pub struct Builder { + #[cfg_attr( + any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") + ), + serde(flatten) + )] inner: ErrorMetadata, } @@ -164,3 +187,36 @@ impl fmt::Display for ErrorMetadata { } impl std::error::Error for ErrorMetadata {} + +#[cfg(all( + test, + any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") + ) +))] +mod test { + use super::*; + + #[test] + /// tests de/ser on ErrorMetaData. + fn test_error_meta_data() { + let mut data = Builder::default() + .code("code") + .message("message") + .custom("hello", "world"); + let ok = serde_json::to_string_pretty(&EMPTY_ERROR_METADATA).unwrap(); + assert_eq!( + &ok, + include_str!("../../test-data/error_meta_data_empty.json") + ); + assert_eq!( + serde_json::from_str(include_str!("../../test-data/error_meta_data.json")).unwrap(), + &data + ); + assert_eq!( + serde_json::from_str(include_str!("../../test-data/error_meta_data.json")).unwrap(), + data.build() + ); + } +} diff --git a/rust-runtime/aws-smithy-types/test_data/error_meta_data.json b/rust-runtime/aws-smithy-types/test_data/error_meta_data.json new file mode 100644 index 00000000000..db7067d86e4 --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/error_meta_data.json @@ -0,0 +1,7 @@ +{ + "code": "code", + "message": "message", + "extras": { + "hello": "world" + } +} diff --git a/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json b/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json new file mode 100644 index 00000000000..41165f4a49c --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json @@ -0,0 +1,5 @@ +{ + "code": null, + "message": null, + "extras": null +} From 81ccbbf992735930d358a54259e06116e34afa7a Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 26 Apr 2023 11:09:48 +0000 Subject: [PATCH 028/312] chore: update CHANGELOG.next.toml --- CHANGELOG.next.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 1832de5613f..3856c9e46d2 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -11,6 +11,13 @@ # meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client | server | all"} # author = "rcoh" + +[[aws-sdk-rust]] +message = "Implements serde support for ErrorMetaData on aws-smithy-types crate." +references = ["smithy-rs#2637"] +meta = { "breaking" = false, "tada" = false, "bug" = true } +author = "thomas-k-cameron" + [[aws-sdk-rust]] message = "The outputs for event stream operations (for example, S3's SelectObjectContent) now implement the `Sync` auto-trait." references = ["smithy-rs#2496"] From 5747deb8a069ca3451c162c8713ce27dba7da6fa Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 26 Apr 2023 11:10:27 +0000 Subject: [PATCH 029/312] Merge commit 'eef5b35a22c4f3c70a7e2387c2cf129da637ef3f' --- buildSrc/src/main/kotlin/CodegenTestCommon.kt | 4 ++++ buildSrc/src/main/kotlin/RustBuildTool.kt | 1 + 2 files changed, 5 insertions(+) diff --git a/buildSrc/src/main/kotlin/CodegenTestCommon.kt b/buildSrc/src/main/kotlin/CodegenTestCommon.kt index 2173c237a64..e42d7e5ed2a 100644 --- a/buildSrc/src/main/kotlin/CodegenTestCommon.kt +++ b/buildSrc/src/main/kotlin/CodegenTestCommon.kt @@ -244,12 +244,14 @@ fun Project.registerCargoCommandsTasks( this.tasks.register(Cargo.CHECK.toString) { dependsOn(dependentTasks) workingDir(outputDir) + environment("RUSTFLAGS", "--cfg aws_sdk_unstable") commandLine("cargo", "check", "--lib", "--tests", "--benches", "--all-features") } this.tasks.register(Cargo.TEST.toString) { dependsOn(dependentTasks) workingDir(outputDir) + environment("RUSTFLAGS", "--cfg aws_sdk_unstable") commandLine("cargo", "test", "--all-features") } @@ -257,12 +259,14 @@ fun Project.registerCargoCommandsTasks( dependsOn(dependentTasks) workingDir(outputDir) environment("RUSTDOCFLAGS", defaultRustDocFlags) + environment("RUSTFLAGS", "--cfg aws_sdk_unstable") commandLine("cargo", "doc", "--no-deps", "--document-private-items") } this.tasks.register(Cargo.CLIPPY.toString) { dependsOn(dependentTasks) workingDir(outputDir) + environment("RUSTFLAGS", "--cfg aws_sdk_unstable") commandLine("cargo", "clippy") } } diff --git a/buildSrc/src/main/kotlin/RustBuildTool.kt b/buildSrc/src/main/kotlin/RustBuildTool.kt index 1e679956487..b8a1a15fb15 100644 --- a/buildSrc/src/main/kotlin/RustBuildTool.kt +++ b/buildSrc/src/main/kotlin/RustBuildTool.kt @@ -28,6 +28,7 @@ private fun runCli( } } .copyTo(action) + action.environment("RUSTFLAGS", "--cfg aws_sdk_unstable") action.execute() } } From 6edcd1a418d73c1a6b4244bace78856d5d1a2fa5 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 26 Apr 2023 11:19:21 +0000 Subject: [PATCH 030/312] chore: update CHANGELOG.next.toml --- CHANGELOG.next.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 29b405f52ad..dbb4772750c 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -11,12 +11,6 @@ # meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client | server | all"} # author = "rcoh" -[[aws-sdk-rust]] -message = "Implements serde support for ErrorMetaData on aws-smithy-types crate." -references = ["smithy-rs#2637"] -meta = { "breaking" = false, "tada" = false, "bug" = true } -author = "thomas-k-cameron" - [[smithy-rs]] message = """ Implement layer for servers to handle [ALB health checks](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/target-group-health-checks.html). @@ -177,3 +171,9 @@ message = "Update MSRV to Rust 1.67.1" references = ["smithy-rs#2611"] meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "all"} author = "jdisanti" + +[[smithy-rs]] +message = "Add RUSTFLAGS = aws_sdk_unstable as environment variable when running Cargo from kotlin." +references = ["smithy-rs#2614"] +meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "all"} +author = "thomas-k-cameron" From b219038472291c9741bc6ebda7ea32a97de1c451 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 26 Apr 2023 11:36:34 +0000 Subject: [PATCH 031/312] update --- rust-runtime/aws-smithy-types/Cargo.toml | 5 + rust-runtime/aws-smithy-types/src/blob.rs | 2 +- .../aws-smithy-types/src/date_time/de.rs | 110 ++++++++++++++++++ .../aws-smithy-types/src/date_time/ser.rs | 27 +++++ rust-runtime/aws-smithy-types/src/document.rs | 6 +- .../aws-smithy-types/src/error/metadata.rs | 48 ++++++++ rust-runtime/aws-smithy-types/src/lib.rs | 2 +- .../test_data/error_meta_data.json | 7 ++ .../test_data/error_meta_data_empty.json | 5 + .../test_data/serialize_document.json | 43 +++++++ 10 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 rust-runtime/aws-smithy-types/src/date_time/de.rs create mode 100644 rust-runtime/aws-smithy-types/src/date_time/ser.rs create mode 100644 rust-runtime/aws-smithy-types/test_data/error_meta_data.json create mode 100644 rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json create mode 100644 rust-runtime/aws-smithy-types/test_data/serialize_document.json diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index a0a62f4bf4b..b2992210abd 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -27,6 +27,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" criterion = "0.4" rand = "0.8.4" +ciborium = "0.2.0" [package.metadata.docs.rs] all-features = true @@ -37,3 +38,7 @@ rustdoc-args = ["--cfg", "docsrs"] [[bench]] name = "base64" harness = false + +[features] +serde-serialize = [] +serde-deserialize = [] diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 0364727d4f0..f4f1da94d8d 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -70,7 +70,7 @@ impl<'de> Visitor<'de> for HumanReadableBlobVisitor { { match base64::decode(v) { Ok(inner) => Ok(Blob { inner }), - Err(e) => Err(serde::de::Error::custom(e)), + Err(e) => Err(E::custom(e)), } } } diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs new file mode 100644 index 00000000000..6f346ea8dee --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -0,0 +1,110 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use super::*; +use serde::de::Visitor; +use serde::Deserialize; + +struct DateTimeVisitor; + +enum VisitorState { + Second, + SubsecondNanos, + Unexpected, +} + +impl VisitorState { + const UNEXPECTED_VISITOR_STATE: &'static str = "Unexpected state. This happens when visitor tries to parse something after finished parsing the `subsec_nanos`."; +} + +struct NonHumanReadableDateTimeVisitor { + state: VisitorState, + seconds: i64, + subsecond_nanos: u32, +} + +fn fail(err_message: M) -> Result +where + M: std::fmt::Display, + E: serde::de::Error, +{ + Err(E::custom(err_message)) +} + +impl<'de> Visitor<'de> for DateTimeVisitor { + type Value = DateTime; + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("expected RFC-3339 Date Time") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + match DateTime::from_str(v, Format::DateTime) { + Ok(e) => Ok(e), + Err(e) => fail(e), + } + } +} + +impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { + type Value = Self; + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("expected (i64, u32)") + } + + fn visit_i64(mut self, v: i64) -> Result + where + E: serde::de::Error, + { + match self.state { + VisitorState::Unexpected => fail(VisitorState::UNEXPECTED_VISITOR_STATE), + VisitorState::Second => { + self.seconds = v; + self.state = VisitorState::SubsecondNanos; + Ok(self) + } + _ => fail("`seconds` value must be i64"), + } + } + + fn visit_u32(mut self, v: u32) -> Result + where + E: serde::de::Error, + { + match self.state { + VisitorState::Unexpected => fail(VisitorState::UNEXPECTED_VISITOR_STATE), + VisitorState::SubsecondNanos => { + self.subsecond_nanos = v; + self.state = VisitorState::Unexpected; + Ok(self) + } + _ => fail("`subsecond_nanos` value must be u32"), + } + } +} + +impl<'de> Deserialize<'de> for DateTime { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + if deserializer.is_human_readable() { + deserializer.deserialize_str(DateTimeVisitor) + } else { + let visitor = NonHumanReadableDateTimeVisitor { + state: VisitorState::Second, + seconds: 0, + subsecond_nanos: 0, + }; + let visitor = deserializer.deserialize_tuple(2, visitor)?; + Ok(DateTime { + seconds: visitor.seconds, + subsecond_nanos: visitor.subsecond_nanos, + }) + } + } +} diff --git a/rust-runtime/aws-smithy-types/src/date_time/ser.rs b/rust-runtime/aws-smithy-types/src/date_time/ser.rs new file mode 100644 index 00000000000..bd8ed29a049 --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/date_time/ser.rs @@ -0,0 +1,27 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use super::*; +use serde::ser::SerializeTuple; + +impl serde::Serialize for DateTime { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::Error; + if serializer.is_human_readable() { + match self.fmt(Format::DateTime) { + Ok(val) => serializer.serialize_str(&val), + Err(e) => Err(Error::custom(e)), + } + } else { + let mut tup_ser = serializer.serialize_tuple(2)?; + tup_ser.serialize_element(&self.seconds)?; + tup_ser.serialize_element(&self.subsecond_nanos)?; + tup_ser.end() + } + } +} diff --git a/rust-runtime/aws-smithy-types/src/document.rs b/rust-runtime/aws-smithy-types/src/document.rs index 8cbae5b3800..9515d26c2d1 100644 --- a/rust-runtime/aws-smithy-types/src/document.rs +++ b/rust-runtime/aws-smithy-types/src/document.rs @@ -4,8 +4,12 @@ */ use crate::Number; +#[cfg(any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") +))] +use serde; use std::collections::HashMap; - /* ANCHOR: document */ /// Document Type diff --git a/rust-runtime/aws-smithy-types/src/error/metadata.rs b/rust-runtime/aws-smithy-types/src/error/metadata.rs index 94af60aaf95..5681fb1d02c 100644 --- a/rust-runtime/aws-smithy-types/src/error/metadata.rs +++ b/rust-runtime/aws-smithy-types/src/error/metadata.rs @@ -62,8 +62,23 @@ impl ProvideErrorMetadata for ErrorMetadata { } /// Builder for [`ErrorMetadata`]. +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-serialize"), + derive(serde::Serialize) +)] +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-deserialize"), + derive(serde::Deserialize) +)] #[derive(Debug, Default)] pub struct Builder { + #[cfg_attr( + any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") + ), + serde(flatten) + )] inner: ErrorMetadata, } @@ -179,3 +194,36 @@ impl fmt::Display for ErrorMetadata { } impl std::error::Error for ErrorMetadata {} + +#[cfg(all( + test, + any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") + ) +))] +mod test { + use super::*; + + #[test] + /// tests de/ser on ErrorMetaData. + fn test_error_meta_data() { + let mut data = Builder::default() + .code("code") + .message("message") + .custom("hello", "world"); + let ok = serde_json::to_string_pretty(&EMPTY_ERROR_METADATA).unwrap(); + assert_eq!( + &ok, + include_str!("../../test-data/error_meta_data_empty.json") + ); + assert_eq!( + serde_json::from_str(include_str!("../../test-data/error_meta_data.json")).unwrap(), + &data + ); + assert_eq!( + serde_json::from_str(include_str!("../../test-data/error_meta_data.json")).unwrap(), + data.build() + ); + } +} diff --git a/rust-runtime/aws-smithy-types/src/lib.rs b/rust-runtime/aws-smithy-types/src/lib.rs index 5042988f603..ffa1c86ea58 100644 --- a/rust-runtime/aws-smithy-types/src/lib.rs +++ b/rust-runtime/aws-smithy-types/src/lib.rs @@ -22,8 +22,8 @@ pub mod retry; pub mod timeout; mod blob; -mod number; mod document; +mod number; pub use blob::Blob; pub use date_time::DateTime; diff --git a/rust-runtime/aws-smithy-types/test_data/error_meta_data.json b/rust-runtime/aws-smithy-types/test_data/error_meta_data.json new file mode 100644 index 00000000000..db7067d86e4 --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/error_meta_data.json @@ -0,0 +1,7 @@ +{ + "code": "code", + "message": "message", + "extras": { + "hello": "world" + } +} diff --git a/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json b/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json new file mode 100644 index 00000000000..41165f4a49c --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json @@ -0,0 +1,5 @@ +{ + "code": null, + "message": null, + "extras": null +} diff --git a/rust-runtime/aws-smithy-types/test_data/serialize_document.json b/rust-runtime/aws-smithy-types/test_data/serialize_document.json new file mode 100644 index 00000000000..dcbac2986ac --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/serialize_document.json @@ -0,0 +1,43 @@ +{ + "null": null, + "true": true, + "pos_int": 1, + "false": false, + "map": { + "array": [ + { + "pos_int": 1, + "float": 0.30000000000000004, + "neg_int": -1, + "hello": "world", + "false": false, + "true": true + }, + "hello-world", + true, + false + ], + "pos_int": 1, + "float": 0.30000000000000004, + "neg_int": -1, + "hello": "world", + "false": false, + "true": true + }, + "float": 0.30000000000000004, + "neg_int": -1, + "hello": "world", + "array": [ + { + "pos_int": 1, + "float": 0.30000000000000004, + "neg_int": -1, + "hello": "world", + "false": false, + "true": true + }, + "hello-world", + true, + false + ] +} From 6138ccdcc88e2a24db95247b7cb026f50e4e31a5 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 26 Apr 2023 11:43:58 +0000 Subject: [PATCH 032/312] chore: update CHANGELOG.next.toml --- CHANGELOG.next.toml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index dbb4772750c..4c4ad74ff94 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -177,3 +177,21 @@ message = "Add RUSTFLAGS = aws_sdk_unstable as environment variable when running references = ["smithy-rs#2614"] meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "all"} author = "thomas-k-cameron" + +[[smithy-rs]] +message = """ +- Implements serde support to Number, Blob, Document, DateTime and ErrorMetaData. +- &'static str on Error type is replaced with Cow to allow serde support. No breaking changes are introduced. +""" +references = ["smithy-rs#2616"] +meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "all"} +author = "thomas-k-cameron" + +[[aws-sdk-rust]] +message = """ +- Implements serde support to Number, Blob, Document, DateTime and ErrorMetaData. +- &'static str on Error type is replaced with Cow to allow serde support. No breaking changes are introduced. +""" +references = ["smithy-rs#2616"] +meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "all"} +author = "thomas-k-cameron" From caaa19355cf5578ae377f1438e1b78221d2add7d Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Wed, 26 Apr 2023 22:06:21 +0900 Subject: [PATCH 033/312] Update CHANGELOG.next.toml --- CHANGELOG.next.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 4c4ad74ff94..4b112c2f042 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -175,7 +175,7 @@ author = "jdisanti" [[smithy-rs]] message = "Add RUSTFLAGS = aws_sdk_unstable as environment variable when running Cargo from kotlin." references = ["smithy-rs#2614"] -meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "all"} +meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "all"} author = "thomas-k-cameron" [[smithy-rs]] @@ -184,7 +184,7 @@ message = """ - &'static str on Error type is replaced with Cow to allow serde support. No breaking changes are introduced. """ references = ["smithy-rs#2616"] -meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "all"} +meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "all"} author = "thomas-k-cameron" [[aws-sdk-rust]] @@ -193,5 +193,5 @@ message = """ - &'static str on Error type is replaced with Cow to allow serde support. No breaking changes are introduced. """ references = ["smithy-rs#2616"] -meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "all"} +meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "all"} author = "thomas-k-cameron" From 8b3b6407ef8db13aaf4b27b8cf30b09f211e68a4 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Wed, 26 Apr 2023 22:33:34 +0900 Subject: [PATCH 034/312] Update CHANGELOG.next.toml --- CHANGELOG.next.toml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 4b112c2f042..3686ce21826 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -172,12 +172,6 @@ references = ["smithy-rs#2611"] meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "all"} author = "jdisanti" -[[smithy-rs]] -message = "Add RUSTFLAGS = aws_sdk_unstable as environment variable when running Cargo from kotlin." -references = ["smithy-rs#2614"] -meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "all"} -author = "thomas-k-cameron" - [[smithy-rs]] message = """ - Implements serde support to Number, Blob, Document, DateTime and ErrorMetaData. From 5df255d8b31ae4f91cc9d4e241b92a84b843b36a Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 00:00:53 +0000 Subject: [PATCH 035/312] FIX error --- .../core/smithy/generators/BuilderGenerator.kt | 2 +- .../core/smithy/generators/RenderSerdeAttribute.kt | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt index 0be116db0a8..082c91d5c39 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt @@ -213,7 +213,7 @@ class BuilderGenerator( writer.docs("A builder for #D.", structureSymbol) metadata.additionalAttributes.render(writer) Attribute(derive(builderDerives)).render(writer) - RenderSerdeAttribute.forBuilders(writer, shape, model) + RenderSerdeAttribute.forStructureShape(writer, shape, model) SensitiveWarning.addDoc(writer, shape) writer.rustBlock("pub struct $builderName") { // add serde diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index 8d5ec34be4f..e92f716da28 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -7,25 +7,22 @@ package software.amazon.smithy.rust.codegen.core.smithy.generators import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.MemberShape +import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.model.traits.ErrorTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.raw +import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.isEventStream import software.amazon.smithy.rust.codegen.core.util.isStreaming // Part of RFC30 public object RenderSerdeAttribute { public fun forStructureShape(writer: RustWriter, shape: StructureShape, model: Model) { - if (shape.members().none { it.isEventStream(model) }) { + if (shape.hasTrait().not() && shape.members().none { it.isEventStream(model) }) { writeAttributes(writer) - } - } - - public fun forBuilders(writer: RustWriter, shape: StructureShape, model: Model) { - if (shape.members().none { it.isEventStream(model) }) { - writeAttributes(writer) - } + }; } public fun skipIfStream(writer: RustWriter, member: MemberShape, model: Model) { From b3c411042d91face943195b09325fe5042ca467a Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 00:30:02 +0000 Subject: [PATCH 036/312] Test to make sure that serde is not added to error types. --- .../smithy/generators/BuilderGeneratorTest.kt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index ec107f3fcb8..7bc10a47fd4 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -137,4 +137,39 @@ internal class BuilderGeneratorTest { } project.compileAndTest() } + + @Test + fun `don't add serde to error types`() { + print("don't add serde to error types") + val provider = testSymbolProvider(model) + val project = TestWorkspace.testProject(provider) + project.moduleFor(inner) { + rust("##![allow(deprecated)]") + StructureGenerator(model, provider, this, inner, emptyList()).render() + StructureGenerator(model, provider, this, struct, emptyList()).render() + implBlock(provider.toSymbol(struct)) { + BuilderGenerator.renderConvenienceMethod(this, provider, struct) + } + unitTest("check_serde_on_error_types") { + rust( + """ + let json_str = r##"{"message": "something"}"##; + let err: MyError = serde_json::from_str(json_str); + assert!(err.is_err()); + let err: Builder = serde_json::from_str(json_str); + assert!(err.is_err()); + + let my_struct1 = MyError::builder().message("something".to_string()).build(); + assert!(serde_json::to_string(my_struct1).is_err()); + let my_struct2 = MyError::builder().message("something".to_string()); + assert!(serde_json::to_string(my_struct2).is_err()); + """, + ) + } + } + project.withModule(provider.moduleForBuilder(struct)) { + BuilderGenerator(model, provider, struct, emptyList()).render(this) + } + project.compileAndTest() + } } From 842c9bd190948b54f1dc02c4995f050d542d7e03 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 00:31:44 +0000 Subject: [PATCH 037/312] remove serde from meta data --- .../aws-smithy-types/src/error/metadata.rs | 56 ------------------- 1 file changed, 56 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/error/metadata.rs b/rust-runtime/aws-smithy-types/src/error/metadata.rs index 5681fb1d02c..8628e235dc1 100644 --- a/rust-runtime/aws-smithy-types/src/error/metadata.rs +++ b/rust-runtime/aws-smithy-types/src/error/metadata.rs @@ -40,14 +40,6 @@ pub const EMPTY_ERROR_METADATA: ErrorMetadata = ErrorMetadata { /// For many services, Errors are modeled. However, many services only partially model errors or don't /// model errors at all. In these cases, the SDK will return this generic error type to expose the /// `code`, `message` and `request_id`. -#[cfg_attr( - all(aws_sdk_unstable, feature = "serde-serialize"), - derive(serde::Serialize) -)] -#[cfg_attr( - all(aws_sdk_unstable, feature = "serde-deserialize"), - derive(serde::Deserialize) -)] #[derive(Debug, Eq, PartialEq, Default, Clone)] pub struct ErrorMetadata { code: Option, @@ -62,23 +54,8 @@ impl ProvideErrorMetadata for ErrorMetadata { } /// Builder for [`ErrorMetadata`]. -#[cfg_attr( - all(aws_sdk_unstable, feature = "serde-serialize"), - derive(serde::Serialize) -)] -#[cfg_attr( - all(aws_sdk_unstable, feature = "serde-deserialize"), - derive(serde::Deserialize) -)] #[derive(Debug, Default)] pub struct Builder { - #[cfg_attr( - any( - all(aws_sdk_unstable, feature = "serde-deserialize"), - all(aws_sdk_unstable, feature = "serde-serialize") - ), - serde(flatten) - )] inner: ErrorMetadata, } @@ -194,36 +171,3 @@ impl fmt::Display for ErrorMetadata { } impl std::error::Error for ErrorMetadata {} - -#[cfg(all( - test, - any( - all(aws_sdk_unstable, feature = "serde-deserialize"), - all(aws_sdk_unstable, feature = "serde-serialize") - ) -))] -mod test { - use super::*; - - #[test] - /// tests de/ser on ErrorMetaData. - fn test_error_meta_data() { - let mut data = Builder::default() - .code("code") - .message("message") - .custom("hello", "world"); - let ok = serde_json::to_string_pretty(&EMPTY_ERROR_METADATA).unwrap(); - assert_eq!( - &ok, - include_str!("../../test-data/error_meta_data_empty.json") - ); - assert_eq!( - serde_json::from_str(include_str!("../../test-data/error_meta_data.json")).unwrap(), - &data - ); - assert_eq!( - serde_json::from_str(include_str!("../../test-data/error_meta_data.json")).unwrap(), - data.build() - ); - } -} From 0e73617b3bbb9c0cf6f6fe301646b5ce02c9cdde Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 00:51:47 +0000 Subject: [PATCH 038/312] FIX --- rust-runtime/aws-smithy-types/src/error/metadata.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/error/metadata.rs b/rust-runtime/aws-smithy-types/src/error/metadata.rs index 8628e235dc1..c126a445da6 100644 --- a/rust-runtime/aws-smithy-types/src/error/metadata.rs +++ b/rust-runtime/aws-smithy-types/src/error/metadata.rs @@ -44,7 +44,7 @@ pub const EMPTY_ERROR_METADATA: ErrorMetadata = ErrorMetadata { pub struct ErrorMetadata { code: Option, message: Option, - extras: Option, String>>, + extras: Option } impl ProvideErrorMetadata for ErrorMetadata { @@ -105,7 +105,7 @@ impl Builder { .extras .as_mut() .unwrap() - .insert(Cow::Borrowed(key), value.into()); + .insert(key, value.into()); self } From c4877fc9743e0d1327827d113b23bbce6802b8ab Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 00:52:30 +0000 Subject: [PATCH 039/312] FIX import --- rust-runtime/aws-smithy-types/src/error/metadata.rs | 1 - rust-toolchain.toml | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/error/metadata.rs b/rust-runtime/aws-smithy-types/src/error/metadata.rs index c126a445da6..25aa4e1eb4e 100644 --- a/rust-runtime/aws-smithy-types/src/error/metadata.rs +++ b/rust-runtime/aws-smithy-types/src/error/metadata.rs @@ -6,7 +6,6 @@ //! Error metadata use crate::retry::{ErrorKind, ProvideErrorKind}; -use std::borrow::Cow; use std::collections::HashMap; use std::fmt; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 588ffd57885..f0c1f0fc627 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,3 @@ [toolchain] -channel = "1.67.1" +channel = "1.68.2" + From 732b23199626958f84f7abab4775978854686e78 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 01:09:59 +0000 Subject: [PATCH 040/312] Refactor code for adding serde --- .../client/smithy/generators/ClientEnumGenerator.kt | 2 +- .../codegen/core/smithy/generators/BuilderGenerator.kt | 3 +-- .../codegen/core/smithy/generators/EnumGenerator.kt | 4 ++-- .../core/smithy/generators/RenderSerdeAttribute.kt | 10 +++++----- .../core/smithy/generators/StructureGenerator.kt | 2 +- .../codegen/core/smithy/generators/UnionGenerator.kt | 2 +- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt index b107955915b..7ed0cf5ec93 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt @@ -99,7 +99,7 @@ data class InfallibleEnumType( """.trimIndent(), ) - RenderSerdeAttribute.writeAttributes(this) + RenderSerdeAttribute.addSerde(this, null, null) context.enumMeta.render(this) rust("struct $UnknownVariantValue(pub(crate) String);") rustBlock("impl $UnknownVariantValue") { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt index 082c91d5c39..7aba968e746 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt @@ -40,7 +40,6 @@ import software.amazon.smithy.rust.codegen.core.smithy.expectRustMetadata import software.amazon.smithy.rust.codegen.core.smithy.isOptional import software.amazon.smithy.rust.codegen.core.smithy.makeOptional import software.amazon.smithy.rust.codegen.core.smithy.rustType -import software.amazon.smithy.rust.codegen.core.smithy.shape import software.amazon.smithy.rust.codegen.core.smithy.traits.SyntheticInputTrait import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.hasTrait @@ -213,7 +212,7 @@ class BuilderGenerator( writer.docs("A builder for #D.", structureSymbol) metadata.additionalAttributes.render(writer) Attribute(derive(builderDerives)).render(writer) - RenderSerdeAttribute.forStructureShape(writer, shape, model) + RenderSerdeAttribute.addSerde(writer, shape, model) SensitiveWarning.addDoc(writer, shape) writer.rustBlock("pub struct $builderName") { // add serde diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt index 4ca9cd26003..9be4815bcbd 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt @@ -221,7 +221,7 @@ open class EnumGenerator( private fun RustWriter.renderUnnamedEnum() { documentShape(shape, model) deprecatedShape(shape) - RenderSerdeAttribute.writeAttributes(this) + RenderSerdeAttribute.addSerde(this, shape, model) SensitiveWarning.addDoc(this, shape) context.enumMeta.render(this) rust("struct ${context.enumName}(String);") @@ -258,7 +258,7 @@ open class EnumGenerator( ) deprecatedShape(shape) - RenderSerdeAttribute.writeAttributes(this) + RenderSerdeAttribute.addSerde(this, shape, model) SensitiveWarning.addDoc(this, shape) context.enumMeta.render(this) rustBlock("enum ${context.enumName}") { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index e92f716da28..4d2792e982e 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -7,8 +7,7 @@ package software.amazon.smithy.rust.codegen.core.smithy.generators import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.MemberShape -import software.amazon.smithy.model.shapes.ShapeId -import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.traits.ErrorTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter @@ -19,10 +18,11 @@ import software.amazon.smithy.rust.codegen.core.util.isStreaming // Part of RFC30 public object RenderSerdeAttribute { - public fun forStructureShape(writer: RustWriter, shape: StructureShape, model: Model) { - if (shape.hasTrait().not() && shape.members().none { it.isEventStream(model) }) { + public fun addSerde(writer: RustWriter, shape: Shape? = null, model: Model? = null) { + if (shape == null || model == null) return; + if (shape.hasTrait() && shape.members().none { it.isEventStream(model) }) { writeAttributes(writer) - }; + } } public fun skipIfStream(writer: RustWriter, member: MemberShape, model: Model) { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt index 5e3e0a2491f..044bfc7189f 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt @@ -164,7 +164,7 @@ open class StructureGenerator( val containerMeta = symbol.expectRustMetadata() writer.documentShape(shape, model) writer.deprecatedShape(shape) - RenderSerdeAttribute.forStructureShape(writer, shape, model) + RenderSerdeAttribute.addSerde(writer, shape, model) SensitiveWarning.addDoc(writer, shape) containerMeta.render(writer) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt index 170729db53d..4b3bc12b285 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt @@ -62,7 +62,7 @@ open class UnionGenerator( open fun render() { writer.documentShape(shape, model) writer.deprecatedShape(shape) - RenderSerdeAttribute.writeAttributes(writer) + RenderSerdeAttribute.addSerde(writer, shape, model) val containerMeta = unionSymbol.expectRustMetadata() containerMeta.render(writer) From 61275aeedfa233a574bbcfeed39e494a1b85b6a5 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Sat, 22 Apr 2023 15:56:02 +0900 Subject: [PATCH 041/312] update blob.rs --- rust-runtime/aws-smithy-types/Cargo.toml | 10 ++ rust-runtime/aws-smithy-types/src/blob.rs | 129 ++++++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 7ebd3ece231..4bdc0f93dda 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -22,6 +22,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" criterion = "0.4" rand = "0.8.4" +ciborium = "0.2.0" [package.metadata.docs.rs] all-features = true @@ -32,3 +33,12 @@ rustdoc-args = ["--cfg", "docsrs"] [[bench]] name = "base64" harness = false + + +[target."cfg(aws_sdk_unstable)".dependencies.serde] +version = "1" +features = ["derive"] + +[features] +serde-serialize = [] +serde-deserialize = [] diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index bdd335c4923..23a782ca740 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -3,6 +3,16 @@ * SPDX-License-Identifier: Apache-2.0 */ +#[cfg(all( + aws_sdk_unstable, + any(feature = "serde-deserialize", feature = "serde-serialize") +))] +use crate::base64; +#[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] +use serde::Serialize; +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +use serde::{de::Visitor, Deserialize}; + /// Binary Blob Type /// /// Blobs represent protocol-agnostic binary content. @@ -30,3 +40,122 @@ impl AsRef<[u8]> for Blob { &self.inner } } + +#[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] +impl Serialize for Blob { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + if serializer.is_human_readable() { + serializer.serialize_str(&crate::base64::encode(&self.inner)) + } else { + serializer.serialize_bytes(&self.inner) + } + } +} + +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +struct HumanReadableBlobVisitor; + +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +impl<'de> Visitor<'de> for HumanReadableBlobVisitor { + type Value = Blob; + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("expected base64 encoded string") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + match base64::decode(v) { + Ok(inner) => Ok(Blob { inner }), + Err(e) => Err(E::custom(e)), + } + } +} + +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +struct NotHumanReadableBlobVisitor; + +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +impl<'de> Visitor<'de> for NotHumanReadableBlobVisitor { + type Value = Blob; + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("expected base64 encoded string") + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: serde::de::Error, + { + Ok(Blob { inner: v }) + } +} + +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +impl<'de> Deserialize<'de> for Blob { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + if deserializer.is_human_readable() { + deserializer.deserialize_str(HumanReadableBlobVisitor) + } else { + deserializer.deserialize_byte_buf(NotHumanReadableBlobVisitor) + } + } +} + +#[cfg(test)] +#[cfg(all( + aws_sdk_unstable, + feature = "serde-serialize", + feature = "serde-deserialize" +))] +mod test { + use crate::Blob; + use serde::{Deserialize, Serialize}; + use std::collections::HashMap; + + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct ForTest { + blob: Blob, + } + + #[test] + fn human_readable_blob() { + let aws_in_base64 = r#"{"blob":"QVdT"}"#; + let for_test = ForTest { + blob: Blob { + inner: vec![b'A', b'W', b'S'], + }, + }; + assert_eq!(for_test, serde_json::from_str(aws_in_base64).unwrap()); + assert_eq!(serde_json::to_string(&for_test).unwrap(), aws_in_base64); + } + + #[test] + fn not_human_readable_blob() { + use std::ffi::CString; + + let for_test = ForTest { + blob: Blob { + inner: vec![b'A', b'W', b'S'], + }, + }; + let mut buf = vec![]; + let res = ciborium::ser::into_writer(&for_test, &mut buf); + assert!(res.is_ok()); + + // checks whether the bytes are deserialiezd properly + let n: HashMap = + ciborium::de::from_reader(std::io::Cursor::new(buf.clone())).unwrap(); + assert!(n.get("blob").is_some()); + assert!(n.get("blob") == CString::new([65, 87, 83]).ok().as_ref()); + + let de: ForTest = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); + assert_eq!(for_test, de); + } +} From d6c2ad9449837d535d970dd99c55b7a3bd06c9b3 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 01:48:11 +0000 Subject: [PATCH 042/312] Add serde support to date time --- .../aws-smithy-types/src/date_time/de.rs | 110 ++++++++++++++++++ .../aws-smithy-types/src/date_time/mod.rs | 51 ++++++++ .../aws-smithy-types/src/date_time/ser.rs | 26 +++++ 3 files changed, 187 insertions(+) create mode 100644 rust-runtime/aws-smithy-types/src/date_time/de.rs create mode 100644 rust-runtime/aws-smithy-types/src/date_time/ser.rs diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs new file mode 100644 index 00000000000..7816a634d90 --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -0,0 +1,110 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + + use super::*; + use serde::de::Visitor; + use serde::Deserialize; + + struct DateTimeVisitor; + + enum VisitorState { + Second, + SubsecondNanos, + Unexpected, + } + + impl VisitorState { + const UNEXPECTED_VISITOR_STATE: &'static str = "Unexpected state. This happens when visitor tries to parse something after finished parsing the `subsec_nanos`."; + } + + struct NonHumanReadableDateTimeVisitor { + state: VisitorState, + seconds: i64, + subsecond_nanos: u32, + } + + fn fail(err_message: M) -> Result + where + M: std::fmt::Display, + E: serde::de::Error, + { + Err(E::custom(err_message)) + } + + impl<'de> Visitor<'de> for DateTimeVisitor { + type Value = DateTime; + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("expected RFC-3339 Date Time") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + match DateTime::from_str(v, Format::DateTime) { + Ok(e) => Ok(e), + Err(e) => fail(e), + } + } + } + + impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { + type Value = Self; + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("expected (i64, u32)") + } + + fn visit_i64(mut self, v: i64) -> Result + where + E: serde::de::Error, + { + match self.state { + VisitorState::Unexpected => fail(VisitorState::UNEXPECTED_VISITOR_STATE), + VisitorState::Second => { + self.seconds = v; + self.state = VisitorState::SubsecondNanos; + Ok(self) + } + _ => fail("`seconds` value must be i64"), + } + } + + fn visit_u32(mut self, v: u32) -> Result + where + E: serde::de::Error, + { + match self.state { + VisitorState::Unexpected => fail(VisitorState::UNEXPECTED_VISITOR_STATE), + VisitorState::SubsecondNanos => { + self.subsecond_nanos = v; + self.state = VisitorState::Unexpected; + Ok(self) + } + _ => fail("`subsecond_nanos` value must be u32"), + } + } + } + + impl<'de> Deserialize<'de> for DateTime { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + if deserializer.is_human_readable() { + deserializer.deserialize_str(DateTimeVisitor) + } else { + let visitor = NonHumanReadableDateTimeVisitor { + state: VisitorState::Second, + seconds: 0, + subsecond_nanos: 0, + }; + let visitor = deserializer.deserialize_tuple(2, visitor)?; + Ok(DateTime { + seconds: visitor.seconds, + subsecond_nanos: visitor.subsecond_nanos, + }) + } + } + } diff --git a/rust-runtime/aws-smithy-types/src/date_time/mod.rs b/rust-runtime/aws-smithy-types/src/date_time/mod.rs index 0459619998e..9739bce0f2d 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/mod.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/mod.rs @@ -16,7 +16,12 @@ use std::time::Duration; use std::time::SystemTime; use std::time::UNIX_EPOCH; +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +mod de; mod format; +#[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] +mod ser; + pub use self::format::DateTimeFormatError; pub use self::format::DateTimeParseError; @@ -552,4 +557,50 @@ mod test { SystemTime::try_from(date_time).unwrap() ); } + + #[cfg(all( + test, + aws_sdk_unstable, + feature = "serde-deserialize", + feature = "serde-serialize" + ))] + #[test] + fn human_readable_datetime() { + use serde::{Deserialize, Serialize}; + + let datetime = DateTime::from_secs(1576540098); + #[derive(Serialize, Deserialize, PartialEq)] + struct Test { + datetime: DateTime, + } + let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; + assert!(serde_json::to_string(&Test { datetime }).ok() == Some(datetime_json.to_string())); + + let test = serde_json::from_str::(&datetime_json).ok(); + assert!(test.is_some()); + assert!(test.unwrap().datetime == datetime); + } + + /// checks that they are serialized into tuples + #[cfg(all( + test, + aws_sdk_unstable, + feature = "serde-deserialize", + feature = "serde-serialize" + ))] + #[test] + fn not_human_readable_datetime() { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(1576540098i64.into()), + ciborium::value::Value::Integer(0u32.into()), + ]); + let datetime = DateTime::from_secs(1576540098); + + let mut buf1 = vec![]; + let mut buf2 = vec![]; + let res1 = ciborium::ser::into_writer(&datetime, &mut buf1); + let res2 = ciborium::ser::into_writer(&cbor, &mut buf2); + assert!(res1.is_ok() && res2.is_ok()); + assert!(buf1 == buf2, "{:#?}", (buf1, buf2)); + } } diff --git a/rust-runtime/aws-smithy-types/src/date_time/ser.rs b/rust-runtime/aws-smithy-types/src/date_time/ser.rs new file mode 100644 index 00000000000..4dc39292ec0 --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/date_time/ser.rs @@ -0,0 +1,26 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use super::*; +use serde::ser::SerializeTuple; + +impl serde::Serialize for DateTime { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + if serializer.is_human_readable() { + match self.fmt(Format::DateTime) { + Ok(val) => serializer.serialize_str(&val), + Err(e) => Err(serde::ser::Error::custom(e)), + } + } else { + let mut tup_ser = serializer.serialize_tuple(2)?; + tup_ser.serialize_element(&self.seconds)?; + tup_ser.serialize_element(&self.subsecond_nanos)?; + tup_ser.end() + } + } +} From 253a865201dc710f12818c79b6bd205e4441482d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 01:26:22 +0000 Subject: [PATCH 043/312] add serde to document --- rust-runtime/aws-smithy-types/src/document.rs | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/rust-runtime/aws-smithy-types/src/document.rs b/rust-runtime/aws-smithy-types/src/document.rs index 4bfb641fe36..38816420b99 100644 --- a/rust-runtime/aws-smithy-types/src/document.rs +++ b/rust-runtime/aws-smithy-types/src/document.rs @@ -4,6 +4,11 @@ */ use crate::Number; +#[cfg(any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") +))] +use serde; use std::collections::HashMap; /* ANCHOR: document */ @@ -15,6 +20,21 @@ use std::collections::HashMap; /// modeled using rigid types, or data that has a schema that evolves outside of the purview of a model. /// The serialization format of a document is an implementation detail of a protocol. #[derive(Debug, Clone, PartialEq)] +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-serialize"), + derive(serde::Serialize) +)] +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-deserialize"), + derive(serde::Deserialize) +)] +#[cfg_attr( + any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") + ), + serde(untagged) +)] pub enum Document { /// JSON object Object(HashMap), @@ -71,3 +91,60 @@ impl From for Document { Document::Number(Number::NegInt(value as i64)) } } + +/* ANCHOR END: document */ + +#[cfg(test)] +mod test { + /// checks if a) serialization of json suceeds and b) it is compatible with serde_json + #[test] + #[cfg(all( + aws_sdk_unstable, + feature = "serde-serialize", + feature = "serde-deserialize" + ))] + fn serialize_json() { + use crate::Document; + use crate::Number; + use std::collections::HashMap; + let mut map: HashMap = HashMap::new(); + // string + map.insert("hello".into(), "world".to_string().into()); + // numbers + map.insert("pos_int".into(), Document::Number(Number::PosInt(1).into())); + map.insert( + "neg_int".into(), + Document::Number(Number::NegInt(-1).into()), + ); + map.insert( + "float".into(), + Document::Number(Number::Float(0.1 + 0.2).into()), + ); + // booleans + map.insert("true".into(), true.into()); + map.insert("false".into(), false.into()); + // check if array with different datatypes would succeed + map.insert( + "array".into(), + vec![ + map.clone().into(), + "hello-world".to_string().into(), + true.into(), + false.into(), + ] + .into(), + ); + // map + map.insert("map".into(), map.clone().into()); + // null + map.insert("null".into(), Document::Null); + let obj = Document::Object(map); + // comparing string isnt going to work since there is no gurantee for the ordering of the keys + let target_file = include_str!("../test_data/serialize_document.json"); + let json: Result = serde_json::from_str(target_file); + // serializer + assert_eq!(serde_json::to_value(&obj).unwrap(), json.unwrap()); + let doc: Result = serde_json::from_str(target_file); + assert_eq!(obj, doc.unwrap()); + } +} From de7971ff1500abef3031471898f8cc9120c3b740 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 02:01:50 +0000 Subject: [PATCH 044/312] Add serde support to number type --- rust-runtime/aws-smithy-types/src/number.rs | 55 ++++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/number.rs b/rust-runtime/aws-smithy-types/src/number.rs index 76fc08a2181..680e382592a 100644 --- a/rust-runtime/aws-smithy-types/src/number.rs +++ b/rust-runtime/aws-smithy-types/src/number.rs @@ -3,11 +3,35 @@ * SPDX-License-Identifier: Apache-2.0 */ +//! A number type that implements Javascript / JSON semantics, modeled on serde_json: +//! + +use crate::error::{TryFromNumberError, TryFromNumberErrorKind}; +#[cfg(all( + aws_sdk_unstable, + any(feature = "serde-serialize", feature = "serde-deserialize") +))] +use serde; use crate::error::{TryFromNumberError, TryFromNumberErrorKind}; /// A number type that implements Javascript / JSON semantics, modeled on serde_json: /// #[derive(Debug, Clone, Copy, PartialEq)] +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-deserialize"), + derive(serde::Deserialize) +)] +#[cfg_attr( + all(aws_sdk_unstable, feature = "serde-serialize"), + derive(serde::Serialize) +)] +#[cfg_attr( + any( + all(aws_sdk_unstable, feature = "serde-deserialize"), + all(aws_sdk_unstable, feature = "serde-serialize") + ), + serde(untagged) +)] pub enum Number { /// Unsigned 64-bit integer value. PosInt(u64), @@ -184,7 +208,7 @@ impl TryFrom for f32 { } #[cfg(test)] -mod number { +mod test { use super::*; use crate::error::{TryFromNumberError, TryFromNumberErrorKind}; @@ -441,4 +465,31 @@ mod number { 1452089100f32 ); } -} + + #[test] + #[cfg(all( + test, + aws_sdk_unstable, + feature = "serde-deserialize", + feature = "serde-serialize" + ))] + /// ensures that numbers are deserialized as expected + /// 0 <= PosInt + /// 0 > NegInt + /// non integer values == Float + fn number_serde() { + let n: Number = serde_json::from_str("1.1").unwrap(); + assert_eq!(n, Number::Float(1.1)); + let n: Number = serde_json::from_str("1").unwrap(); + assert_eq!(n, Number::PosInt(1)); + let n: Number = serde_json::from_str("0").unwrap(); + assert_eq!(n, Number::PosInt(0)); + let n: Number = serde_json::from_str("-1").unwrap(); + assert_eq!(n, Number::NegInt(-1)); + + assert_eq!("1.1", serde_json::to_string(&Number::Float(1.1)).unwrap()); + assert_eq!("1", serde_json::to_string(&Number::PosInt(1)).unwrap()); + assert_eq!("0", serde_json::to_string(&Number::PosInt(0)).unwrap()); + assert_eq!("-1", serde_json::to_string(&Number::NegInt(-1)).unwrap()); + } +} \ No newline at end of file From bf7347a1e8d062704f3b6ccc2ddf1abdbbe35324 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 02:15:09 +0000 Subject: [PATCH 045/312] pre-commit --- rust-runtime/aws-smithy-types/src/number.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/number.rs b/rust-runtime/aws-smithy-types/src/number.rs index 680e382592a..80527cfc104 100644 --- a/rust-runtime/aws-smithy-types/src/number.rs +++ b/rust-runtime/aws-smithy-types/src/number.rs @@ -12,7 +12,6 @@ use crate::error::{TryFromNumberError, TryFromNumberErrorKind}; any(feature = "serde-serialize", feature = "serde-deserialize") ))] use serde; -use crate::error::{TryFromNumberError, TryFromNumberErrorKind}; /// A number type that implements Javascript / JSON semantics, modeled on serde_json: /// @@ -492,4 +491,4 @@ mod test { assert_eq!("0", serde_json::to_string(&Number::PosInt(0)).unwrap()); assert_eq!("-1", serde_json::to_string(&Number::NegInt(-1)).unwrap()); } -} \ No newline at end of file +} From 6e4b68a061637f7407be2cc633d43be24e4225e7 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 27 Apr 2023 11:17:01 +0900 Subject: [PATCH 046/312] Update number.rs --- rust-runtime/aws-smithy-types/src/number.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/number.rs b/rust-runtime/aws-smithy-types/src/number.rs index 80527cfc104..5ae57a08107 100644 --- a/rust-runtime/aws-smithy-types/src/number.rs +++ b/rust-runtime/aws-smithy-types/src/number.rs @@ -207,7 +207,7 @@ impl TryFrom for f32 { } #[cfg(test)] -mod test { +mod number { use super::*; use crate::error::{TryFromNumberError, TryFromNumberErrorKind}; From 6cb751291c5470dbce4e2171ebffd1e61584f2b9 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 02:30:15 +0000 Subject: [PATCH 047/312] pre commit --- .../aws-smithy-types/src/date_time/de.rs | 188 +++++++++--------- 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index 7816a634d90..6f346ea8dee 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -3,108 +3,108 @@ * SPDX-License-Identifier: Apache-2.0 */ - use super::*; - use serde::de::Visitor; - use serde::Deserialize; +use super::*; +use serde::de::Visitor; +use serde::Deserialize; - struct DateTimeVisitor; +struct DateTimeVisitor; - enum VisitorState { - Second, - SubsecondNanos, - Unexpected, - } +enum VisitorState { + Second, + SubsecondNanos, + Unexpected, +} - impl VisitorState { - const UNEXPECTED_VISITOR_STATE: &'static str = "Unexpected state. This happens when visitor tries to parse something after finished parsing the `subsec_nanos`."; - } +impl VisitorState { + const UNEXPECTED_VISITOR_STATE: &'static str = "Unexpected state. This happens when visitor tries to parse something after finished parsing the `subsec_nanos`."; +} - struct NonHumanReadableDateTimeVisitor { - state: VisitorState, - seconds: i64, - subsecond_nanos: u32, - } +struct NonHumanReadableDateTimeVisitor { + state: VisitorState, + seconds: i64, + subsecond_nanos: u32, +} - fn fail(err_message: M) -> Result - where - M: std::fmt::Display, - E: serde::de::Error, - { - Err(E::custom(err_message)) - } +fn fail(err_message: M) -> Result +where + M: std::fmt::Display, + E: serde::de::Error, +{ + Err(E::custom(err_message)) +} - impl<'de> Visitor<'de> for DateTimeVisitor { - type Value = DateTime; - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("expected RFC-3339 Date Time") - } +impl<'de> Visitor<'de> for DateTimeVisitor { + type Value = DateTime; + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("expected RFC-3339 Date Time") + } - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - match DateTime::from_str(v, Format::DateTime) { - Ok(e) => Ok(e), - Err(e) => fail(e), - } - } - } + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + match DateTime::from_str(v, Format::DateTime) { + Ok(e) => Ok(e), + Err(e) => fail(e), + } + } +} - impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { - type Value = Self; - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("expected (i64, u32)") - } +impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { + type Value = Self; + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("expected (i64, u32)") + } - fn visit_i64(mut self, v: i64) -> Result - where - E: serde::de::Error, - { - match self.state { - VisitorState::Unexpected => fail(VisitorState::UNEXPECTED_VISITOR_STATE), - VisitorState::Second => { - self.seconds = v; - self.state = VisitorState::SubsecondNanos; - Ok(self) - } - _ => fail("`seconds` value must be i64"), - } - } + fn visit_i64(mut self, v: i64) -> Result + where + E: serde::de::Error, + { + match self.state { + VisitorState::Unexpected => fail(VisitorState::UNEXPECTED_VISITOR_STATE), + VisitorState::Second => { + self.seconds = v; + self.state = VisitorState::SubsecondNanos; + Ok(self) + } + _ => fail("`seconds` value must be i64"), + } + } - fn visit_u32(mut self, v: u32) -> Result - where - E: serde::de::Error, - { - match self.state { - VisitorState::Unexpected => fail(VisitorState::UNEXPECTED_VISITOR_STATE), - VisitorState::SubsecondNanos => { - self.subsecond_nanos = v; - self.state = VisitorState::Unexpected; - Ok(self) - } - _ => fail("`subsecond_nanos` value must be u32"), - } - } - } + fn visit_u32(mut self, v: u32) -> Result + where + E: serde::de::Error, + { + match self.state { + VisitorState::Unexpected => fail(VisitorState::UNEXPECTED_VISITOR_STATE), + VisitorState::SubsecondNanos => { + self.subsecond_nanos = v; + self.state = VisitorState::Unexpected; + Ok(self) + } + _ => fail("`subsecond_nanos` value must be u32"), + } + } +} - impl<'de> Deserialize<'de> for DateTime { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - if deserializer.is_human_readable() { - deserializer.deserialize_str(DateTimeVisitor) - } else { - let visitor = NonHumanReadableDateTimeVisitor { - state: VisitorState::Second, - seconds: 0, - subsecond_nanos: 0, - }; - let visitor = deserializer.deserialize_tuple(2, visitor)?; - Ok(DateTime { - seconds: visitor.seconds, - subsecond_nanos: visitor.subsecond_nanos, - }) - } - } - } +impl<'de> Deserialize<'de> for DateTime { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + if deserializer.is_human_readable() { + deserializer.deserialize_str(DateTimeVisitor) + } else { + let visitor = NonHumanReadableDateTimeVisitor { + state: VisitorState::Second, + seconds: 0, + subsecond_nanos: 0, + }; + let visitor = deserializer.deserialize_tuple(2, visitor)?; + Ok(DateTime { + seconds: visitor.seconds, + subsecond_nanos: visitor.subsecond_nanos, + }) + } + } +} From d89e8f473896a6e54d8321554d4e8f4eb8141b88 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 27 Apr 2023 12:17:12 +0900 Subject: [PATCH 048/312] Update metadata.rs --- .../aws-smithy-types/src/error/metadata.rs | 61 +------------------ 1 file changed, 2 insertions(+), 59 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/error/metadata.rs b/rust-runtime/aws-smithy-types/src/error/metadata.rs index 5681fb1d02c..25aa4e1eb4e 100644 --- a/rust-runtime/aws-smithy-types/src/error/metadata.rs +++ b/rust-runtime/aws-smithy-types/src/error/metadata.rs @@ -6,7 +6,6 @@ //! Error metadata use crate::retry::{ErrorKind, ProvideErrorKind}; -use std::borrow::Cow; use std::collections::HashMap; use std::fmt; @@ -40,19 +39,11 @@ pub const EMPTY_ERROR_METADATA: ErrorMetadata = ErrorMetadata { /// For many services, Errors are modeled. However, many services only partially model errors or don't /// model errors at all. In these cases, the SDK will return this generic error type to expose the /// `code`, `message` and `request_id`. -#[cfg_attr( - all(aws_sdk_unstable, feature = "serde-serialize"), - derive(serde::Serialize) -)] -#[cfg_attr( - all(aws_sdk_unstable, feature = "serde-deserialize"), - derive(serde::Deserialize) -)] #[derive(Debug, Eq, PartialEq, Default, Clone)] pub struct ErrorMetadata { code: Option, message: Option, - extras: Option, String>>, + extras: Option } impl ProvideErrorMetadata for ErrorMetadata { @@ -62,23 +53,8 @@ impl ProvideErrorMetadata for ErrorMetadata { } /// Builder for [`ErrorMetadata`]. -#[cfg_attr( - all(aws_sdk_unstable, feature = "serde-serialize"), - derive(serde::Serialize) -)] -#[cfg_attr( - all(aws_sdk_unstable, feature = "serde-deserialize"), - derive(serde::Deserialize) -)] #[derive(Debug, Default)] pub struct Builder { - #[cfg_attr( - any( - all(aws_sdk_unstable, feature = "serde-deserialize"), - all(aws_sdk_unstable, feature = "serde-serialize") - ), - serde(flatten) - )] inner: ErrorMetadata, } @@ -128,7 +104,7 @@ impl Builder { .extras .as_mut() .unwrap() - .insert(Cow::Borrowed(key), value.into()); + .insert(key, value.into()); self } @@ -194,36 +170,3 @@ impl fmt::Display for ErrorMetadata { } impl std::error::Error for ErrorMetadata {} - -#[cfg(all( - test, - any( - all(aws_sdk_unstable, feature = "serde-deserialize"), - all(aws_sdk_unstable, feature = "serde-serialize") - ) -))] -mod test { - use super::*; - - #[test] - /// tests de/ser on ErrorMetaData. - fn test_error_meta_data() { - let mut data = Builder::default() - .code("code") - .message("message") - .custom("hello", "world"); - let ok = serde_json::to_string_pretty(&EMPTY_ERROR_METADATA).unwrap(); - assert_eq!( - &ok, - include_str!("../../test-data/error_meta_data_empty.json") - ); - assert_eq!( - serde_json::from_str(include_str!("../../test-data/error_meta_data.json")).unwrap(), - &data - ); - assert_eq!( - serde_json::from_str(include_str!("../../test-data/error_meta_data.json")).unwrap(), - data.build() - ); - } -} From 3d62a68987950506bb74ec43858b6e3a270ba020 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 27 Apr 2023 12:18:57 +0900 Subject: [PATCH 049/312] Update metadata.rs --- rust-runtime/aws-smithy-types/src/error/metadata.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/error/metadata.rs b/rust-runtime/aws-smithy-types/src/error/metadata.rs index 25aa4e1eb4e..5cc044a1734 100644 --- a/rust-runtime/aws-smithy-types/src/error/metadata.rs +++ b/rust-runtime/aws-smithy-types/src/error/metadata.rs @@ -43,7 +43,7 @@ pub const EMPTY_ERROR_METADATA: ErrorMetadata = ErrorMetadata { pub struct ErrorMetadata { code: Option, message: Option, - extras: Option + extras: Option, } impl ProvideErrorMetadata for ErrorMetadata { From 5d850d938ecc288724aa4e6aee11cad8d6afda98 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 27 Apr 2023 12:39:38 +0900 Subject: [PATCH 050/312] Update metadata.rs --- rust-runtime/aws-smithy-types/src/error/metadata.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/error/metadata.rs b/rust-runtime/aws-smithy-types/src/error/metadata.rs index 5cc044a1734..6629753733d 100644 --- a/rust-runtime/aws-smithy-types/src/error/metadata.rs +++ b/rust-runtime/aws-smithy-types/src/error/metadata.rs @@ -43,7 +43,7 @@ pub const EMPTY_ERROR_METADATA: ErrorMetadata = ErrorMetadata { pub struct ErrorMetadata { code: Option, message: Option, - extras: Option, + extras: Option>, } impl ProvideErrorMetadata for ErrorMetadata { From e27abc135ac42ad417d147266c9e4c3a8ab88074 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 27 Apr 2023 12:39:58 +0900 Subject: [PATCH 051/312] Delete error_meta_data.json --- .../aws-smithy-types/test_data/error_meta_data.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 rust-runtime/aws-smithy-types/test_data/error_meta_data.json diff --git a/rust-runtime/aws-smithy-types/test_data/error_meta_data.json b/rust-runtime/aws-smithy-types/test_data/error_meta_data.json deleted file mode 100644 index db7067d86e4..00000000000 --- a/rust-runtime/aws-smithy-types/test_data/error_meta_data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "code": "code", - "message": "message", - "extras": { - "hello": "world" - } -} From b69160d73652a89a437612e260810ec35b7fcee9 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 27 Apr 2023 12:40:12 +0900 Subject: [PATCH 052/312] Delete error_meta_data_empty.json --- .../aws-smithy-types/test_data/error_meta_data_empty.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json diff --git a/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json b/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json deleted file mode 100644 index 41165f4a49c..00000000000 --- a/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "code": null, - "message": null, - "extras": null -} From 54fa8340cb75aaa3e2b362fb14067acaa91273f7 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 03:55:59 +0000 Subject: [PATCH 053/312] FIX --- CHANGELOG.next.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 121601565e7..f0ae279af48 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -16,3 +16,4 @@ message = "The `Debug` implementation for `PropertyBag` now prints a list of the author = "rcoh" references = ["smithy-rs#2612"] meta = { "breaking" = false, "tada" = false, "bug" = false } + From c8acea15fe25067fcb93955c6ee4bdee067faea1 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 27 Apr 2023 12:56:36 +0900 Subject: [PATCH 054/312] Update number.rs --- rust-runtime/aws-smithy-types/src/number.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/number.rs b/rust-runtime/aws-smithy-types/src/number.rs index 80527cfc104..5ae57a08107 100644 --- a/rust-runtime/aws-smithy-types/src/number.rs +++ b/rust-runtime/aws-smithy-types/src/number.rs @@ -207,7 +207,7 @@ impl TryFrom for f32 { } #[cfg(test)] -mod test { +mod number { use super::*; use crate::error::{TryFromNumberError, TryFromNumberErrorKind}; From 2c262f9e5fb1532b202d45d9b2cecdb2699ad7b6 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 04:13:28 +0000 Subject: [PATCH 055/312] serde decorator --- .../client/smithy/RustClientCodegenPlugin.kt | 200 +++++++++--------- .../client/smithy/customize/SerdeDecorator.kt | 28 +++ 2 files changed, 129 insertions(+), 99 deletions(-) create mode 100644 codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt index faa3a01c5df..322e81a94c8 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt @@ -3,103 +3,105 @@ * SPDX-License-Identifier: Apache-2.0 */ -package software.amazon.smithy.rust.codegen.client.smithy + package software.amazon.smithy.rust.codegen.client.smithy -import software.amazon.smithy.build.PluginContext -import software.amazon.smithy.codegen.core.ReservedWordSymbolProvider -import software.amazon.smithy.model.Model -import software.amazon.smithy.model.shapes.ServiceShape -import software.amazon.smithy.rust.codegen.client.smithy.customizations.ApiKeyAuthDecorator -import software.amazon.smithy.rust.codegen.client.smithy.customizations.ClientCustomizations -import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpAuthDecorator -import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpConnectorConfigDecorator -import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator -import software.amazon.smithy.rust.codegen.client.smithy.customize.CombinedClientCodegenDecorator -import software.amazon.smithy.rust.codegen.client.smithy.customize.NoOpEventStreamSigningDecorator -import software.amazon.smithy.rust.codegen.client.smithy.customize.RequiredCustomizations -import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointParamsDecorator -import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointsDecorator -import software.amazon.smithy.rust.codegen.client.smithy.generators.client.FluentClientDecorator -import software.amazon.smithy.rust.codegen.client.testutil.ClientDecoratableBuildPlugin -import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.NonExhaustive -import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordSymbolProvider -import software.amazon.smithy.rust.codegen.core.smithy.BaseSymbolMetadataProvider -import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget -import software.amazon.smithy.rust.codegen.core.smithy.EventStreamSymbolProvider -import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProviderConfig -import software.amazon.smithy.rust.codegen.core.smithy.StreamingShapeMetadataProvider -import software.amazon.smithy.rust.codegen.core.smithy.StreamingShapeSymbolProvider -import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitor -import java.util.logging.Level -import java.util.logging.Logger - -/** - * Rust Client Codegen Plugin - * - * This is the entrypoint for code generation, triggered by the smithy-build plugin. - * `resources/META-INF.services/software.amazon.smithy.build.SmithyBuildPlugin` refers to this class by name which - * enables the smithy-build plugin to invoke `execute` with all Smithy plugin context + models. - */ -class RustClientCodegenPlugin : ClientDecoratableBuildPlugin() { - override fun getName(): String = "rust-client-codegen" - - override fun executeWithDecorator( - context: PluginContext, - vararg decorator: ClientCodegenDecorator, - ) { - // Suppress extremely noisy logs about reserved words - Logger.getLogger(ReservedWordSymbolProvider::class.java.name).level = Level.OFF - // Discover `RustCodegenDecorators` on the classpath. `RustCodegenDecorator` returns different types of - // customizations. A customization is a function of: - // - location (e.g. the mutate section of an operation) - // - context (e.g. the of the operation) - // - writer: The active RustWriter at the given location - val codegenDecorator = - CombinedClientCodegenDecorator.fromClasspath( - context, - ClientCustomizations(), - RequiredCustomizations(), - FluentClientDecorator(), - EndpointsDecorator(), - EndpointParamsDecorator(), - NoOpEventStreamSigningDecorator(), - ApiKeyAuthDecorator(), - HttpAuthDecorator(), - HttpConnectorConfigDecorator(), - *decorator, - ) - - // ClientCodegenVisitor is the main driver of code generation that traverses the model and generates code - ClientCodegenVisitor(context, codegenDecorator).execute() - } - - companion object { - /** - * When generating code, smithy types need to be converted into Rust types—that is the core role of the symbol provider - * - * The Symbol provider is composed of a base [SymbolVisitor] which handles the core functionality, then is layered - * with other symbol providers, documented inline, to handle the full scope of Smithy types. - */ - fun baseSymbolProvider( - settings: ClientRustSettings, - model: Model, - serviceShape: ServiceShape, - rustSymbolProviderConfig: RustSymbolProviderConfig, - codegenDecorator: ClientCodegenDecorator, - ) = - SymbolVisitor(settings, model, serviceShape = serviceShape, config = rustSymbolProviderConfig) - // Generate different types for EventStream shapes (e.g. transcribe streaming) - .let { EventStreamSymbolProvider(rustSymbolProviderConfig.runtimeConfig, it, CodegenTarget.CLIENT) } - // Generate `ByteStream` instead of `Blob` for streaming binary shapes (e.g. S3 GetObject) - .let { StreamingShapeSymbolProvider(it) } - // Add Rust attributes (like `#[derive(PartialEq)]`) to generated shapes - .let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf(NonExhaustive)) } - // Streaming shapes need different derives (e.g. they cannot derive `PartialEq`) - .let { StreamingShapeMetadataProvider(it) } - // Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot - // be the name of an operation input - .let { RustReservedWordSymbolProvider(it, ClientReservedWords) } - // Allows decorators to inject a custom symbol provider - .let { codegenDecorator.symbolProvider(it) } - } -} + import software.amazon.smithy.build.PluginContext + import software.amazon.smithy.codegen.core.ReservedWordSymbolProvider + import software.amazon.smithy.model.Model + import software.amazon.smithy.model.shapes.ServiceShape + import software.amazon.smithy.rust.codegen.client.smithy.customizations.ApiKeyAuthDecorator + import software.amazon.smithy.rust.codegen.client.smithy.customizations.ClientCustomizations + import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpAuthDecorator + import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpConnectorConfigDecorator + import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator + import software.amazon.smithy.rust.codegen.client.smithy.customize.CombinedClientCodegenDecorator + import software.amazon.smithy.rust.codegen.client.smithy.customize.NoOpEventStreamSigningDecorator + import software.amazon.smithy.rust.codegen.client.smithy.customize.RequiredCustomizations + import software.amazon.smithy.rust.codegen.client.smithy.customize.SerdeDecorator + import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointParamsDecorator + import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointsDecorator + import software.amazon.smithy.rust.codegen.client.smithy.generators.client.FluentClientDecorator + import software.amazon.smithy.rust.codegen.client.testutil.ClientDecoratableBuildPlugin + import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.NonExhaustive + import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordSymbolProvider + import software.amazon.smithy.rust.codegen.core.smithy.BaseSymbolMetadataProvider + import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget + import software.amazon.smithy.rust.codegen.core.smithy.EventStreamSymbolProvider + import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProviderConfig + import software.amazon.smithy.rust.codegen.core.smithy.StreamingShapeMetadataProvider + import software.amazon.smithy.rust.codegen.core.smithy.StreamingShapeSymbolProvider + import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitor + import java.util.logging.Level + import java.util.logging.Logger + + /** + * Rust Client Codegen Plugin + * + * This is the entrypoint for code generation, triggered by the smithy-build plugin. + * `resources/META-INF.services/software.amazon.smithy.build.SmithyBuildPlugin` refers to this class by name which + * enables the smithy-build plugin to invoke `execute` with all Smithy plugin context + models. + */ + class RustClientCodegenPlugin : ClientDecoratableBuildPlugin() { + override fun getName(): String = "rust-client-codegen" + + override fun executeWithDecorator( + context: PluginContext, + vararg decorator: ClientCodegenDecorator, + ) { + // Suppress extremely noisy logs about reserved words + Logger.getLogger(ReservedWordSymbolProvider::class.java.name).level = Level.OFF + // Discover `RustCodegenDecorators` on the classpath. `RustCodegenDecorator` returns different types of + // customizations. A customization is a function of: + // - location (e.g. the mutate section of an operation) + // - context (e.g. the of the operation) + // - writer: The active RustWriter at the given location + val codegenDecorator = + CombinedClientCodegenDecorator.fromClasspath( + context, + SerdeDecorator(), + ClientCustomizations(), + RequiredCustomizations(), + FluentClientDecorator(), + EndpointsDecorator(), + EndpointParamsDecorator(), + NoOpEventStreamSigningDecorator(), + ApiKeyAuthDecorator(), + HttpAuthDecorator(), + HttpConnectorConfigDecorator(), + *decorator, + ) + + // ClientCodegenVisitor is the main driver of code generation that traverses the model and generates code + ClientCodegenVisitor(context, codegenDecorator).execute() + } + + companion object { + /** + * When generating code, smithy types need to be converted into Rust types—that is the core role of the symbol provider + * + * The Symbol provider is composed of a base [SymbolVisitor] which handles the core functionality, then is layered + * with other symbol providers, documented inline, to handle the full scope of Smithy types. + */ + fun baseSymbolProvider( + settings: ClientRustSettings, + model: Model, + serviceShape: ServiceShape, + rustSymbolProviderConfig: RustSymbolProviderConfig, + codegenDecorator: ClientCodegenDecorator, + ) = + SymbolVisitor(settings, model, serviceShape = serviceShape, config = rustSymbolProviderConfig) + // Generate different types for EventStream shapes (e.g. transcribe streaming) + .let { EventStreamSymbolProvider(rustSymbolProviderConfig.runtimeConfig, it, CodegenTarget.CLIENT) } + // Generate `ByteStream` instead of `Blob` for streaming binary shapes (e.g. S3 GetObject) + .let { StreamingShapeSymbolProvider(it) } + // Add Rust attributes (like `#[derive(PartialEq)]`) to generated shapes + .let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf(NonExhaustive)) } + // Streaming shapes need different derives (e.g. they cannot derive `PartialEq`) + .let { StreamingShapeMetadataProvider(it) } + // Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot + // be the name of an operation input + .let { RustReservedWordSymbolProvider(it, ClientReservedWords) } + // Allows decorators to inject a custom symbol provider + .let { codegenDecorator.symbolProvider(it) } + } + } \ No newline at end of file diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt new file mode 100644 index 00000000000..7471d405ef8 --- /dev/null +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -0,0 +1,28 @@ +/* +* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +* SPDX-License-Identifier: Apache-2.0 +*/ + +package software.amazon.smithy.rust.codegen.client.smithy.customize + +import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext +import software.amazon.smithy.rust.codegen.core.rustlang.Feature +import software.amazon.smithy.rust.codegen.core.smithy.RustCrate + +/** + * This class, + * - Adds serde as a dependency + * + */ +class SerdeDecorator : ClientCodegenDecorator { + override val name: String = "SerdeDecorator" + override val order: Byte = -1 + + override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + fun _feature(feature_name: String, crate_name: String): Feature { + return Feature(feature_name, false, listOf(crate_name + "/" + feature_name)) + } + rustCrate.mergeFeature(_feature("serde-serialize", "aws-smithy-types")) + rustCrate.mergeFeature(_feature("serde-deserialize", "aws-smithy-types")) + } +} \ No newline at end of file From 3645285aa5101e8c3aaf1ba1392d92c9bff730f7 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 04:15:57 +0000 Subject: [PATCH 056/312] update --- .../client/smithy/RustClientCodegenPlugin.kt | 208 +++++++++--------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt index 322e81a94c8..d8a333b2053 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt @@ -1,107 +1,107 @@ /* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ +* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +* SPDX-License-Identifier: Apache-2.0 +*/ - package software.amazon.smithy.rust.codegen.client.smithy +package software.amazon.smithy.rust.codegen.client.smithy - import software.amazon.smithy.build.PluginContext - import software.amazon.smithy.codegen.core.ReservedWordSymbolProvider - import software.amazon.smithy.model.Model - import software.amazon.smithy.model.shapes.ServiceShape - import software.amazon.smithy.rust.codegen.client.smithy.customizations.ApiKeyAuthDecorator - import software.amazon.smithy.rust.codegen.client.smithy.customizations.ClientCustomizations - import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpAuthDecorator - import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpConnectorConfigDecorator - import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator - import software.amazon.smithy.rust.codegen.client.smithy.customize.CombinedClientCodegenDecorator - import software.amazon.smithy.rust.codegen.client.smithy.customize.NoOpEventStreamSigningDecorator - import software.amazon.smithy.rust.codegen.client.smithy.customize.RequiredCustomizations - import software.amazon.smithy.rust.codegen.client.smithy.customize.SerdeDecorator - import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointParamsDecorator - import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointsDecorator - import software.amazon.smithy.rust.codegen.client.smithy.generators.client.FluentClientDecorator - import software.amazon.smithy.rust.codegen.client.testutil.ClientDecoratableBuildPlugin - import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.NonExhaustive - import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordSymbolProvider - import software.amazon.smithy.rust.codegen.core.smithy.BaseSymbolMetadataProvider - import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget - import software.amazon.smithy.rust.codegen.core.smithy.EventStreamSymbolProvider - import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProviderConfig - import software.amazon.smithy.rust.codegen.core.smithy.StreamingShapeMetadataProvider - import software.amazon.smithy.rust.codegen.core.smithy.StreamingShapeSymbolProvider - import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitor - import java.util.logging.Level - import java.util.logging.Logger - - /** - * Rust Client Codegen Plugin - * - * This is the entrypoint for code generation, triggered by the smithy-build plugin. - * `resources/META-INF.services/software.amazon.smithy.build.SmithyBuildPlugin` refers to this class by name which - * enables the smithy-build plugin to invoke `execute` with all Smithy plugin context + models. - */ - class RustClientCodegenPlugin : ClientDecoratableBuildPlugin() { - override fun getName(): String = "rust-client-codegen" - - override fun executeWithDecorator( - context: PluginContext, - vararg decorator: ClientCodegenDecorator, - ) { - // Suppress extremely noisy logs about reserved words - Logger.getLogger(ReservedWordSymbolProvider::class.java.name).level = Level.OFF - // Discover `RustCodegenDecorators` on the classpath. `RustCodegenDecorator` returns different types of - // customizations. A customization is a function of: - // - location (e.g. the mutate section of an operation) - // - context (e.g. the of the operation) - // - writer: The active RustWriter at the given location - val codegenDecorator = - CombinedClientCodegenDecorator.fromClasspath( - context, - SerdeDecorator(), - ClientCustomizations(), - RequiredCustomizations(), - FluentClientDecorator(), - EndpointsDecorator(), - EndpointParamsDecorator(), - NoOpEventStreamSigningDecorator(), - ApiKeyAuthDecorator(), - HttpAuthDecorator(), - HttpConnectorConfigDecorator(), - *decorator, - ) - - // ClientCodegenVisitor is the main driver of code generation that traverses the model and generates code - ClientCodegenVisitor(context, codegenDecorator).execute() - } - - companion object { - /** - * When generating code, smithy types need to be converted into Rust types—that is the core role of the symbol provider - * - * The Symbol provider is composed of a base [SymbolVisitor] which handles the core functionality, then is layered - * with other symbol providers, documented inline, to handle the full scope of Smithy types. - */ - fun baseSymbolProvider( - settings: ClientRustSettings, - model: Model, - serviceShape: ServiceShape, - rustSymbolProviderConfig: RustSymbolProviderConfig, - codegenDecorator: ClientCodegenDecorator, - ) = - SymbolVisitor(settings, model, serviceShape = serviceShape, config = rustSymbolProviderConfig) - // Generate different types for EventStream shapes (e.g. transcribe streaming) - .let { EventStreamSymbolProvider(rustSymbolProviderConfig.runtimeConfig, it, CodegenTarget.CLIENT) } - // Generate `ByteStream` instead of `Blob` for streaming binary shapes (e.g. S3 GetObject) - .let { StreamingShapeSymbolProvider(it) } - // Add Rust attributes (like `#[derive(PartialEq)]`) to generated shapes - .let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf(NonExhaustive)) } - // Streaming shapes need different derives (e.g. they cannot derive `PartialEq`) - .let { StreamingShapeMetadataProvider(it) } - // Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot - // be the name of an operation input - .let { RustReservedWordSymbolProvider(it, ClientReservedWords) } - // Allows decorators to inject a custom symbol provider - .let { codegenDecorator.symbolProvider(it) } - } - } \ No newline at end of file +import software.amazon.smithy.build.PluginContext +import software.amazon.smithy.codegen.core.ReservedWordSymbolProvider +import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.ServiceShape +import software.amazon.smithy.rust.codegen.client.smithy.customizations.ApiKeyAuthDecorator +import software.amazon.smithy.rust.codegen.client.smithy.customizations.ClientCustomizations +import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpAuthDecorator +import software.amazon.smithy.rust.codegen.client.smithy.customizations.HttpConnectorConfigDecorator +import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator +import software.amazon.smithy.rust.codegen.client.smithy.customize.CombinedClientCodegenDecorator +import software.amazon.smithy.rust.codegen.client.smithy.customize.NoOpEventStreamSigningDecorator +import software.amazon.smithy.rust.codegen.client.smithy.customize.RequiredCustomizations +import software.amazon.smithy.rust.codegen.client.smithy.customize.SerdeDecorator +import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointParamsDecorator +import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointsDecorator +import software.amazon.smithy.rust.codegen.client.smithy.generators.client.FluentClientDecorator +import software.amazon.smithy.rust.codegen.client.testutil.ClientDecoratableBuildPlugin +import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.NonExhaustive +import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.BaseSymbolMetadataProvider +import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget +import software.amazon.smithy.rust.codegen.core.smithy.EventStreamSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProviderConfig +import software.amazon.smithy.rust.codegen.core.smithy.StreamingShapeMetadataProvider +import software.amazon.smithy.rust.codegen.core.smithy.StreamingShapeSymbolProvider +import software.amazon.smithy.rust.codegen.core.smithy.SymbolVisitor +import java.util.logging.Level +import java.util.logging.Logger + +/** + * Rust Client Codegen Plugin +* +* This is the entrypoint for code generation, triggered by the smithy-build plugin. +* `resources/META-INF.services/software.amazon.smithy.build.SmithyBuildPlugin` refers to this class by name which +* enables the smithy-build plugin to invoke `execute` with all Smithy plugin context + models. +*/ +class RustClientCodegenPlugin : ClientDecoratableBuildPlugin() { + override fun getName(): String = "rust-client-codegen" + + override fun executeWithDecorator( + context: PluginContext, + vararg decorator: ClientCodegenDecorator, + ) { + // Suppress extremely noisy logs about reserved words + Logger.getLogger(ReservedWordSymbolProvider::class.java.name).level = Level.OFF + // Discover `RustCodegenDecorators` on the classpath. `RustCodegenDecorator` returns different types of + // customizations. A customization is a function of: + // - location (e.g. the mutate section of an operation) + // - context (e.g. the of the operation) + // - writer: The active RustWriter at the given location + val codegenDecorator = + CombinedClientCodegenDecorator.fromClasspath( + context, + SerdeDecorator(), + ClientCustomizations(), + RequiredCustomizations(), + FluentClientDecorator(), + EndpointsDecorator(), + EndpointParamsDecorator(), + NoOpEventStreamSigningDecorator(), + ApiKeyAuthDecorator(), + HttpAuthDecorator(), + HttpConnectorConfigDecorator(), + *decorator, + ) + + // ClientCodegenVisitor is the main driver of code generation that traverses the model and generates code + ClientCodegenVisitor(context, codegenDecorator).execute() + } + + companion object { + /** + * When generating code, smithy types need to be converted into Rust types—that is the core role of the symbol provider + * + * The Symbol provider is composed of a base [SymbolVisitor] which handles the core functionality, then is layered + * with other symbol providers, documented inline, to handle the full scope of Smithy types. + */ + fun baseSymbolProvider( + settings: ClientRustSettings, + model: Model, + serviceShape: ServiceShape, + rustSymbolProviderConfig: RustSymbolProviderConfig, + codegenDecorator: ClientCodegenDecorator, + ) = + SymbolVisitor(settings, model, serviceShape = serviceShape, config = rustSymbolProviderConfig) + // Generate different types for EventStream shapes (e.g. transcribe streaming) + .let { EventStreamSymbolProvider(rustSymbolProviderConfig.runtimeConfig, it, CodegenTarget.CLIENT) } + // Generate `ByteStream` instead of `Blob` for streaming binary shapes (e.g. S3 GetObject) + .let { StreamingShapeSymbolProvider(it) } + // Add Rust attributes (like `#[derive(PartialEq)]`) to generated shapes + .let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf(NonExhaustive)) } + // Streaming shapes need different derives (e.g. they cannot derive `PartialEq`) + .let { StreamingShapeMetadataProvider(it) } + // Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot + // be the name of an operation input + .let { RustReservedWordSymbolProvider(it, ClientReservedWords) } + // Allows decorators to inject a custom symbol provider + .let { codegenDecorator.symbolProvider(it) } + } +} \ No newline at end of file From fbcbf04dcf25dcbdb9329834ce7cb883df4aa0e1 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 04:16:15 +0000 Subject: [PATCH 057/312] update --- .../client/smithy/RustClientCodegenPlugin.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt index d8a333b2053..fea222cec07 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt @@ -36,11 +36,11 @@ import java.util.logging.Logger /** * Rust Client Codegen Plugin -* -* This is the entrypoint for code generation, triggered by the smithy-build plugin. -* `resources/META-INF.services/software.amazon.smithy.build.SmithyBuildPlugin` refers to this class by name which -* enables the smithy-build plugin to invoke `execute` with all Smithy plugin context + models. -*/ + * + * This is the entrypoint for code generation, triggered by the smithy-build plugin. + * `resources/META-INF.services/software.amazon.smithy.build.SmithyBuildPlugin` refers to this class by name which + * enables the smithy-build plugin to invoke `execute` with all Smithy plugin context + models. + */ class RustClientCodegenPlugin : ClientDecoratableBuildPlugin() { override fun getName(): String = "rust-client-codegen" @@ -78,10 +78,10 @@ class RustClientCodegenPlugin : ClientDecoratableBuildPlugin() { companion object { /** * When generating code, smithy types need to be converted into Rust types—that is the core role of the symbol provider - * - * The Symbol provider is composed of a base [SymbolVisitor] which handles the core functionality, then is layered - * with other symbol providers, documented inline, to handle the full scope of Smithy types. - */ + * + * The Symbol provider is composed of a base [SymbolVisitor] which handles the core functionality, then is layered + * with other symbol providers, documented inline, to handle the full scope of Smithy types. + */ fun baseSymbolProvider( settings: ClientRustSettings, model: Model, From 263eb867d240bcdf994dac2a4d5da3fb80854e7c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 04:17:15 +0000 Subject: [PATCH 058/312] update --- .../rust/codegen/client/smithy/RustClientCodegenPlugin.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt index fea222cec07..2b7e94b5cc5 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt @@ -1,7 +1,7 @@ /* -* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -* SPDX-License-Identifier: Apache-2.0 -*/ + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ package software.amazon.smithy.rust.codegen.client.smithy From 2b1ee72f56353f5fde17b47f9ffa8fcd68b3a39d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 04:19:06 +0000 Subject: [PATCH 059/312] update --- .../rust/codegen/client/smithy/RustClientCodegenPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt index 2b7e94b5cc5..3f21fa2272a 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt @@ -104,4 +104,4 @@ class RustClientCodegenPlugin : ClientDecoratableBuildPlugin() { // Allows decorators to inject a custom symbol provider .let { codegenDecorator.symbolProvider(it) } } -} \ No newline at end of file +} From 0b01612108f784324d16e5ac766a19d192532be7 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 04:21:11 +0000 Subject: [PATCH 060/312] update --- .../rust/codegen/client/smithy/customize/SerdeDecorator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 7471d405ef8..56a777b4708 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -25,4 +25,4 @@ class SerdeDecorator : ClientCodegenDecorator { rustCrate.mergeFeature(_feature("serde-serialize", "aws-smithy-types")) rustCrate.mergeFeature(_feature("serde-deserialize", "aws-smithy-types")) } -} \ No newline at end of file +} From 88b3c435b4c646746b156f385c07a90f4cd392fa Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 04:31:03 +0000 Subject: [PATCH 061/312] - Add feature gates - Add serde related attributes --- .../rust/codegen/core/rustlang/RustType.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index 79dde7de12c..007b1b9bed3 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -475,6 +475,23 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { } } + // These were supposed to be a part of companion object but we decided to move it out to here to avoid NPE + // You can find the discussion here. + // https://github.com/awslabs/smithy-rs/discussions/2248 + public fun SerdeSerialize(): Attribute { + return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-serialize")), derive(RuntimeType.SerdeSerialize))) + } + public fun SerdeDeserialize(): Attribute { + return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-deserialize")), derive(RuntimeType.SerdeDeserialize))) + } + public fun SerdeSkip(): Attribute { + return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))), serde("skip"))) + } + + public fun SerdeSerializeOrDeserialize(): Attribute { + return Attribute(cfg(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))))) + } + companion object { val AllowClippyBoxedLocal = Attribute(allow("clippy::boxed_local")) val AllowClippyLetAndReturn = Attribute(allow("clippy::let_and_return")) @@ -503,6 +520,7 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { val Test = Attribute("test") val TokioTest = Attribute(RuntimeType.Tokio.resolve("test").writable) + val AwsSdkUnstableAttribute = Attribute(cfg("aws_sdk_unstable")) /** * [non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute) @@ -531,10 +549,12 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { } fun all(vararg attrMacros: Writable): Writable = macroWithArgs("all", *attrMacros) + fun cfgAttr(vararg attrMacros: Writable): Writable = macroWithArgs("cfg_attr", *attrMacros) fun allow(lints: Collection): Writable = macroWithArgs("allow", *lints.toTypedArray()) fun allow(vararg lints: String): Writable = macroWithArgs("allow", *lints) fun deny(vararg lints: String): Writable = macroWithArgs("deny", *lints) + fun serde(vararg lints: String): Writable = macroWithArgs("serde", *lints) fun any(vararg attrMacros: Writable): Writable = macroWithArgs("any", *attrMacros) fun cfg(vararg attrMacros: Writable): Writable = macroWithArgs("cfg", *attrMacros) fun cfg(vararg attrMacros: String): Writable = macroWithArgs("cfg", *attrMacros) From 82d296c38fa6794e7a986639d82456f1587b185f Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 04:33:55 +0000 Subject: [PATCH 062/312] Add CfgUnstable feature gate --- .../smithy/rust/codegen/core/rustlang/CargoDependency.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt index 2e372b49894..0ead4d6e7b7 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt @@ -16,6 +16,7 @@ import java.nio.file.Path sealed class DependencyScope { object Dev : DependencyScope() object Compile : DependencyScope() + object CfgUnstable : DependencyScope() object Build : DependencyScope() } @@ -277,5 +278,8 @@ data class CargoDependency( fun smithyRuntimeApi(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-runtime-api") fun smithyTypes(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-types") fun smithyXml(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-xml") + + // behind feature-gate + val Serde = CargoDependency("serde", CratesIo("1.0"), features = setOf("derive"), scope = DependencyScope.CfgUnstable) } } From 5cc6ac97738eb917a08fc4644036c90f3aafa984 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 04:36:36 +0000 Subject: [PATCH 063/312] add serde to runtime type --- .../amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt index f8c656c08ef..b1200b5cb28 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt @@ -249,6 +249,11 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) val ConstrainedTrait = RuntimeType("crate::constrained::Constrained", InlineDependency.constrained()) val MaybeConstrained = RuntimeType("crate::constrained::MaybeConstrained", InlineDependency.constrained()) + // serde types. Gated behind `CfgUnstable`. + val Serde = CargoDependency.Serde.toType() + val SerdeSerialize = Serde.resolve("Serialize") + val SerdeDeserialize = Serde.resolve("Deserialize") + // smithy runtime types fun smithyAsync(runtimeConfig: RuntimeConfig) = CargoDependency.smithyAsync(runtimeConfig).toType() fun smithyChecksums(runtimeConfig: RuntimeConfig) = CargoDependency.smithyChecksums(runtimeConfig).toType() From cc4ba983b44b581aad68a3492a17cc4405bfae03 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 05:08:33 +0000 Subject: [PATCH 064/312] FIX? --- rust-runtime/aws-smithy-types/src/blob.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 501b3a7f190..23a782ca740 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -41,7 +41,6 @@ impl AsRef<[u8]> for Blob { } } - #[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] impl Serialize for Blob { fn serialize(&self, serializer: S) -> Result From d2f48075b2440db0e1a488336253cd808b9d8b6d Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 27 Apr 2023 14:12:20 +0900 Subject: [PATCH 065/312] Update rust-toolchain.toml --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index f0c1f0fc627..fa7280baeb1 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.68.2" +channel = "1.67.1" From 58dd89e4da55e12082e4f0c1f319af393019858f Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 05:17:50 +0000 Subject: [PATCH 066/312] update --- .../rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt | 2 +- .../rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index 4d2792e982e..f0681a262b0 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -19,7 +19,7 @@ import software.amazon.smithy.rust.codegen.core.util.isStreaming // Part of RFC30 public object RenderSerdeAttribute { public fun addSerde(writer: RustWriter, shape: Shape? = null, model: Model? = null) { - if (shape == null || model == null) return; + if (shape == null || model == null) return if (shape.hasTrait() && shape.members().none { it.isEventStream(model) }) { writeAttributes(writer) } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index 7bc10a47fd4..57754f3142b 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -158,7 +158,7 @@ internal class BuilderGeneratorTest { assert!(err.is_err()); let err: Builder = serde_json::from_str(json_str); assert!(err.is_err()); - + let my_struct1 = MyError::builder().message("something".to_string()).build(); assert!(serde_json::to_string(my_struct1).is_err()); let my_struct2 = MyError::builder().message("something".to_string()); From 6e8af770a5fe469f7e0e859490441b14271023aa Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 27 Apr 2023 14:20:58 +0900 Subject: [PATCH 067/312] Delete error_meta_data_empty.json --- .../aws-smithy-types/test_data/error_meta_data_empty.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json diff --git a/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json b/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json deleted file mode 100644 index 41165f4a49c..00000000000 --- a/rust-runtime/aws-smithy-types/test_data/error_meta_data_empty.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "code": null, - "message": null, - "extras": null -} From 3fcfed30e88fc485f03fa95790235046decab0c8 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 27 Apr 2023 14:23:21 +0900 Subject: [PATCH 068/312] Delete error_meta_data.json --- .../aws-smithy-types/test_data/error_meta_data.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 rust-runtime/aws-smithy-types/test_data/error_meta_data.json diff --git a/rust-runtime/aws-smithy-types/test_data/error_meta_data.json b/rust-runtime/aws-smithy-types/test_data/error_meta_data.json deleted file mode 100644 index db7067d86e4..00000000000 --- a/rust-runtime/aws-smithy-types/test_data/error_meta_data.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "code": "code", - "message": "message", - "extras": { - "hello": "world" - } -} From f701ae18ba7d2216778fc4e1dc40c3a3ee74f235 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 05:26:19 +0000 Subject: [PATCH 069/312] add set field --- .../client/FluentClientGenerator.kt | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 6c085fd673b..77e46942419 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -267,6 +267,8 @@ class FluentClientGenerator( ) { val outputType = symbolProvider.toSymbol(operation.outputShape(model)) val errorType = symbolProvider.symbolForOperationError(operation) + val inputBuilderType = symbolProvider.symbolForBuilder(input) + val fnName = clientOperationFnName(operation, symbolProvider) rust("/// Creates a new `${operationSymbol.name}`.") withBlockTemplate( @@ -316,6 +318,7 @@ class FluentClientGenerator( .map_err(#{SdkError}::construction_failure)?; self.handle.client.call(op).await } + """, "CustomizableOperation" to ClientRustModule.Client.customize.toType() .resolve("CustomizableOperation"), @@ -331,6 +334,43 @@ class FluentClientGenerator( generics.toRustGenerics(), ), ) + + // this fixes this error + // error[E0592]: duplicate definitions with name `set_fields` + // --> sdk/connectcases/src/operation/update_case/builders.rs:115:5 + // | + // 78 | / pub fn set_fields( + // 79 | | mut self, + // 80 | | data: crate::operation::update_case::builders::UpdateCaseInputBuilder, + // 81 | | ) -> Self { + // | |_____________- other definition for `set_fields` + // ... + // 115 | / pub fn set_fields( + // 116 | | mut self, + // 117 | | input: std::option::Option>, + // 118 | | ) -> Self { + // | |_____________^ duplicate definitions for `set_fields` + if (inputBuilderType.toString().endsWith("Builder")) { + rustTemplate( + """ + ##[#{AwsSdkUnstableAttribute}] + /// This function replaces the parameter with new one. + /// It is useful when you want to replace the existing data with de-serialized data. + /// ```compile_fail + /// let result_future = async { + /// let deserialized_parameters: $inputBuilderType = serde_json::from_str(&json_string).unwrap(); + /// client.$fnName().set_fields(&deserialized_parameters).send().await + /// }; + /// ``` + pub fn set_fields(mut self, data: $inputBuilderType) -> Self { + self.inner = data; + self + } + """, + "AwsSdkUnstableAttribute" to Attribute.AwsSdkUnstableAttribute.inner, + ) + } + if (enableNewSmithyRuntime) { rustTemplate( """ From f83df7d4591b646312f82ced8be7319df0819e39 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 27 Apr 2023 14:35:32 +0900 Subject: [PATCH 070/312] Update rust-toolchain.toml --- rust-toolchain.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index fa7280baeb1..588ffd57885 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,2 @@ [toolchain] channel = "1.67.1" - From 21c14d35c02945f2af46df45231e25d689dfef7e Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 05:56:00 +0000 Subject: [PATCH 071/312] update --- .../core/smithy/generators/BuilderGenerator.kt | 2 +- .../core/smithy/generators/RenderSerdeAttribute.kt | 14 +++++--------- .../core/smithy/generators/StructureGenerator.kt | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt index 7aba968e746..ffffb14b416 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt @@ -220,7 +220,7 @@ class BuilderGenerator( val memberName = symbolProvider.toMemberName(member) // All fields in the builder are optional. val memberSymbol = symbolProvider.toSymbol(member).makeOptional() - RenderSerdeAttribute.skipIfStream(writer, member, model) + RenderSerdeAttribute.skipIfStream(writer, member, model, shape) SensitiveWarning.addDoc(writer, member) renderBuilderMember(this, memberName, memberSymbol) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index f0681a262b0..3aa85ed7daf 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -20,13 +20,14 @@ import software.amazon.smithy.rust.codegen.core.util.isStreaming public object RenderSerdeAttribute { public fun addSerde(writer: RustWriter, shape: Shape? = null, model: Model? = null) { if (shape == null || model == null) return - if (shape.hasTrait() && shape.members().none { it.isEventStream(model) }) { - writeAttributes(writer) + if (shape.hasTrait().not() && shape.members().none { it.isEventStream(model) }) { + Attribute("").SerdeSerialize().render(writer) + Attribute("").SerdeDeserialize().render(writer) } } - public fun skipIfStream(writer: RustWriter, member: MemberShape, model: Model) { - if (member.isEventStream(model)) { + public fun skipIfStream(writer: RustWriter, member: MemberShape, model: Model, shape: Shape? = null) { + if (member.isEventStream(model) || (shape != null && shape.hasTrait())) { return } if (member.isStreaming(model)) { @@ -40,9 +41,4 @@ public object RenderSerdeAttribute { Attribute("").SerdeSerializeOrDeserialize().render(writer) writer.raw("use serde;") } - - public fun writeAttributes(writer: RustWriter) { - Attribute("").SerdeSerialize().render(writer) - Attribute("").SerdeDeserialize().render(writer) - } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt index 044bfc7189f..932797a9565 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt @@ -171,7 +171,7 @@ open class StructureGenerator( writer.rustBlock("struct $name ${lifetimeDeclaration()}") { writer.forEachMember(members) { member, memberName, memberSymbol -> SensitiveWarning.addDoc(writer, shape) - RenderSerdeAttribute.skipIfStream(writer, member, model) + RenderSerdeAttribute.skipIfStream(writer, member, model, shape) renderStructureMember(writer, member, memberName, memberSymbol) } writeCustomizations(customizations, StructureSection.AdditionalFields(shape)) From 1c0355a7603b6db44f1a6aad3ff0335f6c84b40a Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 06:07:07 +0000 Subject: [PATCH 072/312] update --- .../codegen/core/smithy/generators/BuilderGeneratorTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index 57754f3142b..066d933dc53 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -25,6 +25,7 @@ internal class BuilderGeneratorTest { private val struct = StructureGeneratorTest.struct private val credentials = StructureGeneratorTest.credentials private val secretStructure = StructureGeneratorTest.secretStructure + private val errorStruct = StructureGeneratorTest.error @Test fun `generate builders`() { @@ -140,10 +141,9 @@ internal class BuilderGeneratorTest { @Test fun `don't add serde to error types`() { - print("don't add serde to error types") val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) - project.moduleFor(inner) { + project.moduleFor(errorStruct) { rust("##![allow(deprecated)]") StructureGenerator(model, provider, this, inner, emptyList()).render() StructureGenerator(model, provider, this, struct, emptyList()).render() From 9c934113f4465533fbf8cf49d0a5d18f25a60f0c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 06:54:11 +0000 Subject: [PATCH 073/312] commit --- .../codegen/core/smithy/generators/RenderSerdeAttribute.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index 3aa85ed7daf..cdd534646a2 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -26,10 +26,8 @@ public object RenderSerdeAttribute { } } - public fun skipIfStream(writer: RustWriter, member: MemberShape, model: Model, shape: Shape? = null) { - if (member.isEventStream(model) || (shape != null && shape.hasTrait())) { - return - } + public fun skipIfStream(writer: RustWriter, member: MemberShape, model: Model, shape: Shape) { + if (member.isEventStream(model) || shape.hasTrait().not()) return if (member.isStreaming(model)) { Attribute("").SerdeSkip().render(writer) } From 1879480e15e70d538f822ede465384691e1485e9 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 06:58:32 +0000 Subject: [PATCH 074/312] update --- .../codegen/core/smithy/generators/RenderSerdeAttribute.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index cdd534646a2..84e3a37f5c8 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -20,14 +20,15 @@ import software.amazon.smithy.rust.codegen.core.util.isStreaming public object RenderSerdeAttribute { public fun addSerde(writer: RustWriter, shape: Shape? = null, model: Model? = null) { if (shape == null || model == null) return - if (shape.hasTrait().not() && shape.members().none { it.isEventStream(model) }) { + if (shape.hasTrait()) return + if (shape.members().none { it.isEventStream(model) }) { Attribute("").SerdeSerialize().render(writer) Attribute("").SerdeDeserialize().render(writer) } } public fun skipIfStream(writer: RustWriter, member: MemberShape, model: Model, shape: Shape) { - if (member.isEventStream(model) || shape.hasTrait().not()) return + if (shape.hasTrait() || member.isEventStream(model)) return if (member.isStreaming(model)) { Attribute("").SerdeSkip().render(writer) } From 2ec13671649c0e52be8f7acaf04bd1f234b038a2 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 07:00:19 +0000 Subject: [PATCH 075/312] update --- .../codegen/client/smithy/generators/ClientEnumGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt index 7ed0cf5ec93..cc8853bdeaa 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt @@ -99,7 +99,7 @@ data class InfallibleEnumType( """.trimIndent(), ) - RenderSerdeAttribute.addSerde(this, null, null) + RenderSerdeAttribute.addSerde(this) context.enumMeta.render(this) rust("struct $UnknownVariantValue(pub(crate) String);") rustBlock("impl $UnknownVariantValue") { From 48f6c169042e7198867e5f0d74e5543f8d332e0c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 07:24:34 +0000 Subject: [PATCH 076/312] Refactoring --- .../smithy/generators/BuilderGenerator.kt | 4 ++-- .../core/smithy/generators/EnumGenerator.kt | 4 ++-- .../smithy/generators/RenderSerdeAttribute.kt | 20 ++++++++++++++++--- .../smithy/generators/StructureGenerator.kt | 4 ++-- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt index ffffb14b416..2726dc02a93 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt @@ -213,7 +213,7 @@ class BuilderGenerator( metadata.additionalAttributes.render(writer) Attribute(derive(builderDerives)).render(writer) RenderSerdeAttribute.addSerde(writer, shape, model) - SensitiveWarning.addDoc(writer, shape) + RenderSerdeAttribute.addSensitiveWarningDoc(writer, shape, model) writer.rustBlock("pub struct $builderName") { // add serde for (member in members) { @@ -221,7 +221,7 @@ class BuilderGenerator( // All fields in the builder are optional. val memberSymbol = symbolProvider.toSymbol(member).makeOptional() RenderSerdeAttribute.skipIfStream(writer, member, model, shape) - SensitiveWarning.addDoc(writer, member) + RenderSerdeAttribute.addSensitiveWarningDoc(writer, shape, model) renderBuilderMember(this, memberName, memberSymbol) } writeCustomizations(customizations, BuilderSection.AdditionalFields(shape)) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt index 9be4815bcbd..5f0d3ce8acc 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt @@ -222,7 +222,7 @@ open class EnumGenerator( documentShape(shape, model) deprecatedShape(shape) RenderSerdeAttribute.addSerde(this, shape, model) - SensitiveWarning.addDoc(this, shape) + RenderSerdeAttribute.addSensitiveWarningDoc(this, shape, model) context.enumMeta.render(this) rust("struct ${context.enumName}(String);") implBlock( @@ -259,7 +259,7 @@ open class EnumGenerator( deprecatedShape(shape) RenderSerdeAttribute.addSerde(this, shape, model) - SensitiveWarning.addDoc(this, shape) + RenderSerdeAttribute.addSensitiveWarningDoc(this, shape, model) context.enumMeta.render(this) rustBlock("enum ${context.enumName}") { context.sortedMembers.forEach { member -> member.render(this) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index 84e3a37f5c8..3309cea646b 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -9,6 +9,7 @@ import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.model.traits.ErrorTrait +import software.amazon.smithy.model.traits.SensitiveTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.raw @@ -18,10 +19,23 @@ import software.amazon.smithy.rust.codegen.core.util.isStreaming // Part of RFC30 public object RenderSerdeAttribute { + private const val warningMessage = "/// This data may contain sensitive information; It will not be obscured when serialized.\n" + + // guards to check if you want to add serde attributes + private fun isApplicable(shape: Shape? = null, model: Model? = null): Boolean { + if (shape == null || model == null) return false + if (shape.hasTrait() || shape.members().none { it.isEventStream(model) }) return false + return true + } + + public fun addSensitiveWarningDoc(writer: RustWriter, shape: Shape? = null, model: Model? = null) { + if (isApplicable(shape, model) && shape.hasTrait()) { + writer.writeInline(warningMessage) + } + } + public fun addSerde(writer: RustWriter, shape: Shape? = null, model: Model? = null) { - if (shape == null || model == null) return - if (shape.hasTrait()) return - if (shape.members().none { it.isEventStream(model) }) { + if (isApplicable(shape, model)) { Attribute("").SerdeSerialize().render(writer) Attribute("").SerdeDeserialize().render(writer) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt index 932797a9565..ad111f8832f 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt @@ -165,12 +165,12 @@ open class StructureGenerator( writer.documentShape(shape, model) writer.deprecatedShape(shape) RenderSerdeAttribute.addSerde(writer, shape, model) - SensitiveWarning.addDoc(writer, shape) + RenderSerdeAttribute.addSensitiveWarningDoc(writer, shape, model) containerMeta.render(writer) writer.rustBlock("struct $name ${lifetimeDeclaration()}") { writer.forEachMember(members) { member, memberName, memberSymbol -> - SensitiveWarning.addDoc(writer, shape) + RenderSerdeAttribute.addSensitiveWarningDoc(writer, shape, model) RenderSerdeAttribute.skipIfStream(writer, member, model, shape) renderStructureMember(writer, member, memberName, memberSymbol) } From 962e45fdee745b965c50657b231e96cdd727250e Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 07:27:21 +0000 Subject: [PATCH 077/312] update --- .../smithy/generators/SensitiveWarning.kt | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/SensitiveWarning.kt diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/SensitiveWarning.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/SensitiveWarning.kt deleted file mode 100644 index 59483329b88..00000000000 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/SensitiveWarning.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.rust.codegen.core.smithy.generators - -import software.amazon.smithy.model.shapes.Shape -import software.amazon.smithy.model.traits.SensitiveTrait -import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter -import software.amazon.smithy.rust.codegen.core.util.hasTrait - -object SensitiveWarning { - private const val warningMessage = "/// This data may contain sensitive information; It will not be obscured when serialized.\n" - fun addDoc(writer: RustWriter, shape: T) { - if (shape.hasTrait()) { - writer.writeInline(warningMessage) - } - } -} From f68d2b001a4d930ef6a791ac4cf0403052e20aaa Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 07:39:14 +0000 Subject: [PATCH 078/312] fix --- .../client/smithy/generators/ClientEnumGenerator.kt | 2 +- .../core/smithy/generators/RenderSerdeAttribute.kt | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt index cc8853bdeaa..c547a2f649a 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt @@ -99,7 +99,7 @@ data class InfallibleEnumType( """.trimIndent(), ) - RenderSerdeAttribute.addSerde(this) + RenderSerdeAttribute.addSerdeWithoutShapeModel(this) context.enumMeta.render(this) rust("struct $UnknownVariantValue(pub(crate) String);") rustBlock("impl $UnknownVariantValue") { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index 3309cea646b..dd95543d6b3 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -22,19 +22,23 @@ public object RenderSerdeAttribute { private const val warningMessage = "/// This data may contain sensitive information; It will not be obscured when serialized.\n" // guards to check if you want to add serde attributes - private fun isApplicable(shape: Shape? = null, model: Model? = null): Boolean { - if (shape == null || model == null) return false + private fun isApplicable(shape: Shape, model: Model): Boolean { if (shape.hasTrait() || shape.members().none { it.isEventStream(model) }) return false return true } - public fun addSensitiveWarningDoc(writer: RustWriter, shape: Shape? = null, model: Model? = null) { + public fun addSensitiveWarningDoc(writer: RustWriter, shape: Shape, model: Model) { if (isApplicable(shape, model) && shape.hasTrait()) { writer.writeInline(warningMessage) } } - public fun addSerde(writer: RustWriter, shape: Shape? = null, model: Model? = null) { + public fun addSerdeWithoutShapeModel(writer: RustWriter) { + Attribute("").SerdeSerialize().render(writer) + Attribute("").SerdeDeserialize().render(writer) + } + + public fun addSerde(writer: RustWriter, shape: Shape, model: Model) { if (isApplicable(shape, model)) { Attribute("").SerdeSerialize().render(writer) Attribute("").SerdeDeserialize().render(writer) From 0fd117d4c89a39e6eeb662f671b438ab53cb402f Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 07:45:16 +0000 Subject: [PATCH 079/312] commit changelog.toml --- CHANGELOG.next.toml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index f0ae279af48..7f7f9613052 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -17,3 +17,40 @@ author = "rcoh" references = ["smithy-rs#2612"] meta = { "breaking" = false, "tada" = false, "bug" = false } +[[smithy-rs]] +message = """ +- rust runtime + - Implements serde support to `Number`, `Blob`, `Document`, `DateTime` + +- Core codegen code + - Add sensitive warning + - Add `serde` attributes + - Import `serde` crate to enable `serde(skip)` on some namespaces + - Add `serde` crate behind unstable feature gate on `Cargo.toml` + +- Client codegen code + - add `serde` as dependency behind feature gate + - add `serde` support to uknown variant types +""" +author = "thomas-k-cameron" +references = ["smithy-rs#2615"] +meta = { "breaking" = false, "tada" = false, "bug" = false } + +[[smithy-rs]] +message = """ +- rust runtime + - Implements serde support to `Number`, `Blob`, `Document`, `DateTime` + +- Core codegen code + - Add sensitive warning + - Add `serde` attributes + - Import `serde` crate to enable `serde(skip)` on some namespaces + - Add `serde` crate behind unstable feature gate on `Cargo.toml` + +- Client codegen code + - add `serde` as dependency behind feature gate + - add `serde` support to uknown variant types +""" +author = "thomas-k-cameron" +references = ["smithy-rs#2615"] +meta = { "breaking" = false, "tada" = false, "bug" = false } From 5af2b763a3e97f8fa439a842934070f04ed7aa69 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 07:53:02 +0000 Subject: [PATCH 080/312] update --- CHANGELOG.next.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 7f7f9613052..d880fd6a3db 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -36,7 +36,7 @@ author = "thomas-k-cameron" references = ["smithy-rs#2615"] meta = { "breaking" = false, "tada" = false, "bug" = false } -[[smithy-rs]] +[[aws-sdk-rust]] message = """ - rust runtime - Implements serde support to `Number`, `Blob`, `Document`, `DateTime` From e866bb3074994fa550271cb7da55ace195827b1f Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 07:54:06 +0000 Subject: [PATCH 081/312] Fix line break --- .../rust/codegen/core/smithy/generators/BuilderGenerator.kt | 1 + .../smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt | 1 + .../rust/codegen/core/smithy/generators/StructureGenerator.kt | 1 + .../smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt | 1 + 4 files changed, 4 insertions(+) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt index 2726dc02a93..bac57ebfea5 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt @@ -4,6 +4,7 @@ */ package software.amazon.smithy.rust.codegen.core.smithy.generators + import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.codegen.core.SymbolProvider import software.amazon.smithy.model.Model diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt index 5f0d3ce8acc..e4fe8d3773b 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt @@ -4,6 +4,7 @@ */ package software.amazon.smithy.rust.codegen.core.smithy.generators + import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.MemberShape diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt index ad111f8832f..c54242f4573 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt @@ -4,6 +4,7 @@ */ package software.amazon.smithy.rust.codegen.core.smithy.generators + import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.MemberShape diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt index 4b3bc12b285..d18d006a80d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt @@ -4,6 +4,7 @@ */ package software.amazon.smithy.rust.codegen.core.smithy.generators + import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.codegen.core.SymbolProvider import software.amazon.smithy.model.Model From 970b258c50d7257d84f3b746044c4447d1863cac Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 08:04:12 +0000 Subject: [PATCH 082/312] update --- .../codegen/core/smithy/generators/BuilderGeneratorTest.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index 066d933dc53..12aed842433 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -145,8 +145,7 @@ internal class BuilderGeneratorTest { val project = TestWorkspace.testProject(provider) project.moduleFor(errorStruct) { rust("##![allow(deprecated)]") - StructureGenerator(model, provider, this, inner, emptyList()).render() - StructureGenerator(model, provider, this, struct, emptyList()).render() + StructureGenerator(model, provider, this, errorStruct, emptyList()).render() implBlock(provider.toSymbol(struct)) { BuilderGenerator.renderConvenienceMethod(this, provider, struct) } From 5dceacd0f10460c771c605606a21215b7c4cf64c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 08:40:57 +0000 Subject: [PATCH 083/312] enable unstable features on tests --- .../smithy/rust/codegen/core/testutil/Rust.kt | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 4e0b0f67f98..6c1c5f639cf 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -42,6 +42,19 @@ import java.nio.file.Files.createTempDirectory import java.nio.file.Path import kotlin.io.path.absolutePathString +object Commands { + val CargoEnvDWarnings = mapOf( + "RUSTFLAGS" to "-D warnings --cfg aws_sdk_unstable" + ) + val CargoEnvDDeadCode = mapOf( + "RUSTFLAGS" to "-A dead_code --cfg aws_sdk_unstable" + ) + val CargoTest = "cargo test --all-features" + val CargoCheck = "cargo check --all-features" + val CargoFmt = "cargo fmt " + val CargoClippy = "cargo clippy" +} + val TestModuleDocProvider = object : ModuleDocProvider { override fun docsWriter(module: RustModule.LeafModule): Writable = writable { docs("Some test documentation\n\nSome more details...") @@ -332,14 +345,14 @@ fun TestWriterDelegator.compileAndTest( println("Generated files:") printGeneratedFiles() try { - "cargo fmt".runCommand(baseDir) + Commands.CargoFmt.runCommand(baseDir) } catch (e: Exception) { // cargo fmt errors are useless, ignore } - val env = mapOf("RUSTFLAGS" to "-A dead_code") - val testOutput = "cargo test".runCommand(baseDir, env) + val env = Commands.CargoEnvDDeadCode + val testOutput = Commands.CargoTest.runCommand(baseDir, env) if (runClippy) { - "cargo clippy".runCommand(baseDir, env) + Commands.CargoClippy.runCommand(baseDir, env) } return testOutput } @@ -379,9 +392,9 @@ fun RustWriter.compileAndTest( val testModule = tempDir.resolve("src/$module.rs") try { val testOutput = if ((mainRs.readText() + testModule.readText()).contains("#[test]")) { - "cargo test".runCommand(tempDir.toPath()) + Commands.CargoTest.runCommand(tempDir.toPath()) } else { - "cargo check".runCommand(tempDir.toPath()) + Commands.CargoCheck.runCommand(tempDir.toPath()) } if (expectFailure) { println("Test sources for debugging: file://${testModule.absolutePath}") @@ -488,4 +501,4 @@ fun TestWriterDelegator.unitTest(test: Writable): TestWriterDelegator { return this } -fun String.runWithWarnings(crate: Path) = this.runCommand(crate, mapOf("RUSTFLAGS" to "-D warnings")) +fun String.runWithWarnings(crate: Path) = this.runCommand(crate, Commands.CargoEnvDWarnings) From 39e1cfdb7f77580b5c3248f6e31b8d45be314084 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 08:50:13 +0000 Subject: [PATCH 084/312] Fix trim trailing whitespace --- CHANGELOG.next.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index d880fd6a3db..aaf1672bc76 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -24,7 +24,7 @@ message = """ - Core codegen code - Add sensitive warning - - Add `serde` attributes + - Add `serde` attributes - Import `serde` crate to enable `serde(skip)` on some namespaces - Add `serde` crate behind unstable feature gate on `Cargo.toml` @@ -43,7 +43,7 @@ message = """ - Core codegen code - Add sensitive warning - - Add `serde` attributes + - Add `serde` attributes - Import `serde` crate to enable `serde(skip)` on some namespaces - Add `serde` crate behind unstable feature gate on `Cargo.toml` From 45951cea14f453caf244275c9ceb16926f7415ca Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 08:56:23 +0000 Subject: [PATCH 085/312] commands check --- .../amazon/smithy/rust/codegen/core/testutil/Rust.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 6c1c5f639cf..654511bff34 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -44,15 +44,15 @@ import kotlin.io.path.absolutePathString object Commands { val CargoEnvDWarnings = mapOf( - "RUSTFLAGS" to "-D warnings --cfg aws_sdk_unstable" + "RUSTFLAGS" to "-D warnings --cfg aws_sdk_unstable", ) val CargoEnvDDeadCode = mapOf( - "RUSTFLAGS" to "-A dead_code --cfg aws_sdk_unstable" + "RUSTFLAGS" to "-A dead_code --cfg aws_sdk_unstable", ) - val CargoTest = "cargo test --all-features" - val CargoCheck = "cargo check --all-features" - val CargoFmt = "cargo fmt " - val CargoClippy = "cargo clippy" + const val CargoTest = "cargo test --all-features" + const val CargoCheck = "cargo check --all-features" + const val CargoFmt = "cargo fmt " + const val CargoClippy = "cargo clippy" } val TestModuleDocProvider = object : ModuleDocProvider { From 41a85ccd3910657af823cbd65b466ba65e674038 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 28 Apr 2023 00:37:37 +0900 Subject: [PATCH 086/312] Update BuilderGeneratorTest.kt --- .../codegen/core/smithy/generators/BuilderGeneratorTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index 12aed842433..009922e4a19 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -146,8 +146,8 @@ internal class BuilderGeneratorTest { project.moduleFor(errorStruct) { rust("##![allow(deprecated)]") StructureGenerator(model, provider, this, errorStruct, emptyList()).render() - implBlock(provider.toSymbol(struct)) { - BuilderGenerator.renderConvenienceMethod(this, provider, struct) + implBlock(provider.toSymbol(errorStruct)) { + BuilderGenerator.renderConvenienceMethod(this, provider, errorStruct) } unitTest("check_serde_on_error_types") { rust( From 68654e4ff28a4013192325dbdeb31c8f94a267ea Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 28 Apr 2023 00:38:09 +0900 Subject: [PATCH 087/312] Update BuilderGeneratorTest.kt --- .../codegen/core/smithy/generators/BuilderGeneratorTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index 009922e4a19..1350866dac9 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -166,8 +166,8 @@ internal class BuilderGeneratorTest { ) } } - project.withModule(provider.moduleForBuilder(struct)) { - BuilderGenerator(model, provider, struct, emptyList()).render(this) + project.withModule(provider.moduleForBuilder(errorStruct)) { + BuilderGenerator(model, provider, errorStruct, emptyList()).render(this) } project.compileAndTest() } From e4bdc7d96a801908cb739fee97ddd7c3821c659b Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 17:00:31 +0000 Subject: [PATCH 088/312] FIX --- .../core/smithy/generators/BuilderGeneratorTest.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index 1350866dac9..707603ff983 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -153,15 +153,10 @@ internal class BuilderGeneratorTest { rust( """ let json_str = r##"{"message": "something"}"##; - let err: MyError = serde_json::from_str(json_str); + let err: Result = serde_json::from_str(json_str); assert!(err.is_err()); - let err: Builder = serde_json::from_str(json_str); + let err: Result = serde_json::from_str(json_str); assert!(err.is_err()); - - let my_struct1 = MyError::builder().message("something".to_string()).build(); - assert!(serde_json::to_string(my_struct1).is_err()); - let my_struct2 = MyError::builder().message("something".to_string()); - assert!(serde_json::to_string(my_struct2).is_err()); """, ) } From af52a824d2f3fb0fbc93e52565c2e327acc20d19 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 17:02:17 +0000 Subject: [PATCH 089/312] update --- .../codegen/core/smithy/generators/BuilderGeneratorTest.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index 707603ff983..cb261e8a581 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -150,6 +150,11 @@ internal class BuilderGeneratorTest { BuilderGenerator.renderConvenienceMethod(this, provider, errorStruct) } unitTest("check_serde_on_error_types") { + // it doesn't check if ser is implemented this is because + // there is no way to check if a trait is implemented on runtime + // since de/ser will both be implemented for any struct that implements it + // this will work + // not the best but better than nothing rust( """ let json_str = r##"{"message": "something"}"##; From 53037a23f397dbdab44dc5eb2978a5b6837719a5 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 17:09:01 +0000 Subject: [PATCH 090/312] Refactoring --- rust-runtime/aws-smithy-types/src/blob.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 23a782ca740..88f0079bf09 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -3,15 +3,19 @@ * SPDX-License-Identifier: Apache-2.0 */ -#[cfg(all( - aws_sdk_unstable, - any(feature = "serde-deserialize", feature = "serde-serialize") -))] -use crate::base64; -#[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] -use serde::Serialize; -#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] -use serde::{de::Visitor, Deserialize}; + +#[cfg(aws_sdk_unstable)] +use impl_serde::*; +#[cfg(aws_sdk_unstable)] +mod impl_serde { + #[cfg(feature = "serde-deserialize")] + pub use serde::{de::Visitor, Deserialize}; + #[cfg(feature = "serde-serialize")] + pub use serde::Serialize; + #[cfg(any(feature = "serde-deserialize", feature = "serde-serialize"))] + pub use crate::base64; +} + /// Binary Blob Type /// From cb15e4dfceee3f4ea22a5f19e898c53a03a3cb30 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 17:13:00 +0000 Subject: [PATCH 091/312] https://github.com/awslabs/smithy-rs/pull/2647#pullrequestreview-1404401371 --- rust-runtime/aws-smithy-types/src/blob.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 88f0079bf09..a6b660f70fc 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -118,7 +118,7 @@ impl<'de> Deserialize<'de> for Blob { feature = "serde-serialize", feature = "serde-deserialize" ))] -mod test { +mod test_serde { use crate::Blob; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -163,3 +163,14 @@ mod test { assert_eq!(for_test, de); } } + + +#[cfg(test)] +mod test { + use crate::Blob; + + #[test] + fn is_serde_enabled() { + assert!(serde_json::from_str::("QVdT").is_err()); + } +} \ No newline at end of file From 9463cdd9d4749efeab6b1d9e58113efdd245d00c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 17:16:34 +0000 Subject: [PATCH 092/312] add --- rust-runtime/aws-smithy-types/src/blob.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index a6b660f70fc..c2827bcce6e 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -170,7 +170,9 @@ mod test { use crate::Blob; #[test] - fn is_serde_enabled() { - assert!(serde_json::from_str::("QVdT").is_err()); + fn is_serde_impled_when_serde_is_not_enabled() { + if cfg!(all(aws_sdk_unstable, feature = "serde-deserialize")) { + assert!(serde_json::from_str::("QVdT").is_err()); + } } } \ No newline at end of file From 498f9d3823807b2d0bcb21d46113b8f94fe81166 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 17:16:57 +0000 Subject: [PATCH 093/312] fmt --- rust-runtime/aws-smithy-types/src/blob.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index c2827bcce6e..aa2af6d91e4 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -3,20 +3,18 @@ * SPDX-License-Identifier: Apache-2.0 */ - #[cfg(aws_sdk_unstable)] use impl_serde::*; #[cfg(aws_sdk_unstable)] mod impl_serde { - #[cfg(feature = "serde-deserialize")] - pub use serde::{de::Visitor, Deserialize}; - #[cfg(feature = "serde-serialize")] - pub use serde::Serialize; #[cfg(any(feature = "serde-deserialize", feature = "serde-serialize"))] pub use crate::base64; + #[cfg(feature = "serde-serialize")] + pub use serde::Serialize; + #[cfg(feature = "serde-deserialize")] + pub use serde::{de::Visitor, Deserialize}; } - /// Binary Blob Type /// /// Blobs represent protocol-agnostic binary content. @@ -164,7 +162,6 @@ mod test_serde { } } - #[cfg(test)] mod test { use crate::Blob; @@ -175,4 +172,4 @@ mod test { assert!(serde_json::from_str::("QVdT").is_err()); } } -} \ No newline at end of file +} From a34423ffbb991c0a0c50f72079e33fd92486a8d0 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 17:19:31 +0000 Subject: [PATCH 094/312] FIX --- rust-runtime/aws-smithy-types/src/blob.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index aa2af6d91e4..588076e1c5b 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -168,7 +168,7 @@ mod test { #[test] fn is_serde_impled_when_serde_is_not_enabled() { - if cfg!(all(aws_sdk_unstable, feature = "serde-deserialize")) { + if cfg!(not(all(aws_sdk_unstable, feature = "serde-deserialize"))) { assert!(serde_json::from_str::("QVdT").is_err()); } } From 23b207d65473dd19728106e89548733efcd4cfe9 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 17:20:33 +0000 Subject: [PATCH 095/312] update --- rust-runtime/aws-smithy-types/src/blob.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 588076e1c5b..7ca7ab16c3b 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -168,8 +168,10 @@ mod test { #[test] fn is_serde_impled_when_serde_is_not_enabled() { - if cfg!(not(all(aws_sdk_unstable, feature = "serde-deserialize"))) { + if cfg!(all(aws_sdk_unstable, feature = "serde-deserialize")) { assert!(serde_json::from_str::("QVdT").is_err()); + } else { + assert!(serde_json::from_str::("QVdT").is_ok()); } } } From 65b5cb9adfb66bc26012ac575e750969d5c205d3 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 17:37:41 +0000 Subject: [PATCH 096/312] update --- rust-runtime/aws-smithy-types/src/blob.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 7ca7ab16c3b..58a55e54925 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -161,17 +161,3 @@ mod test_serde { assert_eq!(for_test, de); } } - -#[cfg(test)] -mod test { - use crate::Blob; - - #[test] - fn is_serde_impled_when_serde_is_not_enabled() { - if cfg!(all(aws_sdk_unstable, feature = "serde-deserialize")) { - assert!(serde_json::from_str::("QVdT").is_err()); - } else { - assert!(serde_json::from_str::("QVdT").is_ok()); - } - } -} From ca9da61d5559bf05876be7d525b6c3183acda3c6 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 27 Apr 2023 17:44:12 +0000 Subject: [PATCH 097/312] update test --- .../smithy/generators/BuilderGeneratorTest.kt | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index cb261e8a581..f18a72545ec 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -6,6 +6,7 @@ package software.amazon.smithy.rust.codegen.core.smithy.generators import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertAll import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.AllowDeprecated @@ -18,6 +19,7 @@ import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest import software.amazon.smithy.rust.codegen.core.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.testutil.unitTest +import kotlin.io.path.readText internal class BuilderGeneratorTest { private val model = StructureGeneratorTest.model @@ -149,26 +151,16 @@ internal class BuilderGeneratorTest { implBlock(provider.toSymbol(errorStruct)) { BuilderGenerator.renderConvenienceMethod(this, provider, errorStruct) } - unitTest("check_serde_on_error_types") { - // it doesn't check if ser is implemented this is because - // there is no way to check if a trait is implemented on runtime - // since de/ser will both be implemented for any struct that implements it - // this will work - // not the best but better than nothing - rust( - """ - let json_str = r##"{"message": "something"}"##; - let err: Result = serde_json::from_str(json_str); - assert!(err.is_err()); - let err: Result = serde_json::from_str(json_str); - assert!(err.is_err()); - """, - ) - } } project.withModule(provider.moduleForBuilder(errorStruct)) { BuilderGenerator(model, provider, errorStruct, emptyList()).render(this) } project.compileAndTest() + // checks if there is a serde derive in the code + project.generatedFiles().forEach { + val file = it.readText() + val check = file.contains("derive(serde::Deserialize)") || file.contains("derive(serde::Serialize)") + assert(!check) + } } } From c8c547f252ea5db0d22d3fb97c4e8931cb6a21e7 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 01:16:01 +0000 Subject: [PATCH 098/312] add serde check --- rust-runtime/aws-smithy-types/src/lib.rs | 4 ++ rust-runtime/aws-smithy-types/src/number.rs | 1 + .../aws-smithy-types/src/serde_impl_check.rs | 71 +++++++++++++++++++ .../test_data/template/Cargo.toml | 13 ++++ .../test_data/template/deser.rs | 3 + .../test_data/template/ser.rs | 3 + 6 files changed, 95 insertions(+) create mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_check.rs create mode 100644 rust-runtime/aws-smithy-types/test_data/template/Cargo.toml create mode 100644 rust-runtime/aws-smithy-types/test_data/template/deser.rs create mode 100644 rust-runtime/aws-smithy-types/test_data/template/ser.rs diff --git a/rust-runtime/aws-smithy-types/src/lib.rs b/rust-runtime/aws-smithy-types/src/lib.rs index ffa1c86ea58..f5abc9cb2a2 100644 --- a/rust-runtime/aws-smithy-types/src/lib.rs +++ b/rust-runtime/aws-smithy-types/src/lib.rs @@ -35,3 +35,7 @@ pub use document::Document; )] pub use error::ErrorMetadata as Error; pub use number::Number; + + +#[cfg(test)] +mod serde_impl_check; \ No newline at end of file diff --git a/rust-runtime/aws-smithy-types/src/number.rs b/rust-runtime/aws-smithy-types/src/number.rs index 5ae57a08107..65471c2c515 100644 --- a/rust-runtime/aws-smithy-types/src/number.rs +++ b/rust-runtime/aws-smithy-types/src/number.rs @@ -491,4 +491,5 @@ mod number { assert_eq!("0", serde_json::to_string(&Number::PosInt(0)).unwrap()); assert_eq!("-1", serde_json::to_string(&Number::NegInt(-1)).unwrap()); } + } diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs new file mode 100644 index 00000000000..5ca063b0ada --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -0,0 +1,71 @@ +use std::process::Command; + +/// ensures serde features is not enabled when features are not enabled +fn base(dt: &str) { + let data_type = format!("aws-smithy-types::{dt}"); + let array = [ + "cargo build --all-features", + "cargo build --features serde-serialize", + "cargo build --features serde-deserialize", + ]; + let cmdpath = "/tmp/cmd.sh"; + let deser = include_str!("../test_data/template/ser.rs"); + let ser = include_str!("../test_data/template/deser.rs"); + let cargo = include_str!("../test_data/template/Cargo.toml"); + let replace_data_type = "ReplaceDataType"; + + for cmd in array { + std::fs::write(cmdpath, cmd).unwrap(); + let func = || { + let check = Command::new("bash") + .arg(cmdpath) + .spawn() + .unwrap() + .wait() + .unwrap() + .success(); + assert!(!check); + }; + std::fs::create_dir("/tmp/test").unwrap(); + std::fs::create_dir("/tmp/test/src").unwrap(); + std::fs::write( + "/tmp/test/Cargo.toml", + cargo, + ) + .unwrap(); + std::fs::write( + "/tmp/test/src/main.rs", + ser.replace(replace_data_type, &data_type), + ) + .unwrap(); + func(); + std::fs::write( + "/tmp/test/src/main.rs", + deser.replace(replace_data_type, &data_type), + ) + .unwrap(); + func(); + } +} + + +#[test] +fn number() { + base("Number"); +} + +#[test] +fn blob() { + base("Blob"); +} + + +#[test] +fn document() { + base("Document"); +} + +#[test] +fn date_time() { + base("DateTime"); +} \ No newline at end of file diff --git a/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml b/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml new file mode 100644 index 00000000000..dc3bc25e100 --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "template" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +aws-smithy-types = {path = "./"} + +[features] +serde-serialize = ["aws-smithy-types/serde-serialize"] +serde-deserialize = ["aws-smithy-types/serde-deserialize"] diff --git a/rust-runtime/aws-smithy-types/test_data/template/deser.rs b/rust-runtime/aws-smithy-types/test_data/template/deser.rs new file mode 100644 index 00000000000..c3dbb80897a --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/template/deser.rs @@ -0,0 +1,3 @@ +fn main() { + let dt: Result = serde_json::from_str("some_str"); +} diff --git a/rust-runtime/aws-smithy-types/test_data/template/ser.rs b/rust-runtime/aws-smithy-types/test_data/template/ser.rs new file mode 100644 index 00000000000..8bed7ed7855 --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/template/ser.rs @@ -0,0 +1,3 @@ +fn main() { + serde_json::to_string(&ReplaceDataType::default()); +} From 55983b2ad684a7c4154c157022ea163e5d2f73a9 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 01:19:27 +0000 Subject: [PATCH 099/312] update --- .../aws-smithy-types/src/serde_impl_check.rs | 74 +++++++++++-------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index 5ca063b0ada..d3e071c3a77 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -1,20 +1,42 @@ -use std::process::Command; +use std::{path::PathBuf, process::Command, str::FromStr}; /// ensures serde features is not enabled when features are not enabled +/// Checks whether features are properly gated behind aws_sdk_unstable fn base(dt: &str) { + // data type let data_type = format!("aws-smithy-types::{dt}"); + // commands 2 run let array = [ - "cargo build --all-features", - "cargo build --features serde-serialize", - "cargo build --features serde-deserialize", + ("cargo build --all-features", [true; 2]), + ("cargo build --features serde-serialize", [true; 2]), + ("cargo build --features serde-deserialize", [true; 2]), + // checks if features are properly gated behind serde-serialize/deserialize + ("cargo build --cfg aws_sdk_unstable", [true; 2]), + ( + "cargo build --features serde-serialize --cfg aws_sdk_unstable", + [true; 2], + ), + ( + "cargo build --features serde-deserialize --cfg aws_sdk_unstable", + [true; 2], + ), ]; - let cmdpath = "/tmp/cmd.sh"; + + // const + let replace_data_type = "ReplaceDataType"; + + // templates let deser = include_str!("../test_data/template/ser.rs"); let ser = include_str!("../test_data/template/deser.rs"); let cargo = include_str!("../test_data/template/Cargo.toml"); - let replace_data_type = "ReplaceDataType"; - - for cmd in array { + + // paths + let cmdpath = "/tmp/cmd.sh"; + let base_path = PathBuf::from_str("/tmp/").unwrap().join(dt); + let src_path = base_path.join("src"); + let main_path = src_path.join("main.rs"); + + for (cmd, b) in array { std::fs::write(cmdpath, cmd).unwrap(); let func = || { let check = Command::new("bash") @@ -26,29 +48,22 @@ fn base(dt: &str) { .success(); assert!(!check); }; - std::fs::create_dir("/tmp/test").unwrap(); - std::fs::create_dir("/tmp/test/src").unwrap(); - std::fs::write( - "/tmp/test/Cargo.toml", - cargo, - ) - .unwrap(); - std::fs::write( - "/tmp/test/src/main.rs", - ser.replace(replace_data_type, &data_type), - ) - .unwrap(); - func(); - std::fs::write( - "/tmp/test/src/main.rs", - deser.replace(replace_data_type, &data_type), - ) - .unwrap(); - func(); + + std::fs::create_dir_all(&base_path).unwrap(); + std::fs::create_dir_all(&src_path).unwrap(); + std::fs::write(&base_path.join("Cargo.toml"), cargo).unwrap(); + + if b[0] { + std::fs::write(&main_path, ser.replace(replace_data_type, &data_type)).unwrap(); + func(); + } + if b[1] { + std::fs::write(&main_path, deser.replace(replace_data_type, &data_type)).unwrap(); + func(); + } } } - #[test] fn number() { base("Number"); @@ -59,7 +74,6 @@ fn blob() { base("Blob"); } - #[test] fn document() { base("Document"); @@ -68,4 +82,4 @@ fn document() { #[test] fn date_time() { base("DateTime"); -} \ No newline at end of file +} From 0949e8050dd524e7bc503476bc277a626af6e796 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 01:24:26 +0000 Subject: [PATCH 100/312] update --- .../aws-smithy-types/src/serde_impl_check.rs | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index d3e071c3a77..09b78cd41c7 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -7,18 +7,18 @@ fn base(dt: &str) { let data_type = format!("aws-smithy-types::{dt}"); // commands 2 run let array = [ - ("cargo build --all-features", [true; 2]), - ("cargo build --features serde-serialize", [true; 2]), - ("cargo build --features serde-deserialize", [true; 2]), + ("cargo build --all-features", [true; 2], false), + ("cargo build --features serde-serialize", [true; 2], false), + ("cargo build --features serde-deserialize", [true; 2], false), // checks if features are properly gated behind serde-serialize/deserialize - ("cargo build --cfg aws_sdk_unstable", [true; 2]), + ("cargo build", [true; 2], true), ( - "cargo build --features serde-serialize --cfg aws_sdk_unstable", - [true; 2], + "cargo build --features serde-serialize", + [true; 2], true, ), ( - "cargo build --features serde-deserialize --cfg aws_sdk_unstable", - [true; 2], + "cargo build --features serde-deserialize", + [true; 2], true, ), ]; @@ -36,12 +36,16 @@ fn base(dt: &str) { let src_path = base_path.join("src"); let main_path = src_path.join("main.rs"); - for (cmd, b) in array { + for (cmd, b, env) in array { std::fs::write(cmdpath, cmd).unwrap(); let func = || { - let check = Command::new("bash") - .arg(cmdpath) - .spawn() + let mut cmd = Command::new("bash"); + cmd.arg(cmdpath); + if env { + cmd.env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + } + + let check = cmd.spawn() .unwrap() .wait() .unwrap() From 062d09d00745088cf2f2ea644ea8b65fbd63673d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 01:53:23 +0000 Subject: [PATCH 101/312] add --- .../aws-smithy-types/src/serde_impl_check.rs | 50 +++++++++++-------- .../test_data/template/Cargo.toml | 4 +- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index 09b78cd41c7..2dde0fb142c 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -1,10 +1,10 @@ -use std::{path::PathBuf, process::Command, str::FromStr}; +use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; /// ensures serde features is not enabled when features are not enabled /// Checks whether features are properly gated behind aws_sdk_unstable fn base(dt: &str) { // data type - let data_type = format!("aws-smithy-types::{dt}"); + let data_type = format!("aws_smithy_types::{dt}"); // commands 2 run let array = [ ("cargo build --all-features", [true; 2], false), @@ -14,11 +14,13 @@ fn base(dt: &str) { ("cargo build", [true; 2], true), ( "cargo build --features serde-serialize", - [true; 2], true, + [false, true], + true, ), ( "cargo build --features serde-deserialize", - [true; 2], true, + [true, false], + true, ), ]; @@ -28,40 +30,46 @@ fn base(dt: &str) { // templates let deser = include_str!("../test_data/template/ser.rs"); let ser = include_str!("../test_data/template/deser.rs"); - let cargo = include_str!("../test_data/template/Cargo.toml"); + let cargo = include_str!("../test_data/template/Cargo.toml").replace( + r#"aws-smithy-types = { path = "./" }"#, + &format!( + "aws-smithy-types = {{ path = {:#?} }}", + current_dir().unwrap().to_str().unwrap().to_string() + ), + ); // paths - let cmdpath = "/tmp/cmd.sh"; - let base_path = PathBuf::from_str("/tmp/").unwrap().join(dt); + + let base_path = PathBuf::from_str("/tmp/smithy-rust-test").unwrap().join(dt); + let cmdpath = base_path.join("cmd.sh"); let src_path = base_path.join("src"); let main_path = src_path.join("main.rs"); - for (cmd, b, env) in array { - std::fs::write(cmdpath, cmd).unwrap(); + for (cmd_txt, [check_deser, check_ser], env) in array { + std::fs::create_dir_all(&base_path).unwrap(); + std::fs::create_dir_all(&src_path).unwrap(); + + std::fs::write(&cmdpath, cmd_txt).unwrap(); let func = || { let mut cmd = Command::new("bash"); - cmd.arg(cmdpath); + cmd.current_dir(&base_path); + cmd.arg(&cmdpath.to_str().unwrap().to_string()); if env { cmd.env("RUSTFLAGS", "--cfg aws_sdk_unstable"); } - let check = cmd.spawn() - .unwrap() - .wait() - .unwrap() - .success(); - assert!(!check); + let check = cmd.spawn().unwrap().wait_with_output().unwrap(); + + assert!(!check.status.success(), "{:#?}", (cmd, cmd_txt, check_ser, check_deser, env, dt)); }; - std::fs::create_dir_all(&base_path).unwrap(); - std::fs::create_dir_all(&src_path).unwrap(); - std::fs::write(&base_path.join("Cargo.toml"), cargo).unwrap(); + std::fs::write(&base_path.join("Cargo.toml"), &cargo).unwrap(); - if b[0] { + if check_ser { std::fs::write(&main_path, ser.replace(replace_data_type, &data_type)).unwrap(); func(); } - if b[1] { + if check_deser { std::fs::write(&main_path, deser.replace(replace_data_type, &data_type)).unwrap(); func(); } diff --git a/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml b/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml index dc3bc25e100..9478a1edf77 100644 --- a/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml +++ b/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml @@ -6,8 +6,8 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -aws-smithy-types = {path = "./"} - +aws-smithy-types = { path = "./" } +serde_json = "1.0" [features] serde-serialize = ["aws-smithy-types/serde-serialize"] serde-deserialize = ["aws-smithy-types/serde-deserialize"] From eaca36efdabec9b6fcc92c74415167ddcdcca7f8 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 01:53:23 +0000 Subject: [PATCH 102/312] merge --- .../aws-smithy-types/src/serde_impl_check.rs | 97 +++++++++++++++++++ .../test_data/template/Cargo.toml | 13 +++ 2 files changed, 110 insertions(+) create mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_check.rs create mode 100644 rust-runtime/aws-smithy-types/test_data/template/Cargo.toml diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs new file mode 100644 index 00000000000..2dde0fb142c --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -0,0 +1,97 @@ +use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; + +/// ensures serde features is not enabled when features are not enabled +/// Checks whether features are properly gated behind aws_sdk_unstable +fn base(dt: &str) { + // data type + let data_type = format!("aws_smithy_types::{dt}"); + // commands 2 run + let array = [ + ("cargo build --all-features", [true; 2], false), + ("cargo build --features serde-serialize", [true; 2], false), + ("cargo build --features serde-deserialize", [true; 2], false), + // checks if features are properly gated behind serde-serialize/deserialize + ("cargo build", [true; 2], true), + ( + "cargo build --features serde-serialize", + [false, true], + true, + ), + ( + "cargo build --features serde-deserialize", + [true, false], + true, + ), + ]; + + // const + let replace_data_type = "ReplaceDataType"; + + // templates + let deser = include_str!("../test_data/template/ser.rs"); + let ser = include_str!("../test_data/template/deser.rs"); + let cargo = include_str!("../test_data/template/Cargo.toml").replace( + r#"aws-smithy-types = { path = "./" }"#, + &format!( + "aws-smithy-types = {{ path = {:#?} }}", + current_dir().unwrap().to_str().unwrap().to_string() + ), + ); + + // paths + + let base_path = PathBuf::from_str("/tmp/smithy-rust-test").unwrap().join(dt); + let cmdpath = base_path.join("cmd.sh"); + let src_path = base_path.join("src"); + let main_path = src_path.join("main.rs"); + + for (cmd_txt, [check_deser, check_ser], env) in array { + std::fs::create_dir_all(&base_path).unwrap(); + std::fs::create_dir_all(&src_path).unwrap(); + + std::fs::write(&cmdpath, cmd_txt).unwrap(); + let func = || { + let mut cmd = Command::new("bash"); + cmd.current_dir(&base_path); + cmd.arg(&cmdpath.to_str().unwrap().to_string()); + if env { + cmd.env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + } + + let check = cmd.spawn().unwrap().wait_with_output().unwrap(); + + assert!(!check.status.success(), "{:#?}", (cmd, cmd_txt, check_ser, check_deser, env, dt)); + }; + + std::fs::write(&base_path.join("Cargo.toml"), &cargo).unwrap(); + + if check_ser { + std::fs::write(&main_path, ser.replace(replace_data_type, &data_type)).unwrap(); + func(); + } + if check_deser { + std::fs::write(&main_path, deser.replace(replace_data_type, &data_type)).unwrap(); + func(); + } + } +} + +#[test] +fn number() { + base("Number"); +} + +#[test] +fn blob() { + base("Blob"); +} + +#[test] +fn document() { + base("Document"); +} + +#[test] +fn date_time() { + base("DateTime"); +} diff --git a/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml b/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml new file mode 100644 index 00000000000..9478a1edf77 --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "template" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +aws-smithy-types = { path = "./" } +serde_json = "1.0" +[features] +serde-serialize = ["aws-smithy-types/serde-serialize"] +serde-deserialize = ["aws-smithy-types/serde-deserialize"] From 0cf317721d58823bec695a4c1124558a6bfe2353 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 01:16:01 +0000 Subject: [PATCH 103/312] add serde check --- rust-runtime/aws-smithy-types/src/lib.rs | 4 ++++ rust-runtime/aws-smithy-types/src/serde_impl_check.rs | 2 ++ rust-runtime/aws-smithy-types/test_data/template/Cargo.toml | 1 + rust-runtime/aws-smithy-types/test_data/template/deser.rs | 3 +++ rust-runtime/aws-smithy-types/test_data/template/ser.rs | 3 +++ 5 files changed, 13 insertions(+) create mode 100644 rust-runtime/aws-smithy-types/test_data/template/deser.rs create mode 100644 rust-runtime/aws-smithy-types/test_data/template/ser.rs diff --git a/rust-runtime/aws-smithy-types/src/lib.rs b/rust-runtime/aws-smithy-types/src/lib.rs index ffa1c86ea58..f5abc9cb2a2 100644 --- a/rust-runtime/aws-smithy-types/src/lib.rs +++ b/rust-runtime/aws-smithy-types/src/lib.rs @@ -35,3 +35,7 @@ pub use document::Document; )] pub use error::ErrorMetadata as Error; pub use number::Number; + + +#[cfg(test)] +mod serde_impl_check; \ No newline at end of file diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index 2dde0fb142c..c27059c1d74 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -86,6 +86,7 @@ fn blob() { base("Blob"); } + #[test] fn document() { base("Document"); @@ -95,3 +96,4 @@ fn document() { fn date_time() { base("DateTime"); } + diff --git a/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml b/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml index 9478a1edf77..e349aa9d24a 100644 --- a/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml +++ b/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] aws-smithy-types = { path = "./" } serde_json = "1.0" + [features] serde-serialize = ["aws-smithy-types/serde-serialize"] serde-deserialize = ["aws-smithy-types/serde-deserialize"] diff --git a/rust-runtime/aws-smithy-types/test_data/template/deser.rs b/rust-runtime/aws-smithy-types/test_data/template/deser.rs new file mode 100644 index 00000000000..c3dbb80897a --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/template/deser.rs @@ -0,0 +1,3 @@ +fn main() { + let dt: Result = serde_json::from_str("some_str"); +} diff --git a/rust-runtime/aws-smithy-types/test_data/template/ser.rs b/rust-runtime/aws-smithy-types/test_data/template/ser.rs new file mode 100644 index 00000000000..8bed7ed7855 --- /dev/null +++ b/rust-runtime/aws-smithy-types/test_data/template/ser.rs @@ -0,0 +1,3 @@ +fn main() { + serde_json::to_string(&ReplaceDataType::default()); +} From c26b42ea35f114f1f3d14f7fdf84421a2b0b3be2 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 02:12:20 +0000 Subject: [PATCH 104/312] pre-commit --- rust-runtime/aws-smithy-types/src/lib.rs | 2 +- .../aws-smithy-types/src/serde_impl_check.rs | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/lib.rs b/rust-runtime/aws-smithy-types/src/lib.rs index f5abc9cb2a2..44330a48a82 100644 --- a/rust-runtime/aws-smithy-types/src/lib.rs +++ b/rust-runtime/aws-smithy-types/src/lib.rs @@ -38,4 +38,4 @@ pub use number::Number; #[cfg(test)] -mod serde_impl_check; \ No newline at end of file +mod serde_impl_check; diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index c27059c1d74..5495ddb1ae4 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -1,3 +1,8 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; /// ensures serde features is not enabled when features are not enabled @@ -59,8 +64,12 @@ fn base(dt: &str) { } let check = cmd.spawn().unwrap().wait_with_output().unwrap(); - - assert!(!check.status.success(), "{:#?}", (cmd, cmd_txt, check_ser, check_deser, env, dt)); + + assert!( + !check.status.success(), + "{:#?}", + (cmd, cmd_txt, check_ser, check_deser, env, dt) + ); }; std::fs::write(&base_path.join("Cargo.toml"), &cargo).unwrap(); @@ -86,7 +95,6 @@ fn blob() { base("Blob"); } - #[test] fn document() { base("Document"); @@ -96,4 +104,3 @@ fn document() { fn date_time() { base("DateTime"); } - From bbed7387fc498d6ebd08116a074eb3a0fc1067df Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 02:12:53 +0000 Subject: [PATCH 105/312] update --- rust-runtime/aws-smithy-types/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/lib.rs b/rust-runtime/aws-smithy-types/src/lib.rs index 44330a48a82..5bd41157d72 100644 --- a/rust-runtime/aws-smithy-types/src/lib.rs +++ b/rust-runtime/aws-smithy-types/src/lib.rs @@ -36,6 +36,5 @@ pub use document::Document; pub use error::ErrorMetadata as Error; pub use number::Number; - #[cfg(test)] mod serde_impl_check; From 93e626f7ac3af6a4650cc1afeae7ae3750753ed8 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 02:15:46 +0000 Subject: [PATCH 106/312] update --- .../aws-smithy-types/src/serde_impl_check.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index 5495ddb1ae4..1fdb33848c2 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -12,18 +12,18 @@ fn base(dt: &str) { let data_type = format!("aws_smithy_types::{dt}"); // commands 2 run let array = [ - ("cargo build --all-features", [true; 2], false), - ("cargo build --features serde-serialize", [true; 2], false), - ("cargo build --features serde-deserialize", [true; 2], false), + ("cargo check --all-features", [true; 2], false), + ("cargo check --features serde-serialize", [true; 2], false), + ("cargo check --features serde-deserialize", [true; 2], false), // checks if features are properly gated behind serde-serialize/deserialize - ("cargo build", [true; 2], true), + ("cargo check", [true; 2], true), ( - "cargo build --features serde-serialize", + "cargo check --features serde-serialize", [false, true], true, ), ( - "cargo build --features serde-deserialize", + "cargo check --features serde-deserialize", [true, false], true, ), From 33db0d154c0766d2022781de5d7a5cae81a68a2e Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 03:27:50 +0000 Subject: [PATCH 107/312] add copyright notice --- rust-runtime/aws-smithy-types/test_data/template/deser.rs | 7 ++++++- rust-runtime/aws-smithy-types/test_data/template/ser.rs | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/test_data/template/deser.rs b/rust-runtime/aws-smithy-types/test_data/template/deser.rs index c3dbb80897a..43ac7b430e5 100644 --- a/rust-runtime/aws-smithy-types/test_data/template/deser.rs +++ b/rust-runtime/aws-smithy-types/test_data/template/deser.rs @@ -1,3 +1,8 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + fn main() { - let dt: Result = serde_json::from_str("some_str"); + let _dt: Result = serde_json::from_str("some_str"); } diff --git a/rust-runtime/aws-smithy-types/test_data/template/ser.rs b/rust-runtime/aws-smithy-types/test_data/template/ser.rs index 8bed7ed7855..af6bcd4ad95 100644 --- a/rust-runtime/aws-smithy-types/test_data/template/ser.rs +++ b/rust-runtime/aws-smithy-types/test_data/template/ser.rs @@ -1,3 +1,8 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + fn main() { serde_json::to_string(&ReplaceDataType::default()); } From bda4e51ae4ae2b948085930b55a7b1e33dbc9fed Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 03:49:13 +0000 Subject: [PATCH 108/312] update? --- rust-runtime/aws-smithy-types/src/date_time/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/mod.rs b/rust-runtime/aws-smithy-types/src/date_time/mod.rs index 4b56d1f2d7c..3db4b90099e 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/mod.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/mod.rs @@ -573,7 +573,7 @@ mod test { SystemTime::try_from(date_time).unwrap() ); } - + #[test] fn ord() { let first = DateTime::from_secs_and_nanos(-1, 0); @@ -601,7 +601,7 @@ mod test { assert!(fourth > third); assert!(fourth == fourth); } - + #[cfg(all( test, aws_sdk_unstable, From c4858caacb475054a754cba4a7f6db4cd43092be Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 03:56:14 +0000 Subject: [PATCH 109/312] update --- rust-runtime/aws-smithy-types/Cargo.toml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 028c09d010f..b407c0aa8a0 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -14,7 +14,6 @@ ryu = "1.0.5" time = { version = "0.3.4", features = ["parsing"] } base64-simd = "0.8" - [target."cfg(aws_sdk_unstable)".dependencies.serde] version = "1" features = ["derive"] @@ -39,11 +38,6 @@ rustdoc-args = ["--cfg", "docsrs"] name = "base64" harness = false - -[target."cfg(aws_sdk_unstable)".dependencies.serde] -version = "1" -features = ["derive"] - [features] serde-serialize = [] serde-deserialize = [] From 1b407e6a1f3b1e2a120ecd81f160a97002c2c9b7 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 04:10:21 +0000 Subject: [PATCH 110/312] update --- CHANGELOG.next.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 11580c95afe..d176bc02f65 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -17,6 +17,12 @@ author = "rcoh" references = ["smithy-rs#2612"] meta = { "breaking" = false, "tada" = false, "bug" = false } +[[smithy-rs]] +message = "Implement `Ord` and `PartialOrd` for `DateTime`." +author = "henriiik" +references = ["smithy-rs#2653"] +meta = { "breaking" = false, "tada" = false, "bug" = false } + [[smithy-rs]] message = """ - rust runtime @@ -52,10 +58,4 @@ message = """ - add `serde` support to uknown variant types """ author = "thomas-k-cameron" -references = ["smithy-rs#2615"] - -[[smithy-rs]] -message = "Implement `Ord` and `PartialOrd` for `DateTime`." -author = "henriiik" -references = ["smithy-rs#2653"] -meta = { "breaking" = false, "tada" = false, "bug" = false } +references = ["smithy-rs#2615"] \ No newline at end of file From 3fe6e9212ca4a1067fc2fca9a320e8c7d78a8322 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 04:13:14 +0000 Subject: [PATCH 111/312] FIX --- rust-runtime/aws-smithy-types/src/blob.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 58a55e54925..c428a42b3f7 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -8,11 +8,11 @@ use impl_serde::*; #[cfg(aws_sdk_unstable)] mod impl_serde { #[cfg(any(feature = "serde-deserialize", feature = "serde-serialize"))] - pub use crate::base64; + pub(crate) use crate::base64; #[cfg(feature = "serde-serialize")] - pub use serde::Serialize; + pub(crate) use serde::Serialize; #[cfg(feature = "serde-deserialize")] - pub use serde::{de::Visitor, Deserialize}; + pub(crate) use serde::{de::Visitor, Deserialize}; } /// Binary Blob Type From 65c2beac28c56546c7dd3a380c6f417ab75031ce Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 04:17:32 +0000 Subject: [PATCH 112/312] update --- rust-runtime/aws-smithy-types/src/blob.rs | 107 +++++++++++----------- 1 file changed, 53 insertions(+), 54 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index c428a42b3f7..2916f8bd96e 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -44,72 +44,71 @@ impl AsRef<[u8]> for Blob { } #[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] -impl Serialize for Blob { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - if serializer.is_human_readable() { - serializer.serialize_str(&crate::base64::encode(&self.inner)) - } else { - serializer.serialize_bytes(&self.inner) +mod serde_serialize { + impl Serialize for Blob { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + if serializer.is_human_readable() { + serializer.serialize_str(&crate::base64::encode(&self.inner)) + } else { + serializer.serialize_bytes(&self.inner) + } } } } #[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] -struct HumanReadableBlobVisitor; - -#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] -impl<'de> Visitor<'de> for HumanReadableBlobVisitor { - type Value = Blob; - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("expected base64 encoded string") - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - match base64::decode(v) { - Ok(inner) => Ok(Blob { inner }), - Err(e) => Err(E::custom(e)), +mod serde_deserialize { + struct HumanReadableBlobVisitor; + impl<'de> Visitor<'de> for HumanReadableBlobVisitor { + type Value = Blob; + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("expected base64 encoded string") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + match base64::decode(v) { + Ok(inner) => Ok(Blob { inner }), + Err(e) => Err(E::custom(e)), + } } } -} - -#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] -struct NotHumanReadableBlobVisitor; - -#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] -impl<'de> Visitor<'de> for NotHumanReadableBlobVisitor { - type Value = Blob; - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("expected base64 encoded string") - } - - fn visit_byte_buf(self, v: Vec) -> Result - where - E: serde::de::Error, - { - Ok(Blob { inner: v }) + + struct NotHumanReadableBlobVisitor; + impl<'de> Visitor<'de> for NotHumanReadableBlobVisitor { + type Value = Blob; + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("expected base64 encoded string") + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: serde::de::Error, + { + Ok(Blob { inner: v }) + } } -} - -#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] -impl<'de> Deserialize<'de> for Blob { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - if deserializer.is_human_readable() { - deserializer.deserialize_str(HumanReadableBlobVisitor) - } else { - deserializer.deserialize_byte_buf(NotHumanReadableBlobVisitor) + + impl<'de> Deserialize<'de> for Blob { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + if deserializer.is_human_readable() { + deserializer.deserialize_str(HumanReadableBlobVisitor) + } else { + deserializer.deserialize_byte_buf(NotHumanReadableBlobVisitor) + } } } } + #[cfg(test)] #[cfg(all( aws_sdk_unstable, From 1d229c81216f2e4a2a8685efcb97069fcf2aa15c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 04:26:02 +0000 Subject: [PATCH 113/312] precommit --- rust-runtime/aws-smithy-types/src/blob.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 2916f8bd96e..62810ce7f7a 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -67,7 +67,7 @@ mod serde_deserialize { fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("expected base64 encoded string") } - + fn visit_str(self, v: &str) -> Result where E: serde::de::Error, @@ -78,14 +78,14 @@ mod serde_deserialize { } } } - + struct NotHumanReadableBlobVisitor; impl<'de> Visitor<'de> for NotHumanReadableBlobVisitor { type Value = Blob; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("expected base64 encoded string") } - + fn visit_byte_buf(self, v: Vec) -> Result where E: serde::de::Error, @@ -93,7 +93,7 @@ mod serde_deserialize { Ok(Blob { inner: v }) } } - + impl<'de> Deserialize<'de> for Blob { fn deserialize(deserializer: D) -> Result where From fec286ab577a7ce5732615ccb9f353e1242d0a35 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 04:27:06 +0000 Subject: [PATCH 114/312] fmt --- rust-runtime/aws-smithy-types/src/blob.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 62810ce7f7a..60fc87fb587 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -108,7 +108,6 @@ mod serde_deserialize { } } - #[cfg(test)] #[cfg(all( aws_sdk_unstable, From 95bb4ffdae89e94d08bcde13355d604956b6bdfe Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 28 Apr 2023 04:36:59 +0000 Subject: [PATCH 115/312] update --- .../rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index f18a72545ec..7df4b3d8e20 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -158,7 +158,7 @@ internal class BuilderGeneratorTest { project.compileAndTest() // checks if there is a serde derive in the code project.generatedFiles().forEach { - val file = it.readText() + val file = it.toFile().readText() val check = file.contains("derive(serde::Deserialize)") || file.contains("derive(serde::Serialize)") assert(!check) } From d336069723996ddd20645027df9e04e23e770ac6 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 29 Apr 2023 16:50:18 +0000 Subject: [PATCH 116/312] add meta --- CHANGELOG.next.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index d176bc02f65..d41713b9557 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -58,4 +58,5 @@ message = """ - add `serde` support to uknown variant types """ author = "thomas-k-cameron" -references = ["smithy-rs#2615"] \ No newline at end of file +references = ["smithy-rs#2615"] +meta = { "breaking" = false, "tada" = false, "bug" = false } From 7ce2a50644e7818f98e708af6afc7b50aa59e26d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 29 Apr 2023 16:56:55 +0000 Subject: [PATCH 117/312] update --- rust-runtime/aws-smithy-types/src/blob.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 58a55e54925..78ab5ca6c33 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -3,17 +3,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -#[cfg(aws_sdk_unstable)] -use impl_serde::*; -#[cfg(aws_sdk_unstable)] -mod impl_serde { - #[cfg(any(feature = "serde-deserialize", feature = "serde-serialize"))] - pub use crate::base64; - #[cfg(feature = "serde-serialize")] - pub use serde::Serialize; - #[cfg(feature = "serde-deserialize")] - pub use serde::{de::Visitor, Deserialize}; -} +#[cfg(all( + aws_sdk_unstable, + any(feature = "serde-deserialize", feature = "serde-serialize") +))] +pub use crate::base64; +#[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] +pub use serde::Serialize; +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +pub use serde::{de::Visitor, Deserialize}; /// Binary Blob Type /// From e755eb54f143a2320fd675ef6d864a159df6dfba Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 29 Apr 2023 17:00:24 +0000 Subject: [PATCH 118/312] update --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 588ffd57885..864d3c411a9 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.67.1" +channel = "1.68.2" From 0a98aeccbe91f366fe1c8566ecd474e8cdf6adc7 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 29 Apr 2023 17:01:25 +0000 Subject: [PATCH 119/312] lint --- rust-runtime/aws-smithy-types/src/number.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/number.rs b/rust-runtime/aws-smithy-types/src/number.rs index 65471c2c515..5ae57a08107 100644 --- a/rust-runtime/aws-smithy-types/src/number.rs +++ b/rust-runtime/aws-smithy-types/src/number.rs @@ -491,5 +491,4 @@ mod number { assert_eq!("0", serde_json::to_string(&Number::PosInt(0)).unwrap()); assert_eq!("-1", serde_json::to_string(&Number::NegInt(-1)).unwrap()); } - } From 5240d79399130719e206650bf3dda7a0a1e9d219 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 29 Apr 2023 17:02:21 +0000 Subject: [PATCH 120/312] update --- .../rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index 7df4b3d8e20..62d3b3dc0d6 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -6,7 +6,6 @@ package software.amazon.smithy.rust.codegen.core.smithy.generators import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertAll import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.shapes.Shape import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.AllowDeprecated From 1a70cbdfdf7d790daf37dbaad943f851f0341959 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 29 Apr 2023 17:10:39 +0000 Subject: [PATCH 121/312] update --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 864d3c411a9..588ffd57885 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.68.2" +channel = "1.67.1" From 1cd0c029448858eb85800542b521090063aae0f9 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 29 Apr 2023 17:28:50 +0000 Subject: [PATCH 122/312] add skip field message --- .../core/smithy/generators/RenderSerdeAttribute.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index dd95543d6b3..c350e59d52e 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -5,6 +5,7 @@ package software.amazon.smithy.rust.codegen.core.smithy.generators +import software.amazon.smithy.codegen.core.SymbolContainer import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.Shape @@ -20,6 +21,7 @@ import software.amazon.smithy.rust.codegen.core.util.isStreaming // Part of RFC30 public object RenderSerdeAttribute { private const val warningMessage = "/// This data may contain sensitive information; It will not be obscured when serialized.\n" + private const val skipFieldMessage = "/// This field will note be serialized or deserialized because it's a stream type.\n" // guards to check if you want to add serde attributes private fun isApplicable(shape: Shape, model: Model): Boolean { @@ -46,9 +48,11 @@ public object RenderSerdeAttribute { } public fun skipIfStream(writer: RustWriter, member: MemberShape, model: Model, shape: Shape) { - if (shape.hasTrait() || member.isEventStream(model)) return + if (shape.hasTrait() || member.isEventStream(model))return if (member.isStreaming(model)) { Attribute("").SerdeSkip().render(writer) + } else { + writer.writeInline(skipFieldMessage) } } @@ -56,6 +60,6 @@ public object RenderSerdeAttribute { // we need this for skip serde to work Attribute.AllowUnusedImports.render(writer) Attribute("").SerdeSerializeOrDeserialize().render(writer) - writer.raw("use serde;") + writer.writeInline("use serde;"); } } From f961481b274845c8d483b3d0e12d185d32555c8d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 29 Apr 2023 17:53:13 +0000 Subject: [PATCH 123/312] fix --- .../core/smithy/generators/BuilderGeneratorTest.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index 62d3b3dc0d6..8b30246d5be 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -15,9 +15,13 @@ import software.amazon.smithy.rust.codegen.core.smithy.Default import software.amazon.smithy.rust.codegen.core.smithy.WrappingSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.setDefault import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace +import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest +import software.amazon.smithy.rust.codegen.core.testutil.rustSettings +import software.amazon.smithy.rust.codegen.core.testutil.testRustSettings import software.amazon.smithy.rust.codegen.core.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.testutil.unitTest +import kotlin.io.path.extension import kotlin.io.path.readText internal class BuilderGeneratorTest { @@ -155,11 +159,14 @@ internal class BuilderGeneratorTest { BuilderGenerator(model, provider, errorStruct, emptyList()).render(this) } project.compileAndTest() + // checks if there is a serde derive in the code project.generatedFiles().forEach { - val file = it.toFile().readText() - val check = file.contains("derive(serde::Deserialize)") || file.contains("derive(serde::Serialize)") - assert(!check) + if (it.extension == "rs") { + val file = it.toFile().readText() + val check = file.contains("derive(serde::Deserialize)") || file.contains("derive(serde::Serialize)") + assert(!check) + } } } } From 198bc1c2f3a0beb5f4b4c88bfaf20a800ec8a249 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 29 Apr 2023 17:56:39 +0000 Subject: [PATCH 124/312] update --- .../codegen/core/smithy/generators/RenderSerdeAttribute.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index c350e59d52e..119d31c0833 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -50,9 +50,8 @@ public object RenderSerdeAttribute { public fun skipIfStream(writer: RustWriter, member: MemberShape, model: Model, shape: Shape) { if (shape.hasTrait() || member.isEventStream(model))return if (member.isStreaming(model)) { - Attribute("").SerdeSkip().render(writer) - } else { writer.writeInline(skipFieldMessage) + Attribute("").SerdeSkip().render(writer) } } @@ -60,6 +59,6 @@ public object RenderSerdeAttribute { // we need this for skip serde to work Attribute.AllowUnusedImports.render(writer) Attribute("").SerdeSerializeOrDeserialize().render(writer) - writer.writeInline("use serde;"); + writer.raw("use serde;"); } } From b7e717179bc2b53a756b1ea4274163ead4c0ddbd Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 29 Apr 2023 18:09:15 +0000 Subject: [PATCH 125/312] update --- .../rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index 8b30246d5be..bf4bd78dfa0 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -163,7 +163,7 @@ internal class BuilderGeneratorTest { // checks if there is a serde derive in the code project.generatedFiles().forEach { if (it.extension == "rs") { - val file = it.toFile().readText() + val file = project.baseDir.resolve(it).toFile().readText() val check = file.contains("derive(serde::Deserialize)") || file.contains("derive(serde::Serialize)") assert(!check) } From 34ed2f6c207ad89478a7e58a46b026db53d02a33 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 29 Apr 2023 18:13:15 +0000 Subject: [PATCH 126/312] precommit run --- .../codegen/core/smithy/generators/RenderSerdeAttribute.kt | 3 +-- .../codegen/core/smithy/generators/BuilderGeneratorTest.kt | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index 119d31c0833..89a7862d844 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -5,7 +5,6 @@ package software.amazon.smithy.rust.codegen.core.smithy.generators -import software.amazon.smithy.codegen.core.SymbolContainer import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.Shape @@ -59,6 +58,6 @@ public object RenderSerdeAttribute { // we need this for skip serde to work Attribute.AllowUnusedImports.render(writer) Attribute("").SerdeSerializeOrDeserialize().render(writer) - writer.raw("use serde;"); + writer.raw("use serde;") } } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index bf4bd78dfa0..49103e73c3d 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -15,10 +15,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.Default import software.amazon.smithy.rust.codegen.core.smithy.WrappingSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.setDefault import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace -import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest -import software.amazon.smithy.rust.codegen.core.testutil.rustSettings -import software.amazon.smithy.rust.codegen.core.testutil.testRustSettings import software.amazon.smithy.rust.codegen.core.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.testutil.unitTest import kotlin.io.path.extension From 664d655f4865f2f00e47a3cc72364f7df009e6a1 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 30 Apr 2023 05:43:30 +0000 Subject: [PATCH 127/312] FIX --- .../smithy/generators/RenderSerdeAttribute.kt | 21 +++++++++---------- .../smithy/generators/StructureGenerator.kt | 8 +++---- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index 89a7862d844..9ac06c8c16c 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -24,8 +24,7 @@ public object RenderSerdeAttribute { // guards to check if you want to add serde attributes private fun isApplicable(shape: Shape, model: Model): Boolean { - if (shape.hasTrait() || shape.members().none { it.isEventStream(model) }) return false - return true + return !shape.hasTrait() && shape.members().none { it.isEventStream(model) } } public fun addSensitiveWarningDoc(writer: RustWriter, shape: Shape, model: Model) { @@ -41,23 +40,23 @@ public object RenderSerdeAttribute { public fun addSerde(writer: RustWriter, shape: Shape, model: Model) { if (isApplicable(shape, model)) { - Attribute("").SerdeSerialize().render(writer) - Attribute("").SerdeDeserialize().render(writer) + addSerdeWithoutShapeModel(writer) } } public fun skipIfStream(writer: RustWriter, member: MemberShape, model: Model, shape: Shape) { - if (shape.hasTrait() || member.isEventStream(model))return - if (member.isStreaming(model)) { + if (isApplicable(shape, model) && member.isStreaming(model)) { writer.writeInline(skipFieldMessage) Attribute("").SerdeSkip().render(writer) } } - public fun importSerde(writer: RustWriter) { - // we need this for skip serde to work - Attribute.AllowUnusedImports.render(writer) - Attribute("").SerdeSerializeOrDeserialize().render(writer) - writer.raw("use serde;") + public fun importSerde(writer: RustWriter, shape: Shape, model: Model) { + if (isApplicable(shape, model)) { + // we need this for skip serde to work + Attribute.AllowUnusedImports.render(writer) + Attribute("").SerdeSerializeOrDeserialize().render(writer) + writer.raw("use serde;") + } } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt index c54242f4573..f4a2565b3af 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt @@ -32,6 +32,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.renamedFrom import software.amazon.smithy.rust.codegen.core.smithy.rustType import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.getTrait +import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.redactIfNecessary /** StructureGenerator customization sections */ @@ -154,7 +155,9 @@ open class StructureGenerator( } open fun renderStructureMember(writer: RustWriter, member: MemberShape, memberName: String, memberSymbol: Symbol) { + RenderSerdeAttribute.skipIfStream(writer, member, model, shape) writer.renderMemberDoc(member, memberSymbol) + RenderSerdeAttribute.addSensitiveWarningDoc(writer, shape, model) writer.deprecatedShape(member) memberSymbol.expectRustMetadata().render(writer) writer.write("$memberName: #T,", memberSymbol) @@ -168,17 +171,14 @@ open class StructureGenerator( RenderSerdeAttribute.addSerde(writer, shape, model) RenderSerdeAttribute.addSensitiveWarningDoc(writer, shape, model) containerMeta.render(writer) - writer.rustBlock("struct $name ${lifetimeDeclaration()}") { writer.forEachMember(members) { member, memberName, memberSymbol -> - RenderSerdeAttribute.addSensitiveWarningDoc(writer, shape, model) - RenderSerdeAttribute.skipIfStream(writer, member, model, shape) renderStructureMember(writer, member, memberName, memberSymbol) } writeCustomizations(customizations, StructureSection.AdditionalFields(shape)) } - RenderSerdeAttribute.importSerde(writer) + RenderSerdeAttribute.importSerde(writer, shape, model) renderStructureImpl() if (!containerMeta.hasDebugDerive()) { renderDebugImpl() From 729a19faf7538b602e94c683904edab7f85d71d7 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 06:18:08 +0000 Subject: [PATCH 128/312] refactoring --- .../aws-smithy-types/src/serde_impl_check.rs | 239 +++++++++++------- 1 file changed, 153 insertions(+), 86 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index 1fdb33848c2..4280dc8c530 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -5,102 +5,169 @@ use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; -/// ensures serde features is not enabled when features are not enabled -/// Checks whether features are properly gated behind aws_sdk_unstable -fn base(dt: &str) { - // data type - let data_type = format!("aws_smithy_types::{dt}"); - // commands 2 run - let array = [ - ("cargo check --all-features", [true; 2], false), - ("cargo check --features serde-serialize", [true; 2], false), - ("cargo check --features serde-deserialize", [true; 2], false), - // checks if features are properly gated behind serde-serialize/deserialize - ("cargo check", [true; 2], true), - ( - "cargo check --features serde-serialize", - [false, true], - true, - ), - ( - "cargo check --features serde-deserialize", - [true, false], - true, - ), - ]; - - // const - let replace_data_type = "ReplaceDataType"; - - // templates - let deser = include_str!("../test_data/template/ser.rs"); - let ser = include_str!("../test_data/template/deser.rs"); - let cargo = include_str!("../test_data/template/Cargo.toml").replace( - r#"aws-smithy-types = { path = "./" }"#, - &format!( - "aws-smithy-types = {{ path = {:#?} }}", - current_dir().unwrap().to_str().unwrap().to_string() - ), - ); - - // paths - - let base_path = PathBuf::from_str("/tmp/smithy-rust-test").unwrap().join(dt); - let cmdpath = base_path.join("cmd.sh"); - let src_path = base_path.join("src"); - let main_path = src_path.join("main.rs"); - - for (cmd_txt, [check_deser, check_ser], env) in array { - std::fs::create_dir_all(&base_path).unwrap(); - std::fs::create_dir_all(&src_path).unwrap(); - - std::fs::write(&cmdpath, cmd_txt).unwrap(); - let func = || { - let mut cmd = Command::new("bash"); - cmd.current_dir(&base_path); - cmd.arg(&cmdpath.to_str().unwrap().to_string()); - if env { - cmd.env("RUSTFLAGS", "--cfg aws_sdk_unstable"); - } - - let check = cmd.spawn().unwrap().wait_with_output().unwrap(); - - assert!( - !check.status.success(), - "{:#?}", - (cmd, cmd_txt, check_ser, check_deser, env, dt) - ); - }; - - std::fs::write(&base_path.join("Cargo.toml"), &cargo).unwrap(); - - if check_ser { - std::fs::write(&main_path, ser.replace(replace_data_type, &data_type)).unwrap(); - func(); - } - if check_deser { - std::fs::write(&main_path, deser.replace(replace_data_type, &data_type)).unwrap(); - func(); - } - } +#[test] +fn feature_gate_test_for_number_deserialization() { + // create files + let cargo_project_path = create_cargo_dir(number); + de_test(&cargo_project_path); +} + +#[test] +fn feature_gate_test_for_number_serialization() { + // create files + let cargo_project_path = create_cargo_dir(number); + ser_test(&cargo_project_path); +} + +#[test] +fn feature_gate_test_for_document_deserialization() { + // create files + let cargo_project_path = create_cargo_dir(document); + de_test(&cargo_project_path); } #[test] -fn number() { - base("Number"); +fn feature_gate_test_for_document_serialization() { + // create files + let cargo_project_path = create_cargo_dir(document); + ser_test(&cargo_project_path); } #[test] -fn blob() { - base("Blob"); +fn feature_gate_test_for_datetime_deserialization() { + // create files + let cargo_project_path = create_cargo_dir(datetime); + de_test(&cargo_project_path); } #[test] -fn document() { - base("Document"); +fn feature_gate_test_for_datetime_serialization() { + // create files + let cargo_project_path = create_cargo_dir(datetime); + ser_test(&cargo_project_path); } #[test] -fn date_time() { - base("DateTime"); +fn feature_gate_test_for_number_deserialization() { + // create files + let cargo_project_path = create_cargo_dir(number); + de_test(&cargo_project_path); +} + +#[test] +fn feature_gate_test_for_number_serialization() { + // create files + let cargo_project_path = create_cargo_dir(number); + ser_test(&cargo_project_path); +} + +fn ser_test(cargo_project_path: &PathBuf) { + // runs cargo check --all-features to compile a code that requries serialization feature is needed. + // it is expected to successfully compile. + let cmd = Command::new("bash") + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --all-features"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); + + // runs cargo check --features serde-serialize to compile a code that requries serialization feature is needed. + // it is expected to successfully compile. + let cmd = Command::new("bash") + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-serialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); + + // runs cargo check --features serde-deserialize to compile a code that requries serialization feature is needed. + // it is expected to successfully compile. + let cmd = Command::new("bash") + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-deserialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); + + // runs cargo check to compile a code that requries serialization feature is needed. + // it is expected to successfully compile. + let cmd = Command::new("bash") + .current_dir(&cargo_project_path) + .args(["-c", "cargo check"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); + + // runs cargo check --features serde-serialize to compile a code that requries serialization feature is needed. + // it is expected to fail to compile. + let cmd = Command::new("bash") + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-serialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-deserialize to compile a code that requries serialization feature is needed. + // it is expected to successfully compile. + let cmd = Command::new("bash") + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-deserialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); +} +fn de_test(cargo_project_path: &PathBuf) { + // runs cargo check --all-features to compile a code that requries de-serialization feature is needed. + // it is expected to successfully compile. + let cmd = Command::new("bash") + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --all-features"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); + + // runs cargo check --features serde-serialize to compile a code that requries de-serialization feature is needed. + // it is expected to successfully compile. + let cmd = Command::new("bash") + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-serialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); + + // runs cargo check --features serde-deserialize to compile a code that requries de-serialization feature is needed. + // it is expected to successfully compile. + let cmd = Command::new("bash") + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-deserialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); + + // runs cargo check to compile a code that requries de-serialization feature is needed. + // it is expected to successfully compile. + let cmd = Command::new("bash") + .current_dir(&cargo_project_path) + .args(["-c", "cargo check"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); + + // runs cargo check --features serde-serialize to compile a code that requries de-serialization feature is needed. + // it is expected to successfully compile. + let cmd = Command::new("bash") + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-serialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); + + // runs cargo check --features serde-deserialize to compile a code that requries de-serialization feature is needed. + // it is expected to fail to compile. + let cmd = Command::new("bash") + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-deserialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); } From 0c533ff57c944ccb5f6a6ebb0b9cc8a663f0a211 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 06:29:54 +0000 Subject: [PATCH 129/312] refactoring2 --- .../aws-smithy-types/src/serde_impl_check.rs | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index 4280dc8c530..2296f128f28 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -5,62 +5,71 @@ use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; +/// Tests whether de-serialization feature for number is properly feature gated #[test] fn feature_gate_test_for_number_deserialization() { // create files - let cargo_project_path = create_cargo_dir(number); + let cargo_project_path = create_cargo_dir("Number"); de_test(&cargo_project_path); } +/// Tests whether serialization feature for number is properly feature gated #[test] fn feature_gate_test_for_number_serialization() { // create files - let cargo_project_path = create_cargo_dir(number); + let cargo_project_path = create_cargo_dir("Number"); ser_test(&cargo_project_path); } +/// Tests whether de-serialization feature for document is properly feature gated #[test] fn feature_gate_test_for_document_deserialization() { // create files - let cargo_project_path = create_cargo_dir(document); + let cargo_project_path = create_cargo_dir("Document"); de_test(&cargo_project_path); } +/// Tests whether serialization feature for document is properly feature gated #[test] fn feature_gate_test_for_document_serialization() { // create files - let cargo_project_path = create_cargo_dir(document); + let cargo_project_path = create_cargo_dir("Document"); ser_test(&cargo_project_path); } +/// Tests whether de-serialization feature for datetime is properly feature gated #[test] fn feature_gate_test_for_datetime_deserialization() { // create files - let cargo_project_path = create_cargo_dir(datetime); + let cargo_project_path = create_cargo_dir("DateTime"); de_test(&cargo_project_path); } +/// Tests whether serialization feature for datetime is properly feature gated #[test] fn feature_gate_test_for_datetime_serialization() { // create files - let cargo_project_path = create_cargo_dir(datetime); + let cargo_project_path = create_cargo_dir("DateTime"); ser_test(&cargo_project_path); } +/// Tests whether de-serialization feature for blob is properly feature gated #[test] -fn feature_gate_test_for_number_deserialization() { +fn feature_gate_test_for_blob_deserialization() { // create files - let cargo_project_path = create_cargo_dir(number); + let cargo_project_path = create_cargo_dir("Blob"); de_test(&cargo_project_path); } +/// Tests whether serialization feature for blob is properly feature gated #[test] -fn feature_gate_test_for_number_serialization() { +fn feature_gate_test_for_blob_serialization() { // create files - let cargo_project_path = create_cargo_dir(number); + let cargo_project_path = create_cargo_dir("Blob"); ser_test(&cargo_project_path); } +/// tests whether serialization features are proplery feature fn ser_test(cargo_project_path: &PathBuf) { // runs cargo check --all-features to compile a code that requries serialization feature is needed. // it is expected to successfully compile. @@ -116,6 +125,7 @@ fn ser_test(cargo_project_path: &PathBuf) { let is_success = cmd.spawn().unwrap().wait().unwrap().success(); assert_eq!(is_success, true); } + fn de_test(cargo_project_path: &PathBuf) { // runs cargo check --all-features to compile a code that requries de-serialization feature is needed. // it is expected to successfully compile. From 8491ea1aa4c22347c58c7da30a4b3c9ef3ecb59f Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 06:51:31 +0000 Subject: [PATCH 130/312] update --- .../aws-smithy-types/src/serde_impl_check.rs | 81 +++++++++++++------ 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index 2296f128f28..1e514d82265 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; +use std::{env::current_dir, path::PathBuf, process::Command}; /// Tests whether de-serialization feature for number is properly feature gated #[test] @@ -69,36 +69,60 @@ fn feature_gate_test_for_blob_serialization() { ser_test(&cargo_project_path); } -/// tests whether serialization features are proplery feature + +// create directory and files for testing +fn create_cargo_dir(datatype: &str, enable_ser: bool, enable_deser: bool) -> PathBuf { + let deser = include_str!("../test_data/template/ser.rs"); + let ser = include_str!("../test_data/template/deser.rs"); + + let cargo = include_str!("../test_data/template/Cargo.toml").replace( + r#"aws-smithy-types = { path = "./" }"#, + &format!( + "aws-smithy-types = {{ path = {:#?} }}", + current_dir().unwrap().to_str().unwrap().to_string() + ), + ); + + let base_path = PathBuf::from_str("/tmp/smithy-rust-test") + .unwrap() + .join(datatype); + let src_path = base_path.join("src"); + std::fs::create_dir_all(&base_path).unwrap(); + std::fs::create_dir_all(&src_path).unwrap(); + base_path +} + + fn ser_test(cargo_project_path: &PathBuf) { - // runs cargo check --all-features to compile a code that requries serialization feature is needed. + // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. // it is expected to successfully compile. let cmd = Command::new("bash") .current_dir(&cargo_project_path) - .args(["-c", "cargo check --all-features"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + .args(["-c", "cargo check --all-features"]); let is_success = cmd.spawn().unwrap().wait().unwrap().success(); assert_eq!(is_success, true); - // runs cargo check --features serde-serialize to compile a code that requries serialization feature is needed. + // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. // it is expected to successfully compile. let cmd = Command::new("bash") .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + .args(["-c", "cargo check --features serde-serialize"]); let is_success = cmd.spawn().unwrap().wait().unwrap().success(); assert_eq!(is_success, true); - // runs cargo check --features serde-deserialize to compile a code that requries serialization feature is needed. + // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. // it is expected to successfully compile. let cmd = Command::new("bash") .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + .args(["-c", "cargo check --features serde-deserialize"]); let is_success = cmd.spawn().unwrap().wait().unwrap().success(); assert_eq!(is_success, true); - // runs cargo check to compile a code that requries serialization feature is needed. + // runs cargo check with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. // it is expected to successfully compile. let cmd = Command::new("bash") .current_dir(&cargo_project_path) @@ -107,7 +131,8 @@ fn ser_test(cargo_project_path: &PathBuf) { let is_success = cmd.spawn().unwrap().wait().unwrap().success(); assert_eq!(is_success, true); - // runs cargo check --features serde-serialize to compile a code that requries serialization feature is needed. + // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. // it is expected to fail to compile. let cmd = Command::new("bash") .current_dir(&cargo_project_path) @@ -116,7 +141,8 @@ fn ser_test(cargo_project_path: &PathBuf) { let is_success = cmd.spawn().unwrap().wait().unwrap().success(); assert_eq!(is_success, false); - // runs cargo check --features serde-deserialize to compile a code that requries serialization feature is needed. + // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. // it is expected to successfully compile. let cmd = Command::new("bash") .current_dir(&cargo_project_path) @@ -127,34 +153,35 @@ fn ser_test(cargo_project_path: &PathBuf) { } fn de_test(cargo_project_path: &PathBuf) { - // runs cargo check --all-features to compile a code that requries de-serialization feature is needed. + // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. // it is expected to successfully compile. let cmd = Command::new("bash") .current_dir(&cargo_project_path) - .args(["-c", "cargo check --all-features"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + .args(["-c", "cargo check --all-features"]); let is_success = cmd.spawn().unwrap().wait().unwrap().success(); assert_eq!(is_success, true); - // runs cargo check --features serde-serialize to compile a code that requries de-serialization feature is needed. + // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. // it is expected to successfully compile. let cmd = Command::new("bash") .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + .args(["-c", "cargo check --features serde-serialize"]); let is_success = cmd.spawn().unwrap().wait().unwrap().success(); assert_eq!(is_success, true); - // runs cargo check --features serde-deserialize to compile a code that requries de-serialization feature is needed. + // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. // it is expected to successfully compile. let cmd = Command::new("bash") .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + .args(["-c", "cargo check --features serde-deserialize"]); let is_success = cmd.spawn().unwrap().wait().unwrap().success(); assert_eq!(is_success, true); - // runs cargo check to compile a code that requries de-serialization feature is needed. + // runs cargo check with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. // it is expected to successfully compile. let cmd = Command::new("bash") .current_dir(&cargo_project_path) @@ -163,7 +190,8 @@ fn de_test(cargo_project_path: &PathBuf) { let is_success = cmd.spawn().unwrap().wait().unwrap().success(); assert_eq!(is_success, true); - // runs cargo check --features serde-serialize to compile a code that requries de-serialization feature is needed. + // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. // it is expected to successfully compile. let cmd = Command::new("bash") .current_dir(&cargo_project_path) @@ -172,7 +200,8 @@ fn de_test(cargo_project_path: &PathBuf) { let is_success = cmd.spawn().unwrap().wait().unwrap().success(); assert_eq!(is_success, true); - // runs cargo check --features serde-deserialize to compile a code that requries de-serialization feature is needed. + // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. // it is expected to fail to compile. let cmd = Command::new("bash") .current_dir(&cargo_project_path) From fb16b4312ffcfa9d861ebc021edc60b3f19d0cb6 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 08:50:41 +0000 Subject: [PATCH 131/312] update --- rust-runtime/aws-smithy-types/test_data/template/deser.rs | 2 +- rust-runtime/aws-smithy-types/test_data/template/ser.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-runtime/aws-smithy-types/test_data/template/deser.rs b/rust-runtime/aws-smithy-types/test_data/template/deser.rs index 43ac7b430e5..11a72ee3bae 100644 --- a/rust-runtime/aws-smithy-types/test_data/template/deser.rs +++ b/rust-runtime/aws-smithy-types/test_data/template/deser.rs @@ -4,5 +4,5 @@ */ fn main() { - let _dt: Result = serde_json::from_str("some_str"); + let _dt: Result<$PLACE_HOLDER$, _> = serde_json::from_str("some_str"); } diff --git a/rust-runtime/aws-smithy-types/test_data/template/ser.rs b/rust-runtime/aws-smithy-types/test_data/template/ser.rs index af6bcd4ad95..37899670c60 100644 --- a/rust-runtime/aws-smithy-types/test_data/template/ser.rs +++ b/rust-runtime/aws-smithy-types/test_data/template/ser.rs @@ -4,5 +4,5 @@ */ fn main() { - serde_json::to_string(&ReplaceDataType::default()); + serde_json::to_string(&$PLACE_HOLDER$::default()); } From dd0028f7ecfe632086185f231fc485df295badf4 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 09:01:13 +0000 Subject: [PATCH 132/312] refactoring --- .../aws-smithy-types/src/serde_impl_check.rs | 157 ++++++++++++------ .../test_data/template/deser.rs | 2 +- .../test_data/template/ser.rs | 2 +- 3 files changed, 109 insertions(+), 52 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index 1e514d82265..18787128d76 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -3,13 +3,18 @@ * SPDX-License-Identifier: Apache-2.0 */ -use std::{env::current_dir, path::PathBuf, process::Command}; +use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; + +enum Target { + Ser, + De, +} /// Tests whether de-serialization feature for number is properly feature gated #[test] fn feature_gate_test_for_number_deserialization() { // create files - let cargo_project_path = create_cargo_dir("Number"); + let cargo_project_path = create_cargo_dir("Number", Target::De); de_test(&cargo_project_path); } @@ -17,7 +22,7 @@ fn feature_gate_test_for_number_deserialization() { #[test] fn feature_gate_test_for_number_serialization() { // create files - let cargo_project_path = create_cargo_dir("Number"); + let cargo_project_path = create_cargo_dir("Number", Target::Ser); ser_test(&cargo_project_path); } @@ -25,7 +30,7 @@ fn feature_gate_test_for_number_serialization() { #[test] fn feature_gate_test_for_document_deserialization() { // create files - let cargo_project_path = create_cargo_dir("Document"); + let cargo_project_path = create_cargo_dir("Document", Target::De); de_test(&cargo_project_path); } @@ -33,7 +38,7 @@ fn feature_gate_test_for_document_deserialization() { #[test] fn feature_gate_test_for_document_serialization() { // create files - let cargo_project_path = create_cargo_dir("Document"); + let cargo_project_path = create_cargo_dir("Document", Target::Ser); ser_test(&cargo_project_path); } @@ -41,7 +46,7 @@ fn feature_gate_test_for_document_serialization() { #[test] fn feature_gate_test_for_datetime_deserialization() { // create files - let cargo_project_path = create_cargo_dir("DateTime"); + let cargo_project_path = create_cargo_dir("DateTime", Target::De); de_test(&cargo_project_path); } @@ -49,7 +54,7 @@ fn feature_gate_test_for_datetime_deserialization() { #[test] fn feature_gate_test_for_datetime_serialization() { // create files - let cargo_project_path = create_cargo_dir("DateTime"); + let cargo_project_path = create_cargo_dir("DateTime", Target::Ser); ser_test(&cargo_project_path); } @@ -57,7 +62,7 @@ fn feature_gate_test_for_datetime_serialization() { #[test] fn feature_gate_test_for_blob_deserialization() { // create files - let cargo_project_path = create_cargo_dir("Blob"); + let cargo_project_path = create_cargo_dir("Blob", Target::De); de_test(&cargo_project_path); } @@ -65,16 +70,15 @@ fn feature_gate_test_for_blob_deserialization() { #[test] fn feature_gate_test_for_blob_serialization() { // create files - let cargo_project_path = create_cargo_dir("Blob"); + let cargo_project_path = create_cargo_dir("Blob", Target::Ser); ser_test(&cargo_project_path); } - // create directory and files for testing -fn create_cargo_dir(datatype: &str, enable_ser: bool, enable_deser: bool) -> PathBuf { +fn create_cargo_dir(datatype: &str, target: Target) -> PathBuf { let deser = include_str!("../test_data/template/ser.rs"); let ser = include_str!("../test_data/template/deser.rs"); - + let cargo = include_str!("../test_data/template/Cargo.toml").replace( r#"aws-smithy-types = { path = "./" }"#, &format!( @@ -83,72 +87,101 @@ fn create_cargo_dir(datatype: &str, enable_ser: bool, enable_deser: bool) -> Pat ), ); + // create temp directory let base_path = PathBuf::from_str("/tmp/smithy-rust-test") .unwrap() .join(datatype); let src_path = base_path.join("src"); std::fs::create_dir_all(&base_path).unwrap(); std::fs::create_dir_all(&src_path).unwrap(); + let place_holder = "$PLACE_HOLDER$"; + let contents = match target { + Target::De => deser.replace(place_holder, datatype), + Target::Ser => ser.replace(place_holder, datatype), + }; + std::fs::write(&src_path.join("main.rs"), contents); base_path } - - fn ser_test(cargo_project_path: &PathBuf) { // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. // it is expected to successfully compile. - let cmd = Command::new("bash") + let mut cmd = Command::new("bash"); + + let child = cmd .current_dir(&cargo_project_path) - .args(["-c", "cargo check --all-features"]); - let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + .args(["-c", "cargo check --all-features"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); assert_eq!(is_success, true); // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. // it is expected to successfully compile. - let cmd = Command::new("bash") + let mut cmd = Command::new("bash"); + + let child = cmd .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]); - let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + .args(["-c", "cargo check --features serde-serialize"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); assert_eq!(is_success, true); // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. // it is expected to successfully compile. - let cmd = Command::new("bash") + let mut cmd = Command::new("bash"); + + let child = cmd .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]); - let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + .args(["-c", "cargo check --features serde-deserialize"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); assert_eq!(is_success, true); // runs cargo check with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. // it is expected to successfully compile. - let cmd = Command::new("bash") + let mut cmd = Command::new("bash"); + + let child = cmd .current_dir(&cargo_project_path) .args(["-c", "cargo check"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); - let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); assert_eq!(is_success, true); // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. // it is expected to fail to compile. - let cmd = Command::new("bash") + let mut cmd = Command::new("bash"); + + let child = cmd .current_dir(&cargo_project_path) .args(["-c", "cargo check --features serde-serialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); - let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); assert_eq!(is_success, false); // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. // it is expected to successfully compile. - let cmd = Command::new("bash") + let mut cmd = Command::new("bash"); + + let child = cmd .current_dir(&cargo_project_path) .args(["-c", "cargo check --features serde-deserialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); - let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); assert_eq!(is_success, true); } @@ -156,57 +189,81 @@ fn de_test(cargo_project_path: &PathBuf) { // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. // it is expected to successfully compile. - let cmd = Command::new("bash") + let mut cmd = Command::new("bash"); + + let child = cmd .current_dir(&cargo_project_path) - .args(["-c", "cargo check --all-features"]); - let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + .args(["-c", "cargo check --all-features"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); assert_eq!(is_success, true); // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. // it is expected to successfully compile. - let cmd = Command::new("bash") + let mut cmd = Command::new("bash"); + + let child = cmd .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]); - let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + .args(["-c", "cargo check --features serde-serialize"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); assert_eq!(is_success, true); // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. // it is expected to successfully compile. - let cmd = Command::new("bash") + let mut cmd = Command::new("bash"); + + let child = cmd .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]); - let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + .args(["-c", "cargo check --features serde-deserialize"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); assert_eq!(is_success, true); // runs cargo check with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. // it is expected to successfully compile. - let cmd = Command::new("bash") + let mut cmd = Command::new("bash"); + + let child = cmd .current_dir(&cargo_project_path) .args(["-c", "cargo check"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); - let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); assert_eq!(is_success, true); // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. // it is expected to successfully compile. - let cmd = Command::new("bash") + let mut cmd = Command::new("bash"); + + let child = cmd .current_dir(&cargo_project_path) .args(["-c", "cargo check --features serde-serialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); - let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); assert_eq!(is_success, true); // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. // it is expected to fail to compile. - let cmd = Command::new("bash") + let mut cmd = Command::new("bash"); + + let child = cmd .current_dir(&cargo_project_path) .args(["-c", "cargo check --features serde-deserialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable"); - let is_success = cmd.spawn().unwrap().wait().unwrap().success(); + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); assert_eq!(is_success, false); } diff --git a/rust-runtime/aws-smithy-types/test_data/template/deser.rs b/rust-runtime/aws-smithy-types/test_data/template/deser.rs index 11a72ee3bae..5842682a488 100644 --- a/rust-runtime/aws-smithy-types/test_data/template/deser.rs +++ b/rust-runtime/aws-smithy-types/test_data/template/deser.rs @@ -4,5 +4,5 @@ */ fn main() { - let _dt: Result<$PLACE_HOLDER$, _> = serde_json::from_str("some_str"); + let _dt: Result = serde_json::from_str("some_str"); } diff --git a/rust-runtime/aws-smithy-types/test_data/template/ser.rs b/rust-runtime/aws-smithy-types/test_data/template/ser.rs index 37899670c60..b6211d72635 100644 --- a/rust-runtime/aws-smithy-types/test_data/template/ser.rs +++ b/rust-runtime/aws-smithy-types/test_data/template/ser.rs @@ -4,5 +4,5 @@ */ fn main() { - serde_json::to_string(&$PLACE_HOLDER$::default()); + serde_json::to_string(&aws_smithy_types::$PLACE_HOLDER$::default()); } From 522c5afa6fbbbf269aea58ae0bf8b170abc42bde Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 09:03:39 +0000 Subject: [PATCH 133/312] refactor --- rust-runtime/aws-smithy-types/test_data/template/deser.rs | 3 +++ rust-runtime/aws-smithy-types/test_data/template/ser.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/rust-runtime/aws-smithy-types/test_data/template/deser.rs b/rust-runtime/aws-smithy-types/test_data/template/deser.rs index 5842682a488..3e2cb9cce34 100644 --- a/rust-runtime/aws-smithy-types/test_data/template/deser.rs +++ b/rust-runtime/aws-smithy-types/test_data/template/deser.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +// this is a template for running feature-gate tests. +// $PLACE_HOLDER$ is replaced with relevant data types + fn main() { let _dt: Result = serde_json::from_str("some_str"); } diff --git a/rust-runtime/aws-smithy-types/test_data/template/ser.rs b/rust-runtime/aws-smithy-types/test_data/template/ser.rs index b6211d72635..e4448371fed 100644 --- a/rust-runtime/aws-smithy-types/test_data/template/ser.rs +++ b/rust-runtime/aws-smithy-types/test_data/template/ser.rs @@ -3,6 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +// this is a template for running feature-gate tests. +// $PLACE_HOLDER$ is replaced with relevant data types + fn main() { serde_json::to_string(&aws_smithy_types::$PLACE_HOLDER$::default()); } From 9d9e60f0da5634e8c7aa3eb96e43bf0148856c64 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 09:07:04 +0000 Subject: [PATCH 134/312] update --- .../aws-smithy-types/src/serde_impl_check.rs | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index 18787128d76..164a015ec1e 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -5,6 +5,7 @@ use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; +#[derive(Debug)] enum Target { Ser, De, @@ -76,30 +77,38 @@ fn feature_gate_test_for_blob_serialization() { // create directory and files for testing fn create_cargo_dir(datatype: &str, target: Target) -> PathBuf { - let deser = include_str!("../test_data/template/ser.rs"); - let ser = include_str!("../test_data/template/deser.rs"); - - let cargo = include_str!("../test_data/template/Cargo.toml").replace( - r#"aws-smithy-types = { path = "./" }"#, - &format!( - "aws-smithy-types = {{ path = {:#?} }}", - current_dir().unwrap().to_str().unwrap().to_string() - ), - ); - - // create temp directory - let base_path = PathBuf::from_str("/tmp/smithy-rust-test") + let base_path = PathBuf::from_str("/tmp/smithy-rust-test/") .unwrap() + .join(format!("{target:#?}")) .join(datatype); let src_path = base_path.join("src"); + + // write cargo + { + let cargo = include_str!("../test_data/template/Cargo.toml").replace( + r#"aws-smithy-types = { path = "./" }"#, + &format!( + "aws-smithy-types = {{ path = {:#?} }}", + current_dir().unwrap().to_str().unwrap().to_string() + ), + ); + std::fs::write(&base_path.join("Cargo.toml"), cargo).unwrap(); + }; + + // create temp directory std::fs::create_dir_all(&base_path).unwrap(); std::fs::create_dir_all(&src_path).unwrap(); + + // write main.rs + let deser = include_str!("../test_data/template/ser.rs"); + let ser = include_str!("../test_data/template/deser.rs"); let place_holder = "$PLACE_HOLDER$"; let contents = match target { Target::De => deser.replace(place_holder, datatype), Target::Ser => ser.replace(place_holder, datatype), }; - std::fs::write(&src_path.join("main.rs"), contents); + std::fs::write(&src_path.join("main.rs"), contents).unwrap(); + base_path } fn ser_test(cargo_project_path: &PathBuf) { From 2fda9768f54c90f8674643b1cbc872c4e094d161 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 09:14:37 +0000 Subject: [PATCH 135/312] FIX --- rust-runtime/aws-smithy-types/src/serde_impl_check.rs | 4 ++-- .../aws-smithy-types/test_data/template/{deser.rs => deser} | 0 .../aws-smithy-types/test_data/template/{ser.rs => ser} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename rust-runtime/aws-smithy-types/test_data/template/{deser.rs => deser} (100%) rename rust-runtime/aws-smithy-types/test_data/template/{ser.rs => ser} (100%) diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index 164a015ec1e..9a9d255135c 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -100,8 +100,8 @@ fn create_cargo_dir(datatype: &str, target: Target) -> PathBuf { std::fs::create_dir_all(&src_path).unwrap(); // write main.rs - let deser = include_str!("../test_data/template/ser.rs"); - let ser = include_str!("../test_data/template/deser.rs"); + let ser = include_str!("../test_data/template/ser"); + let deser = include_str!("../test_data/template/deser"); let place_holder = "$PLACE_HOLDER$"; let contents = match target { Target::De => deser.replace(place_holder, datatype), diff --git a/rust-runtime/aws-smithy-types/test_data/template/deser.rs b/rust-runtime/aws-smithy-types/test_data/template/deser similarity index 100% rename from rust-runtime/aws-smithy-types/test_data/template/deser.rs rename to rust-runtime/aws-smithy-types/test_data/template/deser diff --git a/rust-runtime/aws-smithy-types/test_data/template/ser.rs b/rust-runtime/aws-smithy-types/test_data/template/ser similarity index 100% rename from rust-runtime/aws-smithy-types/test_data/template/ser.rs rename to rust-runtime/aws-smithy-types/test_data/template/ser From 995d1f44312d4e117b1bec5c6b3b0a3e82b14202 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 09:35:07 +0000 Subject: [PATCH 136/312] FIX --- rust-runtime/aws-smithy-types/src/serde_impl_check.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index 9a9d255135c..f396b13c14b 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -83,6 +83,10 @@ fn create_cargo_dir(datatype: &str, target: Target) -> PathBuf { .join(datatype); let src_path = base_path.join("src"); + // create temp directory + std::fs::create_dir_all(&base_path).unwrap(); + std::fs::create_dir_all(&src_path).unwrap(); + // write cargo { let cargo = include_str!("../test_data/template/Cargo.toml").replace( @@ -95,10 +99,6 @@ fn create_cargo_dir(datatype: &str, target: Target) -> PathBuf { std::fs::write(&base_path.join("Cargo.toml"), cargo).unwrap(); }; - // create temp directory - std::fs::create_dir_all(&base_path).unwrap(); - std::fs::create_dir_all(&src_path).unwrap(); - // write main.rs let ser = include_str!("../test_data/template/ser"); let deser = include_str!("../test_data/template/deser"); From 3f13bb7ef986bd57e3ae16e239dca2e349bb2b9b Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 11:45:06 +0000 Subject: [PATCH 137/312] FIX Bool was reversed --- .../aws-smithy-types/src/serde_impl_check.rs | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index f396b13c14b..7ed41f3d57a 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -111,11 +111,12 @@ fn create_cargo_dir(datatype: &str, target: Target) -> PathBuf { base_path } + fn ser_test(cargo_project_path: &PathBuf) { // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. - // it is expected to successfully compile. - let mut cmd = Command::new("bash"); + // it is not expected to compile. + let cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -127,8 +128,8 @@ fn ser_test(cargo_project_path: &PathBuf) { // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. - // it is expected to successfully compile. - let mut cmd = Command::new("bash"); + // it is not expected to compile. + let cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -140,8 +141,8 @@ fn ser_test(cargo_project_path: &PathBuf) { // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. - // it is expected to successfully compile. - let mut cmd = Command::new("bash"); + // it is not expected to compile. + let cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -153,8 +154,8 @@ fn ser_test(cargo_project_path: &PathBuf) { // runs cargo check with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. - // it is expected to successfully compile. - let mut cmd = Command::new("bash"); + // it is not expected to compile. + let cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -167,8 +168,8 @@ fn ser_test(cargo_project_path: &PathBuf) { // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. - // it is expected to fail to compile. - let mut cmd = Command::new("bash"); + // it is expected to compile. + let cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -181,8 +182,8 @@ fn ser_test(cargo_project_path: &PathBuf) { // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. - // it is expected to successfully compile. - let mut cmd = Command::new("bash"); + // it is not expected to compile. + let cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -197,8 +198,8 @@ fn ser_test(cargo_project_path: &PathBuf) { fn de_test(cargo_project_path: &PathBuf) { // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. - // it is expected to successfully compile. - let mut cmd = Command::new("bash"); + // it is not expected to compile. + let cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -210,8 +211,8 @@ fn de_test(cargo_project_path: &PathBuf) { // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. - // it is expected to successfully compile. - let mut cmd = Command::new("bash"); + // it is not expected to compile. + let cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -223,8 +224,8 @@ fn de_test(cargo_project_path: &PathBuf) { // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. - // it is expected to successfully compile. - let mut cmd = Command::new("bash"); + // it is not expected to compile. + let cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -236,8 +237,8 @@ fn de_test(cargo_project_path: &PathBuf) { // runs cargo check with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. - // it is expected to successfully compile. - let mut cmd = Command::new("bash"); + // it is not expected to compile. + let cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -250,8 +251,8 @@ fn de_test(cargo_project_path: &PathBuf) { // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. - // it is expected to successfully compile. - let mut cmd = Command::new("bash"); + // it is not expected to compile. + let cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -264,8 +265,8 @@ fn de_test(cargo_project_path: &PathBuf) { // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. - // it is expected to fail to compile. - let mut cmd = Command::new("bash"); + // it is expected to compile. + let cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) From e71caaf7a92f2ed47158a55d2e1eab1c1cc34de5 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 13:16:56 +0000 Subject: [PATCH 138/312] new tests --- rust-runtime/aws-smithy-types/src/blob.rs | 3 + rust-runtime/aws-smithy-types/src/lib.rs | 2 +- .../aws-smithy-types/src/serde_impl_check.rs | 59 +++-- .../aws-smithy-types/src/serde_impl_check_.rs | 237 ++++++++++++++++++ .../src/serde_impl_test/blob.rs | 22 ++ .../src/serde_impl_test/date_time.rs | 22 ++ .../src/serde_impl_test/document.rs | 22 ++ .../src/serde_impl_test/mod.rs | 228 +++++++++++++++++ .../src/serde_impl_test/number.rs | 22 ++ .../aws-smithy-types/test_data/template/ser | 4 +- 10 files changed, 594 insertions(+), 27 deletions(-) create mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_check_.rs create mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/blob.rs create mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/date_time.rs create mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs create mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs create mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 60fc87fb587..c2cc84ec157 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -45,6 +45,7 @@ impl AsRef<[u8]> for Blob { #[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] mod serde_serialize { + use super::*; impl Serialize for Blob { fn serialize(&self, serializer: S) -> Result where @@ -61,6 +62,8 @@ mod serde_serialize { #[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] mod serde_deserialize { + use super::*; + struct HumanReadableBlobVisitor; impl<'de> Visitor<'de> for HumanReadableBlobVisitor { type Value = Blob; diff --git a/rust-runtime/aws-smithy-types/src/lib.rs b/rust-runtime/aws-smithy-types/src/lib.rs index 5bd41157d72..be65634bafb 100644 --- a/rust-runtime/aws-smithy-types/src/lib.rs +++ b/rust-runtime/aws-smithy-types/src/lib.rs @@ -37,4 +37,4 @@ pub use error::ErrorMetadata as Error; pub use number::Number; #[cfg(test)] -mod serde_impl_check; +mod serde_impl_test; diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index 7ed41f3d57a..8645fc1b396 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -105,7 +105,16 @@ fn create_cargo_dir(datatype: &str, target: Target) -> PathBuf { let place_holder = "$PLACE_HOLDER$"; let contents = match target { Target::De => deser.replace(place_holder, datatype), - Target::Ser => ser.replace(place_holder, datatype), + Target::Ser => { + let s = match datatype { + "Blob" => "Blob::new([1, 2,3])", + "Number" => "Number::PosInt(1)", + "Document" => "Document::from(0)", + "DateTime" => "DateTime::from_secs(0)", + _ => panic!() + }; + ser.replace(place_holder, s) + }, }; std::fs::write(&src_path.join("main.rs"), contents).unwrap(); @@ -116,7 +125,7 @@ fn ser_test(cargo_project_path: &PathBuf) { // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. // it is not expected to compile. - let cmd = Command::new("bash"); + let mut cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -124,12 +133,12 @@ fn ser_test(cargo_project_path: &PathBuf) { .spawn(); let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); + assert_eq!(is_success, false); // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. // it is not expected to compile. - let cmd = Command::new("bash"); + let mut cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -137,12 +146,12 @@ fn ser_test(cargo_project_path: &PathBuf) { .spawn(); let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); + assert_eq!(is_success, false); // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. // it is not expected to compile. - let cmd = Command::new("bash"); + let mut cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -150,12 +159,12 @@ fn ser_test(cargo_project_path: &PathBuf) { .spawn(); let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); + assert_eq!(is_success, false); // runs cargo check with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. // it is not expected to compile. - let cmd = Command::new("bash"); + let mut cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -164,12 +173,12 @@ fn ser_test(cargo_project_path: &PathBuf) { .spawn(); let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); + assert_eq!(is_success, false); // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. // it is expected to compile. - let cmd = Command::new("bash"); + let mut cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -178,12 +187,12 @@ fn ser_test(cargo_project_path: &PathBuf) { .spawn(); let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); + assert_eq!(is_success, true); // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require serialization feature. // it is not expected to compile. - let cmd = Command::new("bash"); + let mut cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -192,14 +201,14 @@ fn ser_test(cargo_project_path: &PathBuf) { .spawn(); let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); + assert_eq!(is_success, false); } fn de_test(cargo_project_path: &PathBuf) { // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. // it is not expected to compile. - let cmd = Command::new("bash"); + let mut cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -207,12 +216,12 @@ fn de_test(cargo_project_path: &PathBuf) { .spawn(); let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); + assert_eq!(is_success, false); // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. // it is not expected to compile. - let cmd = Command::new("bash"); + let mut cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -220,12 +229,12 @@ fn de_test(cargo_project_path: &PathBuf) { .spawn(); let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); + assert_eq!(is_success, false); // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. // it is not expected to compile. - let cmd = Command::new("bash"); + let mut cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -233,12 +242,12 @@ fn de_test(cargo_project_path: &PathBuf) { .spawn(); let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); + assert_eq!(is_success, false); // runs cargo check with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. // it is not expected to compile. - let cmd = Command::new("bash"); + let mut cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -247,12 +256,12 @@ fn de_test(cargo_project_path: &PathBuf) { .spawn(); let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); + assert_eq!(is_success, false); // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. // it is not expected to compile. - let cmd = Command::new("bash"); + let mut cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -261,12 +270,12 @@ fn de_test(cargo_project_path: &PathBuf) { .spawn(); let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); + assert_eq!(is_success, false); // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. // the code that it compiles require de-serialization feature. // it is expected to compile. - let cmd = Command::new("bash"); + let mut cmd = Command::new("bash"); let child = cmd .current_dir(&cargo_project_path) @@ -275,5 +284,5 @@ fn de_test(cargo_project_path: &PathBuf) { .spawn(); let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); + assert_eq!(is_success, true); } diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check_.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check_.rs new file mode 100644 index 00000000000..47c50adfbc7 --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check_.rs @@ -0,0 +1,237 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; + +const PLACE_HOLDER: &str = "$PLACE_HOLDER$"; +struct CargoCmd { + cargo_command: &'static str, + is_ser_compilable: bool, + is_deser_compilable: bool, + enable_aws_sdk_unstable: bool, +} + +impl CargoCmd { + const ALL_FEATURE: &str = "cargo check --all-features"; + const SERDE_SERIALIZE: &str = "cargo check --features serde-serialize"; + const SERDE_DESERIALIZE: &str = "cargo check --features serde-serialize"; +} + +#[test] +fn print() { + let array = [ + ("cargo check --all-features", [true; 2], false), + ("cargo check --features serde-serialize", [true; 2], false), + ("cargo check --features serde-deserialize", [true; 2], false), + // checks if features are properly gated behind serde-serialize/deserialize + ("cargo check", [true; 2], true), + ( + "cargo check --features serde-serialize", + [false, true], + true, + ), + ( + "cargo check --features serde-deserialize", + [true, false], + true, + ), + ]; + + let mut ser_stack = "".to_string(); + let mut de_stack = "".to_string(); + for i in array { + let [ser, de] = i.1; + let func = |ser, check2| { + let func = |b| if b { "not" } else { "" }; + let msg = if check2 { + "de-serialization feature" + } else { + "serialization feature" + }; + let env = if i.2 { + r#".env("RUSTFLAGS", "--cfg aws_sdk_unstable")"# + } else { + "" + }; + let s = format! { r#" +// runs {cmd} {env} "--cfg aws_sdk_unstable" enabled. +// the code that it compiles require {msg}. +// it is {ser} expected to compile. +let mut cmd = Command::new("bash"); + +let child = cmd.current_dir(&cargo_project_path) + .args(["-c", {cmd:#?}, "&>", "/dev/null"]) + {env2} + .spawn(); + +let is_success = child.unwrap().wait().unwrap().success(); +assert_eq!(is_success, {ser_bool}); + "#, + cmd = i.0, + ser = func(ser), + ser_bool = ser, + env2 = env, + env = if i.2 { + "with" + } else { + "without" + } + }; + + return s; + }; + + ser_stack.push_str(&func(ser, false)); + de_stack.push_str(&func(de, true)); + } + + let datatypes = ["Number", "Document", "DateTime", "Blob"]; + for dt in datatypes { + println!( + r#" + /// Tests whether de-serialization feature for {dt} is properly feature gated + #[test] + fn feature_gate_test_for_{dt}_deserialization() {{ + // create files + let cargo_project_path = create_cargo_dir({dt2:?}); + de_test(&cargo_project_path); + }} + + /// Tests whether serialization feature for {dt} is properly feature gated + #[test] + fn feature_gate_test_for_{dt}_serialization() {{ + // create files + let cargo_project_path = create_cargo_dir({dt2:?}); + ser_test(&cargo_project_path); + }} + "#, + dt = dt.to_lowercase(), + dt2 = dt, + ); + } + println!( + "fn ser_test(cargo_project_path: &PathBuf) {{{}}}", + ser_stack + ); + println!("fn de_test(cargo_project_path: &PathBuf) {{{}}}", de_stack); +} + +/// ensures serde features is not enabled when features are not enabled +/// Checks whether features are properly gated behind aws_sdk_unstable +fn base(dt: &str) { + // data type + let data_type = format!("aws_smithy_types::{dt}"); + // commands 2 run + let array = [ + ("cargo check --all-features", [true; 2], false), + ("cargo check --features serde-serialize", [true; 2], false), + ("cargo check --features serde-deserialize", [true; 2], false), + // checks if features are properly gated behind serde-serialize/deserialize + ("cargo check", [true; 2], true), + ( + "cargo check --features serde-serialize", + [false, true], + true, + ), + ( + "cargo check --features serde-deserialize", + [true, false], + true, + ), + ]; + + // templates + let deser = include_str!("../test_data/template/ser"); + let ser = include_str!("../test_data/template/deser"); + let cargo = include_str!("../test_data/template/Cargo.toml").replace( + r#"aws-smithy-types = { path = "./" }"#, + &format!( + "aws-smithy-types = {{ path = {:#?} }}", + current_dir().unwrap().to_str().unwrap().to_string() + ), + ); + + // paths + + let base_path = PathBuf::from_str("/tmp/smithy-rust-test").unwrap().join(dt); + let cmdpath = base_path.join("cmd.sh"); + let src_path = base_path.join("src"); + let main_path = src_path.join("main.rs"); + + for (cmd_txt, [check_deser, check_ser], env) in array { + std::fs::create_dir_all(&base_path).unwrap(); + std::fs::create_dir_all(&src_path).unwrap(); + + std::fs::write(&cmdpath, cmd_txt).unwrap(); + let func = |predicted| { + let mut cmd = Command::new("bash"); + cmd.current_dir(&base_path); + cmd.arg(&cmdpath.to_str().unwrap().to_string()); + if env { + cmd.env("RUSTFLAGS", "--cfg aws_sdk_unstable"); + } + println!("{:#?}", cmd); + //let check = cmd.spawn().unwrap().wait_with_output().unwrap(); + /* + assert_eq!( + check.status.success(), + predicted, + "{:#?}", + (cmd, cmd_txt, check_ser, check_deser, env, dt) + ); + */ + }; + + std::fs::write(&base_path.join("Cargo.toml"), &cargo).unwrap(); + + std::fs::write(&main_path, ser.replace(PLACE_HOLDER, &data_type)).unwrap(); + func(check_ser); + std::fs::write(&main_path, deser.replace(PLACE_HOLDER, &data_type)).unwrap(); + func(check_deser); + } +} + +// setup a cargo project for the test +fn create_cargo_dir(datatype: &str) -> PathBuf { + let deser = include_str!("../test_data/template/ser"); + let ser = include_str!("../test_data/template/deser"); + let cargo = include_str!("../test_data/template/Cargo.toml").replace( + r#"aws-smithy-types = { path = "./" }"#, + &format!( + "aws-smithy-types = {{ path = {:#?} }}", + current_dir().unwrap().to_str().unwrap().to_string() + ), + ); + + let base_path = PathBuf::from_str("/tmp/smithy-rust-test") + .unwrap() + .join(datatype); + let src_path = base_path.join("src"); + std::fs::create_dir_all(&base_path).unwrap(); + std::fs::create_dir_all(&src_path).unwrap(); + base_path +} + +#[test] +fn number() { + let cargo_project_path = create_cargo_dir("Number"); + + base("Number"); +} + +#[test] +fn blob() { + base("Blob"); +} + +#[test] +fn document() { + base("Document"); +} + +#[test] +fn date_time() { + base("DateTime"); +} diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/blob.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/blob.rs new file mode 100644 index 00000000000..19684bab18a --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/serde_impl_test/blob.rs @@ -0,0 +1,22 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use super::*; + +/// Tests whether de-serialization feature for blob is properly feature gated +#[test] +fn feature_gate_test_for_blob_deserialization() { + // create files + let cargo_project_path = create_cargo_dir("Blob", Target::De); + de_test(&cargo_project_path); +} + +/// Tests whether serialization feature for blob is properly feature gated +#[test] +fn feature_gate_test_for_blob_serialization() { + // create files + let cargo_project_path = create_cargo_dir("Blob", Target::Ser); + ser_test(&cargo_project_path); +} diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/date_time.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/date_time.rs new file mode 100644 index 00000000000..f8b3a73fa7a --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/serde_impl_test/date_time.rs @@ -0,0 +1,22 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use super::*; + +/// Tests whether de-serialization feature for datetime is properly feature gated +#[test] +fn feature_gate_test_for_datetime_deserialization() { + // create files + let cargo_project_path = create_cargo_dir("DateTime", Target::De); + de_test(&cargo_project_path); +} + +/// Tests whether serialization feature for datetime is properly feature gated +#[test] +fn feature_gate_test_for_datetime_serialization() { + // create files + let cargo_project_path = create_cargo_dir("DateTime", Target::Ser); + ser_test(&cargo_project_path); +} diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs new file mode 100644 index 00000000000..703bbb027cd --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs @@ -0,0 +1,22 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use super::*; + +/// Tests whether de-serialization feature for document is properly feature gated +#[test] +fn feature_gate_test_for_document_deserialization() { + // create files + let cargo_project_path = create_cargo_dir("Document", Target::De); + de_test(&cargo_project_path); +} + +/// Tests whether serialization feature for document is properly feature gated +#[test] +fn feature_gate_test_for_document_serialization() { + // create files + let cargo_project_path = create_cargo_dir("Document", Target::Ser); + ser_test(&cargo_project_path); +} diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs new file mode 100644 index 00000000000..d06cc8fc800 --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs @@ -0,0 +1,228 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; +mod blob; +mod number; +mod date_time; +mod document; + +#[derive(Debug)] +pub(crate) enum Target { + Ser, + De, +} + +// create directory and files for testing +pub(crate) fn create_cargo_dir(datatype: &str, target: Target) -> PathBuf { + let base_path = PathBuf::from_str("/tmp/smithy-rust-test/") + .unwrap() + .join(format!("{target:#?}")) + .join(datatype); + let src_path = base_path.join("src"); + + // create temp directory + std::fs::create_dir_all(&base_path).unwrap(); + std::fs::create_dir_all(&src_path).unwrap(); + + // write cargo + { + let cargo = include_str!("../../test_data/template/Cargo.toml").replace( + r#"aws-smithy-types = { path = "./" }"#, + &format!( + "aws-smithy-types = {{ path = {:#?} }}", + current_dir().unwrap().to_str().unwrap().to_string() + ), + ); + std::fs::write(&base_path.join("Cargo.toml"), cargo).unwrap(); + }; + + // write main.rs + let ser = include_str!("../../test_data/template/ser"); + let deser = include_str!("../../test_data/template/deser"); + let place_holder = "$PLACE_HOLDER$"; + let contents = match target { + Target::De => deser.replace(place_holder, datatype), + Target::Ser => { + let s = match datatype { + "Blob" => "Blob::new([1, 2,3])", + "Number" => "Number::PosInt(1)", + "Document" => "Document::from(0)", + "DateTime" => "DateTime::from_secs(0)", + _ => panic!(), + }; + ser.replace(place_holder, s) + } + }; + std::fs::write(&src_path.join("main.rs"), contents).unwrap(); + + base_path +} + +pub(crate) fn ser_test(cargo_project_path: &PathBuf) { + // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --all-features"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-serialize"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-deserialize"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. + // it is expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-serialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); + + // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-deserialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); +} + +pub(crate) fn de_test(cargo_project_path: &PathBuf) { + // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --all-features"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-serialize"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-deserialize"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-serialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. + // it is expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-deserialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); +} diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs new file mode 100644 index 00000000000..fee4bd818e2 --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs @@ -0,0 +1,22 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use super::*; + +/// Tests whether de-serialization feature for number is properly feature gated +#[test] +fn feature_gate_test_for_number_deserialization() { + // create files + let cargo_project_path = create_cargo_dir("Number", Target::De); + de_test(&cargo_project_path); +} + +/// Tests whether serialization feature for number is properly feature gated +#[test] +fn feature_gate_test_for_number_serialization() { + // create files + let cargo_project_path = create_cargo_dir("Number", Target::Ser); + ser_test(&cargo_project_path); +} diff --git a/rust-runtime/aws-smithy-types/test_data/template/ser b/rust-runtime/aws-smithy-types/test_data/template/ser index e4448371fed..0838ac88c47 100644 --- a/rust-runtime/aws-smithy-types/test_data/template/ser +++ b/rust-runtime/aws-smithy-types/test_data/template/ser @@ -6,6 +6,8 @@ // this is a template for running feature-gate tests. // $PLACE_HOLDER$ is replaced with relevant data types + fn main() { - serde_json::to_string(&aws_smithy_types::$PLACE_HOLDER$::default()); + use aws_smithy_types::*; + serde_json::to_string(&$PLACE_HOLDER$); } From 61ee3f3280a60384a85f4f50f0af15c80747dc06 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 13:17:43 +0000 Subject: [PATCH 139/312] update --- rust-runtime/aws-smithy-types/src/serde_impl_check.rs | 8 ++++---- rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs index 8645fc1b396..a8c26f5d6d4 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs @@ -106,15 +106,15 @@ fn create_cargo_dir(datatype: &str, target: Target) -> PathBuf { let contents = match target { Target::De => deser.replace(place_holder, datatype), Target::Ser => { - let s = match datatype { + let s = match datatype { "Blob" => "Blob::new([1, 2,3])", "Number" => "Number::PosInt(1)", "Document" => "Document::from(0)", "DateTime" => "DateTime::from_secs(0)", - _ => panic!() - }; + _ => panic!(), + }; ser.replace(place_holder, s) - }, + } }; std::fs::write(&src_path.join("main.rs"), contents).unwrap(); diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs index d06cc8fc800..4c64f9d36fe 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs @@ -5,9 +5,9 @@ use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; mod blob; -mod number; mod date_time; mod document; +mod number; #[derive(Debug)] pub(crate) enum Target { From b1d60cb717d67edb72dee03e51c7ea012f205a0c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 13:19:44 +0000 Subject: [PATCH 140/312] update --- .../src/serde_impl_test/date_time.rs | 22 ------------------- .../src/serde_impl_test/document.rs | 22 ------------------- .../src/serde_impl_test/mod.rs | 6 ++--- .../src/serde_impl_test/number.rs | 22 ------------------- 4 files changed, 3 insertions(+), 69 deletions(-) delete mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/date_time.rs delete mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs delete mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/date_time.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/date_time.rs deleted file mode 100644 index f8b3a73fa7a..00000000000 --- a/rust-runtime/aws-smithy-types/src/serde_impl_test/date_time.rs +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use super::*; - -/// Tests whether de-serialization feature for datetime is properly feature gated -#[test] -fn feature_gate_test_for_datetime_deserialization() { - // create files - let cargo_project_path = create_cargo_dir("DateTime", Target::De); - de_test(&cargo_project_path); -} - -/// Tests whether serialization feature for datetime is properly feature gated -#[test] -fn feature_gate_test_for_datetime_serialization() { - // create files - let cargo_project_path = create_cargo_dir("DateTime", Target::Ser); - ser_test(&cargo_project_path); -} diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs deleted file mode 100644 index 703bbb027cd..00000000000 --- a/rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use super::*; - -/// Tests whether de-serialization feature for document is properly feature gated -#[test] -fn feature_gate_test_for_document_deserialization() { - // create files - let cargo_project_path = create_cargo_dir("Document", Target::De); - de_test(&cargo_project_path); -} - -/// Tests whether serialization feature for document is properly feature gated -#[test] -fn feature_gate_test_for_document_serialization() { - // create files - let cargo_project_path = create_cargo_dir("Document", Target::Ser); - ser_test(&cargo_project_path); -} diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs index 4c64f9d36fe..662ef28e563 100644 --- a/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs +++ b/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs @@ -5,9 +5,9 @@ use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; mod blob; -mod date_time; -mod document; -mod number; + + + #[derive(Debug)] pub(crate) enum Target { diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs deleted file mode 100644 index fee4bd818e2..00000000000 --- a/rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use super::*; - -/// Tests whether de-serialization feature for number is properly feature gated -#[test] -fn feature_gate_test_for_number_deserialization() { - // create files - let cargo_project_path = create_cargo_dir("Number", Target::De); - de_test(&cargo_project_path); -} - -/// Tests whether serialization feature for number is properly feature gated -#[test] -fn feature_gate_test_for_number_serialization() { - // create files - let cargo_project_path = create_cargo_dir("Number", Target::Ser); - ser_test(&cargo_project_path); -} From 10a7bf87d7dca27cbfb5c7250936f74c1035b4b0 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 13:20:52 +0000 Subject: [PATCH 141/312] update --- .../aws-smithy-types/src/serde_impl_check_.rs | 237 ------------------ 1 file changed, 237 deletions(-) delete mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_check_.rs diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check_.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check_.rs deleted file mode 100644 index 47c50adfbc7..00000000000 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check_.rs +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; - -const PLACE_HOLDER: &str = "$PLACE_HOLDER$"; -struct CargoCmd { - cargo_command: &'static str, - is_ser_compilable: bool, - is_deser_compilable: bool, - enable_aws_sdk_unstable: bool, -} - -impl CargoCmd { - const ALL_FEATURE: &str = "cargo check --all-features"; - const SERDE_SERIALIZE: &str = "cargo check --features serde-serialize"; - const SERDE_DESERIALIZE: &str = "cargo check --features serde-serialize"; -} - -#[test] -fn print() { - let array = [ - ("cargo check --all-features", [true; 2], false), - ("cargo check --features serde-serialize", [true; 2], false), - ("cargo check --features serde-deserialize", [true; 2], false), - // checks if features are properly gated behind serde-serialize/deserialize - ("cargo check", [true; 2], true), - ( - "cargo check --features serde-serialize", - [false, true], - true, - ), - ( - "cargo check --features serde-deserialize", - [true, false], - true, - ), - ]; - - let mut ser_stack = "".to_string(); - let mut de_stack = "".to_string(); - for i in array { - let [ser, de] = i.1; - let func = |ser, check2| { - let func = |b| if b { "not" } else { "" }; - let msg = if check2 { - "de-serialization feature" - } else { - "serialization feature" - }; - let env = if i.2 { - r#".env("RUSTFLAGS", "--cfg aws_sdk_unstable")"# - } else { - "" - }; - let s = format! { r#" -// runs {cmd} {env} "--cfg aws_sdk_unstable" enabled. -// the code that it compiles require {msg}. -// it is {ser} expected to compile. -let mut cmd = Command::new("bash"); - -let child = cmd.current_dir(&cargo_project_path) - .args(["-c", {cmd:#?}, "&>", "/dev/null"]) - {env2} - .spawn(); - -let is_success = child.unwrap().wait().unwrap().success(); -assert_eq!(is_success, {ser_bool}); - "#, - cmd = i.0, - ser = func(ser), - ser_bool = ser, - env2 = env, - env = if i.2 { - "with" - } else { - "without" - } - }; - - return s; - }; - - ser_stack.push_str(&func(ser, false)); - de_stack.push_str(&func(de, true)); - } - - let datatypes = ["Number", "Document", "DateTime", "Blob"]; - for dt in datatypes { - println!( - r#" - /// Tests whether de-serialization feature for {dt} is properly feature gated - #[test] - fn feature_gate_test_for_{dt}_deserialization() {{ - // create files - let cargo_project_path = create_cargo_dir({dt2:?}); - de_test(&cargo_project_path); - }} - - /// Tests whether serialization feature for {dt} is properly feature gated - #[test] - fn feature_gate_test_for_{dt}_serialization() {{ - // create files - let cargo_project_path = create_cargo_dir({dt2:?}); - ser_test(&cargo_project_path); - }} - "#, - dt = dt.to_lowercase(), - dt2 = dt, - ); - } - println!( - "fn ser_test(cargo_project_path: &PathBuf) {{{}}}", - ser_stack - ); - println!("fn de_test(cargo_project_path: &PathBuf) {{{}}}", de_stack); -} - -/// ensures serde features is not enabled when features are not enabled -/// Checks whether features are properly gated behind aws_sdk_unstable -fn base(dt: &str) { - // data type - let data_type = format!("aws_smithy_types::{dt}"); - // commands 2 run - let array = [ - ("cargo check --all-features", [true; 2], false), - ("cargo check --features serde-serialize", [true; 2], false), - ("cargo check --features serde-deserialize", [true; 2], false), - // checks if features are properly gated behind serde-serialize/deserialize - ("cargo check", [true; 2], true), - ( - "cargo check --features serde-serialize", - [false, true], - true, - ), - ( - "cargo check --features serde-deserialize", - [true, false], - true, - ), - ]; - - // templates - let deser = include_str!("../test_data/template/ser"); - let ser = include_str!("../test_data/template/deser"); - let cargo = include_str!("../test_data/template/Cargo.toml").replace( - r#"aws-smithy-types = { path = "./" }"#, - &format!( - "aws-smithy-types = {{ path = {:#?} }}", - current_dir().unwrap().to_str().unwrap().to_string() - ), - ); - - // paths - - let base_path = PathBuf::from_str("/tmp/smithy-rust-test").unwrap().join(dt); - let cmdpath = base_path.join("cmd.sh"); - let src_path = base_path.join("src"); - let main_path = src_path.join("main.rs"); - - for (cmd_txt, [check_deser, check_ser], env) in array { - std::fs::create_dir_all(&base_path).unwrap(); - std::fs::create_dir_all(&src_path).unwrap(); - - std::fs::write(&cmdpath, cmd_txt).unwrap(); - let func = |predicted| { - let mut cmd = Command::new("bash"); - cmd.current_dir(&base_path); - cmd.arg(&cmdpath.to_str().unwrap().to_string()); - if env { - cmd.env("RUSTFLAGS", "--cfg aws_sdk_unstable"); - } - println!("{:#?}", cmd); - //let check = cmd.spawn().unwrap().wait_with_output().unwrap(); - /* - assert_eq!( - check.status.success(), - predicted, - "{:#?}", - (cmd, cmd_txt, check_ser, check_deser, env, dt) - ); - */ - }; - - std::fs::write(&base_path.join("Cargo.toml"), &cargo).unwrap(); - - std::fs::write(&main_path, ser.replace(PLACE_HOLDER, &data_type)).unwrap(); - func(check_ser); - std::fs::write(&main_path, deser.replace(PLACE_HOLDER, &data_type)).unwrap(); - func(check_deser); - } -} - -// setup a cargo project for the test -fn create_cargo_dir(datatype: &str) -> PathBuf { - let deser = include_str!("../test_data/template/ser"); - let ser = include_str!("../test_data/template/deser"); - let cargo = include_str!("../test_data/template/Cargo.toml").replace( - r#"aws-smithy-types = { path = "./" }"#, - &format!( - "aws-smithy-types = {{ path = {:#?} }}", - current_dir().unwrap().to_str().unwrap().to_string() - ), - ); - - let base_path = PathBuf::from_str("/tmp/smithy-rust-test") - .unwrap() - .join(datatype); - let src_path = base_path.join("src"); - std::fs::create_dir_all(&base_path).unwrap(); - std::fs::create_dir_all(&src_path).unwrap(); - base_path -} - -#[test] -fn number() { - let cargo_project_path = create_cargo_dir("Number"); - - base("Number"); -} - -#[test] -fn blob() { - base("Blob"); -} - -#[test] -fn document() { - base("Document"); -} - -#[test] -fn date_time() { - base("DateTime"); -} From 00efda277f331afdbb189c19a56704bbb12e1c11 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 13:23:21 +0000 Subject: [PATCH 142/312] update --- .../src/serde_impl_test/mod.rs | 228 ++++++++++++++++++ .../src/serde_impl_test/number.rs | 22 ++ 2 files changed, 250 insertions(+) create mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs create mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs new file mode 100644 index 00000000000..7a3380b71c6 --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs @@ -0,0 +1,228 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; + +mod number; + + + +#[derive(Debug)] +pub(crate) enum Target { + Ser, + De, +} + +// create directory and files for testing +pub(crate) fn create_cargo_dir(datatype: &str, target: Target) -> PathBuf { + let base_path = PathBuf::from_str("/tmp/smithy-rust-test/") + .unwrap() + .join(format!("{target:#?}")) + .join(datatype); + let src_path = base_path.join("src"); + + // create temp directory + std::fs::create_dir_all(&base_path).unwrap(); + std::fs::create_dir_all(&src_path).unwrap(); + + // write cargo + { + let cargo = include_str!("../../test_data/template/Cargo.toml").replace( + r#"aws-smithy-types = { path = "./" }"#, + &format!( + "aws-smithy-types = {{ path = {:#?} }}", + current_dir().unwrap().to_str().unwrap().to_string() + ), + ); + std::fs::write(&base_path.join("Cargo.toml"), cargo).unwrap(); + }; + + // write main.rs + let ser = include_str!("../../test_data/template/ser"); + let deser = include_str!("../../test_data/template/deser"); + let place_holder = "$PLACE_HOLDER$"; + let contents = match target { + Target::De => deser.replace(place_holder, datatype), + Target::Ser => { + let s = match datatype { + "Blob" => "Blob::new([1, 2,3])", + "Number" => "Number::PosInt(1)", + "Document" => "Document::from(0)", + "DateTime" => "DateTime::from_secs(0)", + _ => panic!(), + }; + ser.replace(place_holder, s) + } + }; + std::fs::write(&src_path.join("main.rs"), contents).unwrap(); + + base_path +} + +pub(crate) fn ser_test(cargo_project_path: &PathBuf) { + // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --all-features"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-serialize"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-deserialize"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. + // it is expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-serialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); + + // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-deserialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); +} + +pub(crate) fn de_test(cargo_project_path: &PathBuf) { + // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --all-features"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-serialize"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-deserialize"]) + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. + // it is not expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-serialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, false); + + // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. + // the code that it compiles require de-serialization feature. + // it is expected to compile. + let mut cmd = Command::new("bash"); + + let child = cmd + .current_dir(&cargo_project_path) + .args(["-c", "cargo check --features serde-deserialize"]) + .env("RUSTFLAGS", "--cfg aws_sdk_unstable") + .spawn(); + + let is_success = child.unwrap().wait().unwrap().success(); + assert_eq!(is_success, true); +} diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs new file mode 100644 index 00000000000..72ddc596471 --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs @@ -0,0 +1,22 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use super::*; + +/// Tests whether de-serialization feature for blob is properly feature gated +#[test] +fn feature_gate_test_for_blob_deserialization() { + // create files + let cargo_project_path = create_cargo_dir("Number", Target::De); + de_test(&cargo_project_path); +} + +/// Tests whether serialization feature for blob is properly feature gated +#[test] +fn feature_gate_test_for_blob_serialization() { + // create files + let cargo_project_path = create_cargo_dir("Number", Target::Ser); + ser_test(&cargo_project_path); +} From 234b2e4c83cfe8c347ef7d4e6dd9381b7837cbc9 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Tue, 2 May 2023 22:30:01 +0900 Subject: [PATCH 143/312] Delete serde_impl_check.rs --- .../aws-smithy-types/src/serde_impl_check.rs | 288 ------------------ 1 file changed, 288 deletions(-) delete mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_check.rs diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs deleted file mode 100644 index a8c26f5d6d4..00000000000 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; - -#[derive(Debug)] -enum Target { - Ser, - De, -} - -/// Tests whether de-serialization feature for number is properly feature gated -#[test] -fn feature_gate_test_for_number_deserialization() { - // create files - let cargo_project_path = create_cargo_dir("Number", Target::De); - de_test(&cargo_project_path); -} - -/// Tests whether serialization feature for number is properly feature gated -#[test] -fn feature_gate_test_for_number_serialization() { - // create files - let cargo_project_path = create_cargo_dir("Number", Target::Ser); - ser_test(&cargo_project_path); -} - -/// Tests whether de-serialization feature for document is properly feature gated -#[test] -fn feature_gate_test_for_document_deserialization() { - // create files - let cargo_project_path = create_cargo_dir("Document", Target::De); - de_test(&cargo_project_path); -} - -/// Tests whether serialization feature for document is properly feature gated -#[test] -fn feature_gate_test_for_document_serialization() { - // create files - let cargo_project_path = create_cargo_dir("Document", Target::Ser); - ser_test(&cargo_project_path); -} - -/// Tests whether de-serialization feature for datetime is properly feature gated -#[test] -fn feature_gate_test_for_datetime_deserialization() { - // create files - let cargo_project_path = create_cargo_dir("DateTime", Target::De); - de_test(&cargo_project_path); -} - -/// Tests whether serialization feature for datetime is properly feature gated -#[test] -fn feature_gate_test_for_datetime_serialization() { - // create files - let cargo_project_path = create_cargo_dir("DateTime", Target::Ser); - ser_test(&cargo_project_path); -} - -/// Tests whether de-serialization feature for blob is properly feature gated -#[test] -fn feature_gate_test_for_blob_deserialization() { - // create files - let cargo_project_path = create_cargo_dir("Blob", Target::De); - de_test(&cargo_project_path); -} - -/// Tests whether serialization feature for blob is properly feature gated -#[test] -fn feature_gate_test_for_blob_serialization() { - // create files - let cargo_project_path = create_cargo_dir("Blob", Target::Ser); - ser_test(&cargo_project_path); -} - -// create directory and files for testing -fn create_cargo_dir(datatype: &str, target: Target) -> PathBuf { - let base_path = PathBuf::from_str("/tmp/smithy-rust-test/") - .unwrap() - .join(format!("{target:#?}")) - .join(datatype); - let src_path = base_path.join("src"); - - // create temp directory - std::fs::create_dir_all(&base_path).unwrap(); - std::fs::create_dir_all(&src_path).unwrap(); - - // write cargo - { - let cargo = include_str!("../test_data/template/Cargo.toml").replace( - r#"aws-smithy-types = { path = "./" }"#, - &format!( - "aws-smithy-types = {{ path = {:#?} }}", - current_dir().unwrap().to_str().unwrap().to_string() - ), - ); - std::fs::write(&base_path.join("Cargo.toml"), cargo).unwrap(); - }; - - // write main.rs - let ser = include_str!("../test_data/template/ser"); - let deser = include_str!("../test_data/template/deser"); - let place_holder = "$PLACE_HOLDER$"; - let contents = match target { - Target::De => deser.replace(place_holder, datatype), - Target::Ser => { - let s = match datatype { - "Blob" => "Blob::new([1, 2,3])", - "Number" => "Number::PosInt(1)", - "Document" => "Document::from(0)", - "DateTime" => "DateTime::from_secs(0)", - _ => panic!(), - }; - ser.replace(place_holder, s) - } - }; - std::fs::write(&src_path.join("main.rs"), contents).unwrap(); - - base_path -} - -fn ser_test(cargo_project_path: &PathBuf) { - // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --all-features"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); - - // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); -} - -fn de_test(cargo_project_path: &PathBuf) { - // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --all-features"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); -} From c216199245119b272bd2bca7071d5109e026b255 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 13:37:53 +0000 Subject: [PATCH 144/312] document --- .../src/serde_impl_test/document.rs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs new file mode 100644 index 00000000000..703bbb027cd --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs @@ -0,0 +1,22 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use super::*; + +/// Tests whether de-serialization feature for document is properly feature gated +#[test] +fn feature_gate_test_for_document_deserialization() { + // create files + let cargo_project_path = create_cargo_dir("Document", Target::De); + de_test(&cargo_project_path); +} + +/// Tests whether serialization feature for document is properly feature gated +#[test] +fn feature_gate_test_for_document_serialization() { + // create files + let cargo_project_path = create_cargo_dir("Document", Target::Ser); + ser_test(&cargo_project_path); +} From 9aba8618092b3148b8dd5676c4c637a415a14a96 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 2 May 2023 14:29:02 +0000 Subject: [PATCH 145/312] update --- .../src/serde_impl_test/mod.rs | 228 ------------------ .../src/serde_impl_test/number.rs | 22 -- 2 files changed, 250 deletions(-) delete mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs delete mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs deleted file mode 100644 index 7a3380b71c6..00000000000 --- a/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; - -mod number; - - - -#[derive(Debug)] -pub(crate) enum Target { - Ser, - De, -} - -// create directory and files for testing -pub(crate) fn create_cargo_dir(datatype: &str, target: Target) -> PathBuf { - let base_path = PathBuf::from_str("/tmp/smithy-rust-test/") - .unwrap() - .join(format!("{target:#?}")) - .join(datatype); - let src_path = base_path.join("src"); - - // create temp directory - std::fs::create_dir_all(&base_path).unwrap(); - std::fs::create_dir_all(&src_path).unwrap(); - - // write cargo - { - let cargo = include_str!("../../test_data/template/Cargo.toml").replace( - r#"aws-smithy-types = { path = "./" }"#, - &format!( - "aws-smithy-types = {{ path = {:#?} }}", - current_dir().unwrap().to_str().unwrap().to_string() - ), - ); - std::fs::write(&base_path.join("Cargo.toml"), cargo).unwrap(); - }; - - // write main.rs - let ser = include_str!("../../test_data/template/ser"); - let deser = include_str!("../../test_data/template/deser"); - let place_holder = "$PLACE_HOLDER$"; - let contents = match target { - Target::De => deser.replace(place_holder, datatype), - Target::Ser => { - let s = match datatype { - "Blob" => "Blob::new([1, 2,3])", - "Number" => "Number::PosInt(1)", - "Document" => "Document::from(0)", - "DateTime" => "DateTime::from_secs(0)", - _ => panic!(), - }; - ser.replace(place_holder, s) - } - }; - std::fs::write(&src_path.join("main.rs"), contents).unwrap(); - - base_path -} - -pub(crate) fn ser_test(cargo_project_path: &PathBuf) { - // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --all-features"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); - - // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); -} - -pub(crate) fn de_test(cargo_project_path: &PathBuf) { - // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --all-features"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); -} diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs deleted file mode 100644 index 72ddc596471..00000000000 --- a/rust-runtime/aws-smithy-types/src/serde_impl_test/number.rs +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use super::*; - -/// Tests whether de-serialization feature for blob is properly feature gated -#[test] -fn feature_gate_test_for_blob_deserialization() { - // create files - let cargo_project_path = create_cargo_dir("Number", Target::De); - de_test(&cargo_project_path); -} - -/// Tests whether serialization feature for blob is properly feature gated -#[test] -fn feature_gate_test_for_blob_serialization() { - // create files - let cargo_project_path = create_cargo_dir("Number", Target::Ser); - ser_test(&cargo_project_path); -} From c209b130d9bf663043530bbad2c51db46fd796d1 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 3 May 2023 04:47:48 +0000 Subject: [PATCH 146/312] update --- rust-runtime/aws-smithy-types/Cargo.toml | 10 ++ rust-runtime/aws-smithy-types/additional-ci | 4 +- rust-runtime/aws-smithy-types/src/blob.rs | 125 ++++++++++++++++++ .../aws-smithy-types/src/date_time/mod.rs | 44 ++++++ 4 files changed, 182 insertions(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 7ebd3ece231..4bdc0f93dda 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -22,6 +22,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" criterion = "0.4" rand = "0.8.4" +ciborium = "0.2.0" [package.metadata.docs.rs] all-features = true @@ -32,3 +33,12 @@ rustdoc-args = ["--cfg", "docsrs"] [[bench]] name = "base64" harness = false + + +[target."cfg(aws_sdk_unstable)".dependencies.serde] +version = "1" +features = ["derive"] + +[features] +serde-serialize = [] +serde-deserialize = [] diff --git a/rust-runtime/aws-smithy-types/additional-ci b/rust-runtime/aws-smithy-types/additional-ci index c1fd7ce4066..e998967eb52 100755 --- a/rust-runtime/aws-smithy-types/additional-ci +++ b/rust-runtime/aws-smithy-types/additional-ci @@ -5,8 +5,10 @@ # # This script contains additional CI checks to run for this specific package - set -e echo "### Checking for duplicate dependency versions in the normal dependency graph with all features enabled" cargo tree -d --edges normal --all-features + +echo "### Checking whether the features are properly feature-gated" +cargo tree -e no-dev | (grep serde || echo "") \ No newline at end of file diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index bdd335c4923..28a001d3753 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -30,3 +30,128 @@ impl AsRef<[u8]> for Blob { &self.inner } } + +#[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] +mod serde_serialize { + use super::*; + use crate::base64; + use serde::Serialize; + + impl Serialize for Blob { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + if serializer.is_human_readable() { + serializer.serialize_str(&crate::base64::encode(&self.inner)) + } else { + serializer.serialize_bytes(&self.inner) + } + } + } +} + +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +mod serde_deserialize { + use super::*; + use crate::base64; + use serde::{de::Visitor, Deserialize}; + + struct HumanReadableBlobVisitor; + impl<'de> Visitor<'de> for HumanReadableBlobVisitor { + type Value = Blob; + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("expected base64 encoded string") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + match base64::decode(v) { + Ok(inner) => Ok(Blob { inner }), + Err(e) => Err(E::custom(e)), + } + } + } + + struct NotHumanReadableBlobVisitor; + impl<'de> Visitor<'de> for NotHumanReadableBlobVisitor { + type Value = Blob; + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("expected base64 encoded string") + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: serde::de::Error, + { + Ok(Blob { inner: v }) + } + } + + impl<'de> Deserialize<'de> for Blob { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + if deserializer.is_human_readable() { + deserializer.deserialize_str(HumanReadableBlobVisitor) + } else { + deserializer.deserialize_byte_buf(NotHumanReadableBlobVisitor) + } + } + } +} + +#[cfg(test)] +#[cfg(all( + aws_sdk_unstable, + feature = "serde-serialize", + feature = "serde-deserialize" +))] +mod test_serde { + use crate::Blob; + use serde::{Deserialize, Serialize}; + use std::collections::HashMap; + + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct ForTest { + blob: Blob, + } + + #[test] + fn human_readable_blob() { + let aws_in_base64 = r#"{"blob":"QVdT"}"#; + let for_test = ForTest { + blob: Blob { + inner: vec![b'A', b'W', b'S'], + }, + }; + assert_eq!(for_test, serde_json::from_str(aws_in_base64).unwrap()); + assert_eq!(serde_json::to_string(&for_test).unwrap(), aws_in_base64); + } + + #[test] + fn not_human_readable_blob() { + use std::ffi::CString; + + let for_test = ForTest { + blob: Blob { + inner: vec![b'A', b'W', b'S'], + }, + }; + let mut buf = vec![]; + let res = ciborium::ser::into_writer(&for_test, &mut buf); + assert!(res.is_ok()); + + // checks whether the bytes are deserialiezd properly + let n: HashMap = + ciborium::de::from_reader(std::io::Cursor::new(buf.clone())).unwrap(); + assert!(n.get("blob").is_some()); + assert!(n.get("blob") == CString::new([65, 87, 83]).ok().as_ref()); + + let de: ForTest = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); + assert_eq!(for_test, de); + } +} diff --git a/rust-runtime/aws-smithy-types/src/date_time/mod.rs b/rust-runtime/aws-smithy-types/src/date_time/mod.rs index 0459619998e..ea3f5baf6ce 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/mod.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/mod.rs @@ -9,6 +9,7 @@ use crate::date_time::format::rfc3339::AllowOffsets; use crate::date_time::format::DateTimeParseErrorKind; use num_integer::div_mod_floor; use num_integer::Integer; +use std::cmp::Ordering; use std::convert::TryFrom; use std::error::Error as StdError; use std::fmt; @@ -301,6 +302,21 @@ impl From for DateTime { } } +impl PartialOrd for DateTime { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for DateTime { + fn cmp(&self, other: &Self) -> Ordering { + match self.seconds.cmp(&other.seconds) { + Ordering::Equal => self.subsecond_nanos.cmp(&other.subsecond_nanos), + ordering => ordering, + } + } +} + /// Failure to convert a `DateTime` to or from another type. #[derive(Debug)] #[non_exhaustive] @@ -552,4 +568,32 @@ mod test { SystemTime::try_from(date_time).unwrap() ); } + + #[test] + fn ord() { + let first = DateTime::from_secs_and_nanos(-1, 0); + let second = DateTime::from_secs_and_nanos(0, 0); + let third = DateTime::from_secs_and_nanos(0, 1); + let fourth = DateTime::from_secs_and_nanos(1, 0); + + assert!(first == first); + assert!(first < second); + assert!(first < third); + assert!(first < fourth); + + assert!(second > first); + assert!(second == second); + assert!(second < third); + assert!(second < fourth); + + assert!(third > first); + assert!(third > second); + assert!(third == third); + assert!(third < fourth); + + assert!(fourth > first); + assert!(fourth > second); + assert!(fourth > third); + assert!(fourth == fourth); + } } From e2f92de0c953345bd1240cc16832c6d20b3ae919 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 3 May 2023 04:53:28 +0000 Subject: [PATCH 147/312] pre-commit --- rust-runtime/aws-smithy-types/additional-ci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/additional-ci b/rust-runtime/aws-smithy-types/additional-ci index e998967eb52..09ce2a75aef 100755 --- a/rust-runtime/aws-smithy-types/additional-ci +++ b/rust-runtime/aws-smithy-types/additional-ci @@ -11,4 +11,4 @@ echo "### Checking for duplicate dependency versions in the normal dependency gr cargo tree -d --edges normal --all-features echo "### Checking whether the features are properly feature-gated" -cargo tree -e no-dev | (grep serde || echo "") \ No newline at end of file +cargo tree -e no-dev | (grep serde || echo "") From afd64a996e85d3691860c233cd82048ed102ed14 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 5 May 2023 02:52:23 +0000 Subject: [PATCH 148/312] FIX --- rust-runtime/aws-smithy-types/additional-ci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/additional-ci b/rust-runtime/aws-smithy-types/additional-ci index 09ce2a75aef..2d9305d5103 100755 --- a/rust-runtime/aws-smithy-types/additional-ci +++ b/rust-runtime/aws-smithy-types/additional-ci @@ -11,4 +11,4 @@ echo "### Checking for duplicate dependency versions in the normal dependency gr cargo tree -d --edges normal --all-features echo "### Checking whether the features are properly feature-gated" -cargo tree -e no-dev | (grep serde || echo "") +! cargo tree -e no-dev | grep serde From be405e4a112ebc9d98a46794679dbf23a0a725a4 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 5 May 2023 07:12:41 +0000 Subject: [PATCH 149/312] updater --- .github/workflows/benchmark.yml | 18 ------------------ .github/workflows/ci.yml | 15 ++++++++++++++- 2 files changed, 14 insertions(+), 19 deletions(-) delete mode 100644 .github/workflows/benchmark.yml diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml deleted file mode 100644 index a9f268eb659..00000000000 --- a/.github/workflows/benchmark.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: compiletime benchmark -run-name: compile time benchmark -on: - push: - branches: - - main -jobs: - compiletime-benchmark: - name: Compile time benchmark - runs-on: ${{ matrix.test.runner }} - - steps: - - uses: actions/checkout@v3 - with: - path: smithy-rs - ref: ${{ inputs.git_ref }} - - name: compiletime-benchmark - run: bash tools/ci-scripts/compiletime-benchmark \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54ccda52ff9..76b468480a7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -296,6 +296,19 @@ jobs: shell: bash run: cross test --target ${{ matrix.target }} --manifest-path "aws/rust-runtime/Cargo.toml" ${{ matrix.test_aws_exclude }} --workspace + # compile time benchmark + compiletime-benchmark: + name: Compile time benchmark + runs-on: ${{ matrix.test.runner }} + + steps: + - uses: actions/checkout@v3 + with: + path: smithy-rs + ref: ${{ inputs.git_ref }} + - name: compiletime-benchmark + run: bash tools/ci-scripts/compiletime-benchmark + # This job is split out from the rest since it is not required to pass for merge check-sdk-examples: name: Check SDK Examples @@ -331,4 +344,4 @@ jobs: # Pinned to commit hash of v1.2.2 uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe with: - jobs: ${{ toJSON(needs) }} + jobs: ${{ toJSON(needs) }} \ No newline at end of file From 6d1f1dee148872a9bb4b0e86c913e12bd58b23a7 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 5 May 2023 16:47:21 +0900 Subject: [PATCH 150/312] Update ci.yml --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76b468480a7..fa96463d65f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -149,6 +149,8 @@ jobs: runner: smithy_ubuntu-latest_8-core - action: check-aws-sdk-standalone-integration-tests runner: ubuntu-latest + - action: compiletime-benchmark + runner: ubuntu-latest steps: - uses: actions/checkout@v3 with: @@ -344,4 +346,4 @@ jobs: # Pinned to commit hash of v1.2.2 uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe with: - jobs: ${{ toJSON(needs) }} \ No newline at end of file + jobs: ${{ toJSON(needs) }} From 50ad110a575ebae64f85a2eb323bd89fcfc7ec9e Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Tue, 30 May 2023 11:21:37 -0700 Subject: [PATCH 151/312] Shorten doc comment --- rust-runtime/aws-smithy-types/src/number.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/number.rs b/rust-runtime/aws-smithy-types/src/number.rs index 5ae57a08107..3ee46cb077a 100644 --- a/rust-runtime/aws-smithy-types/src/number.rs +++ b/rust-runtime/aws-smithy-types/src/number.rs @@ -3,8 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -//! A number type that implements Javascript / JSON semantics, modeled on serde_json: -//! +//! A number type that implements Javascript / JSON semantics. use crate::error::{TryFromNumberError, TryFromNumberErrorKind}; #[cfg(all( From e387795e15a787367eda48f916f1e9a478ac881d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 30 May 2023 21:40:54 +0000 Subject: [PATCH 152/312] add ciborium --- rust-runtime/aws-smithy-runtime/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/rust-runtime/aws-smithy-runtime/Cargo.toml b/rust-runtime/aws-smithy-runtime/Cargo.toml index 496d50d84b4..62b3662a088 100644 --- a/rust-runtime/aws-smithy-runtime/Cargo.toml +++ b/rust-runtime/aws-smithy-runtime/Cargo.toml @@ -28,6 +28,7 @@ pin-project-lite = "0.2.7" pin-utils = "0.1.0" tokio = { version = "1.25", features = [] } tracing = "0.1.37" +ciborium = "0.2.1" [dev-dependencies] aws-smithy-async = { path = "../aws-smithy-async", features = ["rt-tokio"] } From 37bea6914d3ec89837d9caeea2526e97c9dbf1bc Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 30 May 2023 21:59:31 +0000 Subject: [PATCH 153/312] add ciborium --- rust-runtime/aws-smithy-runtime/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/rust-runtime/aws-smithy-runtime/Cargo.toml b/rust-runtime/aws-smithy-runtime/Cargo.toml index 5c8e098462d..497d1fb005b 100644 --- a/rust-runtime/aws-smithy-runtime/Cargo.toml +++ b/rust-runtime/aws-smithy-runtime/Cargo.toml @@ -25,6 +25,7 @@ http-body = "0.4.5" pin-utils = "0.1.0" tokio = { version = "1.25", features = [] } tracing = "0.1" +ciborium = "0.2.1" [dev-dependencies] tokio = { version = "1.25", features = ["macros", "rt"] } From ff47d3eba06cf8963bd4d76f89c4df36a364239b Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 30 May 2023 22:06:26 +0000 Subject: [PATCH 154/312] update --- rust-runtime/aws-smithy-types/src/date_time/de.rs | 2 -- rust-runtime/aws-smithy-types/src/date_time/mod.rs | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index 6f346ea8dee..fd7b786d3b0 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -12,7 +12,6 @@ struct DateTimeVisitor; enum VisitorState { Second, SubsecondNanos, - Unexpected, } impl VisitorState { @@ -79,7 +78,6 @@ impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { VisitorState::Unexpected => fail(VisitorState::UNEXPECTED_VISITOR_STATE), VisitorState::SubsecondNanos => { self.subsecond_nanos = v; - self.state = VisitorState::Unexpected; Ok(self) } _ => fail("`subsecond_nanos` value must be u32"), diff --git a/rust-runtime/aws-smithy-types/src/date_time/mod.rs b/rust-runtime/aws-smithy-types/src/date_time/mod.rs index 3db4b90099e..0bd9f974620 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/mod.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/mod.rs @@ -602,6 +602,7 @@ mod test { assert!(fourth == fourth); } + /// checks the value can be serialized/de-serialized in human readable datetime format #[cfg(all( test, aws_sdk_unstable, @@ -625,7 +626,7 @@ mod test { assert!(test.unwrap().datetime == datetime); } - /// checks that they are serialized into tuples + /// checks the value can be serialized/deserialized into tuples #[cfg(all( test, aws_sdk_unstable, From d8d516952c75e9f862df03e2b2018806ad4c68b7 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 30 May 2023 23:19:55 +0000 Subject: [PATCH 155/312] update --- rust-runtime/aws-smithy-types/Cargo.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 4bdc0f93dda..7c5c7093c24 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "aws-smithy-types" version = "0.0.0-smithy-rs-head" -authors = ["AWS Rust SDK Team ", "Russell Cohen "] +authors = [ + "AWS Rust SDK Team ", + "Russell Cohen ", +] description = "Types for smithy-rs codegen." edition = "2021" license = "Apache-2.0" @@ -22,7 +25,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" criterion = "0.4" rand = "0.8.4" -ciborium = "0.2.0" +ciborium = { version = "0.2.1", optional = true } [package.metadata.docs.rs] all-features = true From cc92bba6b33891ffd816d4311b97bd4e9f3469ea Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 30 May 2023 23:25:53 +0000 Subject: [PATCH 156/312] update --- rust-runtime/aws-smithy-types/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 7c5c7093c24..4a02b17d2f7 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -22,7 +22,7 @@ base64 = "0.13.0" lazy_static = "1.4" proptest = "1" serde = { version = "1", features = ["derive"] } -serde_json = "1" +serde_json = "1.0.96" criterion = "0.4" rand = "0.8.4" ciborium = { version = "0.2.1", optional = true } From 0874bbd2cabca23da152d2303477129330fe84db Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 31 May 2023 01:10:21 +0000 Subject: [PATCH 157/312] fix --- rust-runtime/aws-smithy-types/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 4a02b17d2f7..3f472388594 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -25,7 +25,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1.0.96" criterion = "0.4" rand = "0.8.4" -ciborium = { version = "0.2.1", optional = true } +ciborium = { version = "0.2.1" } [package.metadata.docs.rs] all-features = true From abcaa831bde86e23a2e55e1ac5de90db2330b188 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 31 May 2023 01:35:36 +0000 Subject: [PATCH 158/312] update --- rust-runtime/aws-smithy-runtime/Cargo.toml | 1 - rust-runtime/aws-smithy-types/Cargo.toml | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-runtime/aws-smithy-runtime/Cargo.toml b/rust-runtime/aws-smithy-runtime/Cargo.toml index 3b18ef215bc..aadbfcac83d 100644 --- a/rust-runtime/aws-smithy-runtime/Cargo.toml +++ b/rust-runtime/aws-smithy-runtime/Cargo.toml @@ -28,7 +28,6 @@ pin-project-lite = "0.2.7" pin-utils = "0.1.0" tokio = { version = "1.25", features = [] } tracing = "0.1.37" -ciborium = "0.2.1" [dev-dependencies] aws-smithy-async = { path = "../aws-smithy-async", features = ["rt-tokio", "test-util"] } diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 3f472388594..426df17554a 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -22,7 +22,7 @@ base64 = "0.13.0" lazy_static = "1.4" proptest = "1" serde = { version = "1", features = ["derive"] } -serde_json = "1.0.96" +serde_json = "1" criterion = "0.4" rand = "0.8.4" ciborium = { version = "0.2.1" } @@ -41,6 +41,7 @@ harness = false [target."cfg(aws_sdk_unstable)".dependencies.serde] version = "1" features = ["derive"] +optional = true [features] serde-serialize = [] From ffe271363f042ba52e43081f55f0862eca8770fd Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 31 May 2023 01:36:18 +0000 Subject: [PATCH 159/312] fix --- rust-runtime/aws-smithy-types/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 426df17554a..7be2ef76065 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -41,7 +41,6 @@ harness = false [target."cfg(aws_sdk_unstable)".dependencies.serde] version = "1" features = ["derive"] -optional = true [features] serde-serialize = [] From cb0a64a0a100115e7c44c06bb01bda71273b0c81 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 31 May 2023 13:01:13 +0000 Subject: [PATCH 160/312] update --- .../aws-smithy-types/src/date_time/de.rs | 31 ++++++++++++ .../aws-smithy-types/src/date_time/mod.rs | 47 ------------------- .../aws-smithy-types/src/date_time/ser.rs | 31 ++++++++++++ 3 files changed, 62 insertions(+), 47 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index fd7b786d3b0..921719c2a95 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -106,3 +106,34 @@ impl<'de> Deserialize<'de> for DateTime { } } } + +/// checks the value can be serialized/de-serialized in human readable datetime format +#[test] +fn human_readable_datetime() { + use serde::{Deserialize, Serialize}; + + let datetime = DateTime::from_secs(1576540098); + #[derive(Serialize, Deserialize, PartialEq)] + struct Test { + datetime: DateTime, + } + let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; + let test = serde_json::from_str::(&datetime_json).ok(); + assert!(test == Some(Test{datetime})); +} + +/// checks the value can be serialized/deserialized into tuples +#[test] +fn not_human_readable_datetime() { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(1576540098i64.into()), + ciborium::value::Value::Integer(0u32.into()), + ]); + let datetime = DateTime::from_secs(1576540098); + + let mut buf1 = vec![]; + let mut buf2 = vec![]; + let _ = ciborium::ser::into_writer(&datetime, &mut buf1); + let res = ciborium::de::from_reader(std::io::Cursor::new(buf1)); + assert_eq!(res == Ok(datetime)); +} diff --git a/rust-runtime/aws-smithy-types/src/date_time/mod.rs b/rust-runtime/aws-smithy-types/src/date_time/mod.rs index 0bd9f974620..8049924de5b 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/mod.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/mod.rs @@ -601,51 +601,4 @@ mod test { assert!(fourth > third); assert!(fourth == fourth); } - - /// checks the value can be serialized/de-serialized in human readable datetime format - #[cfg(all( - test, - aws_sdk_unstable, - feature = "serde-deserialize", - feature = "serde-serialize" - ))] - #[test] - fn human_readable_datetime() { - use serde::{Deserialize, Serialize}; - - let datetime = DateTime::from_secs(1576540098); - #[derive(Serialize, Deserialize, PartialEq)] - struct Test { - datetime: DateTime, - } - let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; - assert!(serde_json::to_string(&Test { datetime }).ok() == Some(datetime_json.to_string())); - - let test = serde_json::from_str::(&datetime_json).ok(); - assert!(test.is_some()); - assert!(test.unwrap().datetime == datetime); - } - - /// checks the value can be serialized/deserialized into tuples - #[cfg(all( - test, - aws_sdk_unstable, - feature = "serde-deserialize", - feature = "serde-serialize" - ))] - #[test] - fn not_human_readable_datetime() { - let cbor = ciborium::value::Value::Array(vec![ - ciborium::value::Value::Integer(1576540098i64.into()), - ciborium::value::Value::Integer(0u32.into()), - ]); - let datetime = DateTime::from_secs(1576540098); - - let mut buf1 = vec![]; - let mut buf2 = vec![]; - let res1 = ciborium::ser::into_writer(&datetime, &mut buf1); - let res2 = ciborium::ser::into_writer(&cbor, &mut buf2); - assert!(res1.is_ok() && res2.is_ok()); - assert!(buf1 == buf2, "{:#?}", (buf1, buf2)); - } } diff --git a/rust-runtime/aws-smithy-types/src/date_time/ser.rs b/rust-runtime/aws-smithy-types/src/date_time/ser.rs index 4dc39292ec0..bd098cc4796 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/ser.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/ser.rs @@ -24,3 +24,34 @@ impl serde::Serialize for DateTime { } } } + +/// checks the value can be serialized/de-serialized in human readable datetime format +#[test] +fn human_readable_datetime() { + use serde::{Deserialize, Serialize}; + + let datetime = DateTime::from_secs(1576540098); + #[derive(Serialize, Deserialize, PartialEq)] + struct Test { + datetime: DateTime, + } + let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; + assert!(serde_json::to_string(&Test { datetime }).ok() == Some(datetime_json.to_string())); +} + +/// checks the value can be serialized/deserialized into tuples +#[test] +fn not_human_readable_datetime() { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(1576540098i64.into()), + ciborium::value::Value::Integer(0u32.into()), + ]); + let datetime = DateTime::from_secs(1576540098); + + let mut buf1 = vec![]; + let mut buf2 = vec![]; + let res1 = ciborium::ser::into_writer(&datetime, &mut buf1); + let res2 = ciborium::ser::into_writer(&cbor, &mut buf2); + assert!(res1.is_ok() && res2.is_ok()); + assert!(buf1 == buf2, "{:#?}", (buf1, buf2)); +} From ab1eef51bb5e05f2945e46bdc3cc78665149e969 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 31 May 2023 13:18:52 +0000 Subject: [PATCH 161/312] lint fix --- rust-runtime/aws-smithy-types/src/date_time/de.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index 921719c2a95..f54ca1e7041 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -119,7 +119,7 @@ fn human_readable_datetime() { } let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; let test = serde_json::from_str::(&datetime_json).ok(); - assert!(test == Some(Test{datetime})); + assert!(test == Some(Test { datetime })); } /// checks the value can be serialized/deserialized into tuples From d9f362b3bf83ead71c0d4b1eff9d710c9b181e10 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 31 May 2023 13:31:45 +0000 Subject: [PATCH 162/312] FIX docs --- rust-runtime/aws-smithy-types/src/date_time/de.rs | 4 ++-- rust-runtime/aws-smithy-types/src/date_time/ser.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index f54ca1e7041..53a0e0384a2 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -107,7 +107,7 @@ impl<'de> Deserialize<'de> for DateTime { } } -/// checks the value can be serialized/de-serialized in human readable datetime format +/// check for human redable format #[test] fn human_readable_datetime() { use serde::{Deserialize, Serialize}; @@ -122,7 +122,7 @@ fn human_readable_datetime() { assert!(test == Some(Test { datetime })); } -/// checks the value can be serialized/deserialized into tuples +/// check for non-human redable format #[test] fn not_human_readable_datetime() { let cbor = ciborium::value::Value::Array(vec![ diff --git a/rust-runtime/aws-smithy-types/src/date_time/ser.rs b/rust-runtime/aws-smithy-types/src/date_time/ser.rs index bd098cc4796..32ebb57db78 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/ser.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/ser.rs @@ -25,7 +25,7 @@ impl serde::Serialize for DateTime { } } -/// checks the value can be serialized/de-serialized in human readable datetime format +/// check for human redable format #[test] fn human_readable_datetime() { use serde::{Deserialize, Serialize}; @@ -39,7 +39,7 @@ fn human_readable_datetime() { assert!(serde_json::to_string(&Test { datetime }).ok() == Some(datetime_json.to_string())); } -/// checks the value can be serialized/deserialized into tuples +/// check for non-human redable format #[test] fn not_human_readable_datetime() { let cbor = ciborium::value::Value::Array(vec![ From fe1cbce731cc28fc58de4d66e2bbadf57c4aa1e9 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 31 May 2023 14:40:29 +0000 Subject: [PATCH 163/312] FIX --- rust-runtime/aws-smithy-runtime/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/rust-runtime/aws-smithy-runtime/Cargo.toml b/rust-runtime/aws-smithy-runtime/Cargo.toml index 3b18ef215bc..aadbfcac83d 100644 --- a/rust-runtime/aws-smithy-runtime/Cargo.toml +++ b/rust-runtime/aws-smithy-runtime/Cargo.toml @@ -28,7 +28,6 @@ pin-project-lite = "0.2.7" pin-utils = "0.1.0" tokio = { version = "1.25", features = [] } tracing = "0.1.37" -ciborium = "0.2.1" [dev-dependencies] aws-smithy-async = { path = "../aws-smithy-async", features = ["rt-tokio", "test-util"] } From 893692ac3ca9632d5dc6dfa7f78353ac93e0c38b Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 00:31:56 +0900 Subject: [PATCH 164/312] Update FluentClientGenerator.kt --- .../client/smithy/generators/client/FluentClientGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 7a62f018342..5997607333b 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -483,7 +483,7 @@ class FluentClientGenerator( """, *middlewareScope, ) - } + } } if (smithyRuntimeMode.generateOrchestrator) { From c2cce088ba6445019b59f2ecb0a84105fcd3890b Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 31 May 2023 17:02:41 +0000 Subject: [PATCH 165/312] update --- .../client/smithy/generators/client/FluentClientGenerator.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 5997607333b..dcb4747d7af 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -372,7 +372,7 @@ class FluentClientGenerator( } } } - + // this fixes this error // error[E0592]: duplicate definitions with name `set_fields` // --> sdk/connectcases/src/operation/update_case/builders.rs:115:5 @@ -408,7 +408,7 @@ class FluentClientGenerator( "AwsSdkUnstableAttribute" to Attribute.AwsSdkUnstableAttribute.inner, ) } - + if (smithyRuntimeMode.generateMiddleware) { val middlewareScope = arrayOf( *preludeScope, From 48c04f8893b8527e696d54998462e0e4205733ca Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 09:00:15 +0000 Subject: [PATCH 166/312] update --- .../client/FluentClientGenerator.kt | 60 +++++++------------ 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index dcb4747d7af..ebb687cffa0 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -30,10 +30,12 @@ import software.amazon.smithy.rust.codegen.core.rustlang.docLink import software.amazon.smithy.rust.codegen.core.rustlang.docs import software.amazon.smithy.rust.codegen.core.rustlang.documentShape import software.amazon.smithy.rust.codegen.core.rustlang.escape +import software.amazon.smithy.rust.codegen.core.rustlang.implBlock import software.amazon.smithy.rust.codegen.core.rustlang.normalizeHtml import software.amazon.smithy.rust.codegen.core.rustlang.qualifiedName import software.amazon.smithy.rust.codegen.core.rustlang.render import software.amazon.smithy.rust.codegen.core.rustlang.rust +import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock import software.amazon.smithy.rust.codegen.core.rustlang.rustBlockTemplate import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.rustTypeParameters @@ -319,9 +321,29 @@ class FluentClientGenerator( val input = operation.inputShape(model) val baseDerives = symbolProvider.toSymbol(input).expectRustMetadata().derives // Filter out any derive that isn't Clone. Then add a Debug derive + // input name + val fluentBuilderName = operation.fluentBuilderType(symbolProvider).name + val fnName = clientOperationFnName(operation, symbolProvider) + implBlock(symbolProvider.symbolForBuilder(input)) { + rustTemplate( + """ + ##[#{AwsSdkUnstableAttribute}] + /// Creates a fluent builder from this builder. + pub fn into_fluent_builder(self, client: &crate::Client) -> $fluentBuilderName { + let fluent_builder = client.$fnName(); + fluent_builder.inner = self; + fluent_builder + } + """, + + "AwsSdkUnstableAttribute" to Attribute.AwsSdkUnstableAttribute.inner, + ) + } + val derives = baseDerives.filter { it == RuntimeType.Clone } + RuntimeType.Debug docs("Fluent builder constructing a request to `${operationSymbol.name}`.\n") + val builderName = operation.fluentBuilderType(symbolProvider).name documentShape(operation, model, autoSuppressMissingDocs = false) deprecatedShape(operation) @@ -352,8 +374,6 @@ class FluentClientGenerator( ) { val outputType = symbolProvider.toSymbol(operation.outputShape(model)) val errorType = symbolProvider.symbolForOperationError(operation) - val inputBuilderType = symbolProvider.symbolForBuilder(input) - val fnName = clientOperationFnName(operation, symbolProvider) rust("/// Creates a new `${operationSymbol.name}`.") withBlockTemplate( @@ -373,42 +393,6 @@ class FluentClientGenerator( } } - // this fixes this error - // error[E0592]: duplicate definitions with name `set_fields` - // --> sdk/connectcases/src/operation/update_case/builders.rs:115:5 - // | - // 78 | / pub fn set_fields( - // 79 | | mut self, - // 80 | | data: crate::operation::update_case::builders::UpdateCaseInputBuilder, - // 81 | | ) -> Self { - // | |_____________- other definition for `set_fields` - // ... - // 115 | / pub fn set_fields( - // 116 | | mut self, - // 117 | | input: std::option::Option>, - // 118 | | ) -> Self { - // | |_____________^ duplicate definitions for `set_fields` - if (inputBuilderType.toString().endsWith("Builder")) { - rustTemplate( - """ - ##[#{AwsSdkUnstableAttribute}] - /// This function replaces the parameter with new one. - /// It is useful when you want to replace the existing data with de-serialized data. - /// ```compile_fail - /// let result_future = async { - /// let deserialized_parameters: $inputBuilderType = serde_json::from_str(&json_string).unwrap(); - /// client.$fnName().set_fields(&deserialized_parameters).send().await - /// }; - /// ``` - pub fn set_fields(mut self, data: $inputBuilderType) -> Self { - self.inner = data; - self - } - """, - "AwsSdkUnstableAttribute" to Attribute.AwsSdkUnstableAttribute.inner, - ) - } - if (smithyRuntimeMode.generateMiddleware) { val middlewareScope = arrayOf( *preludeScope, From bbd94bad3a466c44b9c8eae7c2b29c4a2a8b5361 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 09:10:01 +0000 Subject: [PATCH 167/312] update --- .../generators/client/FluentClientGenerator.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index ebb687cffa0..2e3e5a17844 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -327,15 +327,15 @@ class FluentClientGenerator( implBlock(symbolProvider.symbolForBuilder(input)) { rustTemplate( """ - ##[#{AwsSdkUnstableAttribute}] - /// Creates a fluent builder from this builder. - pub fn into_fluent_builder(self, client: &crate::Client) -> $fluentBuilderName { - let fluent_builder = client.$fnName(); - fluent_builder.inner = self; - fluent_builder - } + ##[#{AwsSdkUnstableAttribute}] + /// Creates a fluent builder from this builder. + pub fn into_fluent_builder(self, client: &crate::Client) -> $fluentBuilderName { + let fluent_builder = client.$fnName(); + fluent_builder.inner = self; + fluent_builder + } """, - + "AwsSdkUnstableAttribute" to Attribute.AwsSdkUnstableAttribute.inner, ) } From 75e84e76ada8e28aa930feb599f60f8a4d05610c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 18:15:46 +0900 Subject: [PATCH 168/312] Update FluentClientGenerator.kt --- .../client/smithy/generators/client/FluentClientGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 2e3e5a17844..53b8a10b8c7 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -330,7 +330,7 @@ class FluentClientGenerator( ##[#{AwsSdkUnstableAttribute}] /// Creates a fluent builder from this builder. pub fn into_fluent_builder(self, client: &crate::Client) -> $fluentBuilderName { - let fluent_builder = client.$fnName(); + let mut fluent_builder = client.$fnName(); fluent_builder.inner = self; fluent_builder } From 2b1a69fc6f3bdbe1ec32f8b489c51d3858d81398 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 09:17:31 +0000 Subject: [PATCH 169/312] update --- rust-runtime/aws-smithy-types/additional-ci | 7 +++++++ rust-runtime/aws-smithy-types/src/date_time/de.rs | 6 ------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/rust-runtime/aws-smithy-types/additional-ci b/rust-runtime/aws-smithy-types/additional-ci index c1fd7ce4066..9c83c21f424 100755 --- a/rust-runtime/aws-smithy-types/additional-ci +++ b/rust-runtime/aws-smithy-types/additional-ci @@ -10,3 +10,10 @@ set -e echo "### Checking for duplicate dependency versions in the normal dependency graph with all features enabled" cargo tree -d --edges normal --all-features + +export RUSTFLAGS="--cfg aws_sdk_unstable" +echo "### Checking for duplicate dependency versions in the normal dependency graph with all features enabled with aws_sdk_unstable flag enabled" +cargo tree -d --edges normal --all-features + +echo "### Checking if it compiles" +cargo check --all-features \ No newline at end of file diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index 53a0e0384a2..965ed9df593 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -14,10 +14,6 @@ enum VisitorState { SubsecondNanos, } -impl VisitorState { - const UNEXPECTED_VISITOR_STATE: &'static str = "Unexpected state. This happens when visitor tries to parse something after finished parsing the `subsec_nanos`."; -} - struct NonHumanReadableDateTimeVisitor { state: VisitorState, seconds: i64, @@ -60,7 +56,6 @@ impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { E: serde::de::Error, { match self.state { - VisitorState::Unexpected => fail(VisitorState::UNEXPECTED_VISITOR_STATE), VisitorState::Second => { self.seconds = v; self.state = VisitorState::SubsecondNanos; @@ -75,7 +70,6 @@ impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { E: serde::de::Error, { match self.state { - VisitorState::Unexpected => fail(VisitorState::UNEXPECTED_VISITOR_STATE), VisitorState::SubsecondNanos => { self.subsecond_nanos = v; Ok(self) From 4dfd9fb4783eda7b47361bc621e797e95ffa3666 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 18:59:03 +0900 Subject: [PATCH 170/312] Delete serde_impl_check.rs --- .../aws-smithy-types/src/serde_impl_check.rs | 106 ------------------ 1 file changed, 106 deletions(-) delete mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_check.rs diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs b/rust-runtime/aws-smithy-types/src/serde_impl_check.rs deleted file mode 100644 index 1fdb33848c2..00000000000 --- a/rust-runtime/aws-smithy-types/src/serde_impl_check.rs +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; - -/// ensures serde features is not enabled when features are not enabled -/// Checks whether features are properly gated behind aws_sdk_unstable -fn base(dt: &str) { - // data type - let data_type = format!("aws_smithy_types::{dt}"); - // commands 2 run - let array = [ - ("cargo check --all-features", [true; 2], false), - ("cargo check --features serde-serialize", [true; 2], false), - ("cargo check --features serde-deserialize", [true; 2], false), - // checks if features are properly gated behind serde-serialize/deserialize - ("cargo check", [true; 2], true), - ( - "cargo check --features serde-serialize", - [false, true], - true, - ), - ( - "cargo check --features serde-deserialize", - [true, false], - true, - ), - ]; - - // const - let replace_data_type = "ReplaceDataType"; - - // templates - let deser = include_str!("../test_data/template/ser.rs"); - let ser = include_str!("../test_data/template/deser.rs"); - let cargo = include_str!("../test_data/template/Cargo.toml").replace( - r#"aws-smithy-types = { path = "./" }"#, - &format!( - "aws-smithy-types = {{ path = {:#?} }}", - current_dir().unwrap().to_str().unwrap().to_string() - ), - ); - - // paths - - let base_path = PathBuf::from_str("/tmp/smithy-rust-test").unwrap().join(dt); - let cmdpath = base_path.join("cmd.sh"); - let src_path = base_path.join("src"); - let main_path = src_path.join("main.rs"); - - for (cmd_txt, [check_deser, check_ser], env) in array { - std::fs::create_dir_all(&base_path).unwrap(); - std::fs::create_dir_all(&src_path).unwrap(); - - std::fs::write(&cmdpath, cmd_txt).unwrap(); - let func = || { - let mut cmd = Command::new("bash"); - cmd.current_dir(&base_path); - cmd.arg(&cmdpath.to_str().unwrap().to_string()); - if env { - cmd.env("RUSTFLAGS", "--cfg aws_sdk_unstable"); - } - - let check = cmd.spawn().unwrap().wait_with_output().unwrap(); - - assert!( - !check.status.success(), - "{:#?}", - (cmd, cmd_txt, check_ser, check_deser, env, dt) - ); - }; - - std::fs::write(&base_path.join("Cargo.toml"), &cargo).unwrap(); - - if check_ser { - std::fs::write(&main_path, ser.replace(replace_data_type, &data_type)).unwrap(); - func(); - } - if check_deser { - std::fs::write(&main_path, deser.replace(replace_data_type, &data_type)).unwrap(); - func(); - } - } -} - -#[test] -fn number() { - base("Number"); -} - -#[test] -fn blob() { - base("Blob"); -} - -#[test] -fn document() { - base("Document"); -} - -#[test] -fn date_time() { - base("DateTime"); -} From 9f2e9c3ba28630c1d66ff87a2b75a714630cef54 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 18:59:31 +0900 Subject: [PATCH 171/312] Delete Cargo.toml --- .../aws-smithy-types/test_data/template/Cargo.toml | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 rust-runtime/aws-smithy-types/test_data/template/Cargo.toml diff --git a/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml b/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml deleted file mode 100644 index 9478a1edf77..00000000000 --- a/rust-runtime/aws-smithy-types/test_data/template/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "template" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -aws-smithy-types = { path = "./" } -serde_json = "1.0" -[features] -serde-serialize = ["aws-smithy-types/serde-serialize"] -serde-deserialize = ["aws-smithy-types/serde-deserialize"] From 98dcb335c644cd1e9bd54717838a47af9fb50e22 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 18:59:33 +0900 Subject: [PATCH 172/312] Delete deser.rs --- rust-runtime/aws-smithy-types/test_data/template/deser.rs | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 rust-runtime/aws-smithy-types/test_data/template/deser.rs diff --git a/rust-runtime/aws-smithy-types/test_data/template/deser.rs b/rust-runtime/aws-smithy-types/test_data/template/deser.rs deleted file mode 100644 index 43ac7b430e5..00000000000 --- a/rust-runtime/aws-smithy-types/test_data/template/deser.rs +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -fn main() { - let _dt: Result = serde_json::from_str("some_str"); -} From 3610a390e199f305626d5735fe669851e5f10af3 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 18:59:35 +0900 Subject: [PATCH 173/312] Delete ser.rs --- rust-runtime/aws-smithy-types/test_data/template/ser.rs | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 rust-runtime/aws-smithy-types/test_data/template/ser.rs diff --git a/rust-runtime/aws-smithy-types/test_data/template/ser.rs b/rust-runtime/aws-smithy-types/test_data/template/ser.rs deleted file mode 100644 index af6bcd4ad95..00000000000 --- a/rust-runtime/aws-smithy-types/test_data/template/ser.rs +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -fn main() { - serde_json::to_string(&ReplaceDataType::default()); -} From a0655b23c56913e0af55df3ad31c85f23e9c1104 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 19:01:28 +0900 Subject: [PATCH 174/312] Update lib.rs --- rust-runtime/aws-smithy-types/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/lib.rs b/rust-runtime/aws-smithy-types/src/lib.rs index 5bd41157d72..ffa1c86ea58 100644 --- a/rust-runtime/aws-smithy-types/src/lib.rs +++ b/rust-runtime/aws-smithy-types/src/lib.rs @@ -35,6 +35,3 @@ pub use document::Document; )] pub use error::ErrorMetadata as Error; pub use number::Number; - -#[cfg(test)] -mod serde_impl_check; From 36502425fb2e961b0bc7ab437f98c1c576db08ce Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 10:09:38 +0000 Subject: [PATCH 175/312] update --- rust-runtime/aws-smithy-types/Cargo.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 7ebd3ece231..97e58ae8708 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -14,6 +14,10 @@ ryu = "1.0.5" time = { version = "0.3.4", features = ["parsing"] } base64-simd = "0.8" +[target."cfg(aws_sdk_unstable)".dependencies.serde] +version = "1" +features = ["derive"] + [dev-dependencies] base64 = "0.13.0" lazy_static = "1.4" @@ -22,6 +26,7 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" criterion = "0.4" rand = "0.8.4" +ciborium = { version = "0.2.1" } [package.metadata.docs.rs] all-features = true @@ -32,3 +37,7 @@ rustdoc-args = ["--cfg", "docsrs"] [[bench]] name = "base64" harness = false + +[features] +serde-serialize = [] +serde-deserialize = [] \ No newline at end of file From ad6acbae895d938274fa7e749a470020572d5978 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 10:14:31 +0000 Subject: [PATCH 176/312] update --- rust-runtime/aws-smithy-types/Cargo.toml | 10 +++++----- rust-runtime/aws-smithy-types/src/date_time/de.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 97e58ae8708..cdda86e7bea 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -14,10 +14,6 @@ ryu = "1.0.5" time = { version = "0.3.4", features = ["parsing"] } base64-simd = "0.8" -[target."cfg(aws_sdk_unstable)".dependencies.serde] -version = "1" -features = ["derive"] - [dev-dependencies] base64 = "0.13.0" lazy_static = "1.4" @@ -38,6 +34,10 @@ rustdoc-args = ["--cfg", "docsrs"] name = "base64" harness = false +[target."cfg(aws_sdk_unstable)".dependencies.serde] +version = "1" +features = ["derive"] + [features] serde-serialize = [] -serde-deserialize = [] \ No newline at end of file +serde-deserialize = [] diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index 965ed9df593..dec43a51533 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -129,5 +129,5 @@ fn not_human_readable_datetime() { let mut buf2 = vec![]; let _ = ciborium::ser::into_writer(&datetime, &mut buf1); let res = ciborium::de::from_reader(std::io::Cursor::new(buf1)); - assert_eq!(res == Ok(datetime)); + assert_eq!(res, Ok(datetime)); } From 47593d4ed0ec2a0c71d27bb9c65c0a0c6cee18d5 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 10:17:57 +0000 Subject: [PATCH 177/312] update --- rust-runtime/aws-smithy-types/src/date_time/de.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index dec43a51533..27225950d33 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -129,5 +129,5 @@ fn not_human_readable_datetime() { let mut buf2 = vec![]; let _ = ciborium::ser::into_writer(&datetime, &mut buf1); let res = ciborium::de::from_reader(std::io::Cursor::new(buf1)); - assert_eq!(res, Ok(datetime)); + assert_eq!(res.ok(), Some(datetime)); } From 84e5758bb273c22f94f8d8e14b9b374be8633455 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 10:20:59 +0000 Subject: [PATCH 178/312] update --- rust-runtime/aws-smithy-types/additional-ci | 7 ------- 1 file changed, 7 deletions(-) diff --git a/rust-runtime/aws-smithy-types/additional-ci b/rust-runtime/aws-smithy-types/additional-ci index 9c83c21f424..c1fd7ce4066 100755 --- a/rust-runtime/aws-smithy-types/additional-ci +++ b/rust-runtime/aws-smithy-types/additional-ci @@ -10,10 +10,3 @@ set -e echo "### Checking for duplicate dependency versions in the normal dependency graph with all features enabled" cargo tree -d --edges normal --all-features - -export RUSTFLAGS="--cfg aws_sdk_unstable" -echo "### Checking for duplicate dependency versions in the normal dependency graph with all features enabled with aws_sdk_unstable flag enabled" -cargo tree -d --edges normal --all-features - -echo "### Checking if it compiles" -cargo check --all-features \ No newline at end of file From 446d2efea424d8014a2beec7822cc7476fcf914b Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 10:23:47 +0000 Subject: [PATCH 179/312] fix --- rust-runtime/aws-smithy-types/src/date_time/de.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index 27225950d33..f865d6e72c8 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -126,7 +126,6 @@ fn not_human_readable_datetime() { let datetime = DateTime::from_secs(1576540098); let mut buf1 = vec![]; - let mut buf2 = vec![]; let _ = ciborium::ser::into_writer(&datetime, &mut buf1); let res = ciborium::de::from_reader(std::io::Cursor::new(buf1)); assert_eq!(res.ok(), Some(datetime)); From 04f294ef05340ca78576e36fce6576d5a7e5d087 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 10:27:25 +0000 Subject: [PATCH 180/312] update --- rust-runtime/aws-smithy-types/src/date_time/de.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index f865d6e72c8..31cc3c886f7 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -126,7 +126,7 @@ fn not_human_readable_datetime() { let datetime = DateTime::from_secs(1576540098); let mut buf1 = vec![]; - let _ = ciborium::ser::into_writer(&datetime, &mut buf1); - let res = ciborium::de::from_reader(std::io::Cursor::new(buf1)); - assert_eq!(res.ok(), Some(datetime)); + let _ = ciborium::ser::into_writer(&cbor, &mut buf1); + let res = ciborium::de::from_reader(std::io::Cursor::new(buf1)).unwrap(); + assert_eq!(res, datetime); } From 535cb68d43f771d333e87965fc8a406021f99f31 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 10:32:10 +0000 Subject: [PATCH 181/312] fix --- rust-runtime/aws-smithy-types/src/date_time/de.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index 31cc3c886f7..ccd81bbc8f0 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -127,6 +127,6 @@ fn not_human_readable_datetime() { let mut buf1 = vec![]; let _ = ciborium::ser::into_writer(&cbor, &mut buf1); - let res = ciborium::de::from_reader(std::io::Cursor::new(buf1)).unwrap(); + let res: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf1)).unwrap(); assert_eq!(res, datetime); } From c047c6e8ace702d1fa8b7721c0e9b8c19b09cdd5 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 14:12:39 +0000 Subject: [PATCH 182/312] FIX --- .../aws-smithy-types/src/date_time/de.rs | 89 +------------------ .../aws-smithy-types/src/date_time/ser.rs | 32 +------ 2 files changed, 8 insertions(+), 113 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index ccd81bbc8f0..d691440a228 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -4,30 +4,11 @@ */ use super::*; -use serde::de::Visitor; +use serde::de::{Error, Visitor}; use serde::Deserialize; struct DateTimeVisitor; -enum VisitorState { - Second, - SubsecondNanos, -} - -struct NonHumanReadableDateTimeVisitor { - state: VisitorState, - seconds: i64, - subsecond_nanos: u32, -} - -fn fail(err_message: M) -> Result -where - M: std::fmt::Display, - E: serde::de::Error, -{ - Err(E::custom(err_message)) -} - impl<'de> Visitor<'de> for DateTimeVisitor { type Value = DateTime; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -40,41 +21,7 @@ impl<'de> Visitor<'de> for DateTimeVisitor { { match DateTime::from_str(v, Format::DateTime) { Ok(e) => Ok(e), - Err(e) => fail(e), - } - } -} - -impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { - type Value = Self; - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("expected (i64, u32)") - } - - fn visit_i64(mut self, v: i64) -> Result - where - E: serde::de::Error, - { - match self.state { - VisitorState::Second => { - self.seconds = v; - self.state = VisitorState::SubsecondNanos; - Ok(self) - } - _ => fail("`seconds` value must be i64"), - } - } - - fn visit_u32(mut self, v: u32) -> Result - where - E: serde::de::Error, - { - match self.state { - VisitorState::SubsecondNanos => { - self.subsecond_nanos = v; - Ok(self) - } - _ => fail("`subsecond_nanos` value must be u32"), + Err(e) => Err(Error::custom(e)), } } } @@ -84,26 +31,13 @@ impl<'de> Deserialize<'de> for DateTime { where D: serde::Deserializer<'de>, { - if deserializer.is_human_readable() { - deserializer.deserialize_str(DateTimeVisitor) - } else { - let visitor = NonHumanReadableDateTimeVisitor { - state: VisitorState::Second, - seconds: 0, - subsecond_nanos: 0, - }; - let visitor = deserializer.deserialize_tuple(2, visitor)?; - Ok(DateTime { - seconds: visitor.seconds, - subsecond_nanos: visitor.subsecond_nanos, - }) - } + deserializer.deserialize_str(DateTimeVisitor) } } /// check for human redable format #[test] -fn human_readable_datetime() { +fn deser() { use serde::{Deserialize, Serialize}; let datetime = DateTime::from_secs(1576540098); @@ -115,18 +49,3 @@ fn human_readable_datetime() { let test = serde_json::from_str::(&datetime_json).ok(); assert!(test == Some(Test { datetime })); } - -/// check for non-human redable format -#[test] -fn not_human_readable_datetime() { - let cbor = ciborium::value::Value::Array(vec![ - ciborium::value::Value::Integer(1576540098i64.into()), - ciborium::value::Value::Integer(0u32.into()), - ]); - let datetime = DateTime::from_secs(1576540098); - - let mut buf1 = vec![]; - let _ = ciborium::ser::into_writer(&cbor, &mut buf1); - let res: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf1)).unwrap(); - assert_eq!(res, datetime); -} diff --git a/rust-runtime/aws-smithy-types/src/date_time/ser.rs b/rust-runtime/aws-smithy-types/src/date_time/ser.rs index 32ebb57db78..e33e9f41e45 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/ser.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/ser.rs @@ -11,23 +11,16 @@ impl serde::Serialize for DateTime { where S: serde::Serializer, { - if serializer.is_human_readable() { - match self.fmt(Format::DateTime) { - Ok(val) => serializer.serialize_str(&val), - Err(e) => Err(serde::ser::Error::custom(e)), - } - } else { - let mut tup_ser = serializer.serialize_tuple(2)?; - tup_ser.serialize_element(&self.seconds)?; - tup_ser.serialize_element(&self.subsecond_nanos)?; - tup_ser.end() + match self.fmt(Format::DateTime) { + Ok(val) => serializer.serialize_str(&val), + Err(e) => Err(serde::ser::Error::custom(e)), } } } /// check for human redable format #[test] -fn human_readable_datetime() { +fn serde() { use serde::{Deserialize, Serialize}; let datetime = DateTime::from_secs(1576540098); @@ -38,20 +31,3 @@ fn human_readable_datetime() { let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; assert!(serde_json::to_string(&Test { datetime }).ok() == Some(datetime_json.to_string())); } - -/// check for non-human redable format -#[test] -fn not_human_readable_datetime() { - let cbor = ciborium::value::Value::Array(vec![ - ciborium::value::Value::Integer(1576540098i64.into()), - ciborium::value::Value::Integer(0u32.into()), - ]); - let datetime = DateTime::from_secs(1576540098); - - let mut buf1 = vec![]; - let mut buf2 = vec![]; - let res1 = ciborium::ser::into_writer(&datetime, &mut buf1); - let res2 = ciborium::ser::into_writer(&cbor, &mut buf2); - assert!(res1.is_ok() && res2.is_ok()); - assert!(buf1 == buf2, "{:#?}", (buf1, buf2)); -} From 739d2c879ba1522ac198f969ddaf34d754ad4fbf Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 1 Jun 2023 14:12:59 +0000 Subject: [PATCH 183/312] update --- rust-runtime/aws-smithy-types/src/date_time/ser.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/ser.rs b/rust-runtime/aws-smithy-types/src/date_time/ser.rs index e33e9f41e45..b60d661098c 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/ser.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/ser.rs @@ -4,7 +4,6 @@ */ use super::*; -use serde::ser::SerializeTuple; impl serde::Serialize for DateTime { fn serialize(&self, serializer: S) -> Result From 72f15cd53e8c1f1cfff6b861ca261d3b81eb2ce4 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 09:27:59 +0000 Subject: [PATCH 184/312] update --- .../aws-smithy-types/src/date_time/de.rs | 98 ++++++++++++++++++- .../aws-smithy-types/src/date_time/mod.rs | 4 +- .../aws-smithy-types/src/date_time/ser.rs | 56 ++++++++++- 3 files changed, 150 insertions(+), 8 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index d691440a228..6d2e378a0af 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -9,6 +9,8 @@ use serde::Deserialize; struct DateTimeVisitor; +struct NonHumanReadableDateTimeVisitor; + impl<'de> Visitor<'de> for DateTimeVisitor { type Value = DateTime; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -26,18 +28,55 @@ impl<'de> Visitor<'de> for DateTimeVisitor { } } +impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { + type Value = DateTime; + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("Datat must be number") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + match seq.size_hint() { + Some(2) => match (seq.next_element()?, seq.next_element()?) { + (Some(seconds), Some(subsecond_nanos)) => Ok(DateTime { + seconds, + subsecond_nanos, + }), + _ => return Err(Error::custom("datatype mismatch")), + }, + None => { + let res = match (seq.next_element()?, seq.next_element()?) { + (Some(seconds), Some(subsecond_nanos)) => Ok(DateTime { + seconds, + subsecond_nanos, + }), + _ => return Err(Error::custom("datatype mismatch")), + }; + return res; + } + _ => Err(Error::custom("Size mismatch")), + } + } +} + impl<'de> Deserialize<'de> for DateTime { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { - deserializer.deserialize_str(DateTimeVisitor) + if deserializer.is_human_readable() { + deserializer.deserialize_str(DateTimeVisitor) + } else { + deserializer.deserialize_tuple(2, NonHumanReadableDateTimeVisitor) + } } } /// check for human redable format #[test] -fn deser() { +fn de_human_readable_datetime() { use serde::{Deserialize, Serialize}; let datetime = DateTime::from_secs(1576540098); @@ -49,3 +88,58 @@ fn deser() { let test = serde_json::from_str::(&datetime_json).ok(); assert!(test == Some(Test { datetime })); } + +/// check for non-human redable format +#[test] +fn de_not_human_readable_datetime() { + { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(1576540098i64.into()), + ciborium::value::Value::Integer(0u32.into()), + ]); + let mut buf = vec![]; + let _ = ciborium::ser::into_writer(&cbor, &mut buf); + let cbor_dt: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); + assert_eq!( + cbor_dt, + DateTime { + seconds: 1576540098i64, + subsecond_nanos: 0 + } + ); + }; + + { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(0i64.into()), + ciborium::value::Value::Integer(0u32.into()), + ]); + let mut buf = vec![]; + let _ = ciborium::ser::into_writer(&cbor, &mut buf); + let cbor_dt: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); + assert_eq!( + cbor_dt, + DateTime { + seconds: 0, + subsecond_nanos: 0 + } + ); + }; + + { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(i64::MAX.into()), + ciborium::value::Value::Integer(u32::MAX.into()), + ]); + let mut buf = vec![]; + let _ = ciborium::ser::into_writer(&cbor, &mut buf); + let cbor_dt: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); + assert_eq!( + cbor_dt, + DateTime { + seconds: i64::MAX, + subsecond_nanos: u32::MAX + } + ); + }; +} \ No newline at end of file diff --git a/rust-runtime/aws-smithy-types/src/date_time/mod.rs b/rust-runtime/aws-smithy-types/src/date_time/mod.rs index baef360f1e9..480d6f3c147 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/mod.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/mod.rs @@ -56,8 +56,8 @@ const NANOS_PER_SECOND_U32: u32 = 1_000_000_000; /// [`time`](https://crates.io/crates/time) or [`chrono`](https://crates.io/crates/chrono). #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub struct DateTime { - seconds: i64, - subsecond_nanos: u32, + pub(crate) seconds: i64, + pub(crate) subsecond_nanos: u32, } /* ANCHOR_END: date_time */ diff --git a/rust-runtime/aws-smithy-types/src/date_time/ser.rs b/rust-runtime/aws-smithy-types/src/date_time/ser.rs index b60d661098c..9d8f80c7bd3 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/ser.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/ser.rs @@ -4,22 +4,30 @@ */ use super::*; +use serde::ser::SerializeTuple; impl serde::Serialize for DateTime { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { - match self.fmt(Format::DateTime) { - Ok(val) => serializer.serialize_str(&val), - Err(e) => Err(serde::ser::Error::custom(e)), + if serializer.is_human_readable() { + match self.fmt(Format::DateTime) { + Ok(val) => serializer.serialize_str(&val), + Err(e) => Err(serde::ser::Error::custom(e)), + } + } else { + let mut tup_ser = serializer.serialize_tuple(2)?; + tup_ser.serialize_element(&self.seconds)?; + tup_ser.serialize_element(&self.subsecond_nanos)?; + tup_ser.end() } } } /// check for human redable format #[test] -fn serde() { +fn ser_human_readable_datetime() { use serde::{Deserialize, Serialize}; let datetime = DateTime::from_secs(1576540098); @@ -30,3 +38,43 @@ fn serde() { let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; assert!(serde_json::to_string(&Test { datetime }).ok() == Some(datetime_json.to_string())); } + +/// check for non-human redable format +#[test] +fn ser_not_human_readable_datetime() { + { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(1576540098i64.into()), + ciborium::value::Value::Integer(0u32.into()), + ]); + let mut buf = vec![]; + let mut buf2 = vec![]; + let _ = ciborium::ser::into_writer(&cbor, &mut buf); + let _ = ciborium::ser::into_writer(&cbor, &mut buf2); + assert_eq!(buf, buf2); + }; + + { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(0i64.into()), + ciborium::value::Value::Integer(0u32.into()), + ]); + let mut buf = vec![]; + let mut buf2 = vec![]; + let _ = ciborium::ser::into_writer(&cbor, &mut buf); + let _ = ciborium::ser::into_writer(&cbor, &mut buf2); + assert_eq!(buf, buf2); + }; + + { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(i64::MAX.into()), + ciborium::value::Value::Integer(u32::MAX.into()), + ]); + let mut buf = vec![]; + let mut buf2 = vec![]; + let _ = ciborium::ser::into_writer(&cbor, &mut buf); + let _ = ciborium::ser::into_writer(&cbor, &mut buf2); + assert_eq!(buf, buf2); + }; +} From ad8f413781a97aeb9a6cb84426ea6340a6ad8ade Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 09:39:25 +0000 Subject: [PATCH 185/312] update fluent client --- .../client/FluentClientGenerator.kt | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 53b8a10b8c7..1a3e575c6af 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -317,6 +317,20 @@ class FluentClientGenerator( } private fun RustWriter.renderFluentBuilder(operation: OperationShape) { + val orchestratorScope = arrayOf( + *preludeScope, + "CustomizableOperation" to ClientRustModule.Client.customize.toType() + .resolve("orchestrator::CustomizableOperation"), + "HttpResponse" to RuntimeType.smithyRuntimeApi(runtimeConfig) + .resolve("client::orchestrator::HttpResponse"), + "Operation" to operationSymbol, + "OperationError" to errorType, + "OperationOutput" to outputType, + "SendResult" to ClientRustModule.Client.customize.toType() + .resolve("internal::SendResult"), + "SdkError" to RuntimeType.sdkError(runtimeConfig), + ) + val operationSymbol = symbolProvider.toSymbol(operation) val input = operation.inputShape(model) val baseDerives = symbolProvider.toSymbol(input).expectRustMetadata().derives @@ -327,16 +341,15 @@ class FluentClientGenerator( implBlock(symbolProvider.symbolForBuilder(input)) { rustTemplate( """ - ##[#{AwsSdkUnstableAttribute}] /// Creates a fluent builder from this builder. - pub fn into_fluent_builder(self, client: &crate::Client) -> $fluentBuilderName { + pub fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> + #{send_bounds:W} { let mut fluent_builder = client.$fnName(); fluent_builder.inner = self; fluent_builder } """, - - "AwsSdkUnstableAttribute" to Attribute.AwsSdkUnstableAttribute.inner, + *orchestratorScope ) } @@ -471,19 +484,6 @@ class FluentClientGenerator( } if (smithyRuntimeMode.generateOrchestrator) { - val orchestratorScope = arrayOf( - *preludeScope, - "CustomizableOperation" to ClientRustModule.Client.customize.toType() - .resolve("orchestrator::CustomizableOperation"), - "HttpResponse" to RuntimeType.smithyRuntimeApi(runtimeConfig) - .resolve("client::orchestrator::HttpResponse"), - "Operation" to operationSymbol, - "OperationError" to errorType, - "OperationOutput" to outputType, - "SendResult" to ClientRustModule.Client.customize.toType() - .resolve("internal::SendResult"), - "SdkError" to RuntimeType.sdkError(runtimeConfig), - ) rustTemplate( """ ##[doc(hidden)] From d1069dc82099b76bb2a8e7c4c97d74fb9b2792fa Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 09:43:10 +0000 Subject: [PATCH 186/312] fix --- .../smithy/generators/client/FluentClientGenerator.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 1a3e575c6af..3cb8b9669d1 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -317,6 +317,9 @@ class FluentClientGenerator( } private fun RustWriter.renderFluentBuilder(operation: OperationShape) { + val outputType = symbolProvider.toSymbol(operation.outputShape(model)) + val errorType = symbolProvider.symbolForOperationError(operation) + val operationSymbol = symbolProvider.toSymbol(operation) val orchestratorScope = arrayOf( *preludeScope, "CustomizableOperation" to ClientRustModule.Client.customize.toType() @@ -331,7 +334,7 @@ class FluentClientGenerator( "SdkError" to RuntimeType.sdkError(runtimeConfig), ) - val operationSymbol = symbolProvider.toSymbol(operation) + val input = operation.inputShape(model) val baseDerives = symbolProvider.toSymbol(input).expectRustMetadata().derives // Filter out any derive that isn't Clone. Then add a Debug derive @@ -385,9 +388,6 @@ class FluentClientGenerator( "client" to RuntimeType.smithyClient(runtimeConfig), "bounds" to generics.bounds, ) { - val outputType = symbolProvider.toSymbol(operation.outputShape(model)) - val errorType = symbolProvider.symbolForOperationError(operation) - rust("/// Creates a new `${operationSymbol.name}`.") withBlockTemplate( "pub(crate) fn new(handle: #{Arc}) -> Self {", From 2cb1e9bb27b5a7a648ddd02e0d7f2ed8b515f932 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 09:46:04 +0000 Subject: [PATCH 187/312] update --- .../client/smithy/generators/client/FluentClientGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 3cb8b9669d1..9af590d0487 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -334,7 +334,7 @@ class FluentClientGenerator( "SdkError" to RuntimeType.sdkError(runtimeConfig), ) - + val input = operation.inputShape(model) val baseDerives = symbolProvider.toSymbol(input).expectRustMetadata().derives // Filter out any derive that isn't Clone. Then add a Debug derive From 663dff3a6a8228232d5a80ab140d4a68706c818d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 09:47:53 +0000 Subject: [PATCH 188/312] update --- .../smithy/generators/client/FluentClientGenerator.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 9af590d0487..a18a07c2ea1 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -35,7 +35,6 @@ import software.amazon.smithy.rust.codegen.core.rustlang.normalizeHtml import software.amazon.smithy.rust.codegen.core.rustlang.qualifiedName import software.amazon.smithy.rust.codegen.core.rustlang.render import software.amazon.smithy.rust.codegen.core.rustlang.rust -import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock import software.amazon.smithy.rust.codegen.core.rustlang.rustBlockTemplate import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.rustTypeParameters @@ -334,7 +333,6 @@ class FluentClientGenerator( "SdkError" to RuntimeType.sdkError(runtimeConfig), ) - val input = operation.inputShape(model) val baseDerives = symbolProvider.toSymbol(input).expectRustMetadata().derives // Filter out any derive that isn't Clone. Then add a Debug derive @@ -343,7 +341,7 @@ class FluentClientGenerator( val fnName = clientOperationFnName(operation, symbolProvider) implBlock(symbolProvider.symbolForBuilder(input)) { rustTemplate( - """ + """ /// Creates a fluent builder from this builder. pub fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> #{send_bounds:W} { @@ -352,14 +350,13 @@ class FluentClientGenerator( fluent_builder } """, - *orchestratorScope + *orchestratorScope, ) } val derives = baseDerives.filter { it == RuntimeType.Clone } + RuntimeType.Debug docs("Fluent builder constructing a request to `${operationSymbol.name}`.\n") - val builderName = operation.fluentBuilderType(symbolProvider).name documentShape(operation, model, autoSuppressMissingDocs = false) deprecatedShape(operation) From 8b38afce204ac091381c23a0d3a5175cbf502816 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 09:50:27 +0000 Subject: [PATCH 189/312] update --- .../client/smithy/generators/client/FluentClientGenerator.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index a18a07c2ea1..3e5fd3c6b18 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -337,17 +337,16 @@ class FluentClientGenerator( val baseDerives = symbolProvider.toSymbol(input).expectRustMetadata().derives // Filter out any derive that isn't Clone. Then add a Debug derive // input name - val fluentBuilderName = operation.fluentBuilderType(symbolProvider).name val fnName = clientOperationFnName(operation, symbolProvider) implBlock(symbolProvider.symbolForBuilder(input)) { rustTemplate( """ /// Creates a fluent builder from this builder. - pub fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> + async pub fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> #{send_bounds:W} { let mut fluent_builder = client.$fnName(); fluent_builder.inner = self; - fluent_builder + fluent_builder.send().await } """, *orchestratorScope, From 525f5723e131ebdd4e6fb149a81041f95193d5f1 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 10:47:43 +0000 Subject: [PATCH 190/312] update --- .../client/FluentClientGenerator.kt | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 3e5fd3c6b18..63e3ddc0383 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -319,19 +319,6 @@ class FluentClientGenerator( val outputType = symbolProvider.toSymbol(operation.outputShape(model)) val errorType = symbolProvider.symbolForOperationError(operation) val operationSymbol = symbolProvider.toSymbol(operation) - val orchestratorScope = arrayOf( - *preludeScope, - "CustomizableOperation" to ClientRustModule.Client.customize.toType() - .resolve("orchestrator::CustomizableOperation"), - "HttpResponse" to RuntimeType.smithyRuntimeApi(runtimeConfig) - .resolve("client::orchestrator::HttpResponse"), - "Operation" to operationSymbol, - "OperationError" to errorType, - "OperationOutput" to outputType, - "SendResult" to ClientRustModule.Client.customize.toType() - .resolve("internal::SendResult"), - "SdkError" to RuntimeType.sdkError(runtimeConfig), - ) val input = operation.inputShape(model) val baseDerives = symbolProvider.toSymbol(input).expectRustMetadata().derives @@ -341,15 +328,21 @@ class FluentClientGenerator( implBlock(symbolProvider.symbolForBuilder(input)) { rustTemplate( """ - /// Creates a fluent builder from this builder. - async pub fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> - #{send_bounds:W} { - let mut fluent_builder = client.$fnName(); - fluent_builder.inner = self; - fluent_builder.send().await - } - """, - *orchestratorScope, + /// Creates a fluent builder from this builder. + async pub fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> + #{send_bounds:W} { + let mut fluent_builder = client.$fnName(); + fluent_builder.inner = self; + fluent_builder.send().await + } + """, + *preludeScope, + "Operation" to operationSymbol, + "OperationError" to errorType, + "OperationOutput" to outputType, + "SdkError" to RuntimeType.sdkError(runtimeConfig), + "SdkSuccess" to RuntimeType.sdkSuccess(runtimeConfig), + "send_bounds" to generics.sendBounds(operationSymbol, outputType, errorType, retryClassifier), ) } @@ -480,6 +473,19 @@ class FluentClientGenerator( } if (smithyRuntimeMode.generateOrchestrator) { + val orchestratorScope = arrayOf( + *preludeScope, + "CustomizableOperation" to ClientRustModule.Client.customize.toType() + .resolve("orchestrator::CustomizableOperation"), + "HttpResponse" to RuntimeType.smithyRuntimeApi(runtimeConfig) + .resolve("client::orchestrator::HttpResponse"), + "Operation" to operationSymbol, + "OperationError" to errorType, + "OperationOutput" to outputType, + "SendResult" to ClientRustModule.Client.customize.toType() + .resolve("internal::SendResult"), + "SdkError" to RuntimeType.sdkError(runtimeConfig), + ) rustTemplate( """ ##[doc(hidden)] From e3367dd314149724beba290fab064bf303b2178c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 11:05:56 +0000 Subject: [PATCH 191/312] update --- .../client/smithy/generators/client/FluentClientGenerator.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 63e3ddc0383..6542758c42f 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -325,11 +325,11 @@ class FluentClientGenerator( // Filter out any derive that isn't Clone. Then add a Debug derive // input name val fnName = clientOperationFnName(operation, symbolProvider) - implBlock(symbolProvider.symbolForBuilder(input)) { + implBlock(input) { rustTemplate( """ /// Creates a fluent builder from this builder. - async pub fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> + pub async fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> #{send_bounds:W} { let mut fluent_builder = client.$fnName(); fluent_builder.inner = self; From f5f1f4ebed530a8dbef93016f23f5ca2e30ac992 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 11:13:16 +0000 Subject: [PATCH 192/312] FIX --- rust-runtime/aws-smithy-types/Cargo.toml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 5655e39112d..60af72da0f0 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -9,6 +9,8 @@ repository = "https://github.com/awslabs/smithy-rs" [features] test-util = [] +serde-serialize = [] +serde-deserialize = [] [dependencies] itoa = "1.0.0" @@ -40,7 +42,3 @@ harness = false [target."cfg(aws_sdk_unstable)".dependencies.serde] version = "1" features = ["derive"] - -[features] -serde-serialize = [] -serde-deserialize = [] From ec9432a0690296d5a1358a519579cb54f2a3e3a1 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 11:18:44 +0000 Subject: [PATCH 193/312] update --- rust-runtime/aws-smithy-types/src/date_time/de.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index 6d2e378a0af..c1fd9f60749 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -142,4 +142,4 @@ fn de_not_human_readable_datetime() { } ); }; -} \ No newline at end of file +} From dc21f199fef5f5c85708ef97ebd504443dc683ff Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 11:34:58 +0000 Subject: [PATCH 194/312] update --- .../client/smithy/generators/client/FluentClientGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 6542758c42f..68284c0e05f 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -325,7 +325,7 @@ class FluentClientGenerator( // Filter out any derive that isn't Clone. Then add a Debug derive // input name val fnName = clientOperationFnName(operation, symbolProvider) - implBlock(input) { + implBlock(symbolProvider.toSymbol(operation.inputShape(model))) { rustTemplate( """ /// Creates a fluent builder from this builder. From 5972800f0f12d5bd5fd6c20c2c437a2b4919a0e1 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 11:53:41 +0000 Subject: [PATCH 195/312] update --- .../client/smithy/generators/client/FluentClientGenerator.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 68284c0e05f..8ef3e99f4fa 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -329,7 +329,7 @@ class FluentClientGenerator( rustTemplate( """ /// Creates a fluent builder from this builder. - pub async fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> + pub async fn send_with<#{generics_decl:W}>(self, client: &crate::Client>) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> #{send_bounds:W} { let mut fluent_builder = client.$fnName(); fluent_builder.inner = self; @@ -337,6 +337,7 @@ class FluentClientGenerator( } """, *preludeScope, + "generics_decl" to generics.decl, "Operation" to operationSymbol, "OperationError" to errorType, "OperationOutput" to outputType, From e850ea29a600ff8144a294892afdef0a51ffcc47 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 12:22:03 +0000 Subject: [PATCH 196/312] update --- .../client/smithy/generators/client/FluentClientGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 8ef3e99f4fa..0f0ddc6fe90 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -329,7 +329,7 @@ class FluentClientGenerator( rustTemplate( """ /// Creates a fluent builder from this builder. - pub async fn send_with<#{generics_decl:W}>(self, client: &crate::Client>) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> + pub async fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> #{send_bounds:W} { let mut fluent_builder = client.$fnName(); fluent_builder.inner = self; From 8b2877e52e050d204f2181fee187809473f134da Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 14:03:32 +0000 Subject: [PATCH 197/312] update --- .../client/FluentClientGenerator.kt | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 0f0ddc6fe90..cd18ac55d7f 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -325,27 +325,28 @@ class FluentClientGenerator( // Filter out any derive that isn't Clone. Then add a Debug derive // input name val fnName = clientOperationFnName(operation, symbolProvider) - implBlock(symbolProvider.toSymbol(operation.inputShape(model))) { - rustTemplate( - """ - /// Creates a fluent builder from this builder. - pub async fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> - #{send_bounds:W} { - let mut fluent_builder = client.$fnName(); - fluent_builder.inner = self; - fluent_builder.send().await - } - """, - *preludeScope, - "generics_decl" to generics.decl, - "Operation" to operationSymbol, - "OperationError" to errorType, - "OperationOutput" to outputType, - "SdkError" to RuntimeType.sdkError(runtimeConfig), - "SdkSuccess" to RuntimeType.sdkSuccess(runtimeConfig), - "send_bounds" to generics.sendBounds(operationSymbol, outputType, errorType, retryClassifier), - ) - } + rustTemplate( + """ + impl #{InputPath} { + /// Creates a fluent builder from this builder. + pub async fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> + #{send_bounds:W} { + let mut fluent_builder = client.$fnName(); + fluent_builder.inner = self; + fluent_builder.send().await + } + } + """, + *preludeScope, + "InputPath" to symbolProvider.toSymbol(input), + "generics_decl" to generics.decl, + "Operation" to operationSymbol, + "OperationError" to errorType, + "OperationOutput" to outputType, + "SdkError" to RuntimeType.sdkError(runtimeConfig), + "SdkSuccess" to RuntimeType.sdkSuccess(runtimeConfig), + "send_bounds" to generics.sendBounds(operationSymbol, outputType, errorType, retryClassifier), + ) val derives = baseDerives.filter { it == RuntimeType.Clone } + RuntimeType.Debug docs("Fluent builder constructing a request to `${operationSymbol.name}`.\n") From 4be97c30a538a06999f955a22551cd085837ba19 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 14:10:31 +0000 Subject: [PATCH 198/312] update --- rust-runtime/aws-smithy-types/src/date_time/de.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index c1fd9f60749..254c3f15cfb 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -39,23 +39,13 @@ impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { A: serde::de::SeqAccess<'de>, { match seq.size_hint() { - Some(2) => match (seq.next_element()?, seq.next_element()?) { + Some(2) | None => match (seq.next_element()?, seq.next_element()?) { (Some(seconds), Some(subsecond_nanos)) => Ok(DateTime { seconds, subsecond_nanos, }), _ => return Err(Error::custom("datatype mismatch")), }, - None => { - let res = match (seq.next_element()?, seq.next_element()?) { - (Some(seconds), Some(subsecond_nanos)) => Ok(DateTime { - seconds, - subsecond_nanos, - }), - _ => return Err(Error::custom("datatype mismatch")), - }; - return res; - } _ => Err(Error::custom("Size mismatch")), } } From ca47afee236f7a6c4ba8d1d75f690f73c34fd4a5 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 14:50:02 +0000 Subject: [PATCH 199/312] change input path --- .../client/smithy/generators/client/FluentClientGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index cd18ac55d7f..e1f7148a9eb 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -338,7 +338,7 @@ class FluentClientGenerator( } """, *preludeScope, - "InputPath" to symbolProvider.toSymbol(input), + "InputPath" to symbolProvider.toSymbol(input).toBuilder(), "generics_decl" to generics.decl, "Operation" to operationSymbol, "OperationError" to errorType, From 3bd1a7b09e3ac0cfc1c3329f2bb6559de17f68cb Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 15:05:45 +0000 Subject: [PATCH 200/312] update --- .../client/smithy/generators/client/FluentClientGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index e1f7148a9eb..9481523f36a 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -338,7 +338,7 @@ class FluentClientGenerator( } """, *preludeScope, - "InputPath" to symbolProvider.toSymbol(input).toBuilder(), + "InputPath" to symbolProvider.symbolForBuilder(input), "generics_decl" to generics.decl, "Operation" to operationSymbol, "OperationError" to errorType, From a0a4651907c82ea3e79daa1e066761b4542aab7d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 2 Jun 2023 15:25:44 +0000 Subject: [PATCH 201/312] update --- .../client/FluentClientGenerator.kt | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 9481523f36a..199718c0670 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -325,9 +325,9 @@ class FluentClientGenerator( // Filter out any derive that isn't Clone. Then add a Debug derive // input name val fnName = clientOperationFnName(operation, symbolProvider) - rustTemplate( - """ - impl #{InputPath} { + implBlock(symbolProvider.symbolForBuilder(input)) { + rustTemplate( + """ /// Creates a fluent builder from this builder. pub async fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> #{send_bounds:W} { @@ -335,18 +335,17 @@ class FluentClientGenerator( fluent_builder.inner = self; fluent_builder.send().await } - } """, - *preludeScope, - "InputPath" to symbolProvider.symbolForBuilder(input), - "generics_decl" to generics.decl, - "Operation" to operationSymbol, - "OperationError" to errorType, - "OperationOutput" to outputType, - "SdkError" to RuntimeType.sdkError(runtimeConfig), - "SdkSuccess" to RuntimeType.sdkSuccess(runtimeConfig), - "send_bounds" to generics.sendBounds(operationSymbol, outputType, errorType, retryClassifier), - ) + *preludeScope, + "generics_decl" to generics.decl, + "Operation" to operationSymbol, + "OperationError" to errorType, + "OperationOutput" to outputType, + "SdkError" to RuntimeType.sdkError(runtimeConfig), + "SdkSuccess" to RuntimeType.sdkSuccess(runtimeConfig), + "send_bounds" to generics.sendBounds(operationSymbol, outputType, errorType, retryClassifier), + ) + } val derives = baseDerives.filter { it == RuntimeType.Clone } + RuntimeType.Debug docs("Fluent builder constructing a request to `${operationSymbol.name}`.\n") From 299e5ece68b99b78e92ea7bd1d94038a2986da1c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 3 Jun 2023 06:21:36 +0000 Subject: [PATCH 202/312] FIX --- .../generators/client/FluentClientGenerator.kt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 199718c0670..b50a423cb08 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -325,18 +325,24 @@ class FluentClientGenerator( // Filter out any derive that isn't Clone. Then add a Debug derive // input name val fnName = clientOperationFnName(operation, symbolProvider) + implBlock(symbolProvider.symbolForBuilder(input)) { rustTemplate( """ - /// Creates a fluent builder from this builder. - pub async fn send_with(self, client: &crate::Client) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> - #{send_bounds:W} { + /// Sends a request with this input using the given client. + pub async fn send_with<#{generics_decl:W}>(self, client: &crate::Client<#{generics_decl}>) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> + #{send_bounds:W} { let mut fluent_builder = client.$fnName(); fluent_builder.inner = self; fluent_builder.send().await - } - """, + } + """, *preludeScope, + "RawResponseType" to if (codegenContext.smithyRuntimeMode.defaultToMiddleware) { + RuntimeType.smithyHttp(runtimeConfig).resolve("operation::Response") + } else { + RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::orchestrator::HttpResponse") + }, "generics_decl" to generics.decl, "Operation" to operationSymbol, "OperationError" to errorType, From 605689edc25c603a22c7fcc659bc70f1b9af73a0 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 3 Jun 2023 09:08:23 +0000 Subject: [PATCH 203/312] updater --- .../client/smithy/generators/client/FluentClientGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index b50a423cb08..39147ffa14f 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -330,7 +330,7 @@ class FluentClientGenerator( rustTemplate( """ /// Sends a request with this input using the given client. - pub async fn send_with<#{generics_decl:W}>(self, client: &crate::Client<#{generics_decl}>) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> + pub async fn send_with<#{generics_decl:W}>(self, client: &crate::Client#{generics_decl:W}) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> #{send_bounds:W} { let mut fluent_builder = client.$fnName(); fluent_builder.inner = self; From 857f3d462a78d0497247c76049b01d53e70d3a42 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 3 Jun 2023 09:31:23 +0000 Subject: [PATCH 204/312] FIX --- .../client/smithy/generators/client/FluentClientGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index d670ca6c889..cbc49966184 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -330,7 +330,7 @@ class FluentClientGenerator( rustTemplate( """ /// Sends a request with this input using the given client. - pub async fn send_with<#{generics_decl:W}>(self, client: &crate::Client#{generics_decl:W}) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> + pub async fn send_with#{generics_decl:W}(self, client: &crate::Client#{generics_decl:W}) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> #{send_bounds:W} { let mut fluent_builder = client.$fnName(); fluent_builder.inner = self; From 7bd13651cbdd394de4097c54c9446ff79a1494c0 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 3 Jun 2023 09:46:35 +0000 Subject: [PATCH 205/312] asdf --- .../client/smithy/generators/client/FluentClientGenerator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index cbc49966184..fc8ab055678 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -343,7 +343,7 @@ class FluentClientGenerator( } else { RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::orchestrator::HttpResponse") }, - "generics_decl" to generics.decl, + "generics_decl" to generics.smithyInst, "Operation" to operationSymbol, "OperationError" to errorType, "OperationOutput" to outputType, From e5cd52fea2f224108e0f212d342c108c886f9501 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 3 Jun 2023 13:31:55 +0000 Subject: [PATCH 206/312] update --- .../client/smithy/generators/client/FluentClientGenerator.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index fc8ab055678..fd694d8e673 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -325,12 +325,11 @@ class FluentClientGenerator( // Filter out any derive that isn't Clone. Then add a Debug derive // input name val fnName = clientOperationFnName(operation, symbolProvider) - implBlock(symbolProvider.symbolForBuilder(input)) { rustTemplate( """ /// Sends a request with this input using the given client. - pub async fn send_with#{generics_decl:W}(self, client: &crate::Client#{generics_decl:W}) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}>> + pub async fn send_with${generics.inst}(self, client: &crate::Client${generics.inst}) -> #{Result}<#{OperationOutput}, #{SdkError}<#{OperationError}, #{RawResponseType}>> #{send_bounds:W} { let mut fluent_builder = client.$fnName(); fluent_builder.inner = self; @@ -343,7 +342,6 @@ class FluentClientGenerator( } else { RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::orchestrator::HttpResponse") }, - "generics_decl" to generics.smithyInst, "Operation" to operationSymbol, "OperationError" to errorType, "OperationOutput" to outputType, From 929ff0d70ec66ac877b8b46eafdbc8072bdbfc06 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Mon, 5 Jun 2023 17:48:06 +0000 Subject: [PATCH 207/312] update --- .../aws-smithy-types/src/date_time/de.rs | 137 ++++++++++-------- .../aws-smithy-types/src/date_time/ser.rs | 102 ++++++------- 2 files changed, 127 insertions(+), 112 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index 254c3f15cfb..3dad4fb231b 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -31,7 +31,16 @@ impl<'de> Visitor<'de> for DateTimeVisitor { impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { type Value = DateTime; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("Datat must be number") + formatter.write_str( + r#"DateTime type expects a tuple of i64 and u32 when deserializing from non human readable format. + ```rust + // Example + NonHumanReadable::Value::TupleWith2Values(( + NonHumanReadable::Value::Int64(2354235i64), + NonHumanReadable::Value::UInt32(1000u32), + )); + ```"# + ); } fn visit_seq(self, mut seq: A) -> Result @@ -64,72 +73,74 @@ impl<'de> Deserialize<'de> for DateTime { } } -/// check for human redable format #[test] -fn de_human_readable_datetime() { - use serde::{Deserialize, Serialize}; +mod test { + + /// check for human redable format + fn de_human_readable_datetime() { + use serde::{Deserialize, Serialize}; - let datetime = DateTime::from_secs(1576540098); - #[derive(Serialize, Deserialize, PartialEq)] - struct Test { - datetime: DateTime, + let datetime = DateTime::from_secs(1576540098); + #[derive(Serialize, Deserialize, PartialEq)] + struct Test { + datetime: DateTime, + } + let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; + let test = serde_json::from_str::(&datetime_json).ok(); + assert!(test == Some(Test { datetime })); } - let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; - let test = serde_json::from_str::(&datetime_json).ok(); - assert!(test == Some(Test { datetime })); -} -/// check for non-human redable format -#[test] -fn de_not_human_readable_datetime() { - { - let cbor = ciborium::value::Value::Array(vec![ - ciborium::value::Value::Integer(1576540098i64.into()), - ciborium::value::Value::Integer(0u32.into()), - ]); - let mut buf = vec![]; - let _ = ciborium::ser::into_writer(&cbor, &mut buf); - let cbor_dt: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); - assert_eq!( - cbor_dt, - DateTime { - seconds: 1576540098i64, - subsecond_nanos: 0 - } - ); - }; + /// check for non-human redable format + fn de_not_human_readable_datetime() { + { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(1576540098i64.into()), + ciborium::value::Value::Integer(0u32.into()), + ]); + let mut buf = vec![]; + let _ = ciborium::ser::into_writer(&cbor, &mut buf); + let cbor_dt: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); + assert_eq!( + cbor_dt, + DateTime { + seconds: 1576540098i64, + subsecond_nanos: 0 + } + ); + }; - { - let cbor = ciborium::value::Value::Array(vec![ - ciborium::value::Value::Integer(0i64.into()), - ciborium::value::Value::Integer(0u32.into()), - ]); - let mut buf = vec![]; - let _ = ciborium::ser::into_writer(&cbor, &mut buf); - let cbor_dt: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); - assert_eq!( - cbor_dt, - DateTime { - seconds: 0, - subsecond_nanos: 0 - } - ); - }; + { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(0i64.into()), + ciborium::value::Value::Integer(0u32.into()), + ]); + let mut buf = vec![]; + let _ = ciborium::ser::into_writer(&cbor, &mut buf); + let cbor_dt: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); + assert_eq!( + cbor_dt, + DateTime { + seconds: 0, + subsecond_nanos: 0 + } + ); + }; - { - let cbor = ciborium::value::Value::Array(vec![ - ciborium::value::Value::Integer(i64::MAX.into()), - ciborium::value::Value::Integer(u32::MAX.into()), - ]); - let mut buf = vec![]; - let _ = ciborium::ser::into_writer(&cbor, &mut buf); - let cbor_dt: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); - assert_eq!( - cbor_dt, - DateTime { - seconds: i64::MAX, - subsecond_nanos: u32::MAX - } - ); - }; + { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(i64::MAX.into()), + ciborium::value::Value::Integer(u32::MAX.into()), + ]); + let mut buf = vec![]; + let _ = ciborium::ser::into_writer(&cbor, &mut buf); + let cbor_dt: DateTime = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); + assert_eq!( + cbor_dt, + DateTime { + seconds: i64::MAX, + subsecond_nanos: u32::MAX + } + ); + }; + } } diff --git a/rust-runtime/aws-smithy-types/src/date_time/ser.rs b/rust-runtime/aws-smithy-types/src/date_time/ser.rs index 9d8f80c7bd3..fa16530a750 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/ser.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/ser.rs @@ -25,56 +25,60 @@ impl serde::Serialize for DateTime { } } -/// check for human redable format #[test] -fn ser_human_readable_datetime() { - use serde::{Deserialize, Serialize}; - - let datetime = DateTime::from_secs(1576540098); - #[derive(Serialize, Deserialize, PartialEq)] - struct Test { - datetime: DateTime, +mod test { + + /// check for human redable format + fn ser_human_readable_datetime() { + use serde::{Deserialize, Serialize}; + + let datetime = DateTime::from_secs(1576540098); + #[derive(Serialize, Deserialize, PartialEq)] + struct Test { + datetime: DateTime, + } + let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; + assert!(serde_json::to_string(&Test { datetime }).ok() == Some(datetime_json.to_string())); + } + + /// check for non-human redable format + fn ser_not_human_readable_datetime() { + { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(1576540098i64.into()), + ciborium::value::Value::Integer(0u32.into()), + ]); + let mut buf = vec![]; + let mut buf2 = vec![]; + let _ = ciborium::ser::into_writer(&cbor, &mut buf); + let _ = ciborium::ser::into_writer(&cbor, &mut buf2); + assert_eq!(buf, buf2); + }; + + { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(0i64.into()), + ciborium::value::Value::Integer(0u32.into()), + ]); + let mut buf = vec![]; + let mut buf2 = vec![]; + let _ = ciborium::ser::into_writer(&cbor, &mut buf); + let _ = ciborium::ser::into_writer(&cbor, &mut buf2); + assert_eq!(buf, buf2); + }; + + { + let cbor = ciborium::value::Value::Array(vec![ + ciborium::value::Value::Integer(i64::MAX.into()), + ciborium::value::Value::Integer(u32::MAX.into()), + ]); + let mut buf = vec![]; + let mut buf2 = vec![]; + let _ = ciborium::ser::into_writer(&cbor, &mut buf); + let _ = ciborium::ser::into_writer(&cbor, &mut buf2); + assert_eq!(buf, buf2); + }; } - let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; - assert!(serde_json::to_string(&Test { datetime }).ok() == Some(datetime_json.to_string())); + } -/// check for non-human redable format -#[test] -fn ser_not_human_readable_datetime() { - { - let cbor = ciborium::value::Value::Array(vec![ - ciborium::value::Value::Integer(1576540098i64.into()), - ciborium::value::Value::Integer(0u32.into()), - ]); - let mut buf = vec![]; - let mut buf2 = vec![]; - let _ = ciborium::ser::into_writer(&cbor, &mut buf); - let _ = ciborium::ser::into_writer(&cbor, &mut buf2); - assert_eq!(buf, buf2); - }; - - { - let cbor = ciborium::value::Value::Array(vec![ - ciborium::value::Value::Integer(0i64.into()), - ciborium::value::Value::Integer(0u32.into()), - ]); - let mut buf = vec![]; - let mut buf2 = vec![]; - let _ = ciborium::ser::into_writer(&cbor, &mut buf); - let _ = ciborium::ser::into_writer(&cbor, &mut buf2); - assert_eq!(buf, buf2); - }; - - { - let cbor = ciborium::value::Value::Array(vec![ - ciborium::value::Value::Integer(i64::MAX.into()), - ciborium::value::Value::Integer(u32::MAX.into()), - ]); - let mut buf = vec![]; - let mut buf2 = vec![]; - let _ = ciborium::ser::into_writer(&cbor, &mut buf); - let _ = ciborium::ser::into_writer(&cbor, &mut buf2); - assert_eq!(buf, buf2); - }; -} From e1c1b40c91e3c05beab75497c1fb94f3dc86048a Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Mon, 5 Jun 2023 17:49:54 +0000 Subject: [PATCH 208/312] fix --- rust-runtime/aws-smithy-types/src/date_time/de.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index 3dad4fb231b..6a7a089ecdf 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -40,7 +40,7 @@ impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { NonHumanReadable::Value::UInt32(1000u32), )); ```"# - ); + ) } fn visit_seq(self, mut seq: A) -> Result From 2eb7c420758fa84095e5ec728c65c031d4058a18 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Mon, 5 Jun 2023 17:56:26 +0000 Subject: [PATCH 209/312] update --- .../aws-smithy-types/src/date_time/de.rs | 16 +++++----------- .../aws-smithy-types/src/date_time/ser.rs | 7 +++++-- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/de.rs b/rust-runtime/aws-smithy-types/src/date_time/de.rs index 6a7a089ecdf..c87a32e0f59 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/de.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/de.rs @@ -31,16 +31,7 @@ impl<'de> Visitor<'de> for DateTimeVisitor { impl<'de> Visitor<'de> for NonHumanReadableDateTimeVisitor { type Value = DateTime; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str( - r#"DateTime type expects a tuple of i64 and u32 when deserializing from non human readable format. - ```rust - // Example - NonHumanReadable::Value::TupleWith2Values(( - NonHumanReadable::Value::Int64(2354235i64), - NonHumanReadable::Value::UInt32(1000u32), - )); - ```"# - ) + formatter.write_str("DateTime type expects a tuple of i64 and u32 when deserializing from non human readable format like CBOR or AVRO, i.e. (i64, u32)") } fn visit_seq(self, mut seq: A) -> Result @@ -73,10 +64,12 @@ impl<'de> Deserialize<'de> for DateTime { } } -#[test] +#[cfg(test)] mod test { + use super::*; /// check for human redable format + #[test] fn de_human_readable_datetime() { use serde::{Deserialize, Serialize}; @@ -91,6 +84,7 @@ mod test { } /// check for non-human redable format + #[test] fn de_not_human_readable_datetime() { { let cbor = ciborium::value::Value::Array(vec![ diff --git a/rust-runtime/aws-smithy-types/src/date_time/ser.rs b/rust-runtime/aws-smithy-types/src/date_time/ser.rs index fa16530a750..1b138b35b40 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/ser.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/ser.rs @@ -25,10 +25,12 @@ impl serde::Serialize for DateTime { } } -#[test] +#[cfg(test)] mod test { - + use super::*; + /// check for human redable format + #[test] fn ser_human_readable_datetime() { use serde::{Deserialize, Serialize}; @@ -42,6 +44,7 @@ mod test { } /// check for non-human redable format + #[test] fn ser_not_human_readable_datetime() { { let cbor = ciborium::value::Value::Array(vec![ From 5639356726406bc70bf56d9f91f06cab32eddc1e Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Mon, 5 Jun 2023 18:06:16 +0000 Subject: [PATCH 210/312] precommit --- rust-runtime/aws-smithy-types/src/date_time/ser.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/ser.rs b/rust-runtime/aws-smithy-types/src/date_time/ser.rs index 1b138b35b40..35fcf0770af 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/ser.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/ser.rs @@ -33,7 +33,7 @@ mod test { #[test] fn ser_human_readable_datetime() { use serde::{Deserialize, Serialize}; - + let datetime = DateTime::from_secs(1576540098); #[derive(Serialize, Deserialize, PartialEq)] struct Test { @@ -42,7 +42,7 @@ mod test { let datetime_json = r#"{"datetime":"2019-12-16T23:48:18Z"}"#; assert!(serde_json::to_string(&Test { datetime }).ok() == Some(datetime_json.to_string())); } - + /// check for non-human redable format #[test] fn ser_not_human_readable_datetime() { @@ -57,7 +57,7 @@ mod test { let _ = ciborium::ser::into_writer(&cbor, &mut buf2); assert_eq!(buf, buf2); }; - + { let cbor = ciborium::value::Value::Array(vec![ ciborium::value::Value::Integer(0i64.into()), @@ -69,7 +69,7 @@ mod test { let _ = ciborium::ser::into_writer(&cbor, &mut buf2); assert_eq!(buf, buf2); }; - + { let cbor = ciborium::value::Value::Array(vec![ ciborium::value::Value::Integer(i64::MAX.into()), @@ -82,6 +82,5 @@ mod test { assert_eq!(buf, buf2); }; } - -} +} From b97a85c841fad4a08ffbfa66c5c75dc33276f3cf Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Mon, 5 Jun 2023 18:14:09 +0000 Subject: [PATCH 211/312] update --- rust-runtime/aws-smithy-types/src/date_time/ser.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/date_time/ser.rs b/rust-runtime/aws-smithy-types/src/date_time/ser.rs index 35fcf0770af..5ea5f55dcd7 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/ser.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/ser.rs @@ -82,5 +82,4 @@ mod test { assert_eq!(buf, buf2); }; } - } From 34eaadbd9d321c4571eb004d4e9ecd42cae84aa3 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Mon, 5 Jun 2023 18:37:10 +0000 Subject: [PATCH 212/312] update --- tools/ci-scripts/compiletime-benchmark | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tools/ci-scripts/compiletime-benchmark diff --git a/tools/ci-scripts/compiletime-benchmark b/tools/ci-scripts/compiletime-benchmark old mode 100644 new mode 100755 From 09672b09a9525397067557bd32ebd08de4f4f394 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Mon, 5 Jun 2023 18:54:06 +0000 Subject: [PATCH 213/312] update --- tools/ci-scripts/compiletime-benchmark | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/ci-scripts/compiletime-benchmark b/tools/ci-scripts/compiletime-benchmark index 50f99ccdff3..6a41f7398b9 100755 --- a/tools/ci-scripts/compiletime-benchmark +++ b/tools/ci-scripts/compiletime-benchmark @@ -17,6 +17,8 @@ function compile() { time cargo build --all-features --release &> /dev/null && cargo clean } +cd smithy-rs + ./gradlew :aws:sdk:assemble DIR=$PWD for variable in $(dir "aws/sdk/build/aws-sdk/sdk"); do From 9570c533a07b36edfe57803d46c3d89e8766ed9d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Mon, 5 Jun 2023 19:41:25 +0000 Subject: [PATCH 214/312] pre-commit --- .../client/smithy/generators/client/FluentClientGenerator.kt | 1 - .../rust/codegen/core/smithy/generators/StructureGenerator.kt | 1 - rust-runtime/aws-smithy-types/Cargo.toml | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 6531b986b4b..fd694d8e673 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -400,7 +400,6 @@ class FluentClientGenerator( } } - if (smithyRuntimeMode.generateMiddleware) { val middlewareScope = arrayOf( *preludeScope, diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt index f4a2565b3af..a8d0b82467b 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt @@ -32,7 +32,6 @@ import software.amazon.smithy.rust.codegen.core.smithy.renamedFrom import software.amazon.smithy.rust.codegen.core.smithy.rustType import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.getTrait -import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.redactIfNecessary /** StructureGenerator customization sections */ diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 905d0f22ff1..6942b97c25a 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -44,4 +44,4 @@ rustdoc-args = ["--cfg", "docsrs"] [[bench]] name = "base64" -harness = false \ No newline at end of file +harness = false From 5f0ad1bedc87eef15c558c8d5cee3ea384c2d4a0 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Mon, 5 Jun 2023 19:41:50 +0000 Subject: [PATCH 215/312] fix --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf474afb0d4..1953018a729 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -305,12 +305,12 @@ jobs: runs-on: ${{ matrix.test.runner }} steps: - - uses: actions/checkout@v3 - with: - path: smithy-rs - ref: ${{ inputs.git_ref }} - - name: compiletime-benchmark - run: bash tools/ci-scripts/compiletime-benchmark + - uses: actions/checkout@v3 + with: + path: smithy-rs + ref: ${{ inputs.git_ref }} + - name: compiletime-benchmark + run: bash tools/ci-scripts/compiletime-benchmark # This job is split out from the rest since it is not required to pass for merge check-sdk-examples: From 1fb69100f62ce66aa25576dec210c167b5bdaa35 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Mon, 5 Jun 2023 19:49:53 +0000 Subject: [PATCH 216/312] update --- rust-runtime/aws-smithy-types/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index 905d0f22ff1..6942b97c25a 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -44,4 +44,4 @@ rustdoc-args = ["--cfg", "docsrs"] [[bench]] name = "base64" -harness = false \ No newline at end of file +harness = false From 76fe11df056ed3faab5e36017a3489ef9419a4e9 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Mon, 5 Jun 2023 19:56:57 +0000 Subject: [PATCH 217/312] fix --- rust-runtime/aws-smithy-types/src/document.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/document.rs b/rust-runtime/aws-smithy-types/src/document.rs index d182bed0f7b..2dafd0325dc 100644 --- a/rust-runtime/aws-smithy-types/src/document.rs +++ b/rust-runtime/aws-smithy-types/src/document.rs @@ -9,7 +9,7 @@ use crate::Number; all(aws_sdk_unstable, feature = "serde-serialize") ))] use serde; -use std::collections::HashMap; +use std::{collections::HashMap, borrow::Cow}; /* ANCHOR: document */ /// Document Type From 2efda16efe474d0a7f5db705be1e58869deca9cb Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 6 Jun 2023 03:07:34 +0000 Subject: [PATCH 218/312] update --- rust-runtime/aws-smithy-types/src/document.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-runtime/aws-smithy-types/src/document.rs b/rust-runtime/aws-smithy-types/src/document.rs index 2dafd0325dc..75612960529 100644 --- a/rust-runtime/aws-smithy-types/src/document.rs +++ b/rust-runtime/aws-smithy-types/src/document.rs @@ -9,7 +9,7 @@ use crate::Number; all(aws_sdk_unstable, feature = "serde-serialize") ))] use serde; -use std::{collections::HashMap, borrow::Cow}; +use std::{borrow::Cow, collections::HashMap}; /* ANCHOR: document */ /// Document Type From b15f93acb0dfe2912d49eb39e9dae5e288deca66 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 14 Jun 2023 17:36:32 +0000 Subject: [PATCH 219/312] fix --- rust-runtime/aws-smithy-types/src/blob.rs | 138 ------------------ rust-runtime/aws-smithy-types/src/document.rs | 87 ++--------- 2 files changed, 12 insertions(+), 213 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 0dca4625bc0..bdd335c4923 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -3,18 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 */ -#[cfg(aws_sdk_unstable)] -use impl_serde::*; -#[cfg(aws_sdk_unstable)] -mod impl_serde { - #[cfg(any(feature = "serde-deserialize", feature = "serde-serialize"))] - pub(crate) use crate::base64; - #[cfg(feature = "serde-serialize")] - pub(crate) use serde::Serialize; - #[cfg(feature = "serde-deserialize")] - pub(crate) use serde::{de::Visitor, Deserialize}; -} - /// Binary Blob Type /// /// Blobs represent protocol-agnostic binary content. @@ -42,129 +30,3 @@ impl AsRef<[u8]> for Blob { &self.inner } } - -#[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] -mod serde_serialize { - use super::*; - use crate::base64; - use serde::Serialize; - - impl Serialize for Blob { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - if serializer.is_human_readable() { - serializer.serialize_str(&crate::base64::encode(&self.inner)) - } else { - serializer.serialize_bytes(&self.inner) - } - } - } -} - -#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] -mod serde_deserialize { - use super::*; - use crate::base64; - use serde::{de::Visitor, Deserialize}; - - struct HumanReadableBlobVisitor; - impl<'de> Visitor<'de> for HumanReadableBlobVisitor { - type Value = Blob; - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("expected base64 encoded string") - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - match base64::decode(v) { - Ok(inner) => Ok(Blob { inner }), - Err(e) => Err(E::custom(e)), - } - } - } - - struct NotHumanReadableBlobVisitor; - impl<'de> Visitor<'de> for NotHumanReadableBlobVisitor { - type Value = Blob; - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("expected bytes") - } - - fn visit_byte_buf(self, v: Vec) -> Result - where - E: serde::de::Error, - { - Ok(Blob { inner: v }) - } - } - - impl<'de> Deserialize<'de> for Blob { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - if deserializer.is_human_readable() { - deserializer.deserialize_str(HumanReadableBlobVisitor) - } else { - deserializer.deserialize_byte_buf(NotHumanReadableBlobVisitor) - } - } - } -} - -#[cfg(test)] -#[cfg(all( - aws_sdk_unstable, - feature = "serde-serialize", - feature = "serde-deserialize" -))] -mod test_serde { - use crate::Blob; - use serde::{Deserialize, Serialize}; - use std::collections::HashMap; - - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct ForTest { - blob: Blob, - } - - #[test] - fn human_readable_blob() { - let aws_in_base64 = r#"{"blob":"QVdT"}"#; - let for_test = ForTest { - blob: Blob { - inner: vec![b'A', b'W', b'S'], - }, - }; - assert_eq!(for_test, serde_json::from_str(aws_in_base64).unwrap()); - assert_eq!(serde_json::to_string(&for_test).unwrap(), aws_in_base64); - } - - #[test] - fn not_human_readable_blob() { - use std::ffi::CString; - - let for_test = ForTest { - blob: Blob { - inner: vec![b'A', b'W', b'S'], - }, - }; - let mut buf = vec![]; - let res = ciborium::ser::into_writer(&for_test, &mut buf); - assert!(res.is_ok()); - - // checks whether the bytes are deserialiezd properly - - let n: HashMap = - ciborium::de::from_reader(std::io::Cursor::new(buf.clone())).unwrap(); - assert!(n.get("blob").is_some()); - assert!(n.get("blob") == CString::new([65, 87, 83]).ok().as_ref()); - - let de: ForTest = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); - assert_eq!(for_test, de); - } -} diff --git a/rust-runtime/aws-smithy-types/src/document.rs b/rust-runtime/aws-smithy-types/src/document.rs index 75612960529..a7c46d04dbb 100644 --- a/rust-runtime/aws-smithy-types/src/document.rs +++ b/rust-runtime/aws-smithy-types/src/document.rs @@ -4,12 +4,9 @@ */ use crate::Number; -#[cfg(any( - all(aws_sdk_unstable, feature = "serde-deserialize"), - all(aws_sdk_unstable, feature = "serde-serialize") -))] -use serde; -use std::{borrow::Cow, collections::HashMap}; +use std::borrow::Cow; +use std::collections::HashMap; + /* ANCHOR: document */ /// Document Type @@ -18,22 +15,7 @@ use std::{borrow::Cow, collections::HashMap}; /// Open content is useful for modeling unstructured data that has no schema, data that can't be /// modeled using rigid types, or data that has a schema that evolves outside of the purview of a model. /// The serialization format of a document is an implementation detail of a protocol. -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr( - all(aws_sdk_unstable, feature = "serde-serialize"), - derive(serde::Serialize) -)] -#[cfg_attr( - all(aws_sdk_unstable, feature = "serde-deserialize"), - derive(serde::Deserialize) -)] -#[cfg_attr( - any( - all(aws_sdk_unstable, feature = "serde-deserialize"), - all(aws_sdk_unstable, feature = "serde-serialize") - ), - serde(untagged) -)] +#[derive(Clone, Debug, PartialEq)] pub enum Document { /// JSON object Object(HashMap), @@ -214,59 +196,14 @@ impl From for Document { } } -/* ANCHOR END: document */ +impl From for Document { + fn from(value: f64) -> Self { + Document::Number(Number::Float(value)) + } +} -#[cfg(test)] -mod test { - /// checks if a) serialization of json suceeds and b) it is compatible with serde_json - #[test] - #[cfg(all( - aws_sdk_unstable, - feature = "serde-serialize", - feature = "serde-deserialize" - ))] - fn serialize_json() { - use crate::Document; - use crate::Number; - use std::collections::HashMap; - let mut map: HashMap = HashMap::new(); - // string - map.insert("hello".into(), "world".to_string().into()); - // numbers - map.insert("pos_int".into(), Document::Number(Number::PosInt(1).into())); - map.insert( - "neg_int".into(), - Document::Number(Number::NegInt(-1).into()), - ); - map.insert( - "float".into(), - Document::Number(Number::Float(0.1 + 0.2).into()), - ); - // booleans - map.insert("true".into(), true.into()); - map.insert("false".into(), false.into()); - // check if array with different datatypes would succeed - map.insert( - "array".into(), - vec![ - map.clone().into(), - "hello-world".to_string().into(), - true.into(), - false.into(), - ] - .into(), - ); - // map - map.insert("map".into(), map.clone().into()); - // null - map.insert("null".into(), Document::Null); - let obj = Document::Object(map); - // comparing string isnt going to work since there is no gurantee for the ordering of the keys - let target_file = include_str!("../test_data/serialize_document.json"); - let json: Result = serde_json::from_str(target_file); - // serializer - assert_eq!(serde_json::to_value(&obj).unwrap(), json.unwrap()); - let doc: Result = serde_json::from_str(target_file); - assert_eq!(obj, doc.unwrap()); +impl From for Document { + fn from(value: Number) -> Self { + Document::Number(value) } } From 388ee1844b71cff0cf816e6988da6aaa220ef93c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Wed, 14 Jun 2023 17:37:50 +0000 Subject: [PATCH 220/312] asdf --- .../src/serde_impl_test/blob.rs | 22 -- .../src/serde_impl_test/document.rs | 22 -- .../src/serde_impl_test/mod.rs | 228 ------------------ 3 files changed, 272 deletions(-) delete mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/blob.rs delete mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs delete mode 100644 rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/blob.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/blob.rs deleted file mode 100644 index 19684bab18a..00000000000 --- a/rust-runtime/aws-smithy-types/src/serde_impl_test/blob.rs +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use super::*; - -/// Tests whether de-serialization feature for blob is properly feature gated -#[test] -fn feature_gate_test_for_blob_deserialization() { - // create files - let cargo_project_path = create_cargo_dir("Blob", Target::De); - de_test(&cargo_project_path); -} - -/// Tests whether serialization feature for blob is properly feature gated -#[test] -fn feature_gate_test_for_blob_serialization() { - // create files - let cargo_project_path = create_cargo_dir("Blob", Target::Ser); - ser_test(&cargo_project_path); -} diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs deleted file mode 100644 index 703bbb027cd..00000000000 --- a/rust-runtime/aws-smithy-types/src/serde_impl_test/document.rs +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use super::*; - -/// Tests whether de-serialization feature for document is properly feature gated -#[test] -fn feature_gate_test_for_document_deserialization() { - // create files - let cargo_project_path = create_cargo_dir("Document", Target::De); - de_test(&cargo_project_path); -} - -/// Tests whether serialization feature for document is properly feature gated -#[test] -fn feature_gate_test_for_document_serialization() { - // create files - let cargo_project_path = create_cargo_dir("Document", Target::Ser); - ser_test(&cargo_project_path); -} diff --git a/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs b/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs deleted file mode 100644 index 662ef28e563..00000000000 --- a/rust-runtime/aws-smithy-types/src/serde_impl_test/mod.rs +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -use std::{env::current_dir, path::PathBuf, process::Command, str::FromStr}; -mod blob; - - - - -#[derive(Debug)] -pub(crate) enum Target { - Ser, - De, -} - -// create directory and files for testing -pub(crate) fn create_cargo_dir(datatype: &str, target: Target) -> PathBuf { - let base_path = PathBuf::from_str("/tmp/smithy-rust-test/") - .unwrap() - .join(format!("{target:#?}")) - .join(datatype); - let src_path = base_path.join("src"); - - // create temp directory - std::fs::create_dir_all(&base_path).unwrap(); - std::fs::create_dir_all(&src_path).unwrap(); - - // write cargo - { - let cargo = include_str!("../../test_data/template/Cargo.toml").replace( - r#"aws-smithy-types = { path = "./" }"#, - &format!( - "aws-smithy-types = {{ path = {:#?} }}", - current_dir().unwrap().to_str().unwrap().to_string() - ), - ); - std::fs::write(&base_path.join("Cargo.toml"), cargo).unwrap(); - }; - - // write main.rs - let ser = include_str!("../../test_data/template/ser"); - let deser = include_str!("../../test_data/template/deser"); - let place_holder = "$PLACE_HOLDER$"; - let contents = match target { - Target::De => deser.replace(place_holder, datatype), - Target::Ser => { - let s = match datatype { - "Blob" => "Blob::new([1, 2,3])", - "Number" => "Number::PosInt(1)", - "Document" => "Document::from(0)", - "DateTime" => "DateTime::from_secs(0)", - _ => panic!(), - }; - ser.replace(place_holder, s) - } - }; - std::fs::write(&src_path.join("main.rs"), contents).unwrap(); - - base_path -} - -pub(crate) fn ser_test(cargo_project_path: &PathBuf) { - // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --all-features"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); - - // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); -} - -pub(crate) fn de_test(cargo_project_path: &PathBuf) { - // runs cargo check --all-features without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --all-features"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-serialize without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-deserialize without "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-serialize with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is not expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-serialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, false); - - // runs cargo check --features serde-deserialize with "--cfg aws_sdk_unstable" enabled. - // the code that it compiles require de-serialization feature. - // it is expected to compile. - let mut cmd = Command::new("bash"); - - let child = cmd - .current_dir(&cargo_project_path) - .args(["-c", "cargo check --features serde-deserialize"]) - .env("RUSTFLAGS", "--cfg aws_sdk_unstable") - .spawn(); - - let is_success = child.unwrap().wait().unwrap().success(); - assert_eq!(is_success, true); -} From 3a998e57b9a8755ea6e804506a27dc171609b5b0 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 20 Jun 2023 06:22:33 +0000 Subject: [PATCH 221/312] fix --- CHANGELOG.next.toml | 38 ------- rust-runtime/aws-smithy-types/Cargo.toml | 8 +- rust-runtime/aws-smithy-types/src/blob.rs | 125 ++++++++++++++++++++++ 3 files changed, 129 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 9420e88f40d..e7157b365ed 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -35,44 +35,6 @@ references = ["smithy-rs#2722", "aws-sdk-rust#703"] meta = { "breaking" = false, "tada" = false, "bug" = true } author = "rcoh" -[[smithy-rs]] -message = """ -- rust runtime - - Implements serde support to `Number`, `Blob`, `Document`, `DateTime` - -- Core codegen code - - Add sensitive warning - - Add `serde` attributes - - Import `serde` crate to enable `serde(skip)` on some namespaces - - Add `serde` crate behind unstable feature gate on `Cargo.toml` - -- Client codegen code - - add `serde` as dependency behind feature gate - - add `serde` support to uknown variant types -""" -author = "thomas-k-cameron" -references = ["smithy-rs#2615"] -meta = { "breaking" = false, "tada" = false, "bug" = false } - -[[aws-sdk-rust]] -message = """ -- rust runtime - - Implements serde support to `Number`, `Blob`, `Document`, `DateTime` - -- Core codegen code - - Add sensitive warning - - Add `serde` attributes - - Import `serde` crate to enable `serde(skip)` on some namespaces - - Add `serde` crate behind unstable feature gate on `Cargo.toml` - -- Client codegen code - - add `serde` as dependency behind feature gate - - add `serde` support to uknown variant types -""" -author = "thomas-k-cameron" -references = ["smithy-rs#2615"] -meta = { "breaking" = false, "tada" = false, "bug" = false } - [[aws-sdk-rust]] message = "`SsoCredentialsProvider`, `AssumeRoleProvider`, and `WebIdentityTokenCredentialsProvider` now use `NoCredentialsCache` internally when fetching credentials using an STS client. This avoids double-caching when these providers are wrapped by `LazyCredentialsCache` when a service client is created." references = ["smithy-rs#2720"] diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index ca611d533f8..ba4d59bb822 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -22,10 +22,6 @@ num-integer = "0.1.44" ryu = "1.0.5" time = { version = "0.3.4", features = ["parsing"] } -[target."cfg(aws_sdk_unstable)".dependencies.serde] -version = "1" -features = ["derive"] - [dev-dependencies] base64 = "0.13.0" ciborium = { version = "0.2.1" } @@ -45,3 +41,7 @@ rustdoc-args = ["--cfg", "docsrs"] [[bench]] name = "base64" harness = false + +[target."cfg(aws_sdk_unstable)".dependencies.serde] +version = "1" +features = ["derive"] diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index bdd335c4923..5365b91249f 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -30,3 +30,128 @@ impl AsRef<[u8]> for Blob { &self.inner } } + +#[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] +mod serde_serialize { + use super::*; + use crate::base64; + use serde::Serialize; + + impl Serialize for Blob { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + if serializer.is_human_readable() { + serializer.serialize_str(&crate::base64::encode(&self.inner)) + } else { + serializer.serialize_bytes(&self.inner) + } + } + } +} + +#[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] +mod serde_deserialize { + use super::*; + use crate::base64; + use serde::{de::Visitor, Deserialize}; + + struct HumanReadableBlobVisitor; + impl<'de> Visitor<'de> for HumanReadableBlobVisitor { + type Value = Blob; + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("expected base64 encoded string") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + match base64::decode(v) { + Ok(inner) => Ok(Blob { inner }), + Err(e) => Err(E::custom(e)), + } + } + } + + struct NotHumanReadableBlobVisitor; + impl<'de> Visitor<'de> for NotHumanReadableBlobVisitor { + type Value = Blob; + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("expected bytes") + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: serde::de::Error, + { + Ok(Blob { inner: v }) + } + } + + impl<'de> Deserialize<'de> for Blob { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + if deserializer.is_human_readable() { + deserializer.deserialize_str(HumanReadableBlobVisitor) + } else { + deserializer.deserialize_byte_buf(NotHumanReadableBlobVisitor) + } + } + } +} + +#[cfg(test)] +#[cfg(all( + aws_sdk_unstable, + feature = "serde-serialize", + feature = "serde-deserialize" +))] +mod test_serde { + use crate::Blob; + use serde::{Deserialize, Serialize}; + use std::collections::HashMap; + + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct ForTest { + blob: Blob, + } + + #[test] + fn human_readable_blob() { + let aws_in_base64 = r#"{"blob":"QVdT"}"#; + let for_test = ForTest { + blob: Blob { + inner: vec![b'A', b'W', b'S'], + }, + }; + assert_eq!(for_test, serde_json::from_str(aws_in_base64).unwrap()); + assert_eq!(serde_json::to_string(&for_test).unwrap(), aws_in_base64); + } + + #[test] + fn not_human_readable_blob() { + use std::ffi::CString; + + let for_test = ForTest { + blob: Blob { + inner: vec![b'A', b'W', b'S'], + }, + }; + let mut buf = vec![]; + let res = ciborium::ser::into_writer(&for_test, &mut buf); + assert!(res.is_ok()); + + // checks whether the bytes are deserialized properly + let n: HashMap = + ciborium::de::from_reader(std::io::Cursor::new(buf.clone())).unwrap(); + assert!(n.get("blob").is_some()); + assert!(n.get("blob") == CString::new([65, 87, 83]).ok().as_ref()); + + let de: ForTest = ciborium::de::from_reader(std::io::Cursor::new(buf)).unwrap(); + assert_eq!(for_test, de); + } +} From ad4ac09cbc9f449044b418bf847ec67953cf5969 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 22 Jun 2023 08:10:47 +0000 Subject: [PATCH 222/312] asdf --- .github/workflows/ci.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5478bfc811e..0cd2c8877b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -154,8 +154,6 @@ jobs: runner: smithy_ubuntu-latest_8-core - action: check-aws-sdk-standalone-integration-tests runner: ubuntu-latest - - action: compiletime-benchmark - runner: ubuntu-latest steps: - uses: actions/checkout@v3 with: @@ -301,19 +299,6 @@ jobs: shell: bash run: cross test --target ${{ matrix.target }} --manifest-path "aws/rust-runtime/Cargo.toml" ${{ matrix.test_aws_exclude }} --workspace - # compile time benchmark - compiletime-benchmark: - name: Compile time benchmark - runs-on: ${{ matrix.test.runner }} - - steps: - - uses: actions/checkout@v3 - with: - path: smithy-rs - ref: ${{ inputs.git_ref }} - - name: compiletime-benchmark - run: bash tools/ci-scripts/compiletime-benchmark - # This job is split out from the rest since it is not required to pass for merge check-sdk-examples: name: Check SDK Examples From e0193699f04fe011979c589aa22b7944c523cd1f Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 22 Jun 2023 08:14:04 +0000 Subject: [PATCH 223/312] fix --- tools/ci-scripts/compiletime-benchmark | 32 ------------------ tools/compiletime-benchmark/format.py | 46 -------------------------- 2 files changed, 78 deletions(-) delete mode 100755 tools/ci-scripts/compiletime-benchmark delete mode 100644 tools/compiletime-benchmark/format.py diff --git a/tools/ci-scripts/compiletime-benchmark b/tools/ci-scripts/compiletime-benchmark deleted file mode 100755 index 6a41f7398b9..00000000000 --- a/tools/ci-scripts/compiletime-benchmark +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -# -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 -# -set -eux - -export TIMEFORMAT=%R -function compile() { - cd $1 && - export CARGORUSTFLAG="" && - cargo build &> /dev/null && cargo clean && - time cargo build &> /dev/null && cargo clean && - time cargo build --release &> /dev/null && cargo clean && - export CARGORUSTFLAG="--cfg aws_sdk_unstable" && - time cargo build --all-features &> /dev/null && cargo clean && - time cargo build --all-features --release &> /dev/null && cargo clean -} - -cd smithy-rs - -./gradlew :aws:sdk:assemble -DIR=$PWD -for variable in $(dir "aws/sdk/build/aws-sdk/sdk"); do - echo "$DIR/aws/sdk/build/aws-sdk/sdk/$variable"; - if [[ $variable != *"aws-"* ]]; then - echo "$variable" &>> /tmp/compiletime-benchmark.txt - compile "$DIR/aws/sdk/build/aws-sdk/sdk/$variable" &>> /tmp/compiletime-benchmark.txt - fi -done - -python3 tools/compiletime-benchmark/format.py diff --git a/tools/compiletime-benchmark/format.py b/tools/compiletime-benchmark/format.py deleted file mode 100644 index 74401e906fe..00000000000 --- a/tools/compiletime-benchmark/format.py +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 -# -def main(): - file = open("/tmp/compiletime-benchmark.txt", "r").read() - stack = [] - idx = 0 - hashmap = {} - for i in file.split("\n"): - idx += 1 - if idx > 5: - idx = 1 - - if idx == 1: - hashmap["sdk"] = i - continue - - i = float(i) - if idx == 2: - hashmap["dev"] = i - elif idx == 3: - hashmap["release"] = i - elif idx == 4: - hashmap["dev-w-all-features"] = i - elif idx == 5: - hashmap["release-w-all-features"] = i - stack.append(hashmap) - hashmap = {} - - header = "|".join(stack[0].keys()) - header = f"|{header}|" - table = [header] - for hashmap in stack: - row = [] - for i in hashmap.keys(): - row.append(str(hashmap[i])) - inner = "|".join(row) - inner = f"|{inner}|" - table.append(inner) - - markdown = "\n".join(table) - print(markdown) - # send markdown to somewhere - -main() From 4f65d8d1018ae3237039e0ed078eaf6345ae9623 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 22 Jun 2023 08:31:02 +0000 Subject: [PATCH 224/312] add --- .../smithy/generators/BuilderGeneratorTest.kt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index ec107f3fcb8..49103e73c3d 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -18,6 +18,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.TestWorkspace import software.amazon.smithy.rust.codegen.core.testutil.compileAndTest import software.amazon.smithy.rust.codegen.core.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.testutil.unitTest +import kotlin.io.path.extension +import kotlin.io.path.readText internal class BuilderGeneratorTest { private val model = StructureGeneratorTest.model @@ -25,6 +27,7 @@ internal class BuilderGeneratorTest { private val struct = StructureGeneratorTest.struct private val credentials = StructureGeneratorTest.credentials private val secretStructure = StructureGeneratorTest.secretStructure + private val errorStruct = StructureGeneratorTest.error @Test fun `generate builders`() { @@ -137,4 +140,30 @@ internal class BuilderGeneratorTest { } project.compileAndTest() } + + @Test + fun `don't add serde to error types`() { + val provider = testSymbolProvider(model) + val project = TestWorkspace.testProject(provider) + project.moduleFor(errorStruct) { + rust("##![allow(deprecated)]") + StructureGenerator(model, provider, this, errorStruct, emptyList()).render() + implBlock(provider.toSymbol(errorStruct)) { + BuilderGenerator.renderConvenienceMethod(this, provider, errorStruct) + } + } + project.withModule(provider.moduleForBuilder(errorStruct)) { + BuilderGenerator(model, provider, errorStruct, emptyList()).render(this) + } + project.compileAndTest() + + // checks if there is a serde derive in the code + project.generatedFiles().forEach { + if (it.extension == "rs") { + val file = project.baseDir.resolve(it).toFile().readText() + val check = file.contains("derive(serde::Deserialize)") || file.contains("derive(serde::Serialize)") + assert(!check) + } + } + } } From 8565bf244f5f5bae4edfa0a7f418284eeba22c4d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 22 Jun 2023 08:43:56 +0000 Subject: [PATCH 225/312] test --- .../smithy/rust/codegen/core/testutil/Rust.kt | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index fa98e87fcb7..fe284706d78 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -42,6 +42,19 @@ import java.nio.file.Files.createTempDirectory import java.nio.file.Path import kotlin.io.path.absolutePathString +object Commands { + val CargoEnvDWarnings = mapOf( + "RUSTFLAGS" to "-D warnings --cfg aws_sdk_unstable", + ) + val CargoEnvDDeadCode = mapOf( + "RUSTFLAGS" to "-A dead_code --cfg aws_sdk_unstable", + ) + const val CargoTest = "cargo test --all-features" + const val CargoCheck = "cargo check --all-features" + const val CargoFmt = "cargo fmt " + const val CargoClippy = "cargo clippy" +} + val TestModuleDocProvider = object : ModuleDocProvider { override fun docsWriter(module: RustModule.LeafModule): Writable = writable { docs("Some test documentation\n\nSome more details...") @@ -332,14 +345,14 @@ fun TestWriterDelegator.compileAndTest( println("Generated files:") printGeneratedFiles() try { - "cargo fmt".runCommand(baseDir) + Commands.CargoFmt.runCommand(baseDir) } catch (e: Exception) { // cargo fmt errors are useless, ignore } - val env = mapOf("RUSTFLAGS" to "-A dead_code") - val testOutput = "cargo test".runCommand(baseDir, env) + val env = Commands.CargoEnvDDeadCode + val testOutput = Commands.CargoTest.runCommand(baseDir, env) if (runClippy) { - "cargo clippy".runCommand(baseDir, env) + Commands.CargoClippy.runCommand(baseDir, env) } return testOutput } @@ -379,9 +392,9 @@ fun RustWriter.compileAndTest( val testModule = tempDir.resolve("src/$module.rs") try { val testOutput = if ((mainRs.readText() + testModule.readText()).contains("#[test]")) { - "cargo test".runCommand(tempDir.toPath()) + Commands.CargoTest.runCommand(tempDir.toPath()) } else { - "cargo check".runCommand(tempDir.toPath()) + Commands.CargoCheck.runCommand(tempDir.toPath()) } if (expectFailure) { println("Test sources for debugging: file://${testModule.absolutePath}") @@ -488,4 +501,4 @@ fun TestWriterDelegator.unitTest(test: Writable): TestWriterDelegator { return this } -fun String.runWithWarnings(crate: Path) = this.runCommand(crate, mapOf("RUSTFLAGS" to "-D warnings")) +fun String.runWithWarnings(crate: Path) = this.runCommand(crate, Commands.CargoEnvDWarnings) From f578b863ff00379d94a739721bde6808cf2b7a29 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 23 Jun 2023 01:57:11 +0900 Subject: [PATCH 226/312] Update codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt Co-authored-by: Zelda Hessler --- .../software/amazon/smithy/rust/codegen/core/testutil/Rust.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index fe284706d78..93da546df84 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -51,7 +51,7 @@ object Commands { ) const val CargoTest = "cargo test --all-features" const val CargoCheck = "cargo check --all-features" - const val CargoFmt = "cargo fmt " + const val CargoFmt = "cargo fmt" const val CargoClippy = "cargo clippy" } From a3e8546d0762878cdea84fe9322d39d6264e3038 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 29 Jun 2023 17:25:38 +0900 Subject: [PATCH 227/312] Update codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt Co-authored-by: John DiSanti --- .../rust/codegen/client/smithy/customize/SerdeDecorator.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 56a777b4708..5800704d7a3 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -10,9 +10,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.Feature import software.amazon.smithy.rust.codegen.core.smithy.RustCrate /** - * This class, - * - Adds serde as a dependency - * + * Decorator that adds the `serde-serialize` and `serde-deserialize` features. */ class SerdeDecorator : ClientCodegenDecorator { override val name: String = "SerdeDecorator" From d614f5f39bbdd7cadb70018076eb54ccdb238d1f Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 29 Jun 2023 10:54:26 +0000 Subject: [PATCH 228/312] Rust.kt --- .../smithy/rust/codegen/core/testutil/Rust.kt | 61 ++++++++++++++----- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index fe284706d78..60f6f2309b7 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -42,16 +42,46 @@ import java.nio.file.Files.createTempDirectory import java.nio.file.Path import kotlin.io.path.absolutePathString +// cargo commands and env values object Commands { - val CargoEnvDWarnings = mapOf( - "RUSTFLAGS" to "-D warnings --cfg aws_sdk_unstable", - ) - val CargoEnvDDeadCode = mapOf( - "RUSTFLAGS" to "-A dead_code --cfg aws_sdk_unstable", - ) - const val CargoTest = "cargo test --all-features" - const val CargoCheck = "cargo check --all-features" - const val CargoFmt = "cargo fmt " + private const val cfgUnstable = "--cfg aws_sdk_unstable" + fun cargoEnvDWarnings(enableUnstable: Boolean): Map { + var s = "-A dead_code " + if (enableUnstable) { + s += cfgUnstable + } + return mapOf( + "RUSTFLAGS" to s, + ) + } + + fun cargoEnvDDeadCode(enableUnstable: Boolean): Map { + var s = "-A dead_code " + if (enableUnstable) { + s += cfgUnstable + } + return mapOf( + "RUSTFLAGS" to s, + ) + } + + private const val allFeature = "--all-features" + + fun cargoTest(enableUnstable: Boolean): String { + var s = "cargo test" + if (enableUnstable) { + s += allFeature + } + return s + } + fun cargoCheck(enableUnstable: Boolean): String { + var s = "cargo check" + if (enableUnstable) { + s += allFeature + } + return s + } + const val CargoFmt = "cargo fmt" const val CargoClippy = "cargo clippy" } @@ -329,6 +359,7 @@ fun FileManifest.printGeneratedFiles() { fun TestWriterDelegator.compileAndTest( runClippy: Boolean = false, expectFailure: Boolean = false, + enableUnstableFlag: Boolean = false ): String { val stubModel = """ namespace fake @@ -349,8 +380,9 @@ fun TestWriterDelegator.compileAndTest( } catch (e: Exception) { // cargo fmt errors are useless, ignore } - val env = Commands.CargoEnvDDeadCode - val testOutput = Commands.CargoTest.runCommand(baseDir, env) + + val env = Commands.cargoEnvDDeadCode(enableUnstableFlag) + val testOutput = Commands.cargoTest(enableUnstableFlag).runCommand(baseDir, env) if (runClippy) { Commands.CargoClippy.runCommand(baseDir, env) } @@ -379,6 +411,7 @@ fun RustWriter.compileAndTest( main: String = "", clippy: Boolean = false, expectFailure: Boolean = false, + enableUnstable: Boolean = false ): String { val deps = this.dependencies.map { RustDependency.fromSymbolDependency(it) }.filterIsInstance() val module = if (this.namespace.contains("::")) { @@ -392,9 +425,9 @@ fun RustWriter.compileAndTest( val testModule = tempDir.resolve("src/$module.rs") try { val testOutput = if ((mainRs.readText() + testModule.readText()).contains("#[test]")) { - Commands.CargoTest.runCommand(tempDir.toPath()) + Commands.cargoTest(enableUnstable).runCommand(tempDir.toPath()) } else { - Commands.CargoCheck.runCommand(tempDir.toPath()) + Commands.cargoCheck(enableUnstable).runCommand(tempDir.toPath()) } if (expectFailure) { println("Test sources for debugging: file://${testModule.absolutePath}") @@ -501,4 +534,4 @@ fun TestWriterDelegator.unitTest(test: Writable): TestWriterDelegator { return this } -fun String.runWithWarnings(crate: Path) = this.runCommand(crate, Commands.CargoEnvDWarnings) +fun String.runWithWarnings(crate: Path, enableUnstableFlag: Boolean) = this.runCommand(crate, Commands.cargoEnvDWarnings(enableUnstableFlag)) From e6512fb0af02b2e2ccc711ce56a72d9f0cae7292 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 29 Jun 2023 11:23:46 +0000 Subject: [PATCH 229/312] asdf --- .../software/amazon/smithy/rust/codegen/core/testutil/Rust.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index ce5465bbd41..7bb7368f528 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -52,7 +52,7 @@ object Commands { return s } } - + fun cargoEnvDWarnings(enableUnstable: Boolean): Map { return mapOf( "RUSTFLAGS" to func("-A dead_code", cfgUnstable, enableUnstable), From 3624b378ca1ea01993472274cf745c0630c102d2 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 29 Jun 2023 11:27:26 +0000 Subject: [PATCH 230/312] pre-commit --- .../software/amazon/smithy/rust/codegen/core/testutil/Rust.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 7bb7368f528..4bfc1b0e18f 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -353,7 +353,7 @@ fun FileManifest.printGeneratedFiles() { fun TestWriterDelegator.compileAndTest( runClippy: Boolean = false, expectFailure: Boolean = false, - enableUnstableFlag: Boolean = false + enableUnstableFlag: Boolean = false, ): String { val stubModel = """ namespace fake @@ -405,7 +405,7 @@ fun RustWriter.compileAndTest( main: String = "", clippy: Boolean = false, expectFailure: Boolean = false, - enableUnstable: Boolean = false + enableUnstable: Boolean = false, ): String { val deps = this.dependencies.map { RustDependency.fromSymbolDependency(it) }.filterIsInstance() val module = if (this.namespace.contains("::")) { From e0311c34ba2b89ed7e02933c6bcb01af9445a730 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 29 Jun 2023 11:39:03 +0000 Subject: [PATCH 231/312] check --- .../software/amazon/smithy/rust/codegen/core/testutil/Rust.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 4bfc1b0e18f..86f37fbd8f4 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -528,4 +528,4 @@ fun TestWriterDelegator.unitTest(test: Writable): TestWriterDelegator { return this } -fun String.runWithWarnings(crate: Path, enableUnstableFlag: Boolean) = this.runCommand(crate, Commands.cargoEnvDWarnings(enableUnstableFlag)) +fun String.runWithWarnings(crate: Path, enableUnstableFlag: Boolean = true) = this.runCommand(crate, Commands.cargoEnvDWarnings(enableUnstableFlag)) From 6e87b131d773f9af2ddf73479f69ec1b84525ddc Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 30 Jun 2023 02:38:14 +0900 Subject: [PATCH 232/312] Update codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt Co-authored-by: John DiSanti --- .../software/amazon/smithy/rust/codegen/core/testutil/Rust.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 86f37fbd8f4..fb2a179812b 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -43,7 +43,7 @@ import java.nio.file.Path import kotlin.io.path.absolutePathString // cargo commands and env values -object Commands { +private object Commands { private const val cfgUnstable = "--cfg aws_sdk_unstable" fun func(s: String, add: String, flag: Boolean): String { if (flag) { From 2f250428796e317ff368e269a04290355ac4a1b1 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 30 Jun 2023 02:38:34 +0900 Subject: [PATCH 233/312] Update codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt Co-authored-by: John DiSanti --- .../amazon/smithy/rust/codegen/core/testutil/Rust.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index fb2a179812b..6579152ceff 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -45,13 +45,7 @@ import kotlin.io.path.absolutePathString // cargo commands and env values private object Commands { private const val cfgUnstable = "--cfg aws_sdk_unstable" - fun func(s: String, add: String, flag: Boolean): String { - if (flag) { - return s + " " + add - } else { - return s - } - } + fun func(s: String, add: String, flag: Boolean): String = if (flag) { "$s $add" } else { s } fun cargoEnvDWarnings(enableUnstable: Boolean): Map { return mapOf( From b0c41339b4f43d9b84a16baa743173dec208e5fd Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 30 Jun 2023 02:43:26 +0900 Subject: [PATCH 234/312] Apply suggestions from code review Co-authored-by: John DiSanti --- .../rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index 1d57501d0a6..84c1ed90cf1 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -164,7 +164,7 @@ internal class BuilderGeneratorTest { project.generatedFiles().forEach { if (it.extension == "rs") { val file = project.baseDir.resolve(it).toFile().readText() - val check = file.contains("derive(serde::Deserialize)") || file.contains("derive(serde::Serialize)") + assertFalse(file.contains("serde::")) assert(!check) } } From 7e06e0c7977bd64b412e49100a8684f268a345cd Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 29 Jun 2023 17:51:03 +0000 Subject: [PATCH 235/312] FIX --- .../amazon/smithy/rust/codegen/core/testutil/Rust.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 6579152ceff..d9e82f25a6b 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -47,13 +47,13 @@ private object Commands { private const val cfgUnstable = "--cfg aws_sdk_unstable" fun func(s: String, add: String, flag: Boolean): String = if (flag) { "$s $add" } else { s } - fun cargoEnvDWarnings(enableUnstable: Boolean): Map { + fun cargoEnvDenyWarnings(enableUnstable: Boolean): Map { return mapOf( - "RUSTFLAGS" to func("-A dead_code", cfgUnstable, enableUnstable), + "RUSTFLAGS" to func("-D warnings", cfgUnstable, enableUnstable), ) } - fun cargoEnvDDeadCode(enableUnstable: Boolean): Map { + fun cargoEnvAllowDeadCode(enableUnstable: Boolean): Map { return mapOf( "RUSTFLAGS" to func("-A dead_code", cfgUnstable, enableUnstable), ) From 84c943d8ed1f464a643bb68d379f80d42524ef21 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 29 Jun 2023 18:53:37 +0000 Subject: [PATCH 236/312] fix --- .../software/amazon/smithy/rust/codegen/core/testutil/Rust.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index d9e82f25a6b..42f3c53a794 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -369,7 +369,7 @@ fun TestWriterDelegator.compileAndTest( // cargo fmt errors are useless, ignore } - val env = Commands.cargoEnvDDeadCode(enableUnstableFlag) + val env = Commands.cargoEnvAllowDeadCode(enableUnstableFlag) val testOutput = Commands.cargoTest(enableUnstableFlag).runCommand(baseDir, env) if (runClippy) { Commands.CargoClippy.runCommand(baseDir, env) @@ -522,4 +522,4 @@ fun TestWriterDelegator.unitTest(test: Writable): TestWriterDelegator { return this } -fun String.runWithWarnings(crate: Path, enableUnstableFlag: Boolean = true) = this.runCommand(crate, Commands.cargoEnvDWarnings(enableUnstableFlag)) +fun String.runWithWarnings(crate: Path, enableUnstableFlag: Boolean = true) = this.runCommand(crate, Commands.cargoEnvDenyWarnings(enableUnstableFlag)) From c2abf697f666619d454d5994b53ae83841526125 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 29 Jun 2023 19:17:13 +0000 Subject: [PATCH 237/312] fix --- .../codegen/core/smithy/generators/BuilderGeneratorTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index 84c1ed90cf1..95021bdd7ab 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -5,6 +5,7 @@ package software.amazon.smithy.rust.codegen.core.smithy.generators +import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.shapes.Shape @@ -164,8 +165,7 @@ internal class BuilderGeneratorTest { project.generatedFiles().forEach { if (it.extension == "rs") { val file = project.baseDir.resolve(it).toFile().readText() - assertFalse(file.contains("serde::")) - assert(!check) + Assertions.assertFalse(file.contains("serde::")) } } } From c358294abc495c42be36007ff4588b4c3db11e48 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 29 Jun 2023 22:59:42 +0000 Subject: [PATCH 238/312] fix --- .../amazon/smithy/rust/codegen/core/testutil/Rust.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 42f3c53a794..f5b382c6971 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -61,12 +61,12 @@ private object Commands { private const val allFeature = "--all-features" - fun cargoTest(enableUnstable: Boolean): String { - return func("cargo test", allFeature, enableUnstable) + fun cargoTest(enableAllFeatures: Boolean): String { + return func("cargo test", allFeature, enableAllFeatures) } - fun cargoCheck(enableUnstable: Boolean): String { - return func("cargo check", allFeature, enableUnstable) + fun cargoCheck(enableAllFeatures: Boolean): String { + return func("cargo check", allFeature, enableAllFeatures) } const val CargoFmt = "cargo fmt" From 99113b5200e217f8b1da7052c35608790d09a1f2 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 29 Jun 2023 23:03:50 +0000 Subject: [PATCH 239/312] enable by default --- .../software/amazon/smithy/rust/codegen/core/testutil/Rust.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index f5b382c6971..e8d11c84631 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -347,7 +347,7 @@ fun FileManifest.printGeneratedFiles() { fun TestWriterDelegator.compileAndTest( runClippy: Boolean = false, expectFailure: Boolean = false, - enableUnstableFlag: Boolean = false, + enableUnstableFlag: Boolean = true, ): String { val stubModel = """ namespace fake From 5a36064821d021e6b089228c755f2bbb9d581e96 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 29 Jun 2023 23:23:14 +0000 Subject: [PATCH 240/312] fix --- .../smithy/rust/codegen/core/testutil/Rust.kt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index e8d11c84631..7d94f8e05c7 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -65,10 +65,18 @@ private object Commands { return func("cargo test", allFeature, enableAllFeatures) } + fun cargoTest(featuresToEnable: Array): String { + return func("cargo test", featuresToEnable.joinToString(" "), true) + } + fun cargoCheck(enableAllFeatures: Boolean): String { return func("cargo check", allFeature, enableAllFeatures) } + fun cargoCheck(featuresToEnable: Array): String { + return func("cargo test", featuresToEnable.joinToString(" "), true) + } + const val CargoFmt = "cargo fmt" const val CargoClippy = "cargo clippy" } @@ -348,6 +356,8 @@ fun TestWriterDelegator.compileAndTest( runClippy: Boolean = false, expectFailure: Boolean = false, enableUnstableFlag: Boolean = true, + enableAllFeatures: Boolean = false, + featuresToEnable: Array? = null, ): String { val stubModel = """ namespace fake @@ -370,7 +380,13 @@ fun TestWriterDelegator.compileAndTest( } val env = Commands.cargoEnvAllowDeadCode(enableUnstableFlag) - val testOutput = Commands.cargoTest(enableUnstableFlag).runCommand(baseDir, env) + + var testCommand = Commands.cargoTest(enableUnstableFlag) + if (featuresToEnable != null) { + testCommand = Commands.cargoCheck(featuresToEnable) + } + + val testOutput = testCommand.runCommand(baseDir, env) if (runClippy) { Commands.CargoClippy.runCommand(baseDir, env) } From a90147ff5be273838a52ffdfe8604ef6a098babf Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Mon, 3 Jul 2023 02:30:11 +0000 Subject: [PATCH 241/312] update --- .../client/smithy/customize/SerdeDecorator.kt | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 56a777b4708..ecf28dd47b1 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -7,7 +7,14 @@ package software.amazon.smithy.rust.codegen.client.smithy.customize import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.core.rustlang.Feature +import software.amazon.smithy.rust.codegen.core.rustlang.Writable +import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RustCrate +import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization +import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection +import software.amazon.smithy.rust.codegen.core.smithy.generators.ModuleDocSection +import software.amazon.smithy.rust.codegen.core.smithy.generators.RenderSerdeAttribute +import software.amazon.smithy.rust.codegen.core.util.getTrait /** * This class, @@ -25,4 +32,40 @@ class SerdeDecorator : ClientCodegenDecorator { rustCrate.mergeFeature(_feature("serde-serialize", "aws-smithy-types")) rustCrate.mergeFeature(_feature("serde-deserialize", "aws-smithy-types")) } + + override fun libRsCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List + ): List = baseCustomizations + SerdeDocGenerator(codegenContext) +} + +class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { + override fun section(section: LibRsSection): Writable { + val isApplicable = RenderSerdeAttribute.isApplicable(codegenContext.serviceShape, codegenContext.model) + val isServiceDoc = section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.ServiceDocs + if (isApplicable && isServiceDoc) { + return writable { + """ + # How to enable `Serialize` and `Deserialize` + This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, + but those traits are behind feature gate. + + As they increase it's compile time dramatically, you should not turn them on unless it's necessary. + Furthermore, implementation of serde is still unstable, and implementation may change anytime in future. + + To enable traits, you must pass `aws_sdk_unstable` to RUSTFLAGS and enable `serde-serialize` or `serde-deserialize` feature. + + e.g. + ```bash + export RUSTFLAGS="--cfg aws_sdk_unstable" + cargo build --features serde-serialize serde-deserialize + ``` + + If you enable `serde-serialize` and/or `serde-deserialize` without `RUSTFLAGS="--cfg aws_sdk_unstable"`, + compilation will fail with warning. + """.trimIndent() + } + } + return emptySection + } } From 79a29575f7eabbba48b6fda95412c8d8b1ca6b00 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 00:29:35 +0000 Subject: [PATCH 242/312] squash --- .../client/smithy/customize/SerdeDecorator.kt | 29 +++++++++---------- .../codegen/core/rustlang/CargoDependency.kt | 3 ++ .../rust/codegen/core/rustlang/RustType.kt | 8 ++--- .../rust/codegen/core/smithy/RuntimeType.kt | 3 ++ .../smithy/generators/RenderSerdeAttribute.kt | 10 +++---- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index ecf28dd47b1..8d507a43146 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -13,8 +13,6 @@ import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection import software.amazon.smithy.rust.codegen.core.smithy.generators.ModuleDocSection -import software.amazon.smithy.rust.codegen.core.smithy.generators.RenderSerdeAttribute -import software.amazon.smithy.rust.codegen.core.util.getTrait /** * This class, @@ -35,37 +33,36 @@ class SerdeDecorator : ClientCodegenDecorator { override fun libRsCustomizations( codegenContext: ClientCodegenContext, - baseCustomizations: List + baseCustomizations: List, ): List = baseCustomizations + SerdeDocGenerator(codegenContext) } class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { override fun section(section: LibRsSection): Writable { - val isApplicable = RenderSerdeAttribute.isApplicable(codegenContext.serviceShape, codegenContext.model) - val isServiceDoc = section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.ServiceDocs - if (isApplicable && isServiceDoc) { + if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.ServiceDocs) { return writable { """ # How to enable `Serialize` and `Deserialize` - This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, + This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, but those traits are behind feature gate. - - As they increase it's compile time dramatically, you should not turn them on unless it's necessary. - Furthermore, implementation of serde is still unstable, and implementation may change anytime in future. - + + As they increase it's compile time dramatically, you should not turn them on unless it's necessary. + Furthermore, implementation of serde is still unstable, and implementation may change anytime in future. + To enable traits, you must pass `aws_sdk_unstable` to RUSTFLAGS and enable `serde-serialize` or `serde-deserialize` feature. - - e.g. + + e.g. ```bash export RUSTFLAGS="--cfg aws_sdk_unstable" cargo build --features serde-serialize serde-deserialize ``` - - If you enable `serde-serialize` and/or `serde-deserialize` without `RUSTFLAGS="--cfg aws_sdk_unstable"`, + + If you enable `serde-serialize` and/or `serde-deserialize` without `RUSTFLAGS="--cfg aws_sdk_unstable"`, compilation will fail with warning. """.trimIndent() } + } else { + return emptySection } - return emptySection } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt index ee097cdc454..f0706913fc0 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt @@ -292,5 +292,8 @@ data class CargoDependency( // behind feature-gate val Serde = CargoDependency("serde", CratesIo("1.0"), features = setOf("derive"), scope = DependencyScope.CfgUnstable) + + // Compile Guard + val CompileGuard = CargoDependency("compilation-guard", CratesIo("0.1.1")) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index 6fc9ca7adf2..e6f3cfa3ca9 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -478,17 +478,17 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { // These were supposed to be a part of companion object but we decided to move it out to here to avoid NPE // You can find the discussion here. // https://github.com/awslabs/smithy-rs/discussions/2248 - public fun SerdeSerialize(): Attribute { + public fun serdeSerialize(): Attribute { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-serialize")), derive(RuntimeType.SerdeSerialize))) } - public fun SerdeDeserialize(): Attribute { + public fun serdeDeserialize(): Attribute { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-deserialize")), derive(RuntimeType.SerdeDeserialize))) } - public fun SerdeSkip(): Attribute { + public fun serdeSkip(): Attribute { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))), serde("skip"))) } - public fun SerdeSerializeOrDeserialize(): Attribute { + public fun serdeSerializeOrDeserialize(): Attribute { return Attribute(cfg(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))))) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt index 5a8f8a0020b..3a1d0f43027 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt @@ -307,6 +307,9 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) val SerdeSerialize = Serde.resolve("Serialize") val SerdeDeserialize = Serde.resolve("Deserialize") + val CompileGuard = CargoDependency.CompileGuard.toType() + val CompileGuardAttr = CompileGuard.resolve("compilation_guard") + // smithy runtime types fun smithyAsync(runtimeConfig: RuntimeConfig) = CargoDependency.smithyAsync(runtimeConfig).toType() fun smithyChecksums(runtimeConfig: RuntimeConfig) = CargoDependency.smithyChecksums(runtimeConfig).toType() diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index 9ac06c8c16c..65d0da58c04 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -23,7 +23,7 @@ public object RenderSerdeAttribute { private const val skipFieldMessage = "/// This field will note be serialized or deserialized because it's a stream type.\n" // guards to check if you want to add serde attributes - private fun isApplicable(shape: Shape, model: Model): Boolean { + fun isApplicable(shape: Shape, model: Model): Boolean { return !shape.hasTrait() && shape.members().none { it.isEventStream(model) } } @@ -34,8 +34,8 @@ public object RenderSerdeAttribute { } public fun addSerdeWithoutShapeModel(writer: RustWriter) { - Attribute("").SerdeSerialize().render(writer) - Attribute("").SerdeDeserialize().render(writer) + Attribute("").serdeSerialize().render(writer) + Attribute("").serdeDeserialize().render(writer) } public fun addSerde(writer: RustWriter, shape: Shape, model: Model) { @@ -47,7 +47,7 @@ public object RenderSerdeAttribute { public fun skipIfStream(writer: RustWriter, member: MemberShape, model: Model, shape: Shape) { if (isApplicable(shape, model) && member.isStreaming(model)) { writer.writeInline(skipFieldMessage) - Attribute("").SerdeSkip().render(writer) + Attribute("").serdeSkip().render(writer) } } @@ -55,7 +55,7 @@ public object RenderSerdeAttribute { if (isApplicable(shape, model)) { // we need this for skip serde to work Attribute.AllowUnusedImports.render(writer) - Attribute("").SerdeSerializeOrDeserialize().render(writer) + Attribute("").serdeSerializeOrDeserialize().render(writer) writer.raw("use serde;") } } From 75c091dd2c2a9bb9853dd1e6b774664e51aa5aff Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 00:52:32 +0000 Subject: [PATCH 243/312] add compilation guard --- .../amazon/smithy/rust/codegen/core/rustlang/RustType.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index c2ad0846663..a5ae97e21be 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -485,6 +485,15 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { public fun serdeDeserialize(): Attribute { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-deserialize")), derive(RuntimeType.SerdeDeserialize))) } + + public fun serdeSerializeCompilationGuard(): Attribute { + return Attribute(cfgAttr(all(not(writable("aws_sdk_unstable")), feature("serde-serialize")), derive(RuntimeType.SerdeSerialize))) + } + + public fun serdeDeserializeCompilationGuard(): Attribute { + return Attribute(cfgAttr(all(not(writable("aws_sdk_unstable")), feature("serde-deserialize")), derive(RuntimeType.SerdeDeserialize))) + } + public fun serdeSkip(): Attribute { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))), serde("skip"))) } From 71cfdf79f9aad358ec78268a64f6645805e13dca Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 01:08:24 +0000 Subject: [PATCH 244/312] update --- .../rust/codegen/core/rustlang/RustType.kt | 16 +++++++++++++++- .../smithy/generators/RenderSerdeAttribute.kt | 3 +++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index a5ae97e21be..eb627736fec 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -491,7 +491,16 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { } public fun serdeDeserializeCompilationGuard(): Attribute { - return Attribute(cfgAttr(all(not(writable("aws_sdk_unstable")), feature("serde-deserialize")), derive(RuntimeType.SerdeDeserialize))) + val comment = """ + You must pass "aws_sdk_unstable" flag to RUSTFLAG. + e.g. + ```bash + export RUSTFLAG="--cfg aws_sdk_unstable" + ``` + + Learn more about this on this SDK's document. + """.trimIndent() + return Attribute(cfgAttr(all(not(writable("aws_sdk_unstable")), feature("serde-deserialize")), attributeWithStringAsArgument(RuntimeType.CompileGuardAttr, comment))) } public fun serdeSkip(): Attribute { @@ -602,6 +611,11 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { } } + fun attributeWithStringAsArgument(runtimeType: RuntimeType, comment: String): Writable = { + // Sorted derives look nicer than unsorted, and it makes test output easier to predict + rustInline("#W(\"$comment\")", runtimeType.writable) + } + fun derive(runtimeTypes: Collection): Writable = derive(*runtimeTypes.toTypedArray()) fun pair(pair: Pair): Writable = { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index 65d0da58c04..ae9327a27fd 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -35,7 +35,10 @@ public object RenderSerdeAttribute { public fun addSerdeWithoutShapeModel(writer: RustWriter) { Attribute("").serdeSerialize().render(writer) + Attribute("").serdeSerializeCompilationGuard().render(writer) + Attribute("").serdeDeserialize().render(writer) + Attribute("").serdeDeserializeCompilationGuard().render(writer) } public fun addSerde(writer: RustWriter, shape: Shape, model: Model) { From 7f8162d46c0d3aa49d3b5c05eb71ab55d90be491 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 01:10:58 +0000 Subject: [PATCH 245/312] update --- .../rust/codegen/core/rustlang/RustType.kt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index eb627736fec..781cc9b2187 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -486,11 +486,7 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-deserialize")), derive(RuntimeType.SerdeDeserialize))) } - public fun serdeSerializeCompilationGuard(): Attribute { - return Attribute(cfgAttr(all(not(writable("aws_sdk_unstable")), feature("serde-serialize")), derive(RuntimeType.SerdeSerialize))) - } - - public fun serdeDeserializeCompilationGuard(): Attribute { + private fun compilationGuard(featureName: String): Attribute { val comment = """ You must pass "aws_sdk_unstable" flag to RUSTFLAG. e.g. @@ -500,7 +496,16 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { Learn more about this on this SDK's document. """.trimIndent() - return Attribute(cfgAttr(all(not(writable("aws_sdk_unstable")), feature("serde-deserialize")), attributeWithStringAsArgument(RuntimeType.CompileGuardAttr, comment))) + + return Attribute(cfgAttr(all(not(writable("aws_sdk_unstable")), feature(featureName)), attributeWithStringAsArgument(RuntimeType.CompileGuardAttr, comment))) + } + + public fun serdeSerializeCompilationGuard(): Attribute { + return compilationGuard("serde-serialize") + } + + public fun serdeDeserializeCompilationGuard(): Attribute { + return compilationGuard("serde-deserialize") } public fun serdeSkip(): Attribute { From ad001ca2537a2a8c4a54117ffa82d25e8e4f26be Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 01:22:49 +0000 Subject: [PATCH 246/312] refactoring --- .../rust/codegen/client/smithy/customize/SerdeDecorator.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 8d507a43146..85b52f739a3 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -24,8 +24,8 @@ class SerdeDecorator : ClientCodegenDecorator { override val order: Byte = -1 override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { - fun _feature(feature_name: String, crate_name: String): Feature { - return Feature(feature_name, false, listOf(crate_name + "/" + feature_name)) + fun _feature(featureName: String, crateName: String): Feature { + return Feature(featureName, false, listOf("$crateName/$featureName")) } rustCrate.mergeFeature(_feature("serde-serialize", "aws-smithy-types")) rustCrate.mergeFeature(_feature("serde-deserialize", "aws-smithy-types")) From c49b208514c07f6d24c2696eb15ed5c9c106db63 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 01:25:02 +0000 Subject: [PATCH 247/312] update --- .../client/smithy/customize/SerdeDecorator.kt | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 5800704d7a3..85b52f739a3 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -7,20 +7,62 @@ package software.amazon.smithy.rust.codegen.client.smithy.customize import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.core.rustlang.Feature +import software.amazon.smithy.rust.codegen.core.rustlang.Writable +import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RustCrate +import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization +import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection +import software.amazon.smithy.rust.codegen.core.smithy.generators.ModuleDocSection /** - * Decorator that adds the `serde-serialize` and `serde-deserialize` features. + * This class, + * - Adds serde as a dependency + * */ class SerdeDecorator : ClientCodegenDecorator { override val name: String = "SerdeDecorator" override val order: Byte = -1 override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { - fun _feature(feature_name: String, crate_name: String): Feature { - return Feature(feature_name, false, listOf(crate_name + "/" + feature_name)) + fun _feature(featureName: String, crateName: String): Feature { + return Feature(featureName, false, listOf("$crateName/$featureName")) } rustCrate.mergeFeature(_feature("serde-serialize", "aws-smithy-types")) rustCrate.mergeFeature(_feature("serde-deserialize", "aws-smithy-types")) } + + override fun libRsCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = baseCustomizations + SerdeDocGenerator(codegenContext) +} + +class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { + override fun section(section: LibRsSection): Writable { + if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.ServiceDocs) { + return writable { + """ + # How to enable `Serialize` and `Deserialize` + This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, + but those traits are behind feature gate. + + As they increase it's compile time dramatically, you should not turn them on unless it's necessary. + Furthermore, implementation of serde is still unstable, and implementation may change anytime in future. + + To enable traits, you must pass `aws_sdk_unstable` to RUSTFLAGS and enable `serde-serialize` or `serde-deserialize` feature. + + e.g. + ```bash + export RUSTFLAGS="--cfg aws_sdk_unstable" + cargo build --features serde-serialize serde-deserialize + ``` + + If you enable `serde-serialize` and/or `serde-deserialize` without `RUSTFLAGS="--cfg aws_sdk_unstable"`, + compilation will fail with warning. + """.trimIndent() + } + } else { + return emptySection + } + } } From 1c249918e1f8dedde4ccfc6cb34495dba86f7a1b Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 02:37:38 +0000 Subject: [PATCH 248/312] update --- .../client/smithy/customize/SerdeDecorator.kt | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 85b52f739a3..23a63538f40 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -24,11 +24,11 @@ class SerdeDecorator : ClientCodegenDecorator { override val order: Byte = -1 override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { - fun _feature(featureName: String, crateName: String): Feature { - return Feature(featureName, false, listOf("$crateName/$featureName")) + fun feature(featureName: String): Feature { + return Feature(featureName, false, listOf("aws-smithy-types/$featureName")) } - rustCrate.mergeFeature(_feature("serde-serialize", "aws-smithy-types")) - rustCrate.mergeFeature(_feature("serde-deserialize", "aws-smithy-types")) + rustCrate.mergeFeature(feature("serde-serialize")) + rustCrate.mergeFeature(feature("serde-deserialize")) } override fun libRsCustomizations( @@ -39,26 +39,14 @@ class SerdeDecorator : ClientCodegenDecorator { class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { override fun section(section: LibRsSection): Writable { - if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.ServiceDocs) { + if (section is LibRsSection.ModuleDoc) { return writable { """ - # How to enable `Serialize` and `Deserialize` + ### How to enable `Serialize` and `Deserialize` This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, but those traits are behind feature gate. As they increase it's compile time dramatically, you should not turn them on unless it's necessary. - Furthermore, implementation of serde is still unstable, and implementation may change anytime in future. - - To enable traits, you must pass `aws_sdk_unstable` to RUSTFLAGS and enable `serde-serialize` or `serde-deserialize` feature. - - e.g. - ```bash - export RUSTFLAGS="--cfg aws_sdk_unstable" - cargo build --features serde-serialize serde-deserialize - ``` - - If you enable `serde-serialize` and/or `serde-deserialize` without `RUSTFLAGS="--cfg aws_sdk_unstable"`, - compilation will fail with warning. """.trimIndent() } } else { From 5b5f201309f07b45c9f0d079c632e532505ab1bd Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 02:37:59 +0000 Subject: [PATCH 249/312] update --- .../core/smithy/generators/LibRsGenerator.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt index 1da954f0860..5c80b3267c5 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt @@ -22,6 +22,7 @@ sealed class ModuleDocSection { data class ServiceDocs(val documentationTraitValue: String?) : ModuleDocSection() object CrateOrganization : ModuleDocSection() object Examples : ModuleDocSection() + object UnstableFeature : ModuleDocSection() } sealed class LibRsSection(name: String) : Section(name) { @@ -62,6 +63,27 @@ class LibRsGenerator( containerDocs(escape(defaultServiceDocs ?: settings.moduleName)) } + // Unstable Feature + docSection(ModuleDocSection.UnstableFeature).also { docs -> + if (docs.isNotEmpty()) { + containerDocs("\n## Unstable Features") + val awsSdkUnstable = """ + Some highly experimental features requires passing `aws_sdk_unstable` to RUSTFLAGS. + e.g. + ```bash + export RUSTFLAGS="--cfg aws_sdk_unstable" + cargo build --features serde-serialize + ``` + + If you enable unstable features without enabling `RUSTFLAGS="--cfg aws_sdk_unstable"`, compilation will fail with a message detailing the reason. + """.trimIndent() + containerDocs(awsSdkUnstable) + docs.forEach { writeTo -> + writeTo(this) + } + } + } + // Crate Organization docSection(ModuleDocSection.CrateOrganization).also { docs -> if (docs.isNotEmpty()) { From 81f7efd7ac4a88d631457cafa1361a70d8865d2c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 03:10:28 +0000 Subject: [PATCH 250/312] update --- .../client/smithy/customize/SerdeDecorator.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 23a63538f40..9714eef0d5b 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -39,18 +39,18 @@ class SerdeDecorator : ClientCodegenDecorator { class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { override fun section(section: LibRsSection): Writable { - if (section is LibRsSection.ModuleDoc) { - return writable { + return if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.UnstableFeature) { + writable { """ - ### How to enable `Serialize` and `Deserialize` - This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, - but those traits are behind feature gate. - - As they increase it's compile time dramatically, you should not turn them on unless it's necessary. - """.trimIndent() + ## How to enable `Serialize` and `Deserialize` + This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, + but those traits are behind feature gate. + + As they increase it's compile time dramatically, you should not turn them on unless it's necessary. + """.trimIndent() } } else { - return emptySection + emptySection } } } From e6dbd9724977f55ca25201660fbc7a29c77a4224 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 03:12:18 +0000 Subject: [PATCH 251/312] update --- .../rust/codegen/core/smithy/generators/LibRsGenerator.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt index 5c80b3267c5..725b3ea250d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt @@ -66,8 +66,8 @@ class LibRsGenerator( // Unstable Feature docSection(ModuleDocSection.UnstableFeature).also { docs -> if (docs.isNotEmpty()) { - containerDocs("\n## Unstable Features") val awsSdkUnstable = """ + # Unstable Features Some highly experimental features requires passing `aws_sdk_unstable` to RUSTFLAGS. e.g. ```bash @@ -75,7 +75,7 @@ class LibRsGenerator( cargo build --features serde-serialize ``` - If you enable unstable features without enabling `RUSTFLAGS="--cfg aws_sdk_unstable"`, compilation will fail with a message detailing the reason. + If you enable unstable features without enabling `RUSTFLAGS="--cfg aws_sdk_unstable"`, compilation will fail with a message describing the reason. """.trimIndent() containerDocs(awsSdkUnstable) docs.forEach { writeTo -> From 9e997b6c8dab2233b980e186702a0f3243b44ac9 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 03:28:10 +0000 Subject: [PATCH 252/312] update --- .../client/smithy/customize/SerdeDecorator.kt | 12 ++++++------ .../core/smithy/generators/LibRsGenerator.kt | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 9714eef0d5b..fba326f85c1 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -42,12 +42,12 @@ class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibR return if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.UnstableFeature) { writable { """ - ## How to enable `Serialize` and `Deserialize` - This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, - but those traits are behind feature gate. - - As they increase it's compile time dramatically, you should not turn them on unless it's necessary. - """.trimIndent() + ## How to enable `Serialize` and `Deserialize` + This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, + but those traits are behind feature gate. + + As they increase it's compile time dramatically, you should not turn them on unless it's necessary. + """.trimIndent() } } else { emptySection diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt index 725b3ea250d..90cd82e4e94 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt @@ -67,15 +67,15 @@ class LibRsGenerator( docSection(ModuleDocSection.UnstableFeature).also { docs -> if (docs.isNotEmpty()) { val awsSdkUnstable = """ - # Unstable Features - Some highly experimental features requires passing `aws_sdk_unstable` to RUSTFLAGS. - e.g. - ```bash - export RUSTFLAGS="--cfg aws_sdk_unstable" - cargo build --features serde-serialize - ``` - - If you enable unstable features without enabling `RUSTFLAGS="--cfg aws_sdk_unstable"`, compilation will fail with a message describing the reason. + # Unstable Features + Some highly experimental features requires passing `aws_sdk_unstable` to RUSTFLAGS. + e.g. + ```bash + export RUSTFLAGS="--cfg aws_sdk_unstable" + cargo build --features serde-serialize + ``` + + If you enable unstable features without enabling `RUSTFLAGS="--cfg aws_sdk_unstable"`, compilation will fail with a message describing the reason. """.trimIndent() containerDocs(awsSdkUnstable) docs.forEach { writeTo -> From 6f35925c26f9aa4ef27190d56d5343401ed49139 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 13:39:52 +0900 Subject: [PATCH 253/312] Rfc30/compiletime benchmark to ci (#22) * - add python packages for compiletime benchmark - add scripts * remove polars * update action * Update ci.yml * updater * Update ci.yml * update * update * update * update * FIX * update * FIX * update * update * Update pull-request-bot.yml * fix * fix * update * asdf * fix * update * fix * update * fix * test * asdf * fix * fix * update * asdf * fix * asdf * dsfg * asdf * fix * asdf * fix * fix * asdf --------- Co-authored-by: Zelda Hessler --- .github/workflows/pull-request-bot.yml | 39 ++++++++++++++++++- tools/ci-scripts/compiletime-benchmark | 47 +++++++++++++++++++++++ tools/compiletime-benchmark/format.py | 53 ++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100755 tools/ci-scripts/compiletime-benchmark create mode 100644 tools/compiletime-benchmark/format.py diff --git a/.github/workflows/pull-request-bot.yml b/.github/workflows/pull-request-bot.yml index 28a5c8aea67..4599adfda5e 100644 --- a/.github/workflows/pull-request-bot.yml +++ b/.github/workflows/pull-request-bot.yml @@ -135,10 +135,45 @@ jobs: run: | aws s3 cp target/doc "s3://${S3_BUCKET_NAME}/docs/${{ inputs.head_revision }}" --recursive + compiletime-benchmark: + runs-on: ubuntu-latest + name: Run Compiletime Benchmark + permissions: + id-token: write + contents: read + pull-requests: write + outputs: + compiletime-benchmark: ${{ steps.compiletime-benchmark.outputs.compiletime-benchmark }} + steps: + - uses: actions/checkout@v3 + - uses: actions/cache@v3 + name: Gradle Cache + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} + restore-keys: | + ${{ runner.os }}-gradle- + # JDK is needed to generate code + - name: Set up JDK + uses: actions/setup-java@v3 + with: + distribution: corretto + java-package: jdk + java-version: ${{ env.java_version }} + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.rust_version }} + - name: run benchmark + id: run-compiletime-benchmark + run: bash tools/ci-scripts/compiletime-benchmark && cat /tmp/compiletime-benchmark.md >> "$GITHUB_OUTPUT" + post-bot-comment: needs: - generate-diff - generate-doc-preview + - compiletime-benchmark runs-on: ubuntu-latest name: Post bot comment permissions: @@ -164,6 +199,8 @@ jobs: issue_number: ${{ inputs.issue_number }}, owner: context.repo.owner, repo: context.repo.repo, - body: '${{ steps.bot-messages.outputs.codegen-diff }}\n\n' + + body: '${{ steps.compiletime-benchmark.outputs.compiletime-benchmark }}\n\n' + + '${{ steps.bot-messages.outputs.codegen-diff }}\n\n' + '${{ needs.generate-doc-preview.outputs.bot-message }}\n\n' + }) diff --git a/tools/ci-scripts/compiletime-benchmark b/tools/ci-scripts/compiletime-benchmark new file mode 100755 index 00000000000..f05f4967347 --- /dev/null +++ b/tools/ci-scripts/compiletime-benchmark @@ -0,0 +1,47 @@ +#!/bin/bash +# +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# +C_YELLOW='\033[1;33m' +C_RESET='\033[0m' +set -xe + +cd smithy-rs +DIR=$PWD + +function log_time() { + cargo clean + echo "$1" + cargo build + { time $1; } &> tmp_time_log.txt + cat tmp_time_log.txt + cat tmp_time_log.txt | grep real >> /tmp/compiletime-benchmark.txt +} + +function compile() { + cd $1 && + export RUSTFLAGS="" && + cargo build && # this is for downloading crates + cargo clean && + log_time "cargo build" && + log_time "cargo build --release" && + export RUSTFLAGS="--cfg aws_sdk_unstable" && + log_time "cargo build --all-features" && + log_time "cargo build --release --all-features" +} + +./gradlew :aws:sdk:assemble + +for variable in $(dir "aws/sdk/build/aws-sdk/sdk"); do + echo $variable + if [[ $variable != *"aws-"* ]]; then + echo "START" &>>/tmp/compiletime-benchmark.txt + echo "$variable" &>>/tmp/compiletime-benchmark.txt + compile "$DIR/aws/sdk/build/aws-sdk/sdk/$variable" + echo "END" &>> /tmp/compiletime-benchmark.txt + fi +done + +cd $DIR +python3 tools/compiletime-benchmark/format.py diff --git a/tools/compiletime-benchmark/format.py b/tools/compiletime-benchmark/format.py new file mode 100644 index 00000000000..d50fad59e4e --- /dev/null +++ b/tools/compiletime-benchmark/format.py @@ -0,0 +1,53 @@ +# +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# + +import itertools + + +def main(): + markdown = parser() + print(markdown) + # write file + with open("/tmp/compiletime-benchmark.md", "w") as f: + f.write(markdown) + f.flush() + f.close() + + +def parser() -> str: + # read file + f = open("/tmp/compiletime-benchmark.txt", "r").read() + iter = map(lambda x: x.split("END"), f.split("START")) + iter = itertools.chain.from_iterable(iter) + + # I could've used a dataframe like pandas but this works. + markdown = "| sdk name | dev | release | dev all features | release all features |" + markdown += "\n" + markdown += "| -------- | --- | ------- | ---------------- | -------------------- |" + + markdown += "\n" + for i in iter: + outputs = [] + print(i) + for l in i.splitlines(): + if not "+" in l: + outputs.append(l.replace("real", "").replace(" ", "", 16)) + + if len(outputs) != 6: + continue + + outputs = outputs[1:] + sdk_name = outputs[0] + row = f"|{sdk_name}|" + \ + "|".join(outputs[1:]) + "|" + + markdown += row + markdown += "\n" + + return markdown + + +if __name__ == '__main__': + main() From 970d4c2a235490df732bda74d727316f0dc03c21 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 14:27:44 +0900 Subject: [PATCH 254/312] Update Rust.kt --- .../smithy/rust/codegen/core/testutil/Rust.kt | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 7d94f8e05c7..87e0c9222dd 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -44,9 +44,16 @@ import kotlin.io.path.absolutePathString // cargo commands and env values private object Commands { + const val CargoFmt = "cargo fmt" + const val CargoClippy = "cargo clippy" + private const val cfgUnstable = "--cfg aws_sdk_unstable" - fun func(s: String, add: String, flag: Boolean): String = if (flag) { "$s $add" } else { s } + private const val allFeature = "--all-features" + + // helper + private fun func(s: String, add: String, flag: Boolean): String = if (flag) { "$s $add" } else { s } + // unstable flag fun cargoEnvDenyWarnings(enableUnstable: Boolean): Map { return mapOf( "RUSTFLAGS" to func("-D warnings", cfgUnstable, enableUnstable), @@ -59,26 +66,14 @@ private object Commands { ) } - private const val allFeature = "--all-features" - + // --all-features fun cargoTest(enableAllFeatures: Boolean): String { return func("cargo test", allFeature, enableAllFeatures) } - fun cargoTest(featuresToEnable: Array): String { - return func("cargo test", featuresToEnable.joinToString(" "), true) - } - fun cargoCheck(enableAllFeatures: Boolean): String { return func("cargo check", allFeature, enableAllFeatures) } - - fun cargoCheck(featuresToEnable: Array): String { - return func("cargo test", featuresToEnable.joinToString(" "), true) - } - - const val CargoFmt = "cargo fmt" - const val CargoClippy = "cargo clippy" } val TestModuleDocProvider = object : ModuleDocProvider { From cc3351424f00e752a062a35590fb0f0243ce9571 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 4 Jul 2023 15:35:17 +0900 Subject: [PATCH 255/312] Update Rust.kt --- .../software/amazon/smithy/rust/codegen/core/testutil/Rust.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 87e0c9222dd..6bc66aaa9cb 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -351,7 +351,7 @@ fun TestWriterDelegator.compileAndTest( runClippy: Boolean = false, expectFailure: Boolean = false, enableUnstableFlag: Boolean = true, - enableAllFeatures: Boolean = false, + enableAllFeatures: Boolean = true, featuresToEnable: Array? = null, ): String { val stubModel = """ From 8d78bd41cced2eaaa26c9c81b58d48dfabcc109d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 6 Jul 2023 15:53:09 +0000 Subject: [PATCH 256/312] fix --- .../smithy/rust/codegen/core/testutil/Rust.kt | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 6bc66aaa9cb..e53102c6859 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -66,14 +66,49 @@ private object Commands { ) } - // --all-features + // enable all features + // e.g. + // ```kotlin + // cargoTest(true) + // // cargo test --all-features + // cargoTest(false) + // // cargo test + // ``` fun cargoTest(enableAllFeatures: Boolean): String { return func("cargo test", allFeature, enableAllFeatures) } + // enable all features + // e.g. + // ```kotlin + // cargoCheck(true) + // // cargo test --all-features + // cargoCheck(false) + // // cargo test + // ``` fun cargoCheck(enableAllFeatures: Boolean): String { return func("cargo check", allFeature, enableAllFeatures) } + + // enable features specified in the array + // e.g. + // ```kotlin + // cargoTest(["serde-serialize", "serde-deserialize"]) + // // cargo test --features serde-serialize serde-deserialize + // ``` + fun cargoTest(featuresToEnable?: Array): String { + return func("cargo test", allFeature, enableAllFeatures) + } + + // enable features specified in the array + // e.g. + // ```kotlin + // cargoCheck(["serde-serialize", "serde-deserialize"]) + // // cargo check --features serde-serialize serde-deserialize + // ``` + fun cargoCheck(featuresToEnable?: Array): String { + return func("cargo check", allFeature, enableAllFeatures) + } } val TestModuleDocProvider = object : ModuleDocProvider { From 7d80faf2b4769abdd2f7371ff96e438ea055a112 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 6 Jul 2023 15:59:24 +0000 Subject: [PATCH 257/312] better docs --- .../amazon/smithy/rust/codegen/core/testutil/Rust.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index e53102c6859..42558282c7e 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -381,6 +381,15 @@ fun FileManifest.printGeneratedFiles() { * Setting `runClippy` to true can be helpful when debugging clippy failures, but * should generally be set to `false` to avoid invalidating the Cargo cache between * every unit test run. + * If you want to enable each features individually, specify the name of the feature on featuresToEnable. + * e.g. + * ```kotlin + * compileAndTest(featuresToEnable = ["this", "that"]) + * ``` + * All features are enabled by default. If you wish to disable them, set enableAllFeatures to False. + * ```kotlin + * compileAndTest(featuresToEnable = false) + * ``` */ fun TestWriterDelegator.compileAndTest( runClippy: Boolean = false, From 5756a4196161b8917d325357970a4b7b3ff7be55 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 6 Jul 2023 16:01:24 +0000 Subject: [PATCH 258/312] update --- .../software/amazon/smithy/rust/codegen/core/testutil/Rust.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 42558282c7e..5223d5aba8f 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -96,7 +96,7 @@ private object Commands { // cargoTest(["serde-serialize", "serde-deserialize"]) // // cargo test --features serde-serialize serde-deserialize // ``` - fun cargoTest(featuresToEnable?: Array): String { + fun cargoTest(featuresToEnable: Array?): String { return func("cargo test", allFeature, enableAllFeatures) } @@ -106,7 +106,7 @@ private object Commands { // cargoCheck(["serde-serialize", "serde-deserialize"]) // // cargo check --features serde-serialize serde-deserialize // ``` - fun cargoCheck(featuresToEnable?: Array): String { + fun cargoCheck(featuresToEnable: Array?): String { return func("cargo check", allFeature, enableAllFeatures) } } From 1496901c25339533bafd7bdf6011babf857ac1c4 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 6 Jul 2023 16:25:56 +0000 Subject: [PATCH 259/312] fix --- .../software/amazon/smithy/rust/codegen/core/testutil/Rust.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 40e4dc2f793..be87f523bf9 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -46,7 +46,7 @@ import kotlin.io.path.absolutePathString private object Commands { const val CargoFmt = "cargo fmt" const val CargoClippy = "cargo clippy" - + private const val cfgUnstable = "--cfg aws_sdk_unstable" private const val allFeature = "--all-features" From 73b40a4748716990cfedc8b9529767f0954ed520 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 6 Jul 2023 16:39:46 +0000 Subject: [PATCH 260/312] fix --- .../smithy/rust/codegen/core/testutil/Rust.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index be87f523bf9..e9b5b94420d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -97,7 +97,12 @@ private object Commands { // // cargo test --features serde-serialize serde-deserialize // ``` fun cargoTest(featuresToEnable: Array?): String { - return func("cargo test", allFeature, enableAllFeatures) + if (featuresToEnable != null) { + val s = featuresToEnable.joinToString { " " } + return "cargo test --features $s" + }else { + return "cargo test" + } } // enable features specified in the array @@ -107,7 +112,12 @@ private object Commands { // // cargo check --features serde-serialize serde-deserialize // ``` fun cargoCheck(featuresToEnable: Array?): String { - return func("cargo check", allFeature, enableAllFeatures) + if (featuresToEnable != null) { + val s = featuresToEnable.joinToString { " " } + return "cargo check --features $s" + }else { + return "cargo check" + } } } From 2647de97f9c0da5cae3e0aacfa869d3f5c793ff2 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Thu, 6 Jul 2023 19:39:03 +0000 Subject: [PATCH 261/312] update --- .../software/amazon/smithy/rust/codegen/core/testutil/Rust.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index e9b5b94420d..9438eb756a0 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -100,7 +100,7 @@ private object Commands { if (featuresToEnable != null) { val s = featuresToEnable.joinToString { " " } return "cargo test --features $s" - }else { + } else { return "cargo test" } } @@ -115,7 +115,7 @@ private object Commands { if (featuresToEnable != null) { val s = featuresToEnable.joinToString { " " } return "cargo check --features $s" - }else { + } else { return "cargo check" } } From ef778af0e7023bf7cdcfb77154226496b84e8f0d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Mon, 10 Jul 2023 22:42:50 +0900 Subject: [PATCH 262/312] Update SerdeDecorator.kt --- .../rust/codegen/client/smithy/customize/SerdeDecorator.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index fba326f85c1..3ac2d37c969 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -15,9 +15,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection import software.amazon.smithy.rust.codegen.core.smithy.generators.ModuleDocSection /** - * This class, - * - Adds serde as a dependency - * + * Decorator that adds the `serde-serialize` and `serde-deserialize` features. */ class SerdeDecorator : ClientCodegenDecorator { override val name: String = "SerdeDecorator" From 0b80ffffb65ffa8f8dee7c306492ec3a59faf3f6 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 03:46:50 +0000 Subject: [PATCH 263/312] fix --- .../client/smithy/customize/SerdeDecorator.kt | 23 ------------------- .../rust/codegen/core/rustlang/RustType.kt | 13 +++++------ 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index eba11a4dbf2..0b457e69927 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -35,29 +35,6 @@ class SerdeDecorator : ClientCodegenDecorator { ): List = baseCustomizations + SerdeDocGenerator(codegenContext) } -class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { - override fun section(section: LibRsSection): Writable { - return if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.UnstableFeature) { - writable { - """ - ## How to enable `Serialize` and `Deserialize` - This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, - but those traits are behind feature gate. - - As they increase it's compile time dramatically, you should not turn them on unless it's necessary. - """.trimIndent() - } - } else { - emptySection - } - } - - override fun libRsCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = baseCustomizations + SerdeDocGenerator(codegenContext) -} - class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { override fun section(section: LibRsSection): Writable { if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.ServiceDocs) { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index 781cc9b2187..638ae2d5cb5 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -487,13 +487,12 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { } private fun compilationGuard(featureName: String): Attribute { - val comment = """ - You must pass "aws_sdk_unstable" flag to RUSTFLAG. - e.g. - ```bash - export RUSTFLAG="--cfg aws_sdk_unstable" - ``` - + val comment = """\n + You must pass \"aws_sdk_unstable\" flag to RUSTFLAG. + e.g. + ```bash + export RUSTFLAG=\"--cfg aws_sdk_unstable\" + ``` Learn more about this on this SDK's document. """.trimIndent() From 770da16bede981f1cc83bc9f6115bec9c7a44aed Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 04:06:36 +0000 Subject: [PATCH 264/312] modified: aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt modified: codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt --- .../smithy/rustsdk/AwsCrateDocsDecorator.kt | 12 ++++++ .../client/smithy/customize/SerdeDecorator.kt | 43 ++++++++++--------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt index f167015ac23..fe91552dc68 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt @@ -11,6 +11,7 @@ import org.jsoup.nodes.TextNode import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator +import software.amazon.smithy.rust.codegen.client.smithy.customize.SerdeDocGenerator import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable @@ -178,6 +179,17 @@ internal class AwsCrateDocGenerator(private val codegenContext: ClientCodegenCon "constructClient" to AwsDocs.constructClient(codegenContext, indent = " "), ) + + template(asComments, SerdeDocGenerator.serdeInfoText()) + + template( + asComments, + """ + + + """.trimIndent(), + ) + template( asComments, """ diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 0b457e69927..5579cf49e66 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -36,29 +36,30 @@ class SerdeDecorator : ClientCodegenDecorator { } class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { + companion object { + public fun serdeInfoText() = """# How to enable `Serialize` and `Deserialize` + This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, + but those traits are behind feature gate. + + As they increase it's compile time dramatically, you should not turn them on unless it's necessary. + Furthermore, implementation of serde is still unstable, and implementation may change anytime in future. + + To enable traits, you must pass `aws_sdk_unstable` to RUSTFLAGS and enable `serde-serialize` or `serde-deserialize` feature. + + e.g. + ```bash + export RUSTFLAGS="--cfg aws_sdk_unstable" + cargo build --features serde-serialize serde-deserialize + ``` + + If you enable `serde-serialize` and/or `serde-deserialize` without `RUSTFLAGS="--cfg aws_sdk_unstable"`, + compilation will fail with warning. + """.trimIndent() + + } override fun section(section: LibRsSection): Writable { if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.ServiceDocs) { - return writable { - """ - # How to enable `Serialize` and `Deserialize` - This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, - but those traits are behind feature gate. - - As they increase it's compile time dramatically, you should not turn them on unless it's necessary. - Furthermore, implementation of serde is still unstable, and implementation may change anytime in future. - - To enable traits, you must pass `aws_sdk_unstable` to RUSTFLAGS and enable `serde-serialize` or `serde-deserialize` feature. - - e.g. - ```bash - export RUSTFLAGS="--cfg aws_sdk_unstable" - cargo build --features serde-serialize serde-deserialize - ``` - - If you enable `serde-serialize` and/or `serde-deserialize` without `RUSTFLAGS="--cfg aws_sdk_unstable"`, - compilation will fail with warning. - """.trimIndent() - } + return writable { serdeInfoText() } } else { return emptySection } From bc1c05c8fce804b082421dfa5cb9fbb3b9740c02 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 04:08:58 +0000 Subject: [PATCH 265/312] asdf --- rust-runtime/aws-smithy-types/src/blob.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 5365b91249f..eebdd60ca21 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -34,7 +34,6 @@ impl AsRef<[u8]> for Blob { #[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] mod serde_serialize { use super::*; - use crate::base64; use serde::Serialize; impl Serialize for Blob { @@ -54,7 +53,6 @@ mod serde_serialize { #[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] mod serde_deserialize { use super::*; - use crate::base64; use serde::{de::Visitor, Deserialize}; struct HumanReadableBlobVisitor; @@ -68,7 +66,7 @@ mod serde_deserialize { where E: serde::de::Error, { - match base64::decode(v) { + match crate::base64::decode(v) { Ok(inner) => Ok(Blob { inner }), Err(e) => Err(E::custom(e)), } From 8becf066432ff905d691727060fd434384df234a Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 08:53:36 +0000 Subject: [PATCH 266/312] fix --- .../client/smithy/customize/SerdeDecorator.kt | 22 ++++++++++--------- .../rust/codegen/core/rustlang/RustType.kt | 12 +++++----- .../codegen/core/smithy/CodegenDelegator.kt | 1 - .../core/smithy/generators/LibRsGenerator.kt | 21 ------------------ 4 files changed, 18 insertions(+), 38 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 5579cf49e66..d0cd7a884d3 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -37,31 +37,33 @@ class SerdeDecorator : ClientCodegenDecorator { class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { companion object { - public fun serdeInfoText() = """# How to enable `Serialize` and `Deserialize` + const val SerdeInfoText = """## How to enable `Serialize` and `Deserialize` + This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, but those traits are behind feature gate. - + As they increase it's compile time dramatically, you should not turn them on unless it's necessary. Furthermore, implementation of serde is still unstable, and implementation may change anytime in future. - + To enable traits, you must pass `aws_sdk_unstable` to RUSTFLAGS and enable `serde-serialize` or `serde-deserialize` feature. - + e.g. - ```bash + ```bash,no_run export RUSTFLAGS="--cfg aws_sdk_unstable" cargo build --features serde-serialize serde-deserialize ``` - + If you enable `serde-serialize` and/or `serde-deserialize` without `RUSTFLAGS="--cfg aws_sdk_unstable"`, compilation will fail with warning. - """.trimIndent() + + """ } override fun section(section: LibRsSection): Writable { - if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.ServiceDocs) { - return writable { serdeInfoText() } + return if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.UnstableFeature) { + writable { SerdeInfoText.trimIndent() } } else { - return emptySection + emptySection } } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index 638ae2d5cb5..ffe9eee4879 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -488,12 +488,12 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { private fun compilationGuard(featureName: String): Attribute { val comment = """\n - You must pass \"aws_sdk_unstable\" flag to RUSTFLAG. - e.g. - ```bash - export RUSTFLAG=\"--cfg aws_sdk_unstable\" - ``` - Learn more about this on this SDK's document. + You must pass \"aws_sdk_unstable\" flag to RUSTFLAG. + e.g. + ```bash + export RUSTFLAG=\"--cfg aws_sdk_unstable\" + ``` + Learn more about this on this SDK's document. """.trimIndent() return Attribute(cfgAttr(all(not(writable("aws_sdk_unstable")), feature(featureName)), attributeWithStringAsArgument(RuntimeType.CompileGuardAttr, comment))) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt index 5ae40c3574d..ed1f79903d0 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt @@ -258,7 +258,6 @@ fun WriterDelegator.finalize( LibRsGenerator(settings, model, libRsCustomizations, requireDocs).render(it) } val cargoDependencies = - this.dependencies.map { RustDependency.fromSymbolDependency(it) } .filterIsInstance().distinct() .mergeDependencyFeatures() diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt index 90cd82e4e94..ebb2da7ea08 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt @@ -63,27 +63,6 @@ class LibRsGenerator( containerDocs(escape(defaultServiceDocs ?: settings.moduleName)) } - // Unstable Feature - docSection(ModuleDocSection.UnstableFeature).also { docs -> - if (docs.isNotEmpty()) { - val awsSdkUnstable = """ - # Unstable Features - Some highly experimental features requires passing `aws_sdk_unstable` to RUSTFLAGS. - e.g. - ```bash - export RUSTFLAGS="--cfg aws_sdk_unstable" - cargo build --features serde-serialize - ``` - - If you enable unstable features without enabling `RUSTFLAGS="--cfg aws_sdk_unstable"`, compilation will fail with a message describing the reason. - """.trimIndent() - containerDocs(awsSdkUnstable) - docs.forEach { writeTo -> - writeTo(this) - } - } - } - // Crate Organization docSection(ModuleDocSection.CrateOrganization).also { docs -> if (docs.isNotEmpty()) { From 2b912722c6e1a2c7b30c9695308e9dccd68061c0 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 08:54:29 +0000 Subject: [PATCH 267/312] asdf --- .../amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt index fe91552dc68..30e2e0ead4a 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt @@ -134,6 +134,7 @@ internal class AwsCrateDocGenerator(private val codegenContext: ClientCodegenCon val compileExample = AwsDocs.canRelyOnAwsConfig(codegenContext) val exampleMode = if (compileExample) "no_run" else "ignore" + val serdeInfoText = "##"+SerdeDocGenerator.SerdeInfoText template( asComments, """ @@ -170,6 +171,9 @@ internal class AwsCrateDocGenerator(private val codegenContext: ClientCodegenCon See the [client documentation](https://docs.rs/$moduleName/latest/$snakeCaseModuleName/client/struct.Client.html) for information on what calls can be made, and the inputs and outputs for each of those calls.${"\n"} + + $serdeInfoText + """.trimIndent().trimStart(), "tokio" to CargoDependency.Tokio.toDevDependency().toType(), "aws_config" to when (compileExample) { @@ -179,14 +183,10 @@ internal class AwsCrateDocGenerator(private val codegenContext: ClientCodegenCon "constructClient" to AwsDocs.constructClient(codegenContext, indent = " "), ) - - template(asComments, SerdeDocGenerator.serdeInfoText()) - template( asComments, """ - - + """.trimIndent(), ) From 40a332222fd9a18ddd204c01c1872676ef0db9ba Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 09:47:14 +0000 Subject: [PATCH 268/312] fix --- .../software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt | 2 +- .../rust/codegen/client/smithy/customize/SerdeDecorator.kt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt index 30e2e0ead4a..c0a203f0e9e 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt @@ -134,7 +134,7 @@ internal class AwsCrateDocGenerator(private val codegenContext: ClientCodegenCon val compileExample = AwsDocs.canRelyOnAwsConfig(codegenContext) val exampleMode = if (compileExample) "no_run" else "ignore" - val serdeInfoText = "##"+SerdeDocGenerator.SerdeInfoText + val serdeInfoText = "##" + SerdeDocGenerator.SerdeInfoText template( asComments, """ diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index d0cd7a884d3..aaa33f1817b 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -37,7 +37,7 @@ class SerdeDecorator : ClientCodegenDecorator { class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { companion object { - const val SerdeInfoText = """## How to enable `Serialize` and `Deserialize` + const val SerdeInfoText = """## How to enable `Serialize` and `Deserialize` This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, but those traits are behind feature gate. @@ -57,7 +57,6 @@ class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibR compilation will fail with warning. """ - } override fun section(section: LibRsSection): Writable { return if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.UnstableFeature) { From b07a3bcf69efeafe8872f1ea48428438b57aa18d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 09:48:33 +0000 Subject: [PATCH 269/312] asdf --- tools/ci-scripts/check-aws-sdk-adhoc-tests | 2 ++ tools/ci-scripts/check-aws-sdk-orchestrator-impl | 2 ++ tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps | 2 +- tools/ci-scripts/check-aws-sdk-smoketest-unit-tests | 2 ++ tools/ci-scripts/check-client-codegen-integration-tests | 2 ++ tools/ci-scripts/check-only-aws-sdk-services | 2 ++ 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/ci-scripts/check-aws-sdk-adhoc-tests b/tools/ci-scripts/check-aws-sdk-adhoc-tests index 911d11f998d..7ccb54a7163 100755 --- a/tools/ci-scripts/check-aws-sdk-adhoc-tests +++ b/tools/ci-scripts/check-aws-sdk-adhoc-tests @@ -7,6 +7,8 @@ C_YELLOW='\033[1;33m' C_RESET='\033[0m' +export RUSTFLAG="--cfg aws_sdk_unstable" + set -eu cd smithy-rs diff --git a/tools/ci-scripts/check-aws-sdk-orchestrator-impl b/tools/ci-scripts/check-aws-sdk-orchestrator-impl index b86ebf3f0f6..04a9fe7aa1f 100755 --- a/tools/ci-scripts/check-aws-sdk-orchestrator-impl +++ b/tools/ci-scripts/check-aws-sdk-orchestrator-impl @@ -9,6 +9,8 @@ C_YELLOW='\033[1;33m' C_RESET='\033[0m' +export RUSTFLAG="--cfg aws_sdk_unstable" + set -eu cd smithy-rs diff --git a/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps b/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps index 38942ef0678..0f0605c2628 100755 --- a/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps +++ b/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps @@ -5,7 +5,7 @@ # set -eux - +export RUSTFLAGS="--cfg aws_sdk_unstable" # Docs, clippy, etc on the smoketest itself pushd aws-sdk-smoketest &>/dev/null diff --git a/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests b/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests index 293af9b43f1..287d5d701bc 100755 --- a/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests +++ b/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests @@ -5,5 +5,7 @@ # set -eux +export RUSTFLAGS="--cfg aws_sdk_unstable" + cd aws-sdk-smoketest cargo test --all-features diff --git a/tools/ci-scripts/check-client-codegen-integration-tests b/tools/ci-scripts/check-client-codegen-integration-tests index 86013436c51..2f77e8598d4 100755 --- a/tools/ci-scripts/check-client-codegen-integration-tests +++ b/tools/ci-scripts/check-client-codegen-integration-tests @@ -5,6 +5,8 @@ # set -eux + +export RUSTFLAG="--cfg aws_sdk_unstable" cd smithy-rs # TODO(enableNewSmithyRuntimeCleanup): Only run the orchestrator version of this diff --git a/tools/ci-scripts/check-only-aws-sdk-services b/tools/ci-scripts/check-only-aws-sdk-services index b15c4133b3d..11470c1b0fd 100755 --- a/tools/ci-scripts/check-only-aws-sdk-services +++ b/tools/ci-scripts/check-only-aws-sdk-services @@ -7,6 +7,8 @@ # this job runs `cargo check` only instead of `cargo test --all-features` set -eux +export RUSTFLAGS="--cfg aws_sdk_unstable" + cd aws-sdk # Remove examples from workspace From 7b0a8254faa844caf3860b76a2049b3775dec51b Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 10:54:41 +0000 Subject: [PATCH 270/312] asdf --- tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps | 2 +- tools/ci-scripts/check-aws-sdk-smoketest-unit-tests | 2 +- tools/ci-scripts/check-only-aws-sdk-services | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps b/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps index 0f0605c2628..45664e156ab 100755 --- a/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps +++ b/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps @@ -5,7 +5,7 @@ # set -eux -export RUSTFLAGS="--cfg aws_sdk_unstable" +export RUSTFLAG="--cfg aws_sdk_unstable" # Docs, clippy, etc on the smoketest itself pushd aws-sdk-smoketest &>/dev/null diff --git a/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests b/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests index 287d5d701bc..73338ebf1b8 100755 --- a/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests +++ b/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests @@ -5,7 +5,7 @@ # set -eux -export RUSTFLAGS="--cfg aws_sdk_unstable" +export RUSTFLAG="--cfg aws_sdk_unstable" cd aws-sdk-smoketest cargo test --all-features diff --git a/tools/ci-scripts/check-only-aws-sdk-services b/tools/ci-scripts/check-only-aws-sdk-services index 11470c1b0fd..f38a75ac8bf 100755 --- a/tools/ci-scripts/check-only-aws-sdk-services +++ b/tools/ci-scripts/check-only-aws-sdk-services @@ -7,7 +7,7 @@ # this job runs `cargo check` only instead of `cargo test --all-features` set -eux -export RUSTFLAGS="--cfg aws_sdk_unstable" +export RUSTFLAG="--cfg aws_sdk_unstable" cd aws-sdk From 535127e79a523fb68df4bba88de680e7ec96b37e Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 11:16:35 +0000 Subject: [PATCH 271/312] update --- rust-runtime/aws-smithy-types/src/blob.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index 5365b91249f..eebdd60ca21 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -34,7 +34,6 @@ impl AsRef<[u8]> for Blob { #[cfg(all(aws_sdk_unstable, feature = "serde-serialize"))] mod serde_serialize { use super::*; - use crate::base64; use serde::Serialize; impl Serialize for Blob { @@ -54,7 +53,6 @@ mod serde_serialize { #[cfg(all(aws_sdk_unstable, feature = "serde-deserialize"))] mod serde_deserialize { use super::*; - use crate::base64; use serde::{de::Visitor, Deserialize}; struct HumanReadableBlobVisitor; @@ -68,7 +66,7 @@ mod serde_deserialize { where E: serde::de::Error, { - match base64::decode(v) { + match crate::base64::decode(v) { Ok(inner) => Ok(Blob { inner }), Err(e) => Err(E::custom(e)), } From 7882c7f383db23b89eb0e3b90fde4c948a24f882 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 11:20:20 +0000 Subject: [PATCH 272/312] asdf --- .github/workflows/pull-request-bot.yml | 39 +------------------ tools/ci-scripts/compiletime-benchmark | 47 ----------------------- tools/compiletime-benchmark/format.py | 53 -------------------------- 3 files changed, 1 insertion(+), 138 deletions(-) delete mode 100755 tools/ci-scripts/compiletime-benchmark delete mode 100644 tools/compiletime-benchmark/format.py diff --git a/.github/workflows/pull-request-bot.yml b/.github/workflows/pull-request-bot.yml index 4599adfda5e..28a5c8aea67 100644 --- a/.github/workflows/pull-request-bot.yml +++ b/.github/workflows/pull-request-bot.yml @@ -135,45 +135,10 @@ jobs: run: | aws s3 cp target/doc "s3://${S3_BUCKET_NAME}/docs/${{ inputs.head_revision }}" --recursive - compiletime-benchmark: - runs-on: ubuntu-latest - name: Run Compiletime Benchmark - permissions: - id-token: write - contents: read - pull-requests: write - outputs: - compiletime-benchmark: ${{ steps.compiletime-benchmark.outputs.compiletime-benchmark }} - steps: - - uses: actions/checkout@v3 - - uses: actions/cache@v3 - name: Gradle Cache - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} - restore-keys: | - ${{ runner.os }}-gradle- - # JDK is needed to generate code - - name: Set up JDK - uses: actions/setup-java@v3 - with: - distribution: corretto - java-package: jdk - java-version: ${{ env.java_version }} - - uses: dtolnay/rust-toolchain@master - with: - toolchain: ${{ env.rust_version }} - - name: run benchmark - id: run-compiletime-benchmark - run: bash tools/ci-scripts/compiletime-benchmark && cat /tmp/compiletime-benchmark.md >> "$GITHUB_OUTPUT" - post-bot-comment: needs: - generate-diff - generate-doc-preview - - compiletime-benchmark runs-on: ubuntu-latest name: Post bot comment permissions: @@ -199,8 +164,6 @@ jobs: issue_number: ${{ inputs.issue_number }}, owner: context.repo.owner, repo: context.repo.repo, - body: '${{ steps.compiletime-benchmark.outputs.compiletime-benchmark }}\n\n' + - '${{ steps.bot-messages.outputs.codegen-diff }}\n\n' + + body: '${{ steps.bot-messages.outputs.codegen-diff }}\n\n' + '${{ needs.generate-doc-preview.outputs.bot-message }}\n\n' - }) diff --git a/tools/ci-scripts/compiletime-benchmark b/tools/ci-scripts/compiletime-benchmark deleted file mode 100755 index f05f4967347..00000000000 --- a/tools/ci-scripts/compiletime-benchmark +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash -# -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 -# -C_YELLOW='\033[1;33m' -C_RESET='\033[0m' -set -xe - -cd smithy-rs -DIR=$PWD - -function log_time() { - cargo clean - echo "$1" - cargo build - { time $1; } &> tmp_time_log.txt - cat tmp_time_log.txt - cat tmp_time_log.txt | grep real >> /tmp/compiletime-benchmark.txt -} - -function compile() { - cd $1 && - export RUSTFLAGS="" && - cargo build && # this is for downloading crates - cargo clean && - log_time "cargo build" && - log_time "cargo build --release" && - export RUSTFLAGS="--cfg aws_sdk_unstable" && - log_time "cargo build --all-features" && - log_time "cargo build --release --all-features" -} - -./gradlew :aws:sdk:assemble - -for variable in $(dir "aws/sdk/build/aws-sdk/sdk"); do - echo $variable - if [[ $variable != *"aws-"* ]]; then - echo "START" &>>/tmp/compiletime-benchmark.txt - echo "$variable" &>>/tmp/compiletime-benchmark.txt - compile "$DIR/aws/sdk/build/aws-sdk/sdk/$variable" - echo "END" &>> /tmp/compiletime-benchmark.txt - fi -done - -cd $DIR -python3 tools/compiletime-benchmark/format.py diff --git a/tools/compiletime-benchmark/format.py b/tools/compiletime-benchmark/format.py deleted file mode 100644 index d50fad59e4e..00000000000 --- a/tools/compiletime-benchmark/format.py +++ /dev/null @@ -1,53 +0,0 @@ -# -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0 -# - -import itertools - - -def main(): - markdown = parser() - print(markdown) - # write file - with open("/tmp/compiletime-benchmark.md", "w") as f: - f.write(markdown) - f.flush() - f.close() - - -def parser() -> str: - # read file - f = open("/tmp/compiletime-benchmark.txt", "r").read() - iter = map(lambda x: x.split("END"), f.split("START")) - iter = itertools.chain.from_iterable(iter) - - # I could've used a dataframe like pandas but this works. - markdown = "| sdk name | dev | release | dev all features | release all features |" - markdown += "\n" - markdown += "| -------- | --- | ------- | ---------------- | -------------------- |" - - markdown += "\n" - for i in iter: - outputs = [] - print(i) - for l in i.splitlines(): - if not "+" in l: - outputs.append(l.replace("real", "").replace(" ", "", 16)) - - if len(outputs) != 6: - continue - - outputs = outputs[1:] - sdk_name = outputs[0] - row = f"|{sdk_name}|" + \ - "|".join(outputs[1:]) + "|" - - markdown += row - markdown += "\n" - - return markdown - - -if __name__ == '__main__': - main() From c99809473597bd83196ae25d9f6035c81ffc2ee3 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 20:35:17 +0900 Subject: [PATCH 273/312] Update check-aws-sdk-smoketest-docs-clippy-udeps --- tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps b/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps index 45664e156ab..0386da42db3 100755 --- a/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps +++ b/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps @@ -5,6 +5,7 @@ # set -eux + export RUSTFLAG="--cfg aws_sdk_unstable" # Docs, clippy, etc on the smoketest itself pushd aws-sdk-smoketest &>/dev/null From 210b9c855bcf25c38c9bbecc6da8ab36e9eb7b4a Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 11:45:38 +0000 Subject: [PATCH 274/312] asdf --- tools/ci-scripts/check-aws-sdk-adhoc-tests | 2 ++ tools/ci-scripts/check-aws-sdk-orchestrator-impl | 2 ++ tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps | 2 ++ tools/ci-scripts/check-aws-sdk-smoketest-unit-tests | 3 +++ tools/ci-scripts/check-client-codegen-integration-tests | 3 +++ tools/ci-scripts/check-only-aws-sdk-services | 3 +++ 6 files changed, 15 insertions(+) diff --git a/tools/ci-scripts/check-aws-sdk-adhoc-tests b/tools/ci-scripts/check-aws-sdk-adhoc-tests index 911d11f998d..7ccb54a7163 100755 --- a/tools/ci-scripts/check-aws-sdk-adhoc-tests +++ b/tools/ci-scripts/check-aws-sdk-adhoc-tests @@ -7,6 +7,8 @@ C_YELLOW='\033[1;33m' C_RESET='\033[0m' +export RUSTFLAG="--cfg aws_sdk_unstable" + set -eu cd smithy-rs diff --git a/tools/ci-scripts/check-aws-sdk-orchestrator-impl b/tools/ci-scripts/check-aws-sdk-orchestrator-impl index b86ebf3f0f6..04a9fe7aa1f 100755 --- a/tools/ci-scripts/check-aws-sdk-orchestrator-impl +++ b/tools/ci-scripts/check-aws-sdk-orchestrator-impl @@ -9,6 +9,8 @@ C_YELLOW='\033[1;33m' C_RESET='\033[0m' +export RUSTFLAG="--cfg aws_sdk_unstable" + set -eu cd smithy-rs diff --git a/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps b/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps index 38942ef0678..af6e0dd3943 100755 --- a/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps +++ b/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps @@ -6,6 +6,8 @@ set -eux +export RUSTFLAG="--cfg aws_sdk_unstable" + # Docs, clippy, etc on the smoketest itself pushd aws-sdk-smoketest &>/dev/null diff --git a/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests b/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests index 293af9b43f1..a04af9e87d0 100755 --- a/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests +++ b/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests @@ -5,5 +5,8 @@ # set -eux + +export RUSTFLAG="--cfg aws_sdk_unstable" + cd aws-sdk-smoketest cargo test --all-features diff --git a/tools/ci-scripts/check-client-codegen-integration-tests b/tools/ci-scripts/check-client-codegen-integration-tests index 86013436c51..32112445f23 100755 --- a/tools/ci-scripts/check-client-codegen-integration-tests +++ b/tools/ci-scripts/check-client-codegen-integration-tests @@ -5,6 +5,9 @@ # set -eux + +export RUSTFLAG="--cfg aws_sdk_unstable" + cd smithy-rs # TODO(enableNewSmithyRuntimeCleanup): Only run the orchestrator version of this diff --git a/tools/ci-scripts/check-only-aws-sdk-services b/tools/ci-scripts/check-only-aws-sdk-services index b15c4133b3d..17d90b2ef9e 100755 --- a/tools/ci-scripts/check-only-aws-sdk-services +++ b/tools/ci-scripts/check-only-aws-sdk-services @@ -7,6 +7,9 @@ # this job runs `cargo check` only instead of `cargo test --all-features` set -eux + +export RUSTFLAG="--cfg aws_sdk_unstable" + cd aws-sdk # Remove examples from workspace From 77bd0ded77378cc1f414f0211ff9ae190ac180fe Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 20:50:20 +0900 Subject: [PATCH 275/312] Update CodegenDelegator.kt --- .../amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt index ed1f79903d0..aaac5553e70 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt @@ -258,6 +258,7 @@ fun WriterDelegator.finalize( LibRsGenerator(settings, model, libRsCustomizations, requireDocs).render(it) } val cargoDependencies = + this.dependencies.map { RustDependency.fromSymbolDependency(it) } .filterIsInstance().distinct() .mergeDependencyFeatures() From 92cd3f839c6546ab8bc1a409abc5d0b7f6c41d0c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 20:50:59 +0900 Subject: [PATCH 276/312] Update LibRsGenerator.kt --- .../smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt index ebb2da7ea08..1da954f0860 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt @@ -22,7 +22,6 @@ sealed class ModuleDocSection { data class ServiceDocs(val documentationTraitValue: String?) : ModuleDocSection() object CrateOrganization : ModuleDocSection() object Examples : ModuleDocSection() - object UnstableFeature : ModuleDocSection() } sealed class LibRsSection(name: String) : Section(name) { From bbb321e6ed56a5292f997ec7c8d97d851b624f3d Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 11:55:06 +0000 Subject: [PATCH 277/312] asdf --- .../client/smithy/customize/SerdeDecorator.kt | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index fba326f85c1..aaa33f1817b 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -15,9 +15,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection import software.amazon.smithy.rust.codegen.core.smithy.generators.ModuleDocSection /** - * This class, - * - Adds serde as a dependency - * + * Decorator that adds the `serde-serialize` and `serde-deserialize` features. */ class SerdeDecorator : ClientCodegenDecorator { override val name: String = "SerdeDecorator" @@ -38,17 +36,31 @@ class SerdeDecorator : ClientCodegenDecorator { } class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { + companion object { + const val SerdeInfoText = """## How to enable `Serialize` and `Deserialize` + + This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, + but those traits are behind feature gate. + + As they increase it's compile time dramatically, you should not turn them on unless it's necessary. + Furthermore, implementation of serde is still unstable, and implementation may change anytime in future. + + To enable traits, you must pass `aws_sdk_unstable` to RUSTFLAGS and enable `serde-serialize` or `serde-deserialize` feature. + + e.g. + ```bash,no_run + export RUSTFLAGS="--cfg aws_sdk_unstable" + cargo build --features serde-serialize serde-deserialize + ``` + + If you enable `serde-serialize` and/or `serde-deserialize` without `RUSTFLAGS="--cfg aws_sdk_unstable"`, + compilation will fail with warning. + + """ + } override fun section(section: LibRsSection): Writable { return if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.UnstableFeature) { - writable { - """ - ## How to enable `Serialize` and `Deserialize` - This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, - but those traits are behind feature gate. - - As they increase it's compile time dramatically, you should not turn them on unless it's necessary. - """.trimIndent() - } + writable { SerdeInfoText.trimIndent() } } else { emptySection } From fa8c04b6dc5a52ae632effb0aef2fc776044c93e Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 12:00:53 +0000 Subject: [PATCH 278/312] asdf --- .../core/smithy/generators/LibRsGenerator.kt | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt index 90cd82e4e94..ebb2da7ea08 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt @@ -63,27 +63,6 @@ class LibRsGenerator( containerDocs(escape(defaultServiceDocs ?: settings.moduleName)) } - // Unstable Feature - docSection(ModuleDocSection.UnstableFeature).also { docs -> - if (docs.isNotEmpty()) { - val awsSdkUnstable = """ - # Unstable Features - Some highly experimental features requires passing `aws_sdk_unstable` to RUSTFLAGS. - e.g. - ```bash - export RUSTFLAGS="--cfg aws_sdk_unstable" - cargo build --features serde-serialize - ``` - - If you enable unstable features without enabling `RUSTFLAGS="--cfg aws_sdk_unstable"`, compilation will fail with a message describing the reason. - """.trimIndent() - containerDocs(awsSdkUnstable) - docs.forEach { writeTo -> - writeTo(this) - } - } - } - // Crate Organization docSection(ModuleDocSection.CrateOrganization).also { docs -> if (docs.isNotEmpty()) { From 918f2cdbdf6a0ada2fcf0003ee5047c447bd716a Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 21:04:20 +0900 Subject: [PATCH 279/312] Update LibRsGenerator.kt --- .../smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt index ebb2da7ea08..1da954f0860 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt @@ -22,7 +22,6 @@ sealed class ModuleDocSection { data class ServiceDocs(val documentationTraitValue: String?) : ModuleDocSection() object CrateOrganization : ModuleDocSection() object Examples : ModuleDocSection() - object UnstableFeature : ModuleDocSection() } sealed class LibRsSection(name: String) : Section(name) { From 8802e835125e9bb61f20502eb2dc2a040be73901 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 21:05:11 +0900 Subject: [PATCH 280/312] Update SerdeDecorator.kt --- .../rust/codegen/client/smithy/customize/SerdeDecorator.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index aaa33f1817b..6602cbd0d9b 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -58,6 +58,8 @@ class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibR """ } + /* + I initially tried to implement with LibRsCustomization but it didn't work some how. override fun section(section: LibRsSection): Writable { return if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.UnstableFeature) { writable { SerdeInfoText.trimIndent() } @@ -65,4 +67,5 @@ class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibR emptySection } } + */ } From 5211559902a61f65c26d6a915407247b94bd9b4a Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 12:15:54 +0000 Subject: [PATCH 281/312] asdf --- .../client/smithy/customize/SerdeDecorator.kt | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 6602cbd0d9b..7c887e456e7 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -29,13 +29,7 @@ class SerdeDecorator : ClientCodegenDecorator { rustCrate.mergeFeature(feature("serde-deserialize")) } - override fun libRsCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = baseCustomizations + SerdeDocGenerator(codegenContext) -} - -class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { + // I initially tried to implement with LibRsCustomization but it didn't work some how. companion object { const val SerdeInfoText = """## How to enable `Serialize` and `Deserialize` @@ -58,14 +52,4 @@ class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibR """ } - /* - I initially tried to implement with LibRsCustomization but it didn't work some how. - override fun section(section: LibRsSection): Writable { - return if (section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.UnstableFeature) { - writable { SerdeInfoText.trimIndent() } - } else { - emptySection - } - } - */ } From c4a41c26eca2d7209c8a5c7b1d4246b849d1ef0c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 16 Jul 2023 12:30:41 +0000 Subject: [PATCH 282/312] update --- .../rust/codegen/client/smithy/customize/SerdeDecorator.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 7c887e456e7..84266f61340 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -7,12 +7,7 @@ package software.amazon.smithy.rust.codegen.client.smithy.customize import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.core.rustlang.Feature -import software.amazon.smithy.rust.codegen.core.rustlang.Writable -import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RustCrate -import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization -import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection -import software.amazon.smithy.rust.codegen.core.smithy.generators.ModuleDocSection /** * Decorator that adds the `serde-serialize` and `serde-deserialize` features. From dd4a511f2b02885eacdd352d91b18326e8ea712a Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Mon, 17 Jul 2023 05:36:35 +0000 Subject: [PATCH 283/312] asdf --- .devcontainer/devcontainer.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100755 index 00000000000..b332f39d783 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,22 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu +{ + "name": "Ubuntu", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/base:jammy" + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} From 982a95ddb30139f34f79713d0418f496a29ce8f4 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Tue, 18 Jul 2023 09:13:29 +0900 Subject: [PATCH 284/312] Delete devcontainer.json --- .devcontainer/devcontainer.json | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100755 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100755 index b332f39d783..00000000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,22 +0,0 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu -{ - "name": "Ubuntu", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/base:jammy" - - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "uname -a", - - // Configure tool-specific properties. - // "customizations": {}, - - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" -} From c969377905e78ddfa5fd3039c838b5dedb529e45 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 30 Jul 2023 09:09:53 +0000 Subject: [PATCH 285/312] fix --- .../software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt index c0a203f0e9e..90b8168f152 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt @@ -11,7 +11,6 @@ import org.jsoup.nodes.TextNode import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator -import software.amazon.smithy.rust.codegen.client.smithy.customize.SerdeDocGenerator import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable @@ -134,7 +133,7 @@ internal class AwsCrateDocGenerator(private val codegenContext: ClientCodegenCon val compileExample = AwsDocs.canRelyOnAwsConfig(codegenContext) val exampleMode = if (compileExample) "no_run" else "ignore" - val serdeInfoText = "##" + SerdeDocGenerator.SerdeInfoText + val serdeInfoText = "##" + SerdeDecorator.SerdeInfoText template( asComments, """ From 7974c27a254a09acb79eef738559549f7733a826 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Sun, 6 Aug 2023 11:11:24 +0900 Subject: [PATCH 286/312] ok --- .../software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt index 90b8168f152..deec4d3cacc 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt @@ -11,6 +11,7 @@ import org.jsoup.nodes.TextNode import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator +import software.amazon.smithy.rust.codegen.client.smithy.customize.SerdeDecorator import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable @@ -133,6 +134,7 @@ internal class AwsCrateDocGenerator(private val codegenContext: ClientCodegenCon val compileExample = AwsDocs.canRelyOnAwsConfig(codegenContext) val exampleMode = if (compileExample) "no_run" else "ignore" + val serdeInfoText = "##" + SerdeDecorator.SerdeInfoText template( asComments, From 4d65b276dd53bbffea906308fba7ee15f290e095 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Sun, 6 Aug 2023 11:15:44 +0900 Subject: [PATCH 287/312] ok --- .../amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt index aaac5553e70..5ae40c3574d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt @@ -258,7 +258,7 @@ fun WriterDelegator.finalize( LibRsGenerator(settings, model, libRsCustomizations, requireDocs).render(it) } val cargoDependencies = - + this.dependencies.map { RustDependency.fromSymbolDependency(it) } .filterIsInstance().distinct() .mergeDependencyFeatures() From 7cbd61086ac91658057eebe2499e7aa1a9598be2 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Sun, 6 Aug 2023 12:36:35 +0900 Subject: [PATCH 288/312] ok --- buildSrc/src/main/kotlin/CodegenTestCommon.kt | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/buildSrc/src/main/kotlin/CodegenTestCommon.kt b/buildSrc/src/main/kotlin/CodegenTestCommon.kt index cc996eae82d..6a3eb5d7860 100644 --- a/buildSrc/src/main/kotlin/CodegenTestCommon.kt +++ b/buildSrc/src/main/kotlin/CodegenTestCommon.kt @@ -7,6 +7,7 @@ import org.gradle.api.Project import org.gradle.api.tasks.Exec import org.gradle.kotlin.dsl.extra import org.gradle.kotlin.dsl.register +import org.gradle.kotlin.dsl.setEnvironment import java.io.File /** @@ -246,29 +247,33 @@ fun Project.registerCargoCommandsTasks( this.tasks.register(Cargo.CHECK.toString) { dependsOn(dependentTasks) workingDir(outputDir) - environment("RUSTFLAGS", "--cfg aws_sdk_unstable") - commandLine("cargo", "check", "--lib", "--tests", "--benches", "--all-features") + + this.commandLine("cargo", "check", "--lib", "--tests", "--benches", "--all-features") + this.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") } this.tasks.register(Cargo.TEST.toString) { dependsOn(dependentTasks) workingDir(outputDir) - environment("RUSTFLAGS", "--cfg aws_sdk_unstable") - commandLine("cargo", "test", "--all-features", "--no-fail-fast") + + this.commandLine("cargo", "test", "--all-features", "--no-fail-fast") + this.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") } this.tasks.register(Cargo.DOCS.toString) { dependsOn(dependentTasks) workingDir(outputDir) environment("RUSTDOCFLAGS", defaultRustDocFlags) - environment("RUSTFLAGS", "--cfg aws_sdk_unstable") - commandLine("cargo", "doc", "--no-deps", "--document-private-items") + + this.commandLine("cargo", "doc", "--no-deps", "--document-private-items") + this.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") } this.tasks.register(Cargo.CLIPPY.toString) { dependsOn(dependentTasks) workingDir(outputDir) - environment("RUSTFLAGS", "--cfg aws_sdk_unstable") - commandLine("cargo", "clippy") + + this.commandLine("cargo", "clippy") + this.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") } } From db5fc497cee1187b8c592c82f5ed2722cc0a02a4 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Sun, 6 Aug 2023 12:53:49 +0900 Subject: [PATCH 289/312] ok --- buildSrc/src/main/kotlin/CodegenTestCommon.kt | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/buildSrc/src/main/kotlin/CodegenTestCommon.kt b/buildSrc/src/main/kotlin/CodegenTestCommon.kt index 6a3eb5d7860..f55a428ad12 100644 --- a/buildSrc/src/main/kotlin/CodegenTestCommon.kt +++ b/buildSrc/src/main/kotlin/CodegenTestCommon.kt @@ -248,16 +248,18 @@ fun Project.registerCargoCommandsTasks( dependsOn(dependentTasks) workingDir(outputDir) - this.commandLine("cargo", "check", "--lib", "--tests", "--benches", "--all-features") - this.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") + val cmd = commandLine("cargo", "check", "--lib", "--tests", "--benches", "--all-features") + cmd.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") + cmd } this.tasks.register(Cargo.TEST.toString) { dependsOn(dependentTasks) workingDir(outputDir) - this.commandLine("cargo", "test", "--all-features", "--no-fail-fast") - this.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") + val cmd = commandLine("cargo", "test", "--all-features", "--no-fail-fast") + cmd.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") + cmd } this.tasks.register(Cargo.DOCS.toString) { @@ -265,15 +267,17 @@ fun Project.registerCargoCommandsTasks( workingDir(outputDir) environment("RUSTDOCFLAGS", defaultRustDocFlags) - this.commandLine("cargo", "doc", "--no-deps", "--document-private-items") - this.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") + val cmd = commandLine("cargo", "doc", "--no-deps", "--document-private-items") + cmd.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") + cmd } this.tasks.register(Cargo.CLIPPY.toString) { dependsOn(dependentTasks) workingDir(outputDir) - this.commandLine("cargo", "clippy") - this.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") + val cmd = commandLine("cargo", "clippy") + cmd.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") + cmd } } From 5ce4723a422358d3281bb9d53fa37fd44c54b39c Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Sun, 6 Aug 2023 13:10:58 +0900 Subject: [PATCH 290/312] ok --- buildSrc/src/main/kotlin/CodegenTestCommon.kt | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/buildSrc/src/main/kotlin/CodegenTestCommon.kt b/buildSrc/src/main/kotlin/CodegenTestCommon.kt index f55a428ad12..4c231724924 100644 --- a/buildSrc/src/main/kotlin/CodegenTestCommon.kt +++ b/buildSrc/src/main/kotlin/CodegenTestCommon.kt @@ -237,6 +237,7 @@ fun Project.registerCargoCommandsTasks( outputDir: File, defaultRustDocFlags: String, ) { + val env = mapOf("RUSTFLAGS" to "--cfg aws_sdk_unstable") val dependentTasks = listOfNotNull( "assemble", @@ -248,18 +249,14 @@ fun Project.registerCargoCommandsTasks( dependsOn(dependentTasks) workingDir(outputDir) - val cmd = commandLine("cargo", "check", "--lib", "--tests", "--benches", "--all-features") - cmd.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") - cmd + commandLine("cargo", "check", "--lib", "--tests", "--benches", "--all-features").environment(env) } this.tasks.register(Cargo.TEST.toString) { dependsOn(dependentTasks) workingDir(outputDir) - val cmd = commandLine("cargo", "test", "--all-features", "--no-fail-fast") - cmd.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") - cmd + commandLine("cargo", "test", "--all-features", "--no-fail-fast").environment(env) } this.tasks.register(Cargo.DOCS.toString) { @@ -267,17 +264,13 @@ fun Project.registerCargoCommandsTasks( workingDir(outputDir) environment("RUSTDOCFLAGS", defaultRustDocFlags) - val cmd = commandLine("cargo", "doc", "--no-deps", "--document-private-items") - cmd.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") - cmd + commandLine("cargo", "doc", "--no-deps", "--document-private-items").environment(env) } this.tasks.register(Cargo.CLIPPY.toString) { dependsOn(dependentTasks) workingDir(outputDir) - val cmd = commandLine("cargo", "clippy") - cmd.setEnvironment("RUSTFLAGS" to "--cfg aws_sdk_unstable") - cmd + commandLine("cargo", "clippy").environment(env) } } From 5345cd0744973d83d3bcf0e29b2693f4d1fd6deb Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Fri, 11 Aug 2023 22:25:13 +0900 Subject: [PATCH 291/312] RUSTFLAG*S* --- .../amazon/smithy/rust/codegen/core/rustlang/RustType.kt | 2 +- tools/ci-scripts/check-aws-sdk-adhoc-tests | 2 +- tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps | 2 +- tools/ci-scripts/check-aws-sdk-smoketest-unit-tests | 2 +- tools/ci-scripts/check-client-codegen-integration-tests | 2 +- tools/ci-scripts/check-only-aws-sdk-services | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index 9e9a1cb5630..b1412106967 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -491,7 +491,7 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { You must pass \"aws_sdk_unstable\" flag to RUSTFLAG. e.g. ```bash - export RUSTFLAG=\"--cfg aws_sdk_unstable\" + export RUSTFLAGS=\"--cfg aws_sdk_unstable\" ``` Learn more about this on this SDK's document. """.trimIndent() diff --git a/tools/ci-scripts/check-aws-sdk-adhoc-tests b/tools/ci-scripts/check-aws-sdk-adhoc-tests index 7ccb54a7163..362d54ab542 100755 --- a/tools/ci-scripts/check-aws-sdk-adhoc-tests +++ b/tools/ci-scripts/check-aws-sdk-adhoc-tests @@ -7,7 +7,7 @@ C_YELLOW='\033[1;33m' C_RESET='\033[0m' -export RUSTFLAG="--cfg aws_sdk_unstable" +export RUSTFLAGS="--cfg aws_sdk_unstable" set -eu cd smithy-rs diff --git a/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps b/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps index 0386da42db3..79969e1661e 100755 --- a/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps +++ b/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps @@ -6,7 +6,7 @@ set -eux -export RUSTFLAG="--cfg aws_sdk_unstable" +export RUSTFLAGS="--cfg aws_sdk_unstable" # Docs, clippy, etc on the smoketest itself pushd aws-sdk-smoketest &>/dev/null diff --git a/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests b/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests index e0dbf5f5559..1e74500f166 100755 --- a/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests +++ b/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests @@ -5,7 +5,7 @@ # set -eux -export RUSTFLAG="--cfg aws_sdk_unstable" +export RUSTFLAGS="--cfg aws_sdk_unstable" cd aws-sdk-smoketest cargo test --all-features diff --git a/tools/ci-scripts/check-client-codegen-integration-tests b/tools/ci-scripts/check-client-codegen-integration-tests index 2f77e8598d4..87914bdb81f 100755 --- a/tools/ci-scripts/check-client-codegen-integration-tests +++ b/tools/ci-scripts/check-client-codegen-integration-tests @@ -6,7 +6,7 @@ set -eux -export RUSTFLAG="--cfg aws_sdk_unstable" +export RUSTFLAGS="--cfg aws_sdk_unstable" cd smithy-rs # TODO(enableNewSmithyRuntimeCleanup): Only run the orchestrator version of this diff --git a/tools/ci-scripts/check-only-aws-sdk-services b/tools/ci-scripts/check-only-aws-sdk-services index f38a75ac8bf..11470c1b0fd 100755 --- a/tools/ci-scripts/check-only-aws-sdk-services +++ b/tools/ci-scripts/check-only-aws-sdk-services @@ -7,7 +7,7 @@ # this job runs `cargo check` only instead of `cargo test --all-features` set -eux -export RUSTFLAG="--cfg aws_sdk_unstable" +export RUSTFLAGS="--cfg aws_sdk_unstable" cd aws-sdk From e4157d3625d1699004db682daf17ce6f301480b9 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 11 Aug 2023 22:50:54 +0900 Subject: [PATCH 292/312] Update CodegenTestCommon.kt --- buildSrc/src/main/kotlin/CodegenTestCommon.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/CodegenTestCommon.kt b/buildSrc/src/main/kotlin/CodegenTestCommon.kt index 4c231724924..c62abd60072 100644 --- a/buildSrc/src/main/kotlin/CodegenTestCommon.kt +++ b/buildSrc/src/main/kotlin/CodegenTestCommon.kt @@ -7,7 +7,6 @@ import org.gradle.api.Project import org.gradle.api.tasks.Exec import org.gradle.kotlin.dsl.extra import org.gradle.kotlin.dsl.register -import org.gradle.kotlin.dsl.setEnvironment import java.io.File /** From 6d007951a6c49f29f1878ee7fba7865a371a04e1 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Fri, 11 Aug 2023 14:36:14 +0000 Subject: [PATCH 293/312] test --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f4208b271ac..c78119969b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,7 @@ env: rust_toolchain_components: clippy,rustfmt ENCRYPTED_DOCKER_PASSWORD: ${{ secrets.ENCRYPTED_DOCKER_PASSWORD }} DOCKER_LOGIN_TOKEN_PASSPHRASE: ${{ secrets.DOCKER_LOGIN_TOKEN_PASSPHRASE }} + RUSTFLAGS: "--cfg aws_sdk_unstable" jobs: # The `generate` job runs scripts that produce artifacts that are required by the `test` job, From fb9892f4f407042a83d752708db8d669afcbda14 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Sat, 12 Aug 2023 01:49:08 +0900 Subject: [PATCH 294/312] ok --- buildSrc/src/main/kotlin/CodegenTestCommon.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/CodegenTestCommon.kt b/buildSrc/src/main/kotlin/CodegenTestCommon.kt index 4c231724924..dd117045a56 100644 --- a/buildSrc/src/main/kotlin/CodegenTestCommon.kt +++ b/buildSrc/src/main/kotlin/CodegenTestCommon.kt @@ -248,8 +248,8 @@ fun Project.registerCargoCommandsTasks( this.tasks.register(Cargo.CHECK.toString) { dependsOn(dependentTasks) workingDir(outputDir) - - commandLine("cargo", "check", "--lib", "--tests", "--benches", "--all-features").environment(env) + environment("RUSTFLAGS", "--cfg aws_sdk_unstable") + commandLine("cargo", "check", "--lib", "--tests", "--benches", "--all-features") } this.tasks.register(Cargo.TEST.toString) { From 6b081781a897385009f57db6920b9e93a4e7225c Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sat, 12 Aug 2023 01:50:17 +0900 Subject: [PATCH 295/312] Update ci.yml --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c78119969b5..f4208b271ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,6 @@ env: rust_toolchain_components: clippy,rustfmt ENCRYPTED_DOCKER_PASSWORD: ${{ secrets.ENCRYPTED_DOCKER_PASSWORD }} DOCKER_LOGIN_TOKEN_PASSPHRASE: ${{ secrets.DOCKER_LOGIN_TOKEN_PASSPHRASE }} - RUSTFLAGS: "--cfg aws_sdk_unstable" jobs: # The `generate` job runs scripts that produce artifacts that are required by the `test` job, From e280f62a545dd98a783ee67d0c8ed0788b44c6e7 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 13 Aug 2023 01:20:41 +0900 Subject: [PATCH 296/312] Update ci.yml --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f4208b271ac..702b3a525f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,8 @@ env: rust_toolchain_components: clippy,rustfmt ENCRYPTED_DOCKER_PASSWORD: ${{ secrets.ENCRYPTED_DOCKER_PASSWORD }} DOCKER_LOGIN_TOKEN_PASSPHRASE: ${{ secrets.DOCKER_LOGIN_TOKEN_PASSPHRASE }} - + RUSTFLAGS: --cfg aws_sdk_unstable + jobs: # The `generate` job runs scripts that produce artifacts that are required by the `test` job, # and also runs some checks/lints so that those are run sooner rather than later. From 14040cb20a17d846f94a2872f0d8b0118f8813f1 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Wed, 23 Aug 2023 23:10:35 +0900 Subject: [PATCH 297/312] revert --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c78119969b5..f4208b271ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,6 @@ env: rust_toolchain_components: clippy,rustfmt ENCRYPTED_DOCKER_PASSWORD: ${{ secrets.ENCRYPTED_DOCKER_PASSWORD }} DOCKER_LOGIN_TOKEN_PASSPHRASE: ${{ secrets.DOCKER_LOGIN_TOKEN_PASSPHRASE }} - RUSTFLAGS: "--cfg aws_sdk_unstable" jobs: # The `generate` job runs scripts that produce artifacts that are required by the `test` job, From 316010ea887c9f91f73e38ff07f9a1db80b7c131 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Wed, 23 Aug 2023 23:12:46 +0900 Subject: [PATCH 298/312] remove export RUSTFLAGS="--cfg aws_sdk_unstable" --- tools/ci-scripts/check-aws-sdk-adhoc-tests | 2 +- tools/ci-scripts/check-aws-sdk-smoketest-unit-tests | 2 +- tools/ci-scripts/check-client-codegen-integration-tests | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/ci-scripts/check-aws-sdk-adhoc-tests b/tools/ci-scripts/check-aws-sdk-adhoc-tests index 362d54ab542..815aa4d83d4 100755 --- a/tools/ci-scripts/check-aws-sdk-adhoc-tests +++ b/tools/ci-scripts/check-aws-sdk-adhoc-tests @@ -7,7 +7,7 @@ C_YELLOW='\033[1;33m' C_RESET='\033[0m' -export RUSTFLAGS="--cfg aws_sdk_unstable" + set -eu cd smithy-rs diff --git a/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests b/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests index 1e74500f166..db7f9d95fa1 100755 --- a/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests +++ b/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests @@ -5,7 +5,7 @@ # set -eux -export RUSTFLAGS="--cfg aws_sdk_unstable" + cd aws-sdk-smoketest cargo test --all-features diff --git a/tools/ci-scripts/check-client-codegen-integration-tests b/tools/ci-scripts/check-client-codegen-integration-tests index 87914bdb81f..83e475c10c5 100755 --- a/tools/ci-scripts/check-client-codegen-integration-tests +++ b/tools/ci-scripts/check-client-codegen-integration-tests @@ -6,7 +6,7 @@ set -eux -export RUSTFLAGS="--cfg aws_sdk_unstable" + cd smithy-rs # TODO(enableNewSmithyRuntimeCleanup): Only run the orchestrator version of this From c948f8df3aa2e9664ca7d67dfc5675641f232cc7 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Wed, 23 Aug 2023 23:14:26 +0900 Subject: [PATCH 299/312] # modified: .github/workflows/ci.yml --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f4208b271ac..fba10185c8e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,6 @@ env: rust_toolchain_components: clippy,rustfmt ENCRYPTED_DOCKER_PASSWORD: ${{ secrets.ENCRYPTED_DOCKER_PASSWORD }} DOCKER_LOGIN_TOKEN_PASSPHRASE: ${{ secrets.DOCKER_LOGIN_TOKEN_PASSPHRASE }} - jobs: # The `generate` job runs scripts that produce artifacts that are required by the `test` job, # and also runs some checks/lints so that those are run sooner rather than later. From 334f428299e8c13bd91741b7652b7737e58add99 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Wed, 23 Aug 2023 23:15:42 +0900 Subject: [PATCH 300/312] asdf --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fba10185c8e..f4208b271ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,7 @@ env: rust_toolchain_components: clippy,rustfmt ENCRYPTED_DOCKER_PASSWORD: ${{ secrets.ENCRYPTED_DOCKER_PASSWORD }} DOCKER_LOGIN_TOKEN_PASSPHRASE: ${{ secrets.DOCKER_LOGIN_TOKEN_PASSPHRASE }} + jobs: # The `generate` job runs scripts that produce artifacts that are required by the `test` job, # and also runs some checks/lints so that those are run sooner rather than later. From 43f1677d67882ca70f5dc335638e434a2c1fb1c4 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Wed, 23 Aug 2023 23:17:08 +0900 Subject: [PATCH 301/312] asdf --- tools/ci-scripts/check-aws-sdk-adhoc-tests | 2 -- tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps | 1 - tools/ci-scripts/check-aws-sdk-smoketest-unit-tests | 2 -- tools/ci-scripts/check-client-codegen-integration-tests | 2 -- tools/ci-scripts/check-only-aws-sdk-services | 2 -- 5 files changed, 9 deletions(-) diff --git a/tools/ci-scripts/check-aws-sdk-adhoc-tests b/tools/ci-scripts/check-aws-sdk-adhoc-tests index 815aa4d83d4..911d11f998d 100755 --- a/tools/ci-scripts/check-aws-sdk-adhoc-tests +++ b/tools/ci-scripts/check-aws-sdk-adhoc-tests @@ -7,8 +7,6 @@ C_YELLOW='\033[1;33m' C_RESET='\033[0m' - - set -eu cd smithy-rs diff --git a/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps b/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps index 79969e1661e..38942ef0678 100755 --- a/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps +++ b/tools/ci-scripts/check-aws-sdk-smoketest-docs-clippy-udeps @@ -6,7 +6,6 @@ set -eux -export RUSTFLAGS="--cfg aws_sdk_unstable" # Docs, clippy, etc on the smoketest itself pushd aws-sdk-smoketest &>/dev/null diff --git a/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests b/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests index db7f9d95fa1..bbf13d54b35 100755 --- a/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests +++ b/tools/ci-scripts/check-aws-sdk-smoketest-unit-tests @@ -5,8 +5,6 @@ # set -eux - - cd aws-sdk-smoketest cargo test --all-features diff --git a/tools/ci-scripts/check-client-codegen-integration-tests b/tools/ci-scripts/check-client-codegen-integration-tests index 83e475c10c5..86013436c51 100755 --- a/tools/ci-scripts/check-client-codegen-integration-tests +++ b/tools/ci-scripts/check-client-codegen-integration-tests @@ -5,8 +5,6 @@ # set -eux - - cd smithy-rs # TODO(enableNewSmithyRuntimeCleanup): Only run the orchestrator version of this diff --git a/tools/ci-scripts/check-only-aws-sdk-services b/tools/ci-scripts/check-only-aws-sdk-services index 11470c1b0fd..b15c4133b3d 100755 --- a/tools/ci-scripts/check-only-aws-sdk-services +++ b/tools/ci-scripts/check-only-aws-sdk-services @@ -7,8 +7,6 @@ # this job runs `cargo check` only instead of `cargo test --all-features` set -eux -export RUSTFLAGS="--cfg aws_sdk_unstable" - cd aws-sdk # Remove examples from workspace From 4ab1f9c8f6bee1eaad6beab578145e1374925697 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Wed, 23 Aug 2023 23:18:21 +0900 Subject: [PATCH 302/312] asdf --- .../smithy/rust/codegen/core/rustlang/CargoDependency.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt index 8f3a02b499f..73a5e9ebbe6 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt @@ -307,8 +307,5 @@ data class CargoDependency( // behind feature-gate val Serde = CargoDependency("serde", CratesIo("1.0"), features = setOf("derive"), scope = DependencyScope.CfgUnstable) - - // Compile Guard - val CompileGuard = CargoDependency("compilation-guard", CratesIo("0.1.1")) } } From c91a155303ea8b04b861e8b2353aa6326c09d05f Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Wed, 23 Aug 2023 23:19:08 +0900 Subject: [PATCH 303/312] asdf --- .../rust/codegen/core/rustlang/RustType.kt | 21 ------------------- .../smithy/generators/RenderSerdeAttribute.kt | 3 --- 2 files changed, 24 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index b1412106967..588370907bd 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -486,27 +486,6 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-deserialize")), derive(RuntimeType.SerdeDeserialize))) } - private fun compilationGuard(featureName: String): Attribute { - val comment = """\n - You must pass \"aws_sdk_unstable\" flag to RUSTFLAG. - e.g. - ```bash - export RUSTFLAGS=\"--cfg aws_sdk_unstable\" - ``` - Learn more about this on this SDK's document. - """.trimIndent() - - return Attribute(cfgAttr(all(not(writable("aws_sdk_unstable")), feature(featureName)), attributeWithStringAsArgument(RuntimeType.CompileGuardAttr, comment))) - } - - public fun serdeSerializeCompilationGuard(): Attribute { - return compilationGuard("serde-serialize") - } - - public fun serdeDeserializeCompilationGuard(): Attribute { - return compilationGuard("serde-deserialize") - } - public fun serdeSkip(): Attribute { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))), serde("skip"))) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index ae9327a27fd..65d0da58c04 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -35,10 +35,7 @@ public object RenderSerdeAttribute { public fun addSerdeWithoutShapeModel(writer: RustWriter) { Attribute("").serdeSerialize().render(writer) - Attribute("").serdeSerializeCompilationGuard().render(writer) - Attribute("").serdeDeserialize().render(writer) - Attribute("").serdeDeserializeCompilationGuard().render(writer) } public fun addSerde(writer: RustWriter, shape: Shape, model: Model) { From 53e37ca66316e32823f8a9d9841bd91a78657167 Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Wed, 23 Aug 2023 23:27:19 +0900 Subject: [PATCH 304/312] asdf --- buildSrc/src/main/kotlin/CodegenTestCommon.kt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/buildSrc/src/main/kotlin/CodegenTestCommon.kt b/buildSrc/src/main/kotlin/CodegenTestCommon.kt index e6a0398f884..2902b8e9f98 100644 --- a/buildSrc/src/main/kotlin/CodegenTestCommon.kt +++ b/buildSrc/src/main/kotlin/CodegenTestCommon.kt @@ -236,7 +236,6 @@ fun Project.registerCargoCommandsTasks( outputDir: File, defaultRustDocFlags: String, ) { - val env = mapOf("RUSTFLAGS" to "--cfg aws_sdk_unstable") val dependentTasks = listOfNotNull( "assemble", @@ -247,29 +246,25 @@ fun Project.registerCargoCommandsTasks( this.tasks.register(Cargo.CHECK.toString) { dependsOn(dependentTasks) workingDir(outputDir) - environment("RUSTFLAGS", "--cfg aws_sdk_unstable") commandLine("cargo", "check", "--lib", "--tests", "--benches", "--all-features") } this.tasks.register(Cargo.TEST.toString) { dependsOn(dependentTasks) workingDir(outputDir) - - commandLine("cargo", "test", "--all-features", "--no-fail-fast").environment(env) + commandLine("cargo", "test", "--all-features", "--no-fail-fast") } this.tasks.register(Cargo.DOCS.toString) { dependsOn(dependentTasks) workingDir(outputDir) environment("RUSTDOCFLAGS", defaultRustDocFlags) - - commandLine("cargo", "doc", "--no-deps", "--document-private-items").environment(env) + commandLine("cargo", "doc", "--no-deps", "--document-private-items") } this.tasks.register(Cargo.CLIPPY.toString) { dependsOn(dependentTasks) workingDir(outputDir) - - commandLine("cargo", "clippy").environment(env) + commandLine("cargo", "clippy") } } From e6947c4980f098d7da177604c3f2a19a5aee4cee Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Thu, 24 Aug 2023 15:43:16 +0900 Subject: [PATCH 305/312] asdf --- .../amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt index 8dbf70686ac..2341c36e5cb 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt @@ -313,9 +313,6 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) val SerdeSerialize = Serde.resolve("Serialize") val SerdeDeserialize = Serde.resolve("Deserialize") - val CompileGuard = CargoDependency.CompileGuard.toType() - val CompileGuardAttr = CompileGuard.resolve("compilation_guard") - // smithy runtime types fun smithyAsync(runtimeConfig: RuntimeConfig) = CargoDependency.smithyAsync(runtimeConfig).toType() fun smithyChecksums(runtimeConfig: RuntimeConfig) = CargoDependency.smithyChecksums(runtimeConfig).toType() From dca47dbcfad7c32cd11a80b0490a9dec7e1e6a6e Mon Sep 17 00:00:00 2001 From: Thomas Cameron <68596478+thomas-k-cameron@users.noreply.github.com> Date: Wed, 6 Sep 2023 21:58:33 +0900 Subject: [PATCH 306/312] update --- .../smithy/rustsdk/AwsCrateDocsDecorator.kt | 6 ++++-- .../client/smithy/customize/SerdeDecorator.kt | 16 +++++++++++++--- .../client/smithy/generators/ServiceGenerator.kt | 1 + .../aws-smithy-compiler-warning/Cargo.toml | 11 +++++++++++ .../aws-smithy-compiler-warning/src/lib.rs | 16 ++++++++++++++++ 5 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 rust-runtime/aws-smithy-compiler-warning/Cargo.toml create mode 100644 rust-runtime/aws-smithy-compiler-warning/src/lib.rs diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt index deec4d3cacc..bd20e0bf53b 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt @@ -135,7 +135,6 @@ internal class AwsCrateDocGenerator(private val codegenContext: ClientCodegenCon val compileExample = AwsDocs.canRelyOnAwsConfig(codegenContext) val exampleMode = if (compileExample) "no_run" else "ignore" - val serdeInfoText = "##" + SerdeDecorator.SerdeInfoText template( asComments, """ @@ -173,7 +172,6 @@ internal class AwsCrateDocGenerator(private val codegenContext: ClientCodegenCon See the [client documentation](https://docs.rs/$moduleName/latest/$snakeCaseModuleName/client/struct.Client.html) for information on what calls can be made, and the inputs and outputs for each of those calls.${"\n"} - $serdeInfoText """.trimIndent().trimStart(), "tokio" to CargoDependency.Tokio.toDevDependency().toType(), @@ -214,6 +212,10 @@ internal class AwsCrateDocGenerator(private val codegenContext: ClientCodegenCon """.trimIndent(), ) + // important ! + // REMOVE THIS LINE WHEN THE SERDE FEATURE IS STABLIZED! + template(asComments, SerdeDecorator.SerdeInfoText.trimIndent()) + if (includeLicense) { template( asComments, diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 84266f61340..6d7a7b4f6d6 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -7,7 +7,12 @@ package software.amazon.smithy.rust.codegen.client.smithy.customize import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.core.rustlang.Feature +import software.amazon.smithy.rust.codegen.core.rustlang.Writable +import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RustCrate +import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization +import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection +import software.amazon.smithy.rust.codegen.core.smithy.generators.ModuleDocSection /** * Decorator that adds the `serde-serialize` and `serde-deserialize` features. @@ -17,16 +22,21 @@ class SerdeDecorator : ClientCodegenDecorator { override val order: Byte = -1 override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + // !IMPORTANT! + // When serde features are stablized (when --cfg aws_sdk_unstable is no longer necessary), you must remove aws-smithy-compiler-warning! + // aws-smithy-compiler-warning crate is there to print warning message during compilation fun feature(featureName: String): Feature { - return Feature(featureName, false, listOf("aws-smithy-types/$featureName")) + return Feature(featureName, false, listOf("aws-smithy-types/$featureName", "aws-smithy-compiler-warning/$featureName")) } rustCrate.mergeFeature(feature("serde-serialize")) rustCrate.mergeFeature(feature("serde-deserialize")) } - // I initially tried to implement with LibRsCustomization but it didn't work some how. + // I initially tried to implement with LibRsCustomization, but it didn't work somehow. companion object { - const val SerdeInfoText = """## How to enable `Serialize` and `Deserialize` + const val SerdeInfoText = """ + + ## How to enable `Serialize` and `Deserialize` This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, but those traits are behind feature gate. diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceGenerator.kt index dfdd302a31e..2d47d80b857 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceGenerator.kt @@ -60,6 +60,7 @@ class ServiceGenerator( rustCrate.lib { Attribute.DocInline.render(this) write("pub use config::Config;") + write("aws_smithy_compiler_warning::compiletime_sdk_error_warning();") } ClientRuntimeTypesReExportGenerator(codegenContext, rustCrate).render() diff --git a/rust-runtime/aws-smithy-compiler-warning/Cargo.toml b/rust-runtime/aws-smithy-compiler-warning/Cargo.toml new file mode 100644 index 00000000000..0e02857eda4 --- /dev/null +++ b/rust-runtime/aws-smithy-compiler-warning/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "aws-smithy-compiler-warning" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[features] +"serde-serialize" = [] +"serde-deserialize" = [] \ No newline at end of file diff --git a/rust-runtime/aws-smithy-compiler-warning/src/lib.rs b/rust-runtime/aws-smithy-compiler-warning/src/lib.rs new file mode 100644 index 00000000000..b4fa42ae304 --- /dev/null +++ b/rust-runtime/aws-smithy-compiler-warning/src/lib.rs @@ -0,0 +1,16 @@ +extern crate proc_macro; + +#[proc_macro] +pub fn compiletime_sdk_error_warning(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { + if cfg!(all(not(aws_sdk_unstable), any(feature = "serde-serialize", feature = "serde-deserialize"))) { + let s = r#" + You must pass `aws_sdk_unstable` flag to the compiler! + e.g. + ``` + export RUSTFLAGS="--cfg aws_sdk_unstable"; + ``` + "#; + eprintln!("{s}"); + }; + ts +} From 077c611f5a9e0a53896cdff49837de61e261f30a Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 3 Dec 2023 01:26:51 +0000 Subject: [PATCH 307/312] update --- .../amazon/smithy/rust/codegen/core/rustlang/RustType.kt | 4 ++-- .../codegen/core/smithy/generators/RenderSerdeAttribute.kt | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index de41a28e7c0..b23ea5696f4 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -489,7 +489,7 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { public fun SerdeSerialize(): Attribute { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-serialize")), derive(RuntimeType.SerdeSerialize))) } - public fun serdeDeserialize(): Attribute { + public fun SerdeDeserialize(): Attribute { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-deserialize")), derive(RuntimeType.SerdeDeserialize))) } @@ -497,7 +497,7 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))), serde("skip"))) } - public fun serdeSerializeOrDeserialize(): Attribute { + public fun SerdeSerializeOrDeserialize(): Attribute { return Attribute(cfg(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))))) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt index 65d0da58c04..4f5c7535e09 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/RenderSerdeAttribute.kt @@ -34,8 +34,8 @@ public object RenderSerdeAttribute { } public fun addSerdeWithoutShapeModel(writer: RustWriter) { - Attribute("").serdeSerialize().render(writer) - Attribute("").serdeDeserialize().render(writer) + Attribute("").SerdeSerialize().render(writer) + Attribute("").SerdeDeserialize().render(writer) } public fun addSerde(writer: RustWriter, shape: Shape, model: Model) { @@ -55,7 +55,7 @@ public object RenderSerdeAttribute { if (isApplicable(shape, model)) { // we need this for skip serde to work Attribute.AllowUnusedImports.render(writer) - Attribute("").serdeSerializeOrDeserialize().render(writer) + Attribute("").SerdeSerializeOrDeserialize().render(writer) writer.raw("use serde;") } } From 8350a45c670460341755cd1dd6db9014cfdb6e80 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 3 Dec 2023 01:29:02 +0000 Subject: [PATCH 308/312] update --- .../amazon/smithy/rust/codegen/core/testutil/Rust.kt | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 175b15facf7..30599ae990a 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -435,23 +435,13 @@ fun TestWriterDelegator.compileAndTest( // cargo fmt errors are useless, ignore } - - val env = Commands.cargoEnvAllowDeadCode(enableUnstableFlag) - - var testCommand = Commands.cargoTest(enableUnstableFlag) - if (featuresToEnable != null) { - testCommand = Commands.cargoCheck(featuresToEnable) - } - - val testOutput = testCommand.runCommand(baseDir, env) - // Clean `RUSTFLAGS` because in CI we pass in `--deny warnings` and // we still generate test code with warnings. // TODO(https://github.com/smithy-lang/smithy-rs/issues/3194) val env = mapOf("RUSTFLAGS" to "") baseDir.writeDotCargoConfigToml(listOf("--allow", "dead_code")) - val testOutput = "cargo test".runCommand(baseDir, env) + val testOutput = testCommand.runCommand(baseDir, env) if (runClippy) { Commands.CargoClippy.runCommand(baseDir, env) From 2ba9b7502afeaefd5d85ac4a92ea154993c8f830 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 3 Dec 2023 02:24:26 +0000 Subject: [PATCH 309/312] modified: codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt modified: codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceGenerator.kt modified: codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt modified: codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt deleted: rust-runtime/aws-smithy-compiler-warning/Cargo.toml deleted: rust-runtime/aws-smithy-compiler-warning/src/lib.rs --- .../client/smithy/customize/SerdeDecorator.kt | 12 ++---------- .../client/smithy/generators/ServiceGenerator.kt | 1 - .../core/smithy/generators/BuilderGenerator.kt | 6 +++--- .../smithy/rust/codegen/core/testutil/Rust.kt | 4 ++-- .../aws-smithy-compiler-warning/Cargo.toml | 11 ----------- .../aws-smithy-compiler-warning/src/lib.rs | 16 ---------------- 6 files changed, 7 insertions(+), 43 deletions(-) delete mode 100644 rust-runtime/aws-smithy-compiler-warning/Cargo.toml delete mode 100644 rust-runtime/aws-smithy-compiler-warning/src/lib.rs diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 6d7a7b4f6d6..3190f20b65a 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -7,12 +7,7 @@ package software.amazon.smithy.rust.codegen.client.smithy.customize import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext import software.amazon.smithy.rust.codegen.core.rustlang.Feature -import software.amazon.smithy.rust.codegen.core.rustlang.Writable -import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RustCrate -import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization -import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection -import software.amazon.smithy.rust.codegen.core.smithy.generators.ModuleDocSection /** * Decorator that adds the `serde-serialize` and `serde-deserialize` features. @@ -22,11 +17,8 @@ class SerdeDecorator : ClientCodegenDecorator { override val order: Byte = -1 override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { - // !IMPORTANT! - // When serde features are stablized (when --cfg aws_sdk_unstable is no longer necessary), you must remove aws-smithy-compiler-warning! - // aws-smithy-compiler-warning crate is there to print warning message during compilation fun feature(featureName: String): Feature { - return Feature(featureName, false, listOf("aws-smithy-types/$featureName", "aws-smithy-compiler-warning/$featureName")) + return Feature(featureName, false, listOf("aws-smithy-types/$featureName")) } rustCrate.mergeFeature(feature("serde-serialize")) rustCrate.mergeFeature(feature("serde-deserialize")) @@ -35,7 +27,7 @@ class SerdeDecorator : ClientCodegenDecorator { // I initially tried to implement with LibRsCustomization, but it didn't work somehow. companion object { const val SerdeInfoText = """ - + ## How to enable `Serialize` and `Deserialize` This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceGenerator.kt index 2d47d80b857..dfdd302a31e 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceGenerator.kt @@ -60,7 +60,6 @@ class ServiceGenerator( rustCrate.lib { Attribute.DocInline.render(this) write("pub use config::Config;") - write("aws_smithy_compiler_warning::compiletime_sdk_error_warning();") } ClientRuntimeTypesReExportGenerator(codegenContext, rustCrate).render() diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt index 8cc48fc1310..a86afa07569 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt @@ -88,7 +88,7 @@ fun MemberShape.enforceRequired( } val shape = this val isOptional = codegenContext.symbolProvider.toSymbol(shape).isOptional() - val field = field.letIf(!isOptional) { field.map { rust("Some(#T)", it) } } + val field2 = field.letIf(!isOptional) { field.map { rust("Some(#T)", it) } } val error = OperationBuildError(codegenContext.runtimeConfig).missingField( codegenContext.symbolProvider.toMemberName(shape), "A required field was not set", ) @@ -96,11 +96,11 @@ fun MemberShape.enforceRequired( is StringShape -> writable { rustTemplate( "#{field}.filter(|f|!AsRef::::as_ref(f).trim().is_empty())", - "field" to field, + "field" to field2, ) } - else -> field + else -> field2 }.map { base -> rustTemplate("#{base}.ok_or_else(||#{error})?", "base" to base, "error" to error) } return unwrapped.letIf(produceOption) { w -> w.map { rust("Some(#T)", it) } } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 30599ae990a..8905d313184 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -441,9 +441,9 @@ fun TestWriterDelegator.compileAndTest( val env = mapOf("RUSTFLAGS" to "") baseDir.writeDotCargoConfigToml(listOf("--allow", "dead_code")) - val testOutput = testCommand.runCommand(baseDir, env) + val testOutput = "cargo test".runCommand(baseDir, env) - if (runClippy) { + if (runClippy) { Commands.CargoClippy.runCommand(baseDir, env) } return testOutput diff --git a/rust-runtime/aws-smithy-compiler-warning/Cargo.toml b/rust-runtime/aws-smithy-compiler-warning/Cargo.toml deleted file mode 100644 index 0e02857eda4..00000000000 --- a/rust-runtime/aws-smithy-compiler-warning/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "aws-smithy-compiler-warning" -version = "0.1.0" -edition = "2021" - -[lib] -proc-macro = true - -[features] -"serde-serialize" = [] -"serde-deserialize" = [] \ No newline at end of file diff --git a/rust-runtime/aws-smithy-compiler-warning/src/lib.rs b/rust-runtime/aws-smithy-compiler-warning/src/lib.rs deleted file mode 100644 index b4fa42ae304..00000000000 --- a/rust-runtime/aws-smithy-compiler-warning/src/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -extern crate proc_macro; - -#[proc_macro] -pub fn compiletime_sdk_error_warning(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { - if cfg!(all(not(aws_sdk_unstable), any(feature = "serde-serialize", feature = "serde-deserialize"))) { - let s = r#" - You must pass `aws_sdk_unstable` flag to the compiler! - e.g. - ``` - export RUSTFLAGS="--cfg aws_sdk_unstable"; - ``` - "#; - eprintln!("{s}"); - }; - ts -} From 8f386af291e0edcbd1f440b2a2622d847d770a55 Mon Sep 17 00:00:00 2001 From: Thomas Cameron Date: Sun, 3 Dec 2023 05:33:22 +0000 Subject: [PATCH 310/312] modified: codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt --- .../smithy/rust/codegen/core/testutil/Rust.kt | 405 ++++++++++-------- 1 file changed, 222 insertions(+), 183 deletions(-) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 8905d313184..8fc7b1cc4b6 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -54,8 +54,38 @@ private object Commands { private const val cfgUnstable = "--cfg aws_sdk_unstable" private const val allFeature = "--all-features" + // test variations + enum class TestVariation { + ALL_FEATURES_WITHOUT_UNSTABLE, + NO_FEATURES_WITHOUT_UNSTABLE, + ALL_FEATURES_WITH_UNSTABLE, + NO_FEATURES_WITH_UNSTABLE, + } + + val ALL_VARIATIONS = listOf( + TestVariation.ALL_FEATURES_WITHOUT_UNSTABLE, + TestVariation.NO_FEATURES_WITHOUT_UNSTABLE, + TestVariation.ALL_FEATURES_WITH_UNSTABLE, + TestVariation.NO_FEATURES_WITH_UNSTABLE, + ) + fun decorateCmd(cmd: String, variation: TestVariation): String { + var data = when (variation) { + TestVariation.ALL_FEATURES_WITHOUT_UNSTABLE -> "$cmd $allFeature" + TestVariation.NO_FEATURES_WITHOUT_UNSTABLE -> cmd + TestVariation.ALL_FEATURES_WITH_UNSTABLE -> "$cmd $allFeature $cfgUnstable" + TestVariation.NO_FEATURES_WITH_UNSTABLE -> "$cmd $cfgUnstable" + } + + return data + } + // helper - private fun func(s: String, add: String, flag: Boolean): String = if (flag) { "$s $add" } else { s } + private fun func(s: String, add: String, flag: Boolean): String = + if (flag) { + "$s $add" + } else { + s + } // unstable flag fun cargoEnvDenyWarnings(enableUnstable: Boolean): Map { @@ -78,8 +108,8 @@ private object Commands { // cargoTest(false) // // cargo test // ``` - fun cargoTest(enableAllFeatures: Boolean): String { - return func("cargo test", allFeature, enableAllFeatures) + fun cargoTest(variation: TestVariation): String { + return decorateCmd("cargo test", variation) } // enable all features @@ -90,50 +120,19 @@ private object Commands { // cargoCheck(false) // // cargo test // ``` - fun cargoCheck(enableAllFeatures: Boolean): String { - return func("cargo check", allFeature, enableAllFeatures) - } - - // enable features specified in the array - // e.g. - // ```kotlin - // cargoTest(["serde-serialize", "serde-deserialize"]) - // // cargo test --features serde-serialize serde-deserialize - // ``` - fun cargoTest(featuresToEnable: Array?): String { - if (featuresToEnable != null) { - val s = featuresToEnable.joinToString { " " } - return "cargo test --features $s" - } else { - return "cargo test" - } - } - - // enable features specified in the array - // e.g. - // ```kotlin - // cargoCheck(["serde-serialize", "serde-deserialize"]) - // // cargo check --features serde-serialize serde-deserialize - // ``` - fun cargoCheck(featuresToEnable: Array?): String { - if (featuresToEnable != null) { - val s = featuresToEnable.joinToString { " " } - return "cargo check --features $s" - } else { - return "cargo check" - } + fun cargoCheck(variation: TestVariation): String { + return decorateCmd("cargo check", variation) } } -val TestModuleDocProvider = object : ModuleDocProvider { - override fun docsWriter(module: RustModule.LeafModule): Writable = writable { - docs("Some test documentation\n\nSome more details...") +val TestModuleDocProvider = + object : ModuleDocProvider { + override fun docsWriter(module: RustModule.LeafModule): Writable = writable { + docs("Some test documentation\n\nSome more details...") + } } -} -/** - * Waiting for Kotlin to stabilize their temp directory functionality - */ +/** Waiting for Kotlin to stabilize their temp directory functionality */ private fun tempDir(directory: File? = null): File { return if (directory != null) { createTempDirectory(directory.toPath(), "smithy-test").toFile() @@ -145,15 +144,17 @@ private fun tempDir(directory: File? = null): File { /** * Creates a Cargo workspace shared among all tests * - * This workspace significantly improves test performance by sharing dependencies between different tests. + * This workspace significantly improves test performance by sharing dependencies between different + * tests. */ object TestWorkspace { private val baseDir by lazy { - val appDataDir = System.getProperty("APPDATA") - ?: System.getenv("XDG_DATA_HOME") - ?: System.getProperty("user.home") - ?.let { Path.of(it, ".local", "share").absolutePathString() } - ?.also { File(it).mkdirs() } + val appDataDir = + System.getProperty("APPDATA") + ?: System.getenv("XDG_DATA_HOME") + ?: System.getProperty("user.home") + ?.let { Path.of(it, ".local", "share").absolutePathString() } + ?.also { File(it).mkdirs() } if (appDataDir != null) { File(Path.of(appDataDir, "smithy-test-workspace").absolutePathString()) } else { @@ -168,32 +169,40 @@ object TestWorkspace { private fun generate() { val cargoToml = baseDir.resolve("Cargo.toml") - val workspaceToml = TomlWriter().write( - mapOf( - "workspace" to mapOf( - "members" to subprojects, - ), - ), - ) + val workspaceToml = + TomlWriter() + .write( + mapOf( + "workspace" to + mapOf( + "members" to subprojects, + ), + ), + ) cargoToml.writeText(workspaceToml) } fun subproject(): File { synchronized(subprojects) { val newProject = tempDir(directory = baseDir) - newProject.resolve("Cargo.toml").writeText( - """ - [package] - name = "stub-${newProject.name}" - version = "0.0.1" - """.trimIndent(), - ) - newProject.resolve("rust-toolchain.toml").writeText( - // help rust select the right version when we run cargo test - // TODO(https://github.com/smithy-lang/smithy-rs/issues/2048): load this from the msrv property using a - // method as we do for runtime crate versions - "[toolchain]\nchannel = \"1.70.0\"\n", - ) + newProject + .resolve("Cargo.toml") + .writeText( + """ + [package] + name = "stub-${newProject.name}" + version = "0.0.1" + """.trimIndent(), + ) + newProject + .resolve("rust-toolchain.toml") + .writeText( + // help rust select the right version when we run cargo test + // TODO(https://github.com/smithy-lang/smithy-rs/issues/2048): load this + // from the msrv property using a + // method as we do for runtime crate versions + "[toolchain]\nchannel = \"1.70.0\"\n", + ) // ensure there at least an empty lib.rs file to avoid broken crates newProject.resolve("src").mkdirs() newProject.resolve("src/lib.rs").writeText("") @@ -217,20 +226,25 @@ object TestWorkspace { FileManifest.create(subprojectDir.toPath()), symbolProvider, codegenConfig, - ).apply { - lib { - // If the test fails before the crate is finalized, we'll end up with a broken crate. - // Since all tests are generated into the same workspace (to avoid re-compilation) a broken crate - // breaks the workspace and all subsequent unit tests. By putting this comment in, we prevent - // that state from occurring. - rust("// touch lib.rs") + ) + .apply { + lib { + // If the test fails before the crate is finalized, we'll end up with a + // broken crate. + // Since all tests are generated into the same workspace (to avoid + // re-compilation) a broken crate + // breaks the workspace and all subsequent unit tests. By putting this + // comment in, we prevent + // that state from occurring. + rust("// touch lib.rs") + } } - } } } /** - * Generates a test plugin context for [model] and returns the plugin context and the path it is rooted it. + * Generates a test plugin context for [model] and returns the plugin context and the path it is + * rooted it. * * Example: * ```kotlin @@ -252,32 +266,45 @@ fun generatePluginContext( val moduleName = "test_${testDir.nameWithoutExtension}" val testPath = testDir.toPath() val manifest = FileManifest.create(testPath) - var settingsBuilder = Node.objectNodeBuilder() - .withMember("module", Node.from(moduleName)) - .withMember("moduleVersion", Node.from(moduleVersion)) - .withMember("moduleDescription", Node.from("test")) - .withMember("moduleAuthors", Node.fromStrings("testgenerator@smithy.com")) - .letIf(service != null) { it.withMember("service", service) } - .withMember( - "runtimeConfig", - Node.objectNodeBuilder().withMember( - "relativePath", - Node.from(((runtimeConfig ?: TestRuntimeConfig).runtimeCrateLocation).path), - ).build(), - ) + var settingsBuilder = + Node.objectNodeBuilder() + .withMember("module", Node.from(moduleName)) + .withMember("moduleVersion", Node.from(moduleVersion)) + .withMember("moduleDescription", Node.from("test")) + .withMember("moduleAuthors", Node.fromStrings("testgenerator@smithy.com")) + .letIf(service != null) { it.withMember("service", service) } + .withMember( + "runtimeConfig", + Node.objectNodeBuilder() + .withMember( + "relativePath", + Node.from( + ( + (runtimeConfig ?: TestRuntimeConfig) + .runtimeCrateLocation + ) + .path, + ), + ) + .build(), + ) if (addModuleToEventStreamAllowList) { - settingsBuilder = settingsBuilder.withMember( - "codegen", - Node.objectNodeBuilder().withMember( - "eventStreamAllowList", - Node.fromStrings(moduleName), - ).build(), - ) + settingsBuilder = + settingsBuilder.withMember( + "codegen", + Node.objectNodeBuilder() + .withMember( + "eventStreamAllowList", + Node.fromStrings(moduleName), + ) + .build(), + ) } val settings = settingsBuilder.merge(additionalSettings).build() - val pluginContext = PluginContext.builder().model(model).fileManifest(manifest).settings(settings).build() + val pluginContext = + PluginContext.builder().model(model).fileManifest(manifest).settings(settings).build() return pluginContext to testPath } @@ -287,9 +314,7 @@ fun RustWriter.unitTest( ) { val testName = name ?: safeName("test") raw("#[test]") - rustBlock("fn $testName()") { - writeWithNoFormatting(test) - } + rustBlock("fn $testName()") { writeWithNoFormatting(test) } } /* @@ -311,16 +336,24 @@ fun RustWriter.unitTest( return testDependenciesOnly { rustBlock("fn $name()", *args, block = block) } } -fun RustWriter.cargoDependencies() = dependencies.map { RustDependency.fromSymbolDependency(it) } - .filterIsInstance().distinct() +fun RustWriter.cargoDependencies() = + dependencies + .map { RustDependency.fromSymbolDependency(it) } + .filterIsInstance() + .distinct() -fun RustWriter.assertNoNewDependencies(block: Writable, dependencyFilter: (CargoDependency) -> String?): RustWriter { +fun RustWriter.assertNoNewDependencies( + block: Writable, + dependencyFilter: (CargoDependency) -> String?, +): RustWriter { val startingDependencies = cargoDependencies().toSet() block(this) val endingDependencies = cargoDependencies().toSet() val newDeps = (endingDependencies - startingDependencies) val invalidDeps = - newDeps.mapNotNull { dep -> dependencyFilter(dep)?.let { message -> message to dep } }.orNullIfEmpty() + newDeps + .mapNotNull { dep -> dependencyFilter(dep)?.let { message -> message to dep } } + .orNullIfEmpty() if (invalidDeps != null) { val badDeps = invalidDeps.map { it.second.rustName } val writtenOut = this.toString() @@ -339,17 +372,16 @@ fun RustWriter.assertNoNewDependencies(block: Writable, dependencyFilter: (Cargo return this } -fun RustWriter.testDependenciesOnly(block: Writable) = assertNoNewDependencies(block) { dep -> - if (dep.scope != DependencyScope.Dev) { - "Cannot add $dep — this writer should only add test dependencies." - } else { - null +fun RustWriter.testDependenciesOnly(block: Writable) = + assertNoNewDependencies(block) { dep -> + if (dep.scope != DependencyScope.Dev) { + "Cannot add $dep — this writer should only add test dependencies." + } else { + null + } } -} -fun testDependenciesOnly(block: Writable): Writable = { - testDependenciesOnly(block) -} +fun testDependenciesOnly(block: Writable): Writable = { testDependenciesOnly(block) } fun RustWriter.tokioTest(name: String, vararg args: Any, block: Writable) { unitTest(name, attribute = Attribute.TokioTest, async = true, block = block, args = args) @@ -378,7 +410,8 @@ class TestWriterDelegator( /** * Generate a new test module * - * This should only be used in test code—the generated module name will be something like `tests_123` + * This should only be used in test code—the generated module name will be something like + * `tests_123` */ fun RustCrate.testModule(block: Writable) = lib { withInlineModule( @@ -389,17 +422,13 @@ fun RustCrate.testModule(block: Writable) = lib { } fun FileManifest.printGeneratedFiles() { - this.files.forEach { path -> - println("file:///$path") - } + this.files.forEach { path -> println("file:///$path") } } /** - * Setting `runClippy` to true can be helpful when debugging clippy failures, but - * should generally be set to `false` to avoid invalidating the Cargo cache between - * every unit test run. - * If you want to enable each features individually, specify the name of the feature on featuresToEnable. - * e.g. + * Setting `runClippy` to true can be helpful when debugging clippy failures, but should generally + * be set to `false` to avoid invalidating the Cargo cache between every unit test run. If you want + * to enable each features individually, specify the name of the feature on featuresToEnable. e.g. * ```kotlin * compileAndTest(featuresToEnable = ["this", "that"]) * ``` @@ -411,16 +440,14 @@ fun FileManifest.printGeneratedFiles() { fun TestWriterDelegator.compileAndTest( runClippy: Boolean = false, expectFailure: Boolean = false, - enableUnstableFlag: Boolean = true, - enableAllFeatures: Boolean = true, - featuresToEnable: Array? = null, ): String { - val stubModel = """ + val stubModel = + """ namespace fake service Fake { version: "123" } - """.asSmithyModel() + """.asSmithyModel() this.finalize( rustSettings(), stubModel, @@ -441,19 +468,24 @@ fun TestWriterDelegator.compileAndTest( val env = mapOf("RUSTFLAGS" to "") baseDir.writeDotCargoConfigToml(listOf("--allow", "dead_code")) - val testOutput = "cargo test".runCommand(baseDir, env) + val sep = "\n======================= OUTPUT ===========================\n" + val allOutputs = Commands.ALL_VARIATIONS.map { + Commands.cargoTest(it).runCommand(baseDir, env) + }.map { "$sep $it" }.joinToString() { it } if (runClippy) { Commands.CargoClippy.runCommand(baseDir, env) } - return testOutput + + return allOutputs } fun Path.writeDotCargoConfigToml(rustFlags: List) { val dotCargoDir = this.resolve(".cargo") Files.createDirectory(dotCargoDir) - dotCargoDir.resolve("config.toml") + dotCargoDir + .resolve("config.toml") .writeText( """ [build] @@ -476,47 +508,50 @@ fun String.shouldParseAsRust() { "rustfmt ${tempFile.absolutePath}".runCommand() } -/** - * Compiles the contents of the given writer (including dependencies) and runs the tests - */ +/** Compiles the contents of the given writer (including dependencies) and runs the tests */ fun RustWriter.compileAndTest( - @Language("Rust", prefix = "fn test() {", suffix = "}") - main: String = "", + @Language("Rust", prefix = "fn test() {", suffix = "}") main: String = "", clippy: Boolean = false, expectFailure: Boolean = false, - enableUnstable: Boolean = false, ): String { - val deps = this.dependencies - .map { RustDependency.fromSymbolDependency(it) } - .filterIsInstance() - .distinct() - .mergeDependencyFeatures() - .mergeIdenticalTestDependencies() - val module = if (this.namespace.contains("::")) { - this.namespace.split("::")[1] - } else { - "lib" - } - val tempDir = this.toString() - .intoCrate(deps, module = module, main = main, strict = clippy) - val mainRs = tempDir.resolve("src/main.rs") - val testModule = tempDir.resolve("src/$module.rs") - try { - val testOutput = if ((mainRs.readText() + testModule.readText()).contains("#[test]")) { - Commands.cargoTest(enableUnstable).runCommand(tempDir.toPath()) + val deps = + this.dependencies + .map { RustDependency.fromSymbolDependency(it) } + .filterIsInstance() + .distinct() + .mergeDependencyFeatures() + .mergeIdenticalTestDependencies() + val module = + if (this.namespace.contains("::")) { + this.namespace.split("::")[1] } else { - Commands.cargoCheck(enableUnstable).runCommand(tempDir.toPath()) + "lib" } - if (expectFailure) { - println("Test sources for debugging: file://${testModule.absolutePath}") - } - return testOutput - } catch (e: CommandError) { - if (!expectFailure) { - println("Test sources for debugging: file://${testModule.absolutePath}") + val tempDir = this.toString().intoCrate(deps, module = module, main = main, strict = clippy) + val mainRs = tempDir.resolve("src/main.rs") + val testModule = tempDir.resolve("src/$module.rs") + + val outputKeep = ArrayList() + for (variation in Commands.ALL_VARIATIONS) { + try { + val testOutput = + if ((mainRs.readText() + testModule.readText()).contains("#[test]")) { + Commands.cargoTest(variation).runCommand(tempDir.toPath()) + } else { + Commands.cargoCheck(variation).runCommand(tempDir.toPath()) + } + outputKeep.add(testOutput) + if (expectFailure) { + println("Test sources for debugging: file://${testModule.absolutePath}") + } + } catch (e: CommandError) { + if (!expectFailure) { + println("Test sources for debugging: file://${testModule.absolutePath}") + } + throw e } - throw e } + return outputKeep.joinToString() { it } } private fun String.intoCrate( @@ -527,18 +562,22 @@ private fun String.intoCrate( ): File { this.shouldParseAsRust() val tempDir = TestWorkspace.subproject() - val cargoToml = RustWriter.toml("Cargo.toml").apply { - CargoTomlGenerator( - moduleName = tempDir.nameWithoutExtension, - moduleVersion = "0.0.1", - moduleAuthors = listOf("Testy McTesterson"), - moduleDescription = null, - moduleLicense = null, - moduleRepository = null, - writer = this, - dependencies = deps, - ).render() - }.toString() + val cargoToml = + RustWriter.toml("Cargo.toml") + .apply { + CargoTomlGenerator( + moduleName = tempDir.nameWithoutExtension, + moduleVersion = "0.0.1", + moduleAuthors = listOf("Testy McTesterson"), + moduleDescription = null, + moduleLicense = null, + moduleRepository = null, + writer = this, + dependencies = deps, + ) + .render() + } + .toString() tempDir.resolve("Cargo.toml").writeText(cargoToml) tempDir.resolve("src").mkdirs() val mainRs = tempDir.resolve("src/main.rs") @@ -586,8 +625,8 @@ fun String.shouldCompile(): File { } /** - * Inserts the provided strings as a main function and executes the result. This is intended to be used to validate - * that generated code compiles and has some basic properties. + * Inserts the provided strings as a main function and executes the result. This is intended to be + * used to validate that generated code compiles and has some basic properties. * * Example usage: * ``` @@ -600,18 +639,18 @@ fun String.compileAndRun(vararg strings: String) { binary.absolutePath.runCommand() } -fun RustCrate.integrationTest(name: String, writable: Writable) = this.withFile("tests/$name.rs", writable) +fun RustCrate.integrationTest(name: String, writable: Writable) = + this.withFile("tests/$name.rs", writable) fun TestWriterDelegator.unitTest(test: Writable): TestWriterDelegator { lib { val name = safeName("test") withInlineModule(RustModule.inlineTests(name), TestModuleDocProvider) { - unitTest(name) { - test(this) - } + unitTest(name) { test(this) } } } return this } -fun String.runWithWarnings(crate: Path, enableUnstableFlag: Boolean = true) = this.runCommand(crate, Commands.cargoEnvDenyWarnings(enableUnstableFlag)) +fun String.runWithWarnings(crate: Path, enableUnstableFlag: Boolean = true) = + this.runCommand(crate, Commands.cargoEnvDenyWarnings(enableUnstableFlag)) From ed9f046ab22f7933dd4cabd68c85504d56d75c8b Mon Sep 17 00:00:00 2001 From: Thomas K Cameron Date: Tue, 23 Jan 2024 06:31:58 +0900 Subject: [PATCH 311/312] merge --- .editorconfig | 2 + .github/workflows/ci.yml | 15 +- .github/workflows/claim-crate-names.yml | 2 +- .../workflows/credentials-verification.yml | 51 + .github/workflows/github-pages.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/update-sdk-next.yml | 2 +- .pre-commit-config.yaml | 7 +- .pre-commit-hooks/kotlin-block-quotes.py | 7 +- .pre-commit-hooks/ktlint.sh | 13 + CHANGELOG.md | 53 + CHANGELOG.next.toml | 89 +- aws/SDK_CHANGELOG.next.json | 209 +- aws/rust-runtime/Cargo.toml | 2 +- aws/rust-runtime/aws-config/Cargo.toml | 3 +- .../aws-config/src/credential_process.rs | 74 +- .../aws-config/src/default_provider.rs | 2 +- .../src/default_provider/credentials.rs | 5 +- .../src/default_provider/retry_config.rs | 2 +- aws/rust-runtime/aws-config/src/ecs.rs | 4 +- aws/rust-runtime/aws-config/src/lib.rs | 29 +- .../aws-config/src/meta/credentials/chain.rs | 6 +- .../aws-config/src/meta/region.rs | 2 +- .../aws-config/src/profile/mod.rs | 2 +- .../aws-config/src/profile/parser.rs | 8 +- .../src/profile/parser/normalize.rs | 7 +- .../aws-config/src/profile/parser/parse.rs | 41 +- .../aws-config/src/profile/parser/source.rs | 4 +- .../aws-config/src/web_identity_token.rs | 4 +- .../env.json | 3 + .../fs/home/.aws/config | 2 + .../fs/home/.aws/credentials | 3 + .../http-traffic.json | 5 + .../test-case.json | 10 + .../test-data/profile-parser-tests.json | 15 +- .../aws-credential-types/Cargo.toml | 3 +- .../src/credentials_impl.rs | 2 +- aws/rust-runtime/aws-endpoint/Cargo.toml | 3 +- aws/rust-runtime/aws-http/Cargo.toml | 1 + .../aws-http/src/content_encoding.rs | 4 +- aws/rust-runtime/aws-hyper/Cargo.toml | 3 +- aws/rust-runtime/aws-inlineable/Cargo.toml | 1 + .../src/apigateway_interceptors.rs | 4 +- .../src/glacier_interceptors.rs | 4 +- aws/rust-runtime/aws-runtime-api/Cargo.toml | 1 + aws/rust-runtime/aws-runtime/Cargo.toml | 1 + .../aws-runtime/src/invocation_id.rs | 2 +- aws/rust-runtime/aws-sig-auth/Cargo.toml | 3 +- aws/rust-runtime/aws-sigv4/Cargo.toml | 13 +- .../aws-sigv4/src/http_request.rs | 7 +- .../src/http_request/canonical_request.rs | 16 +- .../aws-sigv4/src/http_request/error.rs | 4 +- .../aws-sigv4/src/http_request/settings.rs | 2 +- .../aws-sigv4/src/http_request/sign.rs | 73 +- .../aws-sigv4/src/http_request/test.rs | 10 +- aws/rust-runtime/aws-types/Cargo.toml | 1 + .../aws-types/src/os_shim_internal.rs | 4 +- aws/rust-runtime/aws-types/src/sdk_config.rs | 2 +- aws/rust-runtime/build.gradle.kts | 5 + aws/sdk-adhoc-test/build.gradle.kts | 13 +- aws/sdk-codegen/build.gradle.kts | 9 +- .../smithy/rustsdk/AwsCargoDependency.kt | 12 +- .../smithy/rustsdk/AwsCodegenDecorator.kt | 97 +- .../smithy/rustsdk/AwsCrateDocsDecorator.kt | 271 +- .../software/amazon/smithy/rustsdk/AwsDocs.kt | 102 +- .../rustsdk/AwsFluentClientDecorator.kt | 102 +- .../smithy/rustsdk/AwsPresigningDecorator.kt | 202 +- .../amazon/smithy/rustsdk/AwsRuntimeType.kt | 23 +- .../smithy/rustsdk/BaseRequestIdDecorator.kt | 237 +- .../smithy/rustsdk/CrateLicenseDecorator.kt | 5 +- .../smithy/rustsdk/CredentialProviders.kt | 148 +- .../rustsdk/EndpointBuiltInsDecorator.kt | 112 +- .../rustsdk/HttpRequestChecksumDecorator.kt | 97 +- .../rustsdk/HttpResponseChecksumDecorator.kt | 118 +- .../smithy/rustsdk/InlineAwsDependency.kt | 14 +- .../rustsdk/IntegrationTestDependencies.kt | 89 +- .../smithy/rustsdk/InvocationIdDecorator.kt | 107 +- .../rustsdk/RecursionDetectionDecorator.kt | 19 +- .../amazon/smithy/rustsdk/RegionDecorator.kt | 230 +- .../rustsdk/RetryClassifierDecorator.kt | 31 +- .../RetryInformationHeaderDecorator.kt | 27 +- .../smithy/rustsdk/SdkConfigDecorator.kt | 79 +- .../amazon/smithy/rustsdk/SdkSettings.kt | 61 +- .../smithy/rustsdk/SigV4AuthDecorator.kt | 273 +- .../smithy/rustsdk/UserAgentDecorator.kt | 146 +- .../customize/DisabledAuthDecorator.kt | 9 +- .../rustsdk/customize/RemoveDefaults.kt | 23 +- .../customize/RemoveDefaultsDecorator.kt | 108 +- .../customize/ServiceSpecificDecorator.kt | 91 +- .../apigateway/ApiGatewayDecorator.kt | 33 +- .../rustsdk/customize/ec2/Ec2Decorator.kt | 7 +- .../customize/glacier/GlacierDecorator.kt | 117 +- .../customize/route53/Route53Decorator.kt | 64 +- .../rustsdk/customize/s3/S3Decorator.kt | 119 +- .../customize/s3/StripBucketFromPath.kt | 14 +- .../customize/s3control/S3ControlDecorator.kt | 38 +- .../rustsdk/customize/sso/SSODecorator.kt | 6 +- .../rustsdk/customize/sts/STSDecorator.kt | 6 +- .../timestream/TimestreamDecorator.kt | 43 +- .../rustsdk/endpoints/AwsEndpointsStdLib.kt | 21 +- .../endpoints/OperationInputTestGenerator.kt | 171 +- .../rustsdk/endpoints/RequireEndpointRules.kt | 6 +- .../rustsdk/endpoints/StripEndpointTrait.kt | 7 +- .../smithy/rustsdk/traits/PresignableTrait.kt | 3 +- .../main/resources/default-partitions.json | 106 +- .../main/resources/default-sdk-endpoints.json | 44 - .../test/kotlin/AwsCrateDocsDecoratorTest.kt | 52 +- .../test/kotlin/SdkCodegenIntegrationTest.kt | 9 +- .../rustsdk/AwsPresigningDecoratorTest.kt | 108 +- .../rustsdk/CredentialProviderConfigTest.kt | 39 +- .../rustsdk/EndpointBuiltInsDecoratorTest.kt | 15 +- .../rustsdk/EndpointsCredentialsTest.kt | 15 +- .../rustsdk/InvocationIdDecoratorTest.kt | 10 +- .../OperationInputTestGeneratorTests.kt | 42 +- .../smithy/rustsdk/RegionDecoratorTest.kt | 36 +- .../rustsdk/RegionProviderConfigTest.kt | 2 +- .../smithy/rustsdk/SigV4AuthDecoratorTest.kt | 5 +- .../amazon/smithy/rustsdk/TestUtil.kt | 83 +- .../rustsdk/customize/RemoveDefaultsTest.kt | 14 +- .../ec2/EC2MakePrimitivesOptionalTest.kt | 5 +- aws/sdk/aws-models/bedrock-runtime.json | 2 +- aws/sdk/aws-models/config.json | 102 + aws/sdk/aws-models/ec2.json | 3279 +++- aws/sdk/aws-models/ecs.json | 85 +- aws/sdk/aws-models/iam.json | 62 + aws/sdk/aws-models/lambda.json | 167 +- aws/sdk/aws-models/polly.json | 34 +- aws/sdk/aws-models/route53.json | 113 + aws/sdk/aws-models/s3.json | 13560 +++++++++------- aws/sdk/aws-models/sdk-endpoints.json | 1606 +- aws/sdk/aws-models/sdk-partitions.json | 213 + aws/sdk/aws-models/sso-oidc.json | 495 +- aws/sdk/aws-models/sts.json | 8 +- aws/sdk/aws-models/transcribe-streaming.json | 20 +- .../s3-throughput/benchmark/Cargo.toml | 2 +- aws/sdk/build.gradle.kts | 18 +- aws/sdk/integration-tests/dynamodb/Cargo.toml | 4 +- .../tests/test-error-classification.rs | 70 + aws/sdk/integration-tests/lambda/Cargo.toml | 2 +- aws/sdk/integration-tests/s3/Cargo.toml | 2 +- .../s3/tests/status-200-errors.rs | 4 +- .../transcribestreaming/Cargo.toml | 2 +- .../transcribestreaming/tests/test.rs | 2 + aws/sdk/sync-models.py | 45 +- build.gradle.kts | 53 +- buildSrc/src/main/kotlin/CodegenTestCommon.kt | 135 +- buildSrc/src/main/kotlin/CrateSet.kt | 103 +- buildSrc/src/main/kotlin/HashUtils.kt | 6 +- buildSrc/src/main/kotlin/ManifestPatcher.kt | 30 +- .../src/main/kotlin/aws/sdk/CrateVersioner.kt | 110 +- .../main/kotlin/aws/sdk/DocsLandingPage.kt | 15 +- .../src/main/kotlin/aws/sdk/ModelMetadata.kt | 17 +- .../src/main/kotlin/aws/sdk/ServiceLoader.kt | 120 +- .../main/kotlin/aws/sdk/VersionsManifest.kt | 20 +- buildSrc/src/test/kotlin/CrateSetTest.kt | 24 +- .../aws/sdk/IndependentCrateVersionerTest.kt | 369 +- .../test/kotlin/aws/sdk/ModelMetadataTest.kt | 5 +- .../kotlin/aws/sdk/VersionsManifestTest.kt | 55 +- .../model/rest-xml-extras.smithy | 31 + codegen-client/build.gradle.kts | 9 +- .../client/smithy/ClientCodegenContext.kt | 5 +- .../client/smithy/ClientCodegenVisitor.kt | 138 +- .../codegen/client/smithy/ClientReExports.kt | 7 +- .../client/smithy/ClientReservedWords.kt | 52 +- .../codegen/client/smithy/ClientRustModule.kt | 136 +- .../client/smithy/ClientRustSettings.kt | 80 +- .../client/smithy/RustClientCodegenPlugin.kt | 29 +- .../customizations/ClientDocsGenerator.kt | 11 +- .../ConnectionPoisoningConfigCustomization.kt | 27 +- .../customizations/DocsRsMetadataDecorator.kt | 21 +- .../customizations/HttpAuthDecorator.kt | 261 +- .../HttpChecksumRequiredGenerator.kt | 31 +- .../HttpConnectorConfigDecorator.kt | 193 +- .../IdempotencyTokenDecorator.kt | 17 +- .../IdempotencyTokenGenerator.kt | 62 +- .../customizations/IdentityCacheDecorator.kt | 164 +- .../InterceptorConfigCustomization.kt | 28 +- .../customizations/MetadataCustomization.kt | 33 +- .../smithy/customizations/NoAuthDecorator.kt | 25 +- .../ResiliencyConfigCustomization.kt | 39 +- .../RetryClassifierConfigCustomization.kt | 103 +- .../SensitiveOutputDecorator.kt | 23 +- .../customizations/TimeSourceCustomization.kt | 19 +- .../customize/ClientCodegenDecorator.kt | 81 +- .../customize/RequiredCustomizations.kt | 28 +- .../ClientContextConfigCustomization.kt | 10 +- .../endpoint/EndpointConfigCustomization.kt | 41 +- .../endpoint/EndpointParamsDecorator.kt | 15 +- .../smithy/endpoint/EndpointRulesetIndex.kt | 14 +- .../smithy/endpoint/EndpointTypesGenerator.kt | 17 +- .../smithy/endpoint/EndpointsDecorator.kt | 41 +- .../codegen/client/smithy/endpoint/Util.kt | 42 +- .../generators/EndpointParamsGenerator.kt | 144 +- .../EndpointParamsInterceptorGenerator.kt | 99 +- .../generators/EndpointResolverGenerator.kt | 146 +- .../generators/EndpointTestGenerator.kt | 153 +- .../endpoint/rulesgen/ExpressionGenerator.kt | 117 +- .../endpoint/rulesgen/LiteralGenerator.kt | 104 +- .../client/smithy/endpoint/rulesgen/StdLib.kt | 93 +- .../endpoint/rulesgen/TemplateGenerator.kt | 55 +- .../generators/AuthOptionsPluginGenerator.kt | 38 +- .../generators/ClientBuilderInstantiator.kt | 58 +- .../smithy/generators/ClientEnumGenerator.kt | 184 +- .../ConfigOverrideRuntimePluginGenerator.kt | 49 +- .../EndpointTraitBindingGenerator.kt | 52 +- .../smithy/generators/ErrorCorrection.kt | 63 +- .../generators/NestedAccessorGenerator.kt | 26 +- .../generators/OperationCustomization.kt | 21 +- .../smithy/generators/OperationGenerator.kt | 92 +- .../OperationRuntimePluginGenerator.kt | 103 +- .../smithy/generators/PaginatorGenerator.kt | 375 +- .../smithy/generators/SensitiveIndex.kt | 1 + .../smithy/generators/ServiceGenerator.kt | 9 +- .../ServiceRuntimePluginGenerator.kt | 110 +- .../client/CustomizableOperationGenerator.kt | 82 +- .../generators/client/FluentClientCore.kt | 24 +- .../client/FluentClientDecorator.kt | 49 +- .../generators/client/FluentClientDocs.kt | 142 +- .../client/FluentClientGenerator.kt | 256 +- .../IdempotencyTokenProviderCustomization.kt | 61 +- .../config/ServiceConfigGenerator.kt | 280 +- ...lledStreamProtectionConfigCustomization.kt | 128 +- .../smithy/generators/error/ErrorGenerator.kt | 76 +- .../error/OperationErrorGenerator.kt | 90 +- .../generators/error/ServiceErrorGenerator.kt | 115 +- .../http/RequestBindingGenerator.kt | 103 +- .../protocol/ProtocolParserGenerator.kt | 71 +- .../protocol/ProtocolTestGenerator.kt | 196 +- .../protocol/RequestSerializerGenerator.kt | 138 +- .../protocol/ResponseDeserializerGenerator.kt | 77 +- .../smithy/protocols/ClientProtocolLoader.kt | 49 +- .../protocols/HttpBoundProtocolGenerator.kt | 49 +- .../RemoveEventStreamOperations.kt | 28 +- .../testutil/ClientCodegenIntegrationTest.kt | 21 +- .../codegen/client/testutil/TestHelpers.kt | 48 +- .../client/smithy/ClientCodegenVisitorTest.kt | 5 +- .../smithy/EventStreamSymbolProviderTest.kt | 120 +- .../StreamingShapeSymbolProviderTest.kt | 5 +- .../customizations/HttpAuthDecoratorTest.kt | 60 +- .../MetadataCustomizationTest.kt | 25 +- .../ResiliencyConfigCustomizationTest.kt | 1 - .../SensitiveOutputDecoratorTest.kt | 19 +- .../ClientContextConfigCustomizationTest.kt | 5 +- .../endpoint/EndpointResolverGeneratorTest.kt | 38 +- .../smithy/endpoint/EndpointsDecoratorTest.kt | 202 +- .../rulesgen/ExpressionGeneratorTest.kt | 42 +- .../rulesgen/TemplateGeneratorTest.kt | 5 +- .../generators/ClientEnumGeneratorTest.kt | 31 +- .../generators/ClientInstantiatorTest.kt | 5 +- ...onfigOverrideRuntimePluginGeneratorTest.kt | 98 +- .../generators/EndpointTraitBindingsTest.kt | 37 +- .../smithy/generators/ErrorCorrectionTest.kt | 5 +- .../generators/PaginatorGeneratorTest.kt | 5 +- .../smithy/generators/SensitiveIndexTest.kt | 20 +- .../CustomizableOperationGeneratorTest.kt | 10 +- .../client/FluentClientGeneratorTest.kt | 33 +- .../config/ServiceConfigGeneratorTest.kt | 93 +- .../error/OperationErrorGeneratorTest.kt | 5 +- .../error/ServiceErrorGeneratorTest.kt | 5 +- .../http/RequestBindingGeneratorTest.kt | 18 +- .../http/ResponseBindingGeneratorTest.kt | 23 +- .../protocol/ProtocolParserGeneratorTest.kt | 17 +- .../protocol/ProtocolTestGeneratorTest.kt | 339 +- .../protocols/AwsQueryCompatibleTest.kt | 20 +- .../client/smithy/protocols/AwsQueryTest.kt | 5 +- .../client/smithy/protocols/Ec2QueryTest.kt | 5 +- .../client/smithy/protocols/RestJsonTest.kt | 5 +- .../client/smithy/protocols/RestXmlTest.kt | 6 +- .../RemoveEventStreamOperationsTest.kt | 31 +- .../rust/codegen/client/testutil/Matchers.kt | 5 +- .../client/tool/TimeTestSuiteGenerator.kt | 258 +- codegen-core/build.gradle.kts | 96 +- .../rest-json-extras.smithy | 32 + .../smithy/rust/codegen/core/Version.kt | 35 +- .../codegen/core/rustlang/CargoDependency.kt | 98 +- .../codegen/core/rustlang/RustGenerics.kt | 13 +- .../rust/codegen/core/rustlang/RustModule.kt | 86 +- .../core/rustlang/RustReservedWords.kt | 145 +- .../rust/codegen/core/rustlang/RustType.kt | 338 +- .../rust/codegen/core/rustlang/RustWriter.kt | 773 +- .../codegen/core/rustlang/UseDeclarations.kt | 12 +- .../rust/codegen/core/rustlang/Writable.kt | 50 +- .../codegen/core/smithy/CodegenContext.kt | 24 +- .../codegen/core/smithy/CodegenDelegator.kt | 50 +- .../rust/codegen/core/smithy/CodegenTarget.kt | 26 +- .../codegen/core/smithy/CoreRustSettings.kt | 29 +- .../codegen/core/smithy/DirectedWalker.kt | 5 +- .../core/smithy/EventStreamSymbolProvider.kt | 45 +- .../rust/codegen/core/smithy/RuntimeType.kt | 125 +- .../codegen/core/smithy/RustSymbolProvider.kt | 28 +- .../smithy/StreamingTraitSymbolProvider.kt | 5 + .../rust/codegen/core/smithy/SymbolExt.kt | 18 +- .../core/smithy/SymbolMetadataProvider.kt | 75 +- .../rust/codegen/core/smithy/SymbolVisitor.kt | 108 +- .../customizations/AllowLintsCustomization.kt | 121 +- .../CrateVersionCustomization.kt | 20 +- .../customizations/SmithyTypesPubUseExtra.kt | 128 +- .../smithy/customize/CoreCodegenDecorator.kt | 73 +- .../core/smithy/customize/Customization.kt | 15 +- .../smithy/generators/BuilderGenerator.kt | 103 +- .../smithy/generators/BuilderInstantiator.kt | 18 +- .../smithy/generators/CargoTomlGenerator.kt | 57 +- .../generators/DefaultValueGenerator.kt | 14 +- .../core/smithy/generators/EnumGenerator.kt | 47 +- .../core/smithy/generators/Instantiator.kt | 227 +- .../core/smithy/generators/LibRsGenerator.kt | 9 +- .../smithy/generators/StructureGenerator.kt | 71 +- .../core/smithy/generators/UnionGenerator.kt | 15 +- .../generators/error/ErrorImplGenerator.kt | 34 +- .../generators/http/HttpBindingGenerator.kt | 201 +- .../generators/protocol/ProtocolSupport.kt | 4 +- .../codegen/core/smithy/protocols/AwsJson.kt | 56 +- .../codegen/core/smithy/protocols/AwsQuery.kt | 24 +- .../smithy/protocols/AwsQueryCompatible.kt | 29 +- .../codegen/core/smithy/protocols/Ec2Query.kt | 34 +- .../smithy/protocols/HttpBindingResolver.kt | 18 +- .../HttpBoundProtocolPayloadGenerator.kt | 210 +- .../codegen/core/smithy/protocols/Protocol.kt | 2 + .../smithy/protocols/ProtocolFunctions.kt | 57 +- .../codegen/core/smithy/protocols/RestJson.kt | 25 +- .../codegen/core/smithy/protocols/RestXml.kt | 22 +- .../core/smithy/protocols/XmlNameIndex.kt | 1 + .../parse/EventStreamUnmarshallerGenerator.kt | 119 +- .../protocols/parse/JsonParserGenerator.kt | 462 +- .../protocols/parse/RestXmlParserGenerator.kt | 9 +- .../parse/XmlBindingTraitParserGenerator.kt | 295 +- .../EventStreamErrorMarshallerGenerator.kt | 36 +- .../EventStreamMarshallerGenerator.kt | 79 +- .../serialize/JsonSerializerGenerator.kt | 204 +- .../serialize/QuerySerializerGenerator.kt | 171 +- .../protocols/serialize/SerializerUtil.kt | 25 +- .../protocols/serialize/ValueExpression.kt | 19 +- .../XmlBindingTraitSerializerGenerator.kt | 236 +- .../core/smithy/traits/RustBoxTrait.kt | 1 + .../smithy/traits/SyntheticOutputTrait.kt | 6 +- .../transformers/EventStreamNormalizer.kt | 39 +- .../transformers/OperationNormalizer.kt | 48 +- .../transformers/RecursiveShapeBoxer.kt | 28 +- .../codegen/core/testutil/BasicTestModels.kt | 5 +- .../core/testutil/CodegenIntegrationTest.kt | 25 +- .../testutil/DefaultBuilderInstantiator.kt | 12 +- .../testutil/EventStreamMarshallTestCases.kt | 5 +- .../core/testutil/EventStreamTestModels.kt | 162 +- .../EventStreamUnmarshallTestCases.kt | 38 +- .../NamingObstacleCourseTestModels.kt | 303 +- .../smithy/rust/codegen/core/testutil/Rust.kt | 146 +- .../rust/codegen/core/testutil/TestHelpers.kt | 93 +- .../smithy/rust/codegen/core/util/Exec.kt | 19 +- .../smithy/rust/codegen/core/util/LetIf.kt | 23 +- .../smithy/rust/codegen/core/util/Map.kt | 8 +- .../smithy/rust/codegen/core/util/Panic.kt | 2 + .../smithy/rust/codegen/core/util/Smithy.kt | 24 +- .../smithy/rust/codegen/core/util/Strings.kt | 50 +- .../rust/codegen/core/util/Synthetics.kt | 33 +- .../smithy/rust/codegen/core/VersionTest.kt | 83 +- .../core/rustlang/InlineDependencyTest.kt | 22 +- .../codegen/core/rustlang/RustGenericsTest.kt | 62 +- .../core/rustlang/RustReservedWordsTest.kt | 128 +- .../codegen/core/rustlang/RustTypeTest.kt | 58 +- .../codegen/core/rustlang/RustWriterTest.kt | 49 +- .../codegen/core/rustlang/WritableTest.kt | 20 +- .../core/smithy/CodegenDelegatorTest.kt | 69 +- .../codegen/core/smithy/RuntimeTypeTest.kt | 79 +- .../codegen/core/smithy/SymbolVisitorTest.kt | 135 +- .../SmithyTypesPubUseExtraTest.kt | 93 +- .../smithy/generators/BuilderGeneratorTest.kt | 32 +- .../generators/CargoTomlGeneratorTest.kt | 2 +- .../smithy/generators/EnumGeneratorTest.kt | 129 +- .../smithy/generators/InstantiatorTest.kt | 142 +- .../generators/StructureGeneratorTest.kt | 41 +- .../core/smithy/generators/TestEnumType.kt | 61 +- .../smithy/generators/UnionGeneratorTest.kt | 129 +- .../smithy/protocols/ProtocolFunctionsTest.kt | 10 +- .../parse/AwsQueryParserGeneratorTest.kt | 14 +- .../parse/Ec2QueryParserGeneratorTest.kt | 14 +- .../parse/JsonParserGeneratorTest.kt | 16 +- .../XmlBindingTraitParserGeneratorTest.kt | 14 +- .../AwsQuerySerializerGeneratorTest.kt | 43 +- .../Ec2QuerySerializerGeneratorTest.kt | 17 +- .../serialize/JsonSerializerGeneratorTest.kt | 39 +- .../XmlBindingTraitSerializerGeneratorTest.kt | 49 +- .../transformers/EventStreamNormalizerTest.kt | 56 +- .../transformers/OperationNormalizerTest.kt | 20 +- .../transformers/RecursiveShapeBoxerTest.kt | 28 +- .../RecursiveShapesIntegrationTest.kt | 12 +- .../smithy/rust/codegen/core/util/MapTest.kt | 90 +- .../rust/codegen/core/util/StringsTest.kt | 13 +- .../rust/codegen/core/util/SyntheticsTest.kt | 17 +- codegen-server/build.gradle.kts | 9 +- codegen-server/python/build.gradle.kts | 9 +- .../smithy/PythonEventStreamSymbolProvider.kt | 25 +- .../smithy/PythonServerCargoDependency.kt | 10 +- .../smithy/PythonServerCodegenVisitor.kt | 54 +- .../smithy/PythonServerSymbolProvider.kt | 18 +- .../server/python/smithy/PythonType.kt | 105 +- .../smithy/RustServerCodegenPythonPlugin.kt | 3 +- .../PythonServerCodegenDecorator.kt | 133 +- .../ConstrainedPythonBlobGenerator.kt | 17 +- .../generators/PythonApplicationGenerator.kt | 66 +- .../generators/PythonServerEnumGenerator.kt | 51 +- .../PythonServerEventStreamErrorGenerator.kt | 15 +- .../generators/PythonServerModuleGenerator.kt | 37 +- .../PythonServerOperationHandlerGenerator.kt | 10 +- .../PythonServerStructureGenerator.kt | 11 +- .../generators/PythonServerUnionGenerator.kt | 11 +- .../protocols/PythonServerProtocolLoader.kt | 149 +- .../testutil/PythonServerTestHelpers.kt | 5 +- .../PythonServerSymbolProviderTest.kt | 10 +- .../generators/PythonServerTypesTest.kt | 89 +- .../PythonTypeInformationGenerationTest.kt | 5 +- .../ConstrainedShapeSymbolMetadataProvider.kt | 14 +- .../smithy/ConstrainedShapeSymbolProvider.kt | 37 +- .../ConstraintViolationSymbolProvider.kt | 43 +- .../rust/codegen/server/smithy/Constraints.kt | 158 +- .../DeriveEqAndHashSymbolMetadataProvider.kt | 6 + .../LengthTraitValidationErrorMessage.kt | 19 +- ...atternTraitEscapedSpecialCharsValidator.kt | 29 +- .../PubCrateConstrainedShapeSymbolProvider.kt | 18 +- .../RangeTraitValidationErrorMessage.kt | 19 +- .../RustCrateInlineModuleComposingWriter.kt | 59 +- .../server/smithy/RustServerCodegenPlugin.kt | 49 +- .../server/smithy/ServerCargoDependency.kt | 3 +- .../server/smithy/ServerCodegenContext.kt | 4 +- .../server/smithy/ServerCodegenVisitor.kt | 133 +- .../server/smithy/ServerReservedWords.kt | 11 +- .../server/smithy/ServerRuntimeType.kt | 7 +- .../codegen/server/smithy/ServerRustModule.kt | 93 +- .../server/smithy/ServerRustSettings.kt | 67 +- .../server/smithy/ServerSymbolProviders.kt | 58 +- .../UnconstrainedShapeSymbolProvider.kt | 13 +- .../smithy/ValidateUnsupportedConstraints.kt | 269 +- .../AdditionalErrorsDecorator.kt | 20 +- ...ingOverMapOrCollectionJsonCustomization.kt | 30 +- ...eforeSerializingMemberJsonCustomization.kt | 32 +- ...mValidationExceptionWithReasonDecorator.kt | 325 +- .../ServerRequiredCustomizations.kt | 8 +- .../SmithyValidationExceptionDecorator.kt | 197 +- .../customize/ServerCodegenDecorator.kt | 30 +- .../generators/ConstrainedBlobGenerator.kt | 76 +- .../ConstrainedCollectionGenerator.kt | 31 +- .../generators/ConstrainedMapGenerator.kt | 28 +- .../ConstrainedMapGeneratorCommon.kt | 12 +- .../generators/ConstrainedNumberGenerator.kt | 91 +- .../ConstrainedShapeGeneratorCommon.kt | 16 +- .../generators/ConstrainedStringGenerator.kt | 129 +- .../smithy/generators/DocHandlerGenerator.kt | 22 +- .../smithy/generators/LenghTraitCommon.kt | 15 +- .../MapConstraintViolationGenerator.kt | 26 +- .../PubCrateConstrainedCollectionGenerator.kt | 26 +- .../PubCrateConstrainedMapGenerator.kt | 28 +- .../smithy/generators/ScopeMacroGenerator.kt | 281 +- .../ServerBuilderConstraintViolations.kt | 38 +- .../generators/ServerBuilderGenerator.kt | 113 +- .../ServerBuilderGeneratorCommon.kt | 119 +- ...rGeneratorWithoutPublicConstrainedTypes.kt | 43 +- .../smithy/generators/ServerBuilderSymbol.kt | 30 +- .../smithy/generators/ServerEnumGenerator.kt | 120 +- .../ServerHttpSensitivityGenerator.kt | 474 +- .../smithy/generators/ServerInstantiator.kt | 52 +- .../ServerOperationErrorGenerator.kt | 21 +- .../generators/ServerOperationGenerator.kt | 15 +- .../smithy/generators/ServerRootGenerator.kt | 33 +- .../ServerRuntimeTypesReExportsGenerator.kt | 7 +- .../generators/ServerServiceGenerator.kt | 1211 +- .../generators/ServiceConfigGenerator.kt | 417 +- .../server/smithy/generators/TraitInfo.kt | 15 +- .../UnconstrainedCollectionGenerator.kt | 42 +- .../generators/UnconstrainedMapGenerator.kt | 137 +- .../generators/UnconstrainedUnionGenerator.kt | 125 +- .../ValidationExceptionConversionGenerator.kt | 5 + .../http/RestRequestSpecGenerator.kt | 46 +- .../http/ServerRequestBindingGenerator.kt | 50 +- .../http/ServerResponseBindingGenerator.kt | 75 +- .../generators/protocol/ServerProtocol.kt | 53 +- .../protocol/ServerProtocolTestGenerator.kt | 544 +- .../server/smithy/protocols/ServerAwsJson.kt | 48 +- .../ServerHttpBoundProtocolGenerator.kt | 369 +- .../smithy/protocols/ServerProtocolLoader.kt | 96 +- .../server/smithy/protocols/ServerRestJson.kt | 16 +- .../smithy/protocols/ServerRestXmlFactory.kt | 4 +- .../testutil/ServerCodegenIntegrationTest.kt | 22 +- .../smithy/testutil/ServerTestHelpers.kt | 78 +- .../traits/ConstraintViolationRustBoxTrait.kt | 1 + ...hapeReachableFromOperationInputTagTrait.kt | 20 +- ...ToConstrainedOperationInputsInAllowList.kt | 22 +- .../ConstrainedMemberTransform.kt | 75 +- .../RecursiveConstraintViolationBoxer.kt | 9 +- ...ShapesReachableFromOperationInputTagger.kt | 41 +- .../smithy/ConstraintsMemberShapeTest.kt | 167 +- .../smithy/CustomShapeSymbolProviderTest.kt | 29 +- ...riveEqAndHashSymbolMetadataProviderTest.kt | 62 +- ...rnTraitEscapedSpecialCharsValidatorTest.kt | 96 +- ...CrateConstrainedShapeSymbolProviderTest.kt | 36 +- .../RecursiveConstraintViolationsTest.kt | 94 +- ...ustCrateInlineModuleComposingWriterTest.kt | 57 +- .../server/smithy/ServerCodegenVisitorTest.kt | 5 +- ...ateUnsupportedConstraintsAreNotUsedTest.kt | 84 +- .../AdditionalErrorsDecoratorTest.kt | 5 +- ...idationExceptionWithReasonDecoratorTest.kt | 29 +- ...ionNotAttachedErrorMessageDecoratorTest.kt | 46 +- .../ConstrainedBlobGeneratorTest.kt | 48 +- .../ConstrainedCollectionGeneratorTest.kt | 216 +- .../generators/ConstrainedMapGeneratorTest.kt | 63 +- .../ConstrainedNumberGeneratorTest.kt | 7 +- .../ConstrainedStringGeneratorTest.kt | 89 +- .../ServerBuilderConstraintViolationsTest.kt | 6 +- .../ServerBuilderDefaultValuesTest.kt | 319 +- .../generators/ServerBuilderGeneratorTest.kt | 18 +- .../generators/ServerEnumGeneratorTest.kt | 5 +- .../ServerHttpSensitivityGeneratorTest.kt | 69 +- .../generators/ServerInstantiatorTest.kt | 91 +- .../ServerOperationErrorGeneratorTest.kt | 5 +- .../generators/ServiceConfigGeneratorTest.kt | 248 +- .../RecursiveConstraintViolationBoxerTest.kt | 7 +- codegen-server/typescript/build.gradle.kts | 9 +- .../smithy/RustServerCodegenTsPlugin.kt | 45 +- .../smithy/TsServerCargoDependency.kt | 7 +- .../smithy/TsServerCodegenVisitor.kt | 54 +- .../smithy/TsServerSymbolProvider.kt | 5 + .../TsServerCodegenDecorator.kt | 48 +- .../generators/TsApplicationGenerator.kt | 17 +- .../generators/TsServerEnumGenerator.kt | 23 +- .../generators/TsServerStructureGenerator.kt | 12 +- examples/Cargo.toml | 1 + .../pokemon-service-client-usage/Cargo.toml | 2 + .../custom-header-using-interceptor.rs | 5 +- .../examples/response-header-interceptor.rs | 5 +- examples/pokemon-service-tls/Cargo.toml | 3 +- examples/pokemon-service-tls/src/main.rs | 59 +- .../tests/custom_connectors.rs | 14 +- examples/python/pokemon_service.py | 2 + gradle.properties | 14 +- rust-runtime/Cargo.toml | 2 + rust-runtime/aws-smithy-async/Cargo.toml | 3 +- .../src/future/pagination_stream.rs | 7 + rust-runtime/aws-smithy-checksums/Cargo.toml | 3 +- rust-runtime/aws-smithy-client/Cargo.toml | 3 +- .../aws-smithy-eventstream/Cargo.toml | 1 + .../aws-smithy-eventstream/src/frame.rs | 4 +- rust-runtime/aws-smithy-http-auth/Cargo.toml | 3 +- .../aws-smithy-http-server-python/Cargo.toml | 3 +- .../Cargo.toml | 1 + .../aws-smithy-http-server/Cargo.toml | 6 +- .../src/instrumentation/plugin.rs | 2 +- .../instrumentation/sensitivity/headers.rs | 2 +- .../instrumentation/sensitivity/request.rs | 2 +- .../instrumentation/sensitivity/response.rs | 2 +- .../instrumentation/sensitivity/uri/label.rs | 2 + .../src/instrumentation/service.rs | 4 +- .../aws-smithy-http-server/src/plugin/mod.rs | 3 +- rust-runtime/aws-smithy-http-tower/Cargo.toml | 3 +- rust-runtime/aws-smithy-http/Cargo.toml | 5 +- rust-runtime/aws-smithy-http/src/endpoint.rs | 49 +- rust-runtime/aws-smithy-http/src/header.rs | 2 +- rust-runtime/aws-smithy-http/src/operation.rs | 43 +- rust-runtime/aws-smithy-json/Cargo.toml | 1 + rust-runtime/aws-smithy-json/src/escape.rs | 8 +- .../aws-smithy-mocks-experimental/Cargo.toml | 27 + .../aws-smithy-mocks-experimental/LICENSE | 175 + .../aws-smithy-mocks-experimental/README.md | 7 + .../examples/s3-getobject-mocks.rs | 112 + .../aws-smithy-mocks-experimental/src/lib.rs | 337 + .../tests/get-object-mocks.rs | 98 + .../aws-smithy-protocol-test/Cargo.toml | 1 + rust-runtime/aws-smithy-query/Cargo.toml | 1 + .../aws-smithy-runtime-api/Cargo.toml | 1 + .../src/client/connection.rs | 6 +- .../src/client/endpoint.rs | 156 + .../src/client/identity.rs | 35 +- .../src/client/interceptors.rs | 2 +- .../src/client/orchestrator.rs | 35 + .../src/client/result.rs | 36 +- .../src/client/runtime_components.rs | 96 +- .../src/client/runtime_plugin.rs | 2 +- .../aws-smithy-runtime-api/src/lib.rs | 2 +- rust-runtime/aws-smithy-runtime/Cargo.toml | 8 +- rust-runtime/aws-smithy-runtime/src/client.rs | 2 + .../aws-smithy-runtime/src/client/endpoint.rs | 65 + .../src/client/http/hyper_014.rs | 2 +- .../src/client/http/test_util.rs | 10 +- .../client/http/test_util/capture_request.rs | 2 +- .../src/client/http/test_util/dvr.rs | 6 +- .../src/client/http/test_util/dvr/record.rs | 2 +- .../src/client/orchestrator/endpoints.rs | 10 +- .../src/test_util/assertions.rs | 2 +- .../aws-smithy-types-convert/Cargo.toml | 4 + .../aws-smithy-types-convert/README.md | 2 +- .../external-types.toml | 2 + .../aws-smithy-types-convert/src/lib.rs | 3 + .../aws-smithy-types-convert/src/stream.rs | 62 + rust-runtime/aws-smithy-types/Cargo.toml | 7 +- rust-runtime/aws-smithy-types/additional-ci | 3 + rust-runtime/aws-smithy-types/src/blob.rs | 2 +- rust-runtime/aws-smithy-types/src/body.rs | 31 +- .../src/body/http_body_0_4_x.rs | 16 +- .../src/body/http_body_1_x.rs | 267 + .../aws-smithy-types/src/byte_stream.rs | 29 +- .../src/byte_stream/bytestream_util.rs | 9 +- .../src/byte_stream/http_body_1_x.rs | 21 + .../aws-smithy-types/src/config_bag.rs | 8 +- .../aws-smithy-types/src/date_time/mod.rs | 2 +- .../aws-smithy-types/src/primitive.rs | 4 +- rust-runtime/aws-smithy-xml/Cargo.toml | 1 + rust-runtime/build.gradle.kts | 5 + rust-runtime/inlineable/Cargo.toml | 5 +- .../inlineable/src/endpoint_lib/s3.rs | 2 +- .../inlineable/src/endpoint_lib/substring.rs | 2 +- rust-toolchain.toml | 2 +- tools/ci-build/Dockerfile | 22 +- tools/ci-build/changelogger/Cargo.lock | 573 +- tools/ci-build/changelogger/src/render.rs | 6 +- tools/ci-build/crate-hasher/Cargo.lock | 354 +- tools/ci-build/crate-hasher/tests/test.rs | 4 +- tools/ci-build/difftags/Cargo.lock | 56 +- tools/ci-build/publisher/Cargo.lock | 669 +- tools/ci-build/publisher/Cargo.toml | 4 +- .../publisher/src/cargo/get_owners.rs | 2 +- tools/ci-build/publisher/src/lib.rs | 2 +- tools/ci-build/publisher/src/package.rs | 7 +- tools/ci-build/publisher/src/publish.rs | 2 +- .../publisher/src/subcommand/fix_manifests.rs | 151 +- .../src/subcommand/fix_manifests/validate.rs | 146 +- .../publisher/src/subcommand/publish.rs | 2 +- .../publisher/src/subcommand/yank_release.rs | 39 +- tools/ci-build/publisher/src/yank.rs | 27 + .../runtime-release-dryrun/Cargo.lock | 353 + .../runtime-release-dryrun/Cargo.toml | 11 + .../runtime-release-dryrun/src/main.rs | 182 + tools/ci-build/runtime-versioner/Cargo.lock | 1635 ++ tools/ci-build/runtime-versioner/Cargo.toml | 29 + tools/ci-build/runtime-versioner/src/audit.rs | 259 + tools/ci-build/runtime-versioner/src/index.rs | 109 + tools/ci-build/runtime-versioner/src/main.rs | 82 + tools/ci-build/runtime-versioner/src/repo.rs | 43 + tools/ci-build/runtime-versioner/src/tag.rs | 121 + tools/ci-build/runtime-versioner/src/util.rs | 16 + .../runtime-versioner/test-common/Cargo.toml | 10 + .../runtime-versioner/test-common/src/lib.rs | 100 + .../runtime-versioner/test_data/.gitignore | 2 + .../runtime-versioner/test_data/Makefile | 22 + .../runtime-versioner/test_data/README.md | 14 + .../test_data/already_published_version.toml | 28 + .../test_data/base_crates_io_index.toml | 28 + .../test_data/test_base.git.tar.gz | Bin 0 -> 49188 bytes .../runtime-versioner/tests/test_audit.rs | 80 + .../tests/test_previous_release_tag.rs | 25 + tools/ci-build/sdk-lints/Cargo.lock | 619 +- tools/ci-build/sdk-lints/Cargo.toml | 2 +- tools/ci-build/sdk-lints/src/lint.rs | 10 +- .../ci-build/sdk-lints/src/lint_cargo_toml.rs | 11 +- tools/ci-build/sdk-lints/src/readmes.rs | 7 +- tools/ci-build/sdk-versioner/Cargo.lock | 544 +- .../ci-build/smithy-rs-tool-common/Cargo.toml | 5 +- .../smithy-rs-tool-common/src/changelog.rs | 8 +- .../smithy-rs-tool-common/src/command.rs | 75 + .../src/git/get_current_tag.rs | 2 +- .../ci-build/smithy-rs-tool-common/src/lib.rs | 2 + .../src/retry.rs | 138 +- .../smithy-rs-tool-common/src/shell.rs | 10 +- tools/ci-cdk/canary-lambda/src/canary.rs | 1 + tools/ci-cdk/canary-runner/Cargo.lock | 41 +- tools/ci-cdk/canary-runner/Cargo.toml | 4 +- .../ci-cdk/canary-runner/src/build_bundle.rs | 37 +- tools/ci-scripts/check-rust-runtimes | 6 +- tools/ci-scripts/check-tools | 1 + .../ci-scripts/configure-tls/configure-badssl | 23 +- .../configure-tls/new-badssl-dockerfile | 88 + tools/echo-server/Cargo.lock | 297 +- 668 files changed, 38923 insertions(+), 22186 deletions(-) create mode 100644 .github/workflows/credentials-verification.yml create mode 100755 .pre-commit-hooks/ktlint.sh create mode 100644 aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/env.json create mode 100644 aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/fs/home/.aws/config create mode 100644 aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/fs/home/.aws/credentials create mode 100644 aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/http-traffic.json create mode 100644 aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/test-case.json mode change 100644 => 120000 aws/sdk-codegen/src/main/resources/default-partitions.json delete mode 100644 aws/sdk-codegen/src/main/resources/default-sdk-endpoints.json create mode 100644 aws/sdk/aws-models/sdk-partitions.json create mode 100644 aws/sdk/integration-tests/dynamodb/tests/test-error-classification.rs create mode 100644 rust-runtime/aws-smithy-mocks-experimental/Cargo.toml create mode 100644 rust-runtime/aws-smithy-mocks-experimental/LICENSE create mode 100644 rust-runtime/aws-smithy-mocks-experimental/README.md create mode 100644 rust-runtime/aws-smithy-mocks-experimental/examples/s3-getobject-mocks.rs create mode 100644 rust-runtime/aws-smithy-mocks-experimental/src/lib.rs create mode 100644 rust-runtime/aws-smithy-mocks-experimental/tests/get-object-mocks.rs create mode 100644 rust-runtime/aws-smithy-runtime/src/client/endpoint.rs create mode 100644 rust-runtime/aws-smithy-types-convert/src/stream.rs create mode 100644 rust-runtime/aws-smithy-types/src/body/http_body_1_x.rs create mode 100644 rust-runtime/aws-smithy-types/src/byte_stream/http_body_1_x.rs create mode 100644 tools/ci-build/publisher/src/yank.rs create mode 100644 tools/ci-build/runtime-release-dryrun/Cargo.lock create mode 100644 tools/ci-build/runtime-release-dryrun/Cargo.toml create mode 100644 tools/ci-build/runtime-release-dryrun/src/main.rs create mode 100644 tools/ci-build/runtime-versioner/Cargo.lock create mode 100644 tools/ci-build/runtime-versioner/Cargo.toml create mode 100644 tools/ci-build/runtime-versioner/src/audit.rs create mode 100644 tools/ci-build/runtime-versioner/src/index.rs create mode 100644 tools/ci-build/runtime-versioner/src/main.rs create mode 100644 tools/ci-build/runtime-versioner/src/repo.rs create mode 100644 tools/ci-build/runtime-versioner/src/tag.rs create mode 100644 tools/ci-build/runtime-versioner/src/util.rs create mode 100644 tools/ci-build/runtime-versioner/test-common/Cargo.toml create mode 100644 tools/ci-build/runtime-versioner/test-common/src/lib.rs create mode 100644 tools/ci-build/runtime-versioner/test_data/.gitignore create mode 100644 tools/ci-build/runtime-versioner/test_data/Makefile create mode 100644 tools/ci-build/runtime-versioner/test_data/README.md create mode 100644 tools/ci-build/runtime-versioner/test_data/already_published_version.toml create mode 100644 tools/ci-build/runtime-versioner/test_data/base_crates_io_index.toml create mode 100644 tools/ci-build/runtime-versioner/test_data/test_base.git.tar.gz create mode 100644 tools/ci-build/runtime-versioner/tests/test_audit.rs create mode 100644 tools/ci-build/runtime-versioner/tests/test_previous_release_tag.rs create mode 100644 tools/ci-build/smithy-rs-tool-common/src/command.rs rename tools/ci-build/{publisher => smithy-rs-tool-common}/src/retry.rs (55%) create mode 100644 tools/ci-scripts/configure-tls/new-badssl-dockerfile diff --git a/.editorconfig b/.editorconfig index 55bfe517da2..f87c1664096 100644 --- a/.editorconfig +++ b/.editorconfig @@ -17,3 +17,5 @@ ktlint_standard_filename = disabled ktlint_standard_max-line-length = disabled ktlint_standard_argument-list-wrapping = disabled ktlint_standard_parameter-list-wrapping = disabled +ktlint_standard_property-naming = disabled +ktlint_standard_comment-wrapping = disabled diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c56ec564cfd..ac4c842466b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ on: required: false env: - rust_version: 1.70.0 + rust_version: 1.72.0 rust_toolchain_components: clippy,rustfmt ENCRYPTED_DOCKER_PASSWORD: ${{ secrets.ENCRYPTED_DOCKER_PASSWORD }} DOCKER_LOGIN_TOKEN_PASSPHRASE: ${{ secrets.DOCKER_LOGIN_TOKEN_PASSPHRASE }} @@ -92,6 +92,7 @@ jobs: runner: smithy_ubuntu-latest_8-core - action: check-rust-runtimes runner: smithy_ubuntu-latest_8-core + fetch-depth: 0 - action: check-sdk-codegen-unit-tests runner: ubuntu-latest - action: check-server-codegen-integration-tests @@ -119,6 +120,8 @@ jobs: with: path: smithy-rs ref: ${{ inputs.git_ref }} + # Defaults to 1 if not set + fetch-depth: ${{ matrix.test.fetch-depth }} - name: Run ${{ matrix.test.action }} uses: ./smithy-rs/.github/actions/docker-build with: @@ -202,9 +205,10 @@ jobs: popd &>/dev/null done - # We make sure that Smithy-rs can be compiled on platforms that are not natively supported by GitHub actions. - # We run as many tests we can on those platforms because they require a more complicated setup involving architecture - # emulation. + # We make sure that smithy-rs can be compiled on platforms that are not + # natively supported by GitHub actions. We run as many tests as we can on + # those platforms, but not all of them, because they require a more + # complicated setup involving architecture emulation. test-exotic-platform-support: name: Exotic platform support runs-on: ubuntu-latest @@ -212,7 +216,8 @@ jobs: fail-fast: false matrix: include: - # We always exclude aws-smithy-http-server-python since the Python framework is experimental. + # We always exclude `aws-smithy-http-server-python` and + # `aws-smithy-http-server-typescript` since they are experimental. - target: i686-unknown-linux-gnu build_smithy_rs_features: --all-features build_aws_exclude: '' diff --git a/.github/workflows/claim-crate-names.yml b/.github/workflows/claim-crate-names.yml index 12b7df9fff4..846e341764f 100644 --- a/.github/workflows/claim-crate-names.yml +++ b/.github/workflows/claim-crate-names.yml @@ -10,7 +10,7 @@ concurrency: cancel-in-progress: true env: - rust_version: 1.70.0 + rust_version: 1.72.1 name: Claim unpublished crate names on crates.io run-name: ${{ github.workflow }} diff --git a/.github/workflows/credentials-verification.yml b/.github/workflows/credentials-verification.yml new file mode 100644 index 00000000000..9d05a15086c --- /dev/null +++ b/.github/workflows/credentials-verification.yml @@ -0,0 +1,51 @@ +name: Daily credentials verification +on: + schedule: + # Runs 00:00 UTC every day + - cron: 0 0 * * * + workflow_dispatch: + +jobs: + # Verifies the token used by the bot to publish crates to crates.io + verify-crates-io-token: + name: Verify Crates.io Token + runs-on: ubuntu-latest + steps: + - name: Checkout smithy-rs + uses: actions/checkout@v3 + - name: Verify Crates.io Token + shell: bash + env: + RELEASE_AUTOMATION_BOT_CRATESIO_TOKEN: ${{ secrets.RELEASE_AUTOMATION_BOT_CRATESIO_TOKEN }} + run: | + cargo login -- "${RELEASE_AUTOMATION_BOT_CRATESIO_TOKEN}" + echo "Checking cargo auth token..." + # "cargo login" only saves a token and does not actually use it, so we use "cargo yank" to verify the token. + # This version has already been yanked, so it is safe to execute the command below repeatedly. + # This command succeeds if we have a token with permission to yank the crate. + cargo yank aws-sigv4 --version 0.55.0 + - name: Notify Slack on Failure + if: failure() + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + run: | + curl -X POST "${SLACK_WEBHOOK_URL}" -H 'Content-type: application/json' \ + --data '{"workflow_msg":"⚠️ Invalid crates.io token. Create a new token as soon as possible!"}' + + # Verifies the token used to perform actions on the repository on behalf of the bot user + verify-personal-access-token: + name: Verify Personal Access Token + runs-on: ubuntu-latest + steps: + - name: Checkout smithy-rs + # To test the validity of the personal access token, we only need to perform checkout with the specified token. + uses: actions/checkout@v3 + with: + token: ${{ secrets.RELEASE_AUTOMATION_BOT_PAT }} + - name: Notify Slack on Failure + if: failure() + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + run: | + curl -X POST "${SLACK_WEBHOOK_URL}" -H 'Content-type: application/json' \ + --data '{"workflow_msg":"⚠️ Invalid GitHub personal access token. Create a new token as soon as possible!"}' diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index a24f3b3ce64..6c6c641dae1 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -8,7 +8,7 @@ on: name: Update GitHub Pages env: - rust_version: 1.70.0 + rust_version: 1.72.1 # Allow only one doc pages build to run at a time for the entire smithy-rs repo concurrency: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 914ed8b5449..37fcdb81fad 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ concurrency: cancel-in-progress: true env: - rust_version: 1.70.0 + rust_version: 1.72.1 name: Release smithy-rs run-name: ${{ inputs.dry_run && 'Dry run' || 'Prod run' }} - ${{ github.workflow }} ${{ inputs.stable_semantic_version }}/${{ inputs.unstable_semantic_version }} (${{ inputs.commit_sha }}) diff --git a/.github/workflows/update-sdk-next.yml b/.github/workflows/update-sdk-next.yml index 5de480ab41a..b4ce960e0de 100644 --- a/.github/workflows/update-sdk-next.yml +++ b/.github/workflows/update-sdk-next.yml @@ -45,7 +45,7 @@ jobs: - name: Set up Rust uses: dtolnay/rust-toolchain@master with: - toolchain: 1.70.0 + toolchain: 1.72.1 - name: Delete old SDK run: | - name: Generate a fresh SDK diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 16924be2112..b29005e2067 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,8 +9,6 @@ repos: - repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks rev: v2.11.0 hooks: - - id: pretty-format-kotlin - args: [--autofix, --ktlint-version, 0.48.2] - id: pretty-format-yaml args: [--autofix, --indent, '2'] - id: pretty-format-rust @@ -18,6 +16,11 @@ repos: files: ^.*\.rs$ - repo: local hooks: + - id: ktlint + name: Ktlint + entry: ./.pre-commit-hooks/ktlint.sh + language: system + files: ^.*\.kt$ - id: kotlin-block-quotes name: Kotlin Block Quotes entry: ./.pre-commit-hooks/kotlin-block-quotes.py diff --git a/.pre-commit-hooks/kotlin-block-quotes.py b/.pre-commit-hooks/kotlin-block-quotes.py index 8a05f49550d..adbbbcffa85 100755 --- a/.pre-commit-hooks/kotlin-block-quotes.py +++ b/.pre-commit-hooks/kotlin-block-quotes.py @@ -64,7 +64,7 @@ def starts_or_ends_block_quote(line, inside_block_quotes): # Returns the indentation of a line def line_indent(line): - indent = re.search("[^\s]", line) + indent = re.search(r"[^\s]", line) if indent != None: return indent.start(0) else: @@ -72,7 +72,7 @@ def line_indent(line): # Changes the indentation of a line def adjust_indent(line, indent): - old_indent = re.search("[^\s]", line) + old_indent = re.search(r"[^\s]", line) if old_indent == None: return line line = line[old_indent.start(0):] @@ -168,7 +168,8 @@ def fix_file(file_name): print("INFO: Fixed indentation in `" + file_name + "`.") return True else: - print("INFO: `" + file_name + "` is fine.") + # This print is useful when debugging this script, but spammy otherwise. Leave it commented. + # print("INFO: `" + file_name + "` is fine.") return False class SelfTest(unittest.TestCase): diff --git a/.pre-commit-hooks/ktlint.sh b/.pre-commit-hooks/ktlint.sh new file mode 100755 index 00000000000..18cfe0772f4 --- /dev/null +++ b/.pre-commit-hooks/ktlint.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# + +set -e + +cd "$(git rev-parse --show-toplevel)" +# `-q`: run gradle in quiet mode +# `--console plain`: Turn off the fancy terminal printing in gradle +# `2>/dev/null`: Suppress the build success/failure output at the end since pre-commit will report failures +./gradlew -q --console plain ktlintPreCommit -DktlintPreCommitArgs="$*" 2>/dev/null diff --git a/CHANGELOG.md b/CHANGELOG.md index 86150e6ba43..0ccafaf7f76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,57 @@ +January 18th, 2024 +================== +**New this release:** +- (client, [smithy-rs#3318](https://github.com/smithy-lang/smithy-rs/issues/3318)) `EndpointPrefix` and `apply_endpoint` moved from aws-smithy-http to aws-smithy-runtime-api so that is in a stable (1.x) crate. A deprecated type alias was left in place with a note showing the new location. +- (client, [smithy-rs#3325](https://github.com/smithy-lang/smithy-rs/issues/3325)) The `Metadata` storable was moved from aws_smithy_http into aws_smithy_runtime_api. A deprecated type alias was left in place with a note showing where the new location is. + + +January 10th, 2024 +================== +**New this release:** +- :tada: (all, [smithy-rs#3300](https://github.com/smithy-lang/smithy-rs/issues/3300), [aws-sdk-rust#977](https://github.com/awslabs/aws-sdk-rust/issues/977)) Add support for constructing [`SdkBody`] and [`ByteStream`] from `http-body` 1.0 bodies. Note that this is initial support and works via a backwards compatibility shim to http-body 0.4. Hyper 1.0 is not supported. +- :tada: (all, [smithy-rs#3333](https://github.com/smithy-lang/smithy-rs/issues/3333), [aws-sdk-rust#998](https://github.com/awslabs/aws-sdk-rust/issues/998), [aws-sdk-rust#1010](https://github.com/awslabs/aws-sdk-rust/issues/1010)) Add `as_service_err()` to `SdkError` to allow checking the type of an error is without taking ownership. +- (client, [smithy-rs#3299](https://github.com/smithy-lang/smithy-rs/issues/3299), @Ploppz) Add `PaginationStreamExt` extension trait to `aws-smithy-types-convert` behind the `convert-streams` feature. This makes it possible to treat a paginator as a [`futures_core::Stream`](https://docs.rs/futures-core/latest/futures_core/stream/trait.Stream.html), allowing customers to use stream combinators like [`map`](https://docs.rs/tokio-stream/latest/tokio_stream/trait.StreamExt.html#method.map) and [`filter`](https://docs.rs/tokio-stream/latest/tokio_stream/trait.StreamExt.html#method.filter). + + Example: + + ```rust + use aws_smithy_types_convert::stream::PaginationStreamExt + let stream = s3_client.list_objects_v2().bucket("...").into_paginator().send().into_stream_03x(); + ``` +- :bug: (client, [smithy-rs#3252](https://github.com/smithy-lang/smithy-rs/issues/3252), [smithy-rs#3312](https://github.com/smithy-lang/smithy-rs/issues/3312), @milesziemer) Serialize 0/false in query parameters, and ignore actual default value during serialization instead of just 0/false. See [changelog discussion](https://github.com/smithy-lang/smithy-rs/discussions/3312) for details. +- (all, [smithy-rs#3292](https://github.com/smithy-lang/smithy-rs/issues/3292)) `requireEndpointResolver: false` is no longer required to remove the need for an endpoint resolver. Instead, `"awsSdkBuilder"` (default false), now _removes_ that requirement. + +**Contributors** +Thank you for your contributions! ❤ +- @Ploppz ([smithy-rs#3299](https://github.com/smithy-lang/smithy-rs/issues/3299)) +- @milesziemer ([smithy-rs#3252](https://github.com/smithy-lang/smithy-rs/issues/3252), [smithy-rs#3312](https://github.com/smithy-lang/smithy-rs/issues/3312)) + + +December 13th, 2023 +=================== + +December 11th, 2023 +=================== +**New this release:** +- :bug: (client, [smithy-rs#3305](https://github.com/smithy-lang/smithy-rs/issues/3305)) `crate::event_receiver::EventReceiver` is now re-exported as `crate::primitives::event_stream::EventReceiver` when a service supports event stream operations. + + +December 8th, 2023 +================== +**New this release:** +- :tada: (all, [smithy-rs#3121](https://github.com/smithy-lang/smithy-rs/issues/3121), [smithy-rs#3295](https://github.com/smithy-lang/smithy-rs/issues/3295)) All generated docs now include docsrs labels when features are required +- :bug: (client, [smithy-rs#3262](https://github.com/smithy-lang/smithy-rs/issues/3262)) Loading native TLS trusted certs for the default HTTP client now only occurs if the default HTTP client is not overridden in config. +- (client, [smithy-rs#3277](https://github.com/smithy-lang/smithy-rs/issues/3277)) Improve the error messages for when auth fails to select an auth scheme for a request. +- (client, [smithy-rs#3282](https://github.com/smithy-lang/smithy-rs/issues/3282)) Fix documentation and examples on HyperConnector and HyperClientBuilder. +- (client, [aws-sdk-rust#990](https://github.com/awslabs/aws-sdk-rust/issues/990), @declanvk) Expose local socket address from ConnectionMetadata. +- (all, [smithy-rs#3294](https://github.com/smithy-lang/smithy-rs/issues/3294)) [`Number`](https://docs.rs/aws-smithy-types/latest/aws_smithy_types/enum.Number.html) `TryInto` implementations now succesfully convert from `f64` to numeric types when no precision is lost. This fixes some deserialization issues where numbers like `25.0` were sent when `Byte` fields were expected. + +**Contributors** +Thank you for your contributions! ❤ +- @declanvk ([aws-sdk-rust#990](https://github.com/awslabs/aws-sdk-rust/issues/990)) + + December 1st, 2023 ================== **New this release:** diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index 77a969b1940..fc4c4c2578b 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -9,91 +9,4 @@ # message = "Fix typos in module documentation for generated crates" # references = ["smithy-rs#920"] # meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client | server | all"} -# author = "rcoh" - -[[aws-sdk-rust]] -message = "Loading native TLS trusted certs for the default HTTP client now only occurs if the default HTTP client is not overridden in config." -references = ["smithy-rs#3262"] -meta = { "breaking" = false, "tada" = false, "bug" = true } -author = "jdisanti" - -[[smithy-rs]] -message = "Loading native TLS trusted certs for the default HTTP client now only occurs if the default HTTP client is not overridden in config." -references = ["smithy-rs#3262"] -meta = { "breaking" = false, "tada" = false, "bug" = true, "target" = "client" } -author = "jdisanti" - -[[aws-sdk-rust]] -message = """Client creation now takes microseconds instead of milliseconds. -Previously, it would take 2-3 milliseconds for each client instantiation due to time spent compiling regexes. -For applications that used several clients, this would increase start-up time in cases where it really matters, -such as for AWS Lambda cold starts. This time was improved by both changing regex implementation and caching the -result of the compilation.""" -references = ["aws-sdk-rust#975", "smithy-rs#3269"] -meta = { "breaking" = false, "tada" = true, "bug" = false } -author = "jdisanti" - -[[aws-sdk-rust]] -message = """Add `test_credentials` to `ConfigLoader` in `aws_config`. This allows the following pattern during tests: - -```rust -async fn main() { - let conf = aws_config::defaults(BehaviorVersion::latest()) - .test_credentials() - .await; -} -``` - -This is designed for unit tests and using local mocks like DynamoDB Local and LocalStack with the SDK. -""" -meta = { "breaking" = false, "tada" = true, "bug" = false } -author = "rcoh" -references = ["smithy-rs#3279", "aws-sdk-rust#971"] - -[[aws-sdk-rust]] -message = "Improve the error messages for when auth fails to select an auth scheme for a request." -references = ["aws-sdk-rust#979", "smithy-rs#3277"] -meta = { "breaking" = false, "tada" = false, "bug" = false } -author = "jdisanti" - -[[smithy-rs]] -message = "Improve the error messages for when auth fails to select an auth scheme for a request." -references = ["smithy-rs#3277"] -meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client" } -author = "jdisanti" - -[[aws-sdk-rust]] -message = "Fix documentation and examples on HyperConnector and HyperClientBuilder." -references = ["aws-sdk-rust#986", "smithy-rs#3282"] -meta = { "breaking" = false, "tada" = false, "bug" = false } -author = "jdisanti" - -[[smithy-rs]] -message = "Fix documentation and examples on HyperConnector and HyperClientBuilder." -references = ["smithy-rs#3282"] -meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client" } -author = "jdisanti" - -[[smithy-rs]] -message = "Expose local socket address from ConnectionMetadata." -references = ["aws-sdk-rust#990"] -meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client" } -author = "declanvk" - -[[smithy-rs]] -message = "All generated docs now include docsrs labels when features are required" -references = ["smithy-rs#3121", "smithy-rs#3295"] -meta = { "breaking" = false, "tada" = true, "bug" = false, "target" = "all" } -author = "rcoh" - -[[aws-sdk-rust]] -message = "All generated docs now include docsrs labels when features are required" -references = ["smithy-rs#3121", "smithy-rs#3295"] -meta = { "breaking" = false, "tada" = true, "bug" = false } -author = "rcoh" - -[[smithy-rs]] -message = "[`Number`](https://docs.rs/aws-smithy-types/latest/aws_smithy_types/enum.Number.html) `TryInto` implementations now succesfully convert from `f64` to numeric types when no precision is lost. This fixes some deserialization issues where numbers like `25.0` were sent when `Byte` fields were expected." -references = ["smithy-rs#3294"] -meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "all" } -author = "rcoh" +# author = "rcoh" \ No newline at end of file diff --git a/aws/SDK_CHANGELOG.next.json b/aws/SDK_CHANGELOG.next.json index 8823e0a91ab..298b0700c63 100644 --- a/aws/SDK_CHANGELOG.next.json +++ b/aws/SDK_CHANGELOG.next.json @@ -6,90 +6,241 @@ "smithy-rs": [], "aws-sdk-rust": [ { - "message": "Make properties of S3Control PublicAccessBlockConfiguration optional. Previously, they defaulted to false, but this created invalid requests.", + "message": "Loading native TLS trusted certs for the default HTTP client now only occurs if the default HTTP client is not overridden in config.", "meta": { "bug": true, - "breaking": true, + "breaking": false, "tada": false }, - "author": "milesziemer", + "author": "jdisanti", "references": [ - "smithy-rs#3246" + "smithy-rs#3262" ], - "since-commit": "e155c3048b9989fe406ef575d461ea01dfaf294c", + "since-commit": "fc335cbc87e70aa63895828fca55b51795b94a6c", "age": 5 }, { - "message": "Allow `--` to be used in bucket names for S3", + "message": "Client creation now takes microseconds instead of milliseconds.\nPreviously, it would take 2-3 milliseconds for each client instantiation due to time spent compiling regexes.\nFor applications that used several clients, this would increase start-up time in cases where it really matters,\nsuch as for AWS Lambda cold starts. This time was improved by both changing regex implementation and caching the\nresult of the compilation.", "meta": { - "bug": true, + "bug": false, + "breaking": false, + "tada": true + }, + "author": "jdisanti", + "references": [ + "aws-sdk-rust#975", + "smithy-rs#3269" + ], + "since-commit": "fc335cbc87e70aa63895828fca55b51795b94a6c", + "age": 5 + }, + { + "message": "Add `test_credentials` to `ConfigLoader` in `aws_config`. This allows the following pattern during tests:\n\n```rust\nasync fn main() {\n let conf = aws_config::defaults(BehaviorVersion::latest())\n .test_credentials()\n .await;\n}\n```\n\nThis is designed for unit tests and using local mocks like DynamoDB Local and LocalStack with the SDK.\n", + "meta": { + "bug": false, + "breaking": false, + "tada": true + }, + "author": "rcoh", + "references": [ + "smithy-rs#3279", + "aws-sdk-rust#971" + ], + "since-commit": "fc335cbc87e70aa63895828fca55b51795b94a6c", + "age": 5 + }, + { + "message": "Improve the error messages for when auth fails to select an auth scheme for a request.", + "meta": { + "bug": false, + "breaking": false, + "tada": false + }, + "author": "jdisanti", + "references": [ + "aws-sdk-rust#979", + "smithy-rs#3277" + ], + "since-commit": "fc335cbc87e70aa63895828fca55b51795b94a6c", + "age": 5 + }, + { + "message": "Fix documentation and examples on HyperConnector and HyperClientBuilder.", + "meta": { + "bug": false, "breaking": false, "tada": false }, + "author": "jdisanti", + "references": [ + "aws-sdk-rust#986", + "smithy-rs#3282" + ], + "since-commit": "fc335cbc87e70aa63895828fca55b51795b94a6c", + "age": 5 + }, + { + "message": "All generated docs now include docsrs labels when features are required", + "meta": { + "bug": false, + "breaking": false, + "tada": true + }, "author": "rcoh", "references": [ - "smithy-rs#3253" + "smithy-rs#3121", + "smithy-rs#3295" ], - "since-commit": "48e3c95a3f10eebd5a637f8e7670c4232cdabbe4", + "since-commit": "fc335cbc87e70aa63895828fca55b51795b94a6c", + "age": 5 + }, + { + "message": "`crate::event_receiver::EventReceiver` is now re-exported as `crate::primitives::event_stream::EventReceiver` when a service supports event stream operations.", + "meta": { + "bug": true, + "breaking": false, + "tada": false + }, + "author": "ysaito1001", + "references": [ + "smithy-rs#3305" + ], + "since-commit": "9f0ba850e03241f657e2e40ca185780e0a5878cb", "age": 4 }, { - "message": "Retry additional classes of H2 errors (H2 GoAway & H2 ResetStream)", + "message": "Add support for constructing [`SdkBody`] and [`ByteStream`] from `http-body` 1.0 bodies. Note that this is initial support and works via a backwards compatibility shim to http-body 0.4. Hyper 1.0 is not supported.", "meta": { "bug": false, "breaking": false, - "tada": false + "tada": true }, "author": "rcoh", "references": [ - "aws-sdk-rust#738", - "aws-sdk-rust#858" + "smithy-rs#3300", + "aws-sdk-rust#977" + ], + "since-commit": "e235a2fd9ec45335a3b2018028c2d3a2ac13ffdf", + "age": 2 + }, + { + "message": " Add `PaginationStreamExt` extension trait to `aws-smithy-types-convert` behind the `convert-streams` feature. This makes it possible to treat a paginator as a [`futures_core::Stream`](https://docs.rs/futures-core/latest/futures_core/stream/trait.Stream.html), allowing customers to use stream combinators like [`map`](https://docs.rs/tokio-stream/latest/tokio_stream/trait.StreamExt.html#method.map) and [`filter`](https://docs.rs/tokio-stream/latest/tokio_stream/trait.StreamExt.html#method.filter).\n\nExample:\n\n```rust\nuse aws_smithy_types_convert::stream::PaginationStreamExt\nlet stream = s3_client.list_objects_v2().bucket(\"...\").into_paginator().send().into_stream_03x();\n```\n", + "meta": { + "bug": false, + "breaking": false, + "tada": false + }, + "author": "Ploppz", + "references": [ + "smithy-rs#3299" ], - "since-commit": "88970ba88ef45266aade152c7c1da8e90b24c0d7", + "since-commit": "e235a2fd9ec45335a3b2018028c2d3a2ac13ffdf", "age": 2 }, { - "message": "Make some properties for IoT types optional. Previously, they defaulted to false, but that isn't how the service actual works.", + "message": "Serialize 0/false in query parameters, and ignore actual default value during serialization instead of just 0/false. See [changelog discussion](https://github.com/smithy-lang/smithy-rs/discussions/3312) for details.", "meta": { "bug": true, - "breaking": true, + "breaking": false, "tada": false }, "author": "milesziemer", "references": [ - "smithy-rs#3256" + "smithy-rs#3252", + "smithy-rs#3312" + ], + "since-commit": "e235a2fd9ec45335a3b2018028c2d3a2ac13ffdf", + "age": 2 + }, + { + "message": "Add `as_service_err()` to `SdkError` to allow checking the type of an error is without taking ownership.", + "meta": { + "bug": false, + "breaking": false, + "tada": true + }, + "author": "rcoh", + "references": [ + "smithy-rs#3333", + "aws-sdk-rust#998", + "aws-sdk-rust#1010" ], - "since-commit": "88970ba88ef45266aade152c7c1da8e90b24c0d7", + "since-commit": "e235a2fd9ec45335a3b2018028c2d3a2ac13ffdf", "age": 2 }, { - "message": "Fix `config::Builder::set_credentials_provider` to override a credentials provider previously set.", + "message": "Fix bug in `CredentialsProcess` provider where `expiry` was incorrectly treated as a required field.", "meta": { "bug": true, "breaking": false, "tada": false }, - "author": "ysaito1001", + "author": "rcoh", "references": [ - "aws-sdk-rust#973", - "smithy-rs#3278" + "smithy-rs#3335", + "aws-sdk-rust#1021" ], - "since-commit": "529b3f03e2b945ea2e5e879183ccfd8e74b7377c", - "age": 1 + "since-commit": "e235a2fd9ec45335a3b2018028c2d3a2ac13ffdf", + "age": 2 + }, + { + "message": "~/.aws/config and ~/.aws/credentials now parse keys in a case-insensitive way. This means the `AWS_SECRET_ACCESS_KEY` is supported in addition to `aws_secret_access_key`.", + "meta": { + "bug": true, + "breaking": false, + "tada": false + }, + "author": "rcoh", + "references": [ + "aws-sdk#574", + "aws-sdk-rust#1020", + "smithy-rs#3344" + ], + "since-commit": "e235a2fd9ec45335a3b2018028c2d3a2ac13ffdf", + "age": 2 }, { - "message": "`config::Config::credentials_provider` has been broken since `release-2023-11-15` and is now marked as `deprecated` explicitly.", + "message": "`EndpointPrefix` and `apply_endpoint` moved from aws-smithy-http to aws-smithy-runtime-api so that is in a stable (1.x) crate. A deprecated type alias was left in place with a note showing the new location.", "meta": { "bug": false, "breaking": false, "tada": false }, - "author": "ysaito1001", + "author": "jdisanti", + "references": [ + "smithy-rs#3318" + ], + "since-commit": "edf6e77bfa991aef9afa5acf293a911f7982511a", + "age": 1 + }, + { + "message": "Fix bug where overriding the credentials at the operation level failed if credentials were already set.", + "meta": { + "bug": true, + "breaking": false, + "tada": false + }, + "author": "rcoh", + "references": [ + "aws-sdk-rust#901", + "smithy-rs#3363" + ], + "since-commit": "edf6e77bfa991aef9afa5acf293a911f7982511a", + "age": 1 + }, + { + "message": "Add `apply_to_request_http1x` to `aws-sigv4` to enable signing http = 1.0 requests.", + "meta": { + "bug": false, + "breaking": false, + "tada": true + }, + "author": "rcoh", "references": [ - "smithy-rs#3251", - "smithy-rs#3278" + "aws-sdk-rust#1041", + "smithy-rs#3366" ], - "since-commit": "529b3f03e2b945ea2e5e879183ccfd8e74b7377c", + "since-commit": "edf6e77bfa991aef9afa5acf293a911f7982511a", "age": 1 } ], diff --git a/aws/rust-runtime/Cargo.toml b/aws/rust-runtime/Cargo.toml index 0e32e03bfc6..03bc62f1516 100644 --- a/aws/rust-runtime/Cargo.toml +++ b/aws/rust-runtime/Cargo.toml @@ -1,7 +1,7 @@ # Note: this workspace exists solely for the convenience of running tests. These packages will all eventually # end up in the final SDK workspace. [workspace] - +resolver = "2" members = [ "aws-credential-types", "aws-endpoint", diff --git a/aws/rust-runtime/aws-config/Cargo.toml b/aws/rust-runtime/aws-config/Cargo.toml index b124e10dd4f..b9552409687 100644 --- a/aws/rust-runtime/aws-config/Cargo.toml +++ b/aws/rust-runtime/aws-config/Cargo.toml @@ -56,7 +56,7 @@ aws-sdk-ssooidc = { path = "../../sdk/build/aws-sdk/sdk/ssooidc", default-featur [dev-dependencies] aws-smithy-runtime = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-runtime", features = ["client", "connector-hyper-0-14-x", "test-util"] } aws-smithy-runtime-api = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-runtime-api", features = ["test-util"] } -futures-util = { version = "0.3.16", default-features = false } +futures-util = { version = "0.3.29", default-features = false } tracing-test = "0.2.1" tracing-subscriber = { version = "0.3.16", features = ["fmt", "json"] } @@ -77,6 +77,7 @@ aws-smithy-async = { path = "../../sdk/build/aws-sdk/sdk/aws-smithy-async", feat [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/aws/rust-runtime/aws-config/src/credential_process.rs b/aws/rust-runtime/aws-config/src/credential_process.rs index a46c6298c6b..e60ce4a241c 100644 --- a/aws/rust-runtime/aws-config/src/credential_process.rs +++ b/aws/rust-runtime/aws-config/src/credential_process.rs @@ -7,7 +7,7 @@ //! Credentials Provider for external process -use crate::json_credentials::{json_parse_loop, InvalidJsonCredentials, RefreshableCredentials}; +use crate::json_credentials::{json_parse_loop, InvalidJsonCredentials}; use crate::sensitive_command::CommandWithSensitiveArgs; use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials}; use aws_credential_types::Credentials; @@ -120,25 +120,12 @@ impl CredentialProcessProvider { )) })?; - match parse_credential_process_json_credentials(output) { - Ok(RefreshableCredentials { - access_key_id, - secret_access_key, - session_token, - expiration, - .. - }) => Ok(Credentials::new( - access_key_id, - secret_access_key, - Some(session_token.to_string()), - expiration.into(), - "CredentialProcess", - )), - Err(invalid) => Err(CredentialsError::provider_error(format!( + parse_credential_process_json_credentials(output).map_err(|invalid| { + CredentialsError::provider_error(format!( "Error retrieving credentials from external process, could not parse response: {}", invalid - ))), - } + )) + }) } } @@ -149,7 +136,7 @@ impl CredentialProcessProvider { /// Keys are case insensitive. pub(crate) fn parse_credential_process_json_credentials( credentials_response: &str, -) -> Result, InvalidJsonCredentials> { +) -> Result { let mut version = None; let mut access_key_id = None; let mut secret_access_key = None; @@ -206,25 +193,32 @@ pub(crate) fn parse_credential_process_json_credentials( let access_key_id = access_key_id.ok_or(InvalidJsonCredentials::MissingField("AccessKeyId"))?; let secret_access_key = secret_access_key.ok_or(InvalidJsonCredentials::MissingField("SecretAccessKey"))?; - let session_token = session_token.ok_or(InvalidJsonCredentials::MissingField("Token"))?; - let expiration = expiration.ok_or(InvalidJsonCredentials::MissingField("Expiration"))?; - let expiration = - SystemTime::try_from(OffsetDateTime::parse(&expiration, &Rfc3339).map_err(|err| { + let expiration = expiration.map(parse_expiration).transpose()?; + if expiration.is_none() { + tracing::debug!("no expiration provided for credentials provider credentials. these credentials will never be refreshed.") + } + Ok(Credentials::new( + access_key_id, + secret_access_key, + session_token.map(|tok| tok.to_string()), + expiration, + "CredentialProcess", + )) +} + +fn parse_expiration(expiration: impl AsRef) -> Result { + SystemTime::try_from( + OffsetDateTime::parse(expiration.as_ref(), &Rfc3339).map_err(|err| { InvalidJsonCredentials::InvalidField { field: "Expiration", err: err.into(), } - })?) - .map_err(|_| { - InvalidJsonCredentials::Other( - "credential expiration time cannot be represented by a DateTime".into(), - ) - })?; - Ok(RefreshableCredentials { - access_key_id, - secret_access_key, - session_token, - expiration, + })?, + ) + .map_err(|_| { + InvalidJsonCredentials::Other( + "credential expiration time cannot be represented by a DateTime".into(), + ) }) } @@ -258,6 +252,18 @@ mod test { ); } + #[tokio::test] + async fn test_credential_process_no_expiry() { + let provider = CredentialProcessProvider::new(String::from( + r#"echo '{ "Version": 1, "AccessKeyId": "ASIARTESTID", "SecretAccessKey": "TESTSECRETKEY" }'"#, + )); + let creds = provider.provide_credentials().await.expect("valid creds"); + assert_eq!(creds.access_key_id(), "ASIARTESTID"); + assert_eq!(creds.secret_access_key(), "TESTSECRETKEY"); + assert_eq!(creds.session_token(), None); + assert_eq!(creds.expiry(), None); + } + #[tokio::test] async fn credentials_process_timeouts() { let provider = CredentialProcessProvider::new(String::from("sleep 1000")); diff --git a/aws/rust-runtime/aws-config/src/default_provider.rs b/aws/rust-runtime/aws-config/src/default_provider.rs index 78cec3edfa1..21de20dd5ca 100644 --- a/aws/rust-runtime/aws-config/src/default_provider.rs +++ b/aws/rust-runtime/aws-config/src/default_provider.rs @@ -5,7 +5,7 @@ //! Providers that implement the default AWS provider chain //! -//! Default Provider chains for [`region`](crate::default_provider::region), [`credentials`](crate::default_provider::credentials), +//! Default Provider chains for [`region`], [`credentials`], //! [retries](crate::default_provider::retry_config), [timeouts](crate::default_provider::timeout_config) and //! [app name](crate::default_provider::app_name). //! diff --git a/aws/rust-runtime/aws-config/src/default_provider/credentials.rs b/aws/rust-runtime/aws-config/src/default_provider/credentials.rs index 7c9aaa06e71..2999117c293 100644 --- a/aws/rust-runtime/aws-config/src/default_provider/credentials.rs +++ b/aws/rust-runtime/aws-config/src/default_provider/credentials.rs @@ -25,7 +25,7 @@ pub async fn default_provider() -> impl ProvideCredentials { /// Default AWS Credential Provider Chain /// /// Resolution order: -/// 1. Environment variables: [`EnvironmentVariableCredentialsProvider`](crate::environment::EnvironmentVariableCredentialsProvider) +/// 1. Environment variables: [`EnvironmentVariableCredentialsProvider`] /// 2. Shared config (`~/.aws/config`, `~/.aws/credentials`): [`SharedConfigCredentialsProvider`](crate::profile::ProfileFileCredentialsProvider) /// 3. [Web Identity Tokens](crate::web_identity_token) /// 4. ECS (IAM Roles for Tasks) & General HTTP credentials: [`ecs`](crate::ecs) @@ -90,7 +90,7 @@ impl ProvideCredentials for DefaultCredentialsChain { } } -/// Builder for [`DefaultCredentialsChain`](DefaultCredentialsChain) +/// Builder for [`DefaultCredentialsChain`]. #[derive(Debug, Default)] pub struct Builder { profile_file_builder: crate::profile::credentials::Builder, @@ -268,6 +268,7 @@ mod test { make_test!(prefer_environment); make_test!(profile_static_keys); + make_test!(profile_static_keys_case_insensitive); make_test!(web_identity_token_env); make_test!(web_identity_source_profile_no_env); make_test!(web_identity_token_invalid_jwt); diff --git a/aws/rust-runtime/aws-config/src/default_provider/retry_config.rs b/aws/rust-runtime/aws-config/src/default_provider/retry_config.rs index 1f260000d04..a0ba777190f 100644 --- a/aws/rust-runtime/aws-config/src/default_provider/retry_config.rs +++ b/aws/rust-runtime/aws-config/src/default_provider/retry_config.rs @@ -81,7 +81,7 @@ impl Builder { self } - /// Attempt to create a [RetryConfig](aws_smithy_types::retry::RetryConfig) from following sources in order: + /// Attempt to create a [`RetryConfig`] from following sources in order: /// 1. Environment variables: `AWS_MAX_ATTEMPTS` & `AWS_RETRY_MODE` /// 2. Profile file: `max_attempts` and `retry_mode` /// 3. [RetryConfig::standard()](aws_smithy_types::retry::RetryConfig::standard) diff --git a/aws/rust-runtime/aws-config/src/ecs.rs b/aws/rust-runtime/aws-config/src/ecs.rs index ed0125b69a2..eb731b7349c 100644 --- a/aws/rust-runtime/aws-config/src/ecs.rs +++ b/aws/rust-runtime/aws-config/src/ecs.rs @@ -49,7 +49,7 @@ use crate::http_credential_provider::HttpCredentialProvider; use crate::provider_config::ProviderConfig; use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials}; -use aws_smithy_http::endpoint::apply_endpoint; +use aws_smithy_runtime::client::endpoint::apply_endpoint; use aws_smithy_runtime_api::client::dns::{ResolveDns, ResolveDnsError, SharedDnsResolver}; use aws_smithy_runtime_api::client::http::HttpConnectorSettings; use aws_smithy_runtime_api::shared::IntoShared; @@ -272,7 +272,7 @@ impl Builder { /// Override the DNS resolver used to validate URIs /// - /// URIs must refer to loopback addresses. The [`ResolveDns`](aws_smithy_runtime_api::client::dns::ResolveDns) + /// URIs must refer to loopback addresses. The [`ResolveDns`] /// implementation is used to retrieve IP addresses for a given domain. pub fn dns(mut self, dns: impl ResolveDns + 'static) -> Self { self.dns = Some(dns.into_shared()); diff --git a/aws/rust-runtime/aws-config/src/lib.rs b/aws/rust-runtime/aws-config/src/lib.rs index 8b67d520cc3..afb0f9ea2c5 100644 --- a/aws/rust-runtime/aws-config/src/lib.rs +++ b/aws/rust-runtime/aws-config/src/lib.rs @@ -14,15 +14,16 @@ rustdoc::missing_crate_level_docs, unreachable_pub )] +// Allow disallowed methods in tests +#![cfg_attr(test, allow(clippy::disallowed_methods))] //! `aws-config` provides implementations of region and credential resolution. //! //! These implementations can be used either via the default chain implementation //! [`from_env`]/[`ConfigLoader`] or ad-hoc individual credential and region providers. //! -//! [`ConfigLoader`](ConfigLoader) can combine different configuration sources into an AWS shared-config: -//! [`SdkConfig`](aws_types::SdkConfig). [`SdkConfig`](aws_types::SdkConfig) can be used configure -//! an AWS service client. +//! [`ConfigLoader`] can combine different configuration sources into an AWS shared-config: +//! [`SdkConfig`]. `SdkConfig` can be used configure an AWS service client. //! //! # Examples //! @@ -241,7 +242,7 @@ mod loader { Set(SharedCredentialsProvider), } - /// Load a cross-service [`SdkConfig`](aws_types::SdkConfig) from the environment + /// Load a cross-service [`SdkConfig`] from the environment /// /// This builder supports overriding individual components of the generated config. Overriding a component /// will skip the standard resolution chain from **for that component**. For example, @@ -271,13 +272,13 @@ mod loader { } impl ConfigLoader { - /// Sets the [`BehaviorVersion`] used to build [`SdkConfig`](aws_types::SdkConfig). + /// Sets the [`BehaviorVersion`] used to build [`SdkConfig`]. pub fn behavior_version(mut self, behavior_version: BehaviorVersion) -> Self { self.behavior_version = Some(behavior_version); self } - /// Override the region used to build [`SdkConfig`](aws_types::SdkConfig). + /// Override the region used to build [`SdkConfig`]. /// /// # Examples /// ```no_run @@ -293,7 +294,7 @@ mod loader { self } - /// Override the retry_config used to build [`SdkConfig`](aws_types::SdkConfig). + /// Override the retry_config used to build [`SdkConfig`]. /// /// # Examples /// ```no_run @@ -311,7 +312,7 @@ mod loader { self } - /// Override the timeout config used to build [`SdkConfig`](aws_types::SdkConfig). + /// Override the timeout config used to build [`SdkConfig`]. /// /// **Note: This only sets timeouts for calls to AWS services.** Timeouts for the credentials /// provider chain are configured separately. @@ -358,7 +359,7 @@ mod loader { self } - /// Override the [`HttpClient`](aws_smithy_runtime_api::client::http::HttpClient) for this [`ConfigLoader`]. + /// Override the [`HttpClient`] for this [`ConfigLoader`]. /// /// The HTTP client will be used for both AWS services and credentials providers. /// @@ -394,7 +395,7 @@ mod loader { self } - /// Override the identity cache used to build [`SdkConfig`](aws_types::SdkConfig). + /// Override the identity cache used to build [`SdkConfig`]. /// /// The identity cache caches AWS credentials and SSO tokens. By default, a lazy cache is used /// that will load credentials upon first request, cache them, and then reload them during @@ -428,7 +429,7 @@ mod loader { self } - /// Override the credentials provider used to build [`SdkConfig`](aws_types::SdkConfig). + /// Override the credentials provider used to build [`SdkConfig`]. /// /// # Examples /// @@ -486,7 +487,7 @@ mod loader { self.credentials_provider(Credentials::for_tests()) } - /// Override the name of the app used to build [`SdkConfig`](aws_types::SdkConfig). + /// Override the name of the app used to build [`SdkConfig`]. /// /// This _optional_ name is used to identify the application in the user agent that /// gets sent along with requests. @@ -610,7 +611,7 @@ mod loader { self } - /// Override the [`StalledStreamProtectionConfig`] used to build [`SdkConfig`](aws_types::SdkConfig). + /// Override the [`StalledStreamProtectionConfig`] used to build [`SdkConfig`]. /// /// This configures stalled stream protection. When enabled, download streams /// that stop (stream no data) for longer than a configured grace period will return an error. @@ -651,7 +652,7 @@ mod loader { /// /// NOTE: When an override is provided, the default implementation is **not** used as a fallback. /// This means that if you provide a region provider that does not return a region, no region will - /// be set in the resulting [`SdkConfig`](aws_types::SdkConfig) + /// be set in the resulting [`SdkConfig`]. pub async fn load(self) -> SdkConfig { let time_source = self.time_source.unwrap_or_default(); diff --git a/aws/rust-runtime/aws-config/src/meta/credentials/chain.rs b/aws/rust-runtime/aws-config/src/meta/credentials/chain.rs index 732d2b08fdd..884c016bf17 100644 --- a/aws/rust-runtime/aws-config/src/meta/credentials/chain.rs +++ b/aws/rust-runtime/aws-config/src/meta/credentials/chain.rs @@ -14,11 +14,9 @@ use tracing::Instrument; /// Credentials provider that checks a series of inner providers /// /// Each provider will be evaluated in order: -/// * If a provider returns valid [`Credentials`](aws_credential_types::Credentials) they will be returned immediately. +/// * If a provider returns valid [`Credentials`] they will be returned immediately. /// No other credential providers will be used. -/// * Otherwise, if a provider returns -/// [`CredentialsError::CredentialsNotLoaded`](aws_credential_types::provider::error::CredentialsError::CredentialsNotLoaded), -/// the next provider will be checked. +/// * Otherwise, if a provider returns [`CredentialsError::CredentialsNotLoaded`], the next provider will be checked. /// * Finally, if a provider returns any other error condition, an error will be returned immediately. /// /// # Examples diff --git a/aws/rust-runtime/aws-config/src/meta/region.rs b/aws/rust-runtime/aws-config/src/meta/region.rs index 737f7949fd5..343dd1ac229 100644 --- a/aws/rust-runtime/aws-config/src/meta/region.rs +++ b/aws/rust-runtime/aws-config/src/meta/region.rs @@ -127,7 +127,7 @@ pub mod future { } } -/// Provide a [`Region`](Region) to use with AWS requests +/// Provide a [`Region`] to use with AWS requests /// /// For most cases [`default_provider`](crate::default_provider::region::default_provider) will be the best option, implementing /// a standard provider chain. diff --git a/aws/rust-runtime/aws-config/src/profile/mod.rs b/aws/rust-runtime/aws-config/src/profile/mod.rs index 56490f33352..d57aa7ab784 100644 --- a/aws/rust-runtime/aws-config/src/profile/mod.rs +++ b/aws/rust-runtime/aws-config/src/profile/mod.rs @@ -6,7 +6,7 @@ //! Load configuration from AWS Profiles //! //! AWS profiles are typically stored in `~/.aws/config` and `~/.aws/credentials`. For more details -//! see the [`load`](parser::load) function. +//! see the [`load`] function. mod parser; diff --git a/aws/rust-runtime/aws-config/src/profile/parser.rs b/aws/rust-runtime/aws-config/src/profile/parser.rs index ef291e264ba..dfa705823e4 100644 --- a/aws/rust-runtime/aws-config/src/profile/parser.rs +++ b/aws/rust-runtime/aws-config/src/profile/parser.rs @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -use crate::profile::parser::parse::parse_profile_file; +use crate::profile::parser::parse::{parse_profile_file, to_ascii_lowercase}; use crate::profile::parser::source::Source; use crate::profile::profile_file::ProfileFiles; use aws_types::os_shim_internal::{Env, Fs}; @@ -149,7 +149,7 @@ impl ProfileSet { /// An individual configuration profile /// -/// An AWS config may be composed of a multiple named profiles within a [`ProfileSet`](ProfileSet) +/// An AWS config may be composed of a multiple named profiles within a [`ProfileSet`]. #[derive(Debug, Clone, Eq, PartialEq)] pub struct Profile { name: String, @@ -169,7 +169,9 @@ impl Profile { /// Returns a reference to the property named `name` pub fn get(&self, name: &str) -> Option<&str> { - self.properties.get(name).map(|prop| prop.value()) + self.properties + .get(to_ascii_lowercase(name).as_ref()) + .map(|prop| prop.value()) } } diff --git a/aws/rust-runtime/aws-config/src/profile/parser/normalize.rs b/aws/rust-runtime/aws-config/src/profile/parser/normalize.rs index 5b3b5c1ea8c..36518d9ef71 100644 --- a/aws/rust-runtime/aws-config/src/profile/parser/normalize.rs +++ b/aws/rust-runtime/aws-config/src/profile/parser/normalize.rs @@ -113,9 +113,9 @@ pub(super) fn merge_in( } } -fn merge_into_base(target: &mut Profile, profile: HashMap<&str, Cow<'_, str>>) { +fn merge_into_base(target: &mut Profile, profile: HashMap, Cow<'_, str>>) { for (k, v) in profile { - match validate_identifier(k) { + match validate_identifier(k.as_ref()) { Ok(k) => { target .properties @@ -146,6 +146,7 @@ fn validate_identifier(input: &str) -> Result<&str, ()> { #[cfg(test)] mod tests { + use std::borrow::Cow; use std::collections::HashMap; use tracing_test::traced_test; @@ -218,7 +219,7 @@ mod tests { let mut profile: RawProfileSet<'_> = HashMap::new(); profile.insert("default", { let mut out = HashMap::new(); - out.insert("invalid key", "value".into()); + out.insert(Cow::Borrowed("invalid key"), "value".into()); out }); let mut base = ProfileSet::empty(); diff --git a/aws/rust-runtime/aws-config/src/profile/parser/parse.rs b/aws/rust-runtime/aws-config/src/profile/parser/parse.rs index 1d3c3acb057..062c32fa343 100644 --- a/aws/rust-runtime/aws-config/src/profile/parser/parse.rs +++ b/aws/rust-runtime/aws-config/src/profile/parser/parse.rs @@ -19,7 +19,7 @@ use std::error::Error; use std::fmt::{self, Display, Formatter}; /// A set of profiles that still carries a reference to the underlying data -pub(super) type RawProfileSet<'a> = HashMap<&'a str, HashMap<&'a str, Cow<'a, str>>>; +pub(super) type RawProfileSet<'a> = HashMap<&'a str, HashMap, Cow<'a, str>>>; /// Characters considered to be whitespace by the spec /// @@ -98,7 +98,7 @@ enum State<'a> { Starting, ReadingProfile { profile: &'a str, - property: Option<&'a str>, + property: Option>, is_subproperty: bool, }, } @@ -152,7 +152,7 @@ impl<'a> Parser<'a> { .map_err(|err| err.into_error("property", location.clone()))?; self.state = State::ReadingProfile { profile: name, - property: Some(k), + property: Some(k.clone()), is_subproperty: v.is_empty(), }; current_profile.insert(k, v.into()); @@ -184,7 +184,7 @@ impl<'a> Parser<'a> { self.data .get_mut(*profile) .expect("profile must exist") - .get_mut(*property) + .get_mut(property.as_ref()) .expect("property must exist") } State::ReadingProfile { @@ -246,7 +246,7 @@ impl PropertyError { } /// Parse a property line into a key-value pair -fn parse_property_line(line: &str) -> Result<(&str, &str), PropertyError> { +fn parse_property_line(line: &str) -> Result<(Cow<'_, str>, &str), PropertyError> { let line = prepare_line(line, true); let (k, v) = line.split_once('=').ok_or(PropertyError::NoEquals)?; let k = k.trim_matches(WHITESPACE); @@ -254,7 +254,15 @@ fn parse_property_line(line: &str) -> Result<(&str, &str), PropertyError> { if k.is_empty() { return Err(PropertyError::NoName); } - Ok((k, v)) + Ok((to_ascii_lowercase(k), v)) +} + +pub(crate) fn to_ascii_lowercase(s: &str) -> Cow<'_, str> { + if s.bytes().any(|b| b.is_ascii_uppercase()) { + Cow::Owned(s.to_ascii_lowercase()) + } else { + Cow::Borrowed(s) + } } /// Prepare a line for parsing @@ -291,23 +299,30 @@ mod test { use crate::profile::parser::parse::{parse_property_line, PropertyError}; use crate::profile::parser::source::File; use crate::profile::profile_file::ProfileFileKind; + use std::borrow::Cow; // most test cases covered by the JSON test suite #[test] fn property_parsing() { - assert_eq!(parse_property_line("a = b"), Ok(("a", "b"))); - assert_eq!(parse_property_line("a=b"), Ok(("a", "b"))); - assert_eq!(parse_property_line("a = b "), Ok(("a", "b"))); - assert_eq!(parse_property_line(" a = b "), Ok(("a", "b"))); - assert_eq!(parse_property_line(" a = b 🐱 "), Ok(("a", "b 🐱"))); + fn ok<'a>(key: &'a str, value: &'a str) -> Result<(Cow<'a, str>, &'a str), PropertyError> { + Ok((Cow::Borrowed(key), value)) + } + + assert_eq!(parse_property_line("a = b"), ok("a", "b")); + assert_eq!(parse_property_line("a=b"), ok("a", "b")); + assert_eq!(parse_property_line("a = b "), ok("a", "b")); + assert_eq!(parse_property_line(" a = b "), ok("a", "b")); + assert_eq!(parse_property_line(" a = b 🐱 "), ok("a", "b 🐱")); assert_eq!(parse_property_line("a b"), Err(PropertyError::NoEquals)); assert_eq!(parse_property_line("= b"), Err(PropertyError::NoName)); - assert_eq!(parse_property_line("a = "), Ok(("a", ""))); + assert_eq!(parse_property_line("a = "), ok("a", "")); assert_eq!( parse_property_line("something_base64=aGVsbG8gZW50aHVzaWFzdGljIHJlYWRlcg=="), - Ok(("something_base64", "aGVsbG8gZW50aHVzaWFzdGljIHJlYWRlcg==")) + ok("something_base64", "aGVsbG8gZW50aHVzaWFzdGljIHJlYWRlcg==") ); + + assert_eq!(parse_property_line("ABc = DEF"), ok("abc", "DEF")); } #[test] diff --git a/aws/rust-runtime/aws-config/src/profile/parser/source.rs b/aws/rust-runtime/aws-config/src/profile/parser/source.rs index 1b859fcee90..12931843d10 100644 --- a/aws/rust-runtime/aws-config/src/profile/parser/source.rs +++ b/aws/rust-runtime/aws-config/src/profile/parser/source.rs @@ -38,7 +38,7 @@ pub(super) struct File { pub(super) contents: String, } -/// Load a [Source](Source) from a given environment and filesystem. +/// Load a [`Source`] from a given environment and filesystem. pub(super) async fn load( proc_env: &os_shim_internal::Env, fs: &os_shim_internal::Fs, @@ -77,7 +77,7 @@ fn file_contents_to_string(path: &Path, contents: Vec) -> String { /// Loads an AWS Config file /// /// Both the default & the overriding patterns may contain `~/` which MUST be expanded to the users -/// home directory in a platform-aware way (see [`expand_home`](expand_home)) +/// home directory in a platform-aware way (see [`expand_home`]). /// /// Arguments: /// * `kind`: The type of config file to load diff --git a/aws/rust-runtime/aws-config/src/web_identity_token.rs b/aws/rust-runtime/aws-config/src/web_identity_token.rs index 7ae4e2f8b0e..bb1a72a163e 100644 --- a/aws/rust-runtime/aws-config/src/web_identity_token.rs +++ b/aws/rust-runtime/aws-config/src/web_identity_token.rs @@ -158,7 +158,7 @@ impl WebIdentityTokenCredentialsProvider { } } -/// Builder for [`WebIdentityTokenCredentialsProvider`](WebIdentityTokenCredentialsProvider) +/// Builder for [`WebIdentityTokenCredentialsProvider`]. #[derive(Debug, Default)] pub struct Builder { source: Option, @@ -183,7 +183,7 @@ impl Builder { self } - /// Configure this builder to use [`StaticConfiguration`](StaticConfiguration) + /// Configure this builder to use [`StaticConfiguration`]. /// /// WebIdentityToken providers load credentials from the file system. The file system path used /// may either determine be loaded from environment variables (default), or via a statically diff --git a/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/env.json b/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/env.json new file mode 100644 index 00000000000..55fcfbeb051 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/env.json @@ -0,0 +1,3 @@ +{ + "HOME": "/home" +} diff --git a/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/fs/home/.aws/config b/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/fs/home/.aws/config new file mode 100644 index 00000000000..a8c11c6e8c4 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/fs/home/.aws/config @@ -0,0 +1,2 @@ +[default] +region = us-east-1 diff --git a/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/fs/home/.aws/credentials b/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/fs/home/.aws/credentials new file mode 100644 index 00000000000..bac520774d7 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/fs/home/.aws/credentials @@ -0,0 +1,3 @@ +[default] +AWS_ACCESS_KEY_ID = correct_key +AWS_SECRET_ACCESS_KEY = correct_secret diff --git a/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/http-traffic.json b/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/http-traffic.json new file mode 100644 index 00000000000..489a35c6115 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/http-traffic.json @@ -0,0 +1,5 @@ +{ + "events": [], + "docs": "test case uses static creds, no network requests", + "version": "V0" +} diff --git a/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/test-case.json b/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/test-case.json new file mode 100644 index 00000000000..c56a02bac65 --- /dev/null +++ b/aws/rust-runtime/aws-config/test-data/default-provider-chain/profile_static_keys_case_insensitive/test-case.json @@ -0,0 +1,10 @@ +{ + "name": "profile_static_keys", + "docs": "load static keys from a profile", + "result": { + "Ok": { + "access_key_id": "correct_key", + "secret_access_key": "correct_secret" + } + } +} diff --git a/aws/rust-runtime/aws-config/test-data/profile-parser-tests.json b/aws/rust-runtime/aws-config/test-data/profile-parser-tests.json index 70ce8a046ec..6f6f2a8a706 100644 --- a/aws/rust-runtime/aws-config/test-data/profile-parser-tests.json +++ b/aws/rust-runtime/aws-config/test-data/profile-parser-tests.json @@ -452,6 +452,19 @@ } } }, + { + "name": "Duplicate properties in duplicate profiles use the last one defined (case insensitive).", + "input": { + "configFile": "[profile foo]\nName = value\n[profile foo]\nname = value2" + }, + "output": { + "profiles": { + "foo": { + "name": "value2" + } + } + } + }, { "name": "Default profile with profile prefix overrides default profile without prefix when profile prefix is first.", "input": { @@ -518,7 +531,7 @@ "output": { "profiles": { "foo": { - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_": "value" + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789-_": "value" } } } diff --git a/aws/rust-runtime/aws-credential-types/Cargo.toml b/aws/rust-runtime/aws-credential-types/Cargo.toml index 865542ca0e1..9b25683c15e 100644 --- a/aws/rust-runtime/aws-credential-types/Cargo.toml +++ b/aws/rust-runtime/aws-credential-types/Cargo.toml @@ -18,12 +18,13 @@ aws-smithy-runtime-api = { path = "../../../rust-runtime/aws-smithy-runtime-api" zeroize = "1" [dev-dependencies] -async-trait = "0.1.51" # used to test compatibility +async-trait = "0.1.74" # used to test compatibility tokio = { version = "1.23.1", features = ["full", "test-util", "rt"] } [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/aws/rust-runtime/aws-credential-types/src/credentials_impl.rs b/aws/rust-runtime/aws-credential-types/src/credentials_impl.rs index 5dbc14b4d3c..c7595bb66c2 100644 --- a/aws/rust-runtime/aws-credential-types/src/credentials_impl.rs +++ b/aws/rust-runtime/aws-credential-types/src/credentials_impl.rs @@ -95,7 +95,7 @@ impl Credentials { /// /// This function requires the `hardcoded-credentials` feature to be enabled. /// - /// [`Credentials`](crate::Credentials) implement + /// [`Credentials`] implement /// [`ProvideCredentials`](crate::provider::ProvideCredentials) directly, so no custom provider /// implementation is required when wiring these up to a client: /// ```rust diff --git a/aws/rust-runtime/aws-endpoint/Cargo.toml b/aws/rust-runtime/aws-endpoint/Cargo.toml index 9c2cc01257d..444f05299d5 100644 --- a/aws/rust-runtime/aws-endpoint/Cargo.toml +++ b/aws/rust-runtime/aws-endpoint/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aws-endpoint" -version = "0.0.0-smithy-rs-head" +version = "0.60.3" authors = ["AWS Rust SDK Team ", "Russell Cohen "] description = "This crate is no longer used by the AWS SDK and is deprecated." edition = "2021" @@ -10,5 +10,6 @@ repository = "https://github.com/smithy-lang/smithy-rs" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/aws/rust-runtime/aws-http/Cargo.toml b/aws/rust-runtime/aws-http/Cargo.toml index a6303982f65..e33b302d648 100644 --- a/aws/rust-runtime/aws-http/Cargo.toml +++ b/aws/rust-runtime/aws-http/Cargo.toml @@ -24,5 +24,6 @@ tokio = { version = "1.23.1", features = ["macros", "rt", "time"] } [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/aws/rust-runtime/aws-http/src/content_encoding.rs b/aws/rust-runtime/aws-http/src/content_encoding.rs index dc9c62a1c7a..2c00cff9cb9 100644 --- a/aws/rust-runtime/aws-http/src/content_encoding.rs +++ b/aws/rust-runtime/aws-http/src/content_encoding.rs @@ -21,7 +21,7 @@ pub mod header_value { pub const AWS_CHUNKED: &str = "aws-chunked"; } -/// Options used when constructing an [`AwsChunkedBody`][AwsChunkedBody]. +/// Options used when constructing an [`AwsChunkedBody`]. #[derive(Debug, Default)] #[non_exhaustive] pub struct AwsChunkedBodyOptions { @@ -35,7 +35,7 @@ pub struct AwsChunkedBodyOptions { } impl AwsChunkedBodyOptions { - /// Create a new [`AwsChunkedBodyOptions`][AwsChunkedBodyOptions] + /// Create a new [`AwsChunkedBodyOptions`]. pub fn new(stream_length: u64, trailer_lengths: Vec) -> Self { Self { stream_length, diff --git a/aws/rust-runtime/aws-hyper/Cargo.toml b/aws/rust-runtime/aws-hyper/Cargo.toml index 3e52efb0c33..45e23962de4 100644 --- a/aws/rust-runtime/aws-hyper/Cargo.toml +++ b/aws/rust-runtime/aws-hyper/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aws-hyper" -version = "0.0.0-smithy-rs-head" +version = "0.60.3" authors = ["AWS Rust SDK Team ", "Russell Cohen "] description = "This crate has been removed and is deprecated." edition = "2021" @@ -10,5 +10,6 @@ repository = "https://github.com/smithy-lang/smithy-rs" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/aws/rust-runtime/aws-inlineable/Cargo.toml b/aws/rust-runtime/aws-inlineable/Cargo.toml index bb684af7616..514aa0c2d8c 100644 --- a/aws/rust-runtime/aws-inlineable/Cargo.toml +++ b/aws/rust-runtime/aws-inlineable/Cargo.toml @@ -40,5 +40,6 @@ tokio = { version = "1.23.1", features = ["macros", "rt", "io-util"] } [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/aws/rust-runtime/aws-inlineable/src/apigateway_interceptors.rs b/aws/rust-runtime/aws-inlineable/src/apigateway_interceptors.rs index c7eaad04c1a..e7374eb6727 100644 --- a/aws/rust-runtime/aws-inlineable/src/apigateway_interceptors.rs +++ b/aws/rust-runtime/aws-inlineable/src/apigateway_interceptors.rs @@ -15,7 +15,9 @@ use http::HeaderValue; /// Interceptor that adds an Accept header to API Gateway requests. #[derive(Debug, Default)] -pub(crate) struct AcceptHeaderInterceptor; +pub(crate) struct AcceptHeaderInterceptor { + _priv: (), +} impl Intercept for AcceptHeaderInterceptor { fn name(&self) -> &'static str { diff --git a/aws/rust-runtime/aws-inlineable/src/glacier_interceptors.rs b/aws/rust-runtime/aws-inlineable/src/glacier_interceptors.rs index 845b2ef21fe..d6a95415800 100644 --- a/aws/rust-runtime/aws-inlineable/src/glacier_interceptors.rs +++ b/aws/rust-runtime/aws-inlineable/src/glacier_interceptors.rs @@ -121,7 +121,9 @@ impl Intercept for GlacierApiVersionInterceptor { /// Adds a glacier tree hash checksum to the HTTP Request #[derive(Debug, Default)] -pub(crate) struct GlacierTreeHashHeaderInterceptor; +pub(crate) struct GlacierTreeHashHeaderInterceptor { + _priv: (), +} impl Intercept for GlacierTreeHashHeaderInterceptor { fn name(&self) -> &'static str { diff --git a/aws/rust-runtime/aws-runtime-api/Cargo.toml b/aws/rust-runtime/aws-runtime-api/Cargo.toml index 920384f5548..5524a8f7b04 100644 --- a/aws/rust-runtime/aws-runtime-api/Cargo.toml +++ b/aws/rust-runtime/aws-runtime-api/Cargo.toml @@ -12,6 +12,7 @@ repository = "https://github.com/smithy-lang/smithy-rs" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/aws/rust-runtime/aws-runtime/Cargo.toml b/aws/rust-runtime/aws-runtime/Cargo.toml index b255e8b8421..4ba2423b9be 100644 --- a/aws/rust-runtime/aws-runtime/Cargo.toml +++ b/aws/rust-runtime/aws-runtime/Cargo.toml @@ -43,6 +43,7 @@ tracing-test = "0.2.4" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/aws/rust-runtime/aws-runtime/src/invocation_id.rs b/aws/rust-runtime/aws-runtime/src/invocation_id.rs index b64a621a15f..a0928310db0 100644 --- a/aws/rust-runtime/aws-runtime/src/invocation_id.rs +++ b/aws/rust-runtime/aws-runtime/src/invocation_id.rs @@ -201,7 +201,7 @@ mod test_util { impl NoInvocationIdGenerator { /// Create a new [`NoInvocationIdGenerator`]. pub fn new() -> Self { - Self::default() + Self } } diff --git a/aws/rust-runtime/aws-sig-auth/Cargo.toml b/aws/rust-runtime/aws-sig-auth/Cargo.toml index 56909a48113..1a5be72fb7d 100644 --- a/aws/rust-runtime/aws-sig-auth/Cargo.toml +++ b/aws/rust-runtime/aws-sig-auth/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aws-sig-auth" -version = "0.0.0-smithy-rs-head" +version = "0.60.3" authors = ["AWS Rust SDK Team ", "Russell Cohen "] description = "This crate is no longer used by the AWS SDK and is deprecated." edition = "2021" @@ -10,5 +10,6 @@ repository = "https://github.com/smithy-lang/smithy-rs" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/aws/rust-runtime/aws-sigv4/Cargo.toml b/aws/rust-runtime/aws-sigv4/Cargo.toml index 6fe06159cab..f29a2ba01ca 100644 --- a/aws/rust-runtime/aws-sigv4/Cargo.toml +++ b/aws/rust-runtime/aws-sigv4/Cargo.toml @@ -9,9 +9,10 @@ license = "Apache-2.0" repository = "https://github.com/smithy-lang/smithy-rs" [features] -default = ["sign-http"] -http0-compat = ["dep:http"] -sign-http = ["dep:http", "dep:percent-encoding", "dep:form_urlencoded"] +default = ["sign-http", "http1"] +http0-compat = ["dep:http0"] +http1 = ["dep:http"] +sign-http = ["dep:http0", "dep:percent-encoding", "dep:form_urlencoded"] sign-eventstream = ["dep:aws-smithy-eventstream"] sigv4a = ["dep:p256", "dep:crypto-bigint", "dep:subtle", "dep:zeroize", "dep:ring"] @@ -25,8 +26,9 @@ bytes = "1" form_urlencoded = { version = "1.0", optional = true } hex = "0.4" hmac = "0.12" -http = { version = "0.2", optional = true } -num-bigint = { version = "0.4", optional = true } +http0 = { version = "0.2", optional = true, package = "http" } +http = { version = "1", optional = true } +num-bigint = { version = "0.4.2", optional = true } once_cell = "1.8" p256 = { version = "0.11", features = ["ecdsa"], optional = true } percent-encoding = { version = "2.1", optional = true } @@ -68,6 +70,7 @@ required-features = [ "sigv4a" ] [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/aws/rust-runtime/aws-sigv4/src/http_request.rs b/aws/rust-runtime/aws-sigv4/src/http_request.rs index 6bb6b9235c2..2bd0c92903d 100644 --- a/aws/rust-runtime/aws-sigv4/src/http_request.rs +++ b/aws/rust-runtime/aws-sigv4/src/http_request.rs @@ -13,14 +13,15 @@ //! # use aws_credential_types::Credentials; //! use aws_smithy_runtime_api::client::identity::Identity; //! # use aws_sigv4::http_request::SignableBody; -//! #[cfg(feature = "http0-compat")] +//! #[cfg(feature = "http1")] //! fn test() -> Result<(), aws_sigv4::http_request::SigningError> { //! use aws_sigv4::http_request::{sign, SigningSettings, SigningParams, SignableRequest}; //! use aws_sigv4::sign::v4; -//! use http; +//! use http0; //! use std::time::SystemTime; //! //! // Set up information and settings for the signing +//! // You can obtain credentials from `SdkConfig`. //! let identity = Credentials::new( //! "AKIDEXAMPLE", //! "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", @@ -49,7 +50,7 @@ //! let mut my_req = http::Request::new("..."); //! // Sign and then apply the signature to the request //! let (signing_instructions, _signature) = sign(signable_request, &signing_params)?.into_parts(); -//! signing_instructions.apply_to_request_http0x(&mut my_req); +//! signing_instructions.apply_to_request_http1x(&mut my_req); //! # Ok(()) //! # } //! ``` diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs b/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs index 32b6cfe4f3d..5fae247dd2a 100644 --- a/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs +++ b/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs @@ -15,8 +15,8 @@ use crate::http_request::{PayloadChecksumKind, SignableBody, SignatureLocation, use crate::sign::v4::sha256_hex_string; use crate::SignatureVersion; use aws_smithy_http::query_writer::QueryWriter; -use http::header::{AsHeaderName, HeaderName, HOST}; -use http::{HeaderMap, HeaderValue, Uri}; +use http0::header::{AsHeaderName, HeaderName, HOST}; +use http0::{HeaderMap, HeaderValue, Uri}; use std::borrow::Cow; use std::cmp::Ordering; use std::convert::TryFrom; @@ -626,7 +626,7 @@ mod tests { use aws_credential_types::Credentials; use aws_smithy_http::query_writer::QueryWriter; use aws_smithy_runtime_api::client::identity::Identity; - use http::{HeaderValue, Uri}; + use http0::{HeaderValue, Uri}; use pretty_assertions::assert_eq; use proptest::{prelude::*, proptest}; use std::borrow::Cow; @@ -794,7 +794,7 @@ mod tests { #[test] fn test_tilde_in_uri() { - let req = http::Request::builder() + let req = http0::Request::builder() .uri("https://s3.us-east-1.amazonaws.com/my-bucket?list-type=2&prefix=~objprefix&single&k=&unreserved=-_.~").body("").unwrap().into(); let req = SignableRequest::from(&req); let identity = Credentials::for_tests().into(); @@ -815,7 +815,7 @@ mod tests { query_writer.insert("list-type", "2"); query_writer.insert("prefix", &all_printable_ascii_chars); - let req = http::Request::builder() + let req = http0::Request::builder() .uri(query_writer.build_uri()) .body("") .unwrap() @@ -863,7 +863,7 @@ mod tests { // It should exclude authorization, user-agent, x-amzn-trace-id headers from presigning #[test] fn non_presigning_header_exclusion() { - let request = http::Request::builder() + let request = http0::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com") .header("authorization", "test-authorization") .header("content-type", "application/xml") @@ -895,7 +895,7 @@ mod tests { // It should exclude authorization, user-agent, x-amz-user-agent, x-amzn-trace-id headers from presigning #[test] fn presigning_header_exclusion() { - let request = http::Request::builder() + let request = http0::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com") .header("authorization", "test-authorization") .header("content-type", "application/xml") @@ -944,7 +944,7 @@ mod tests { valid_input, ) ) { - let mut request_builder = http::Request::builder() + let mut request_builder = http0::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com") .header("content-type", "application/xml") .header("content-length", "0"); diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/error.rs b/aws/rust-runtime/aws-sigv4/src/http_request/error.rs index 39f57dffa5d..6f53783ff80 100644 --- a/aws/rust-runtime/aws-sigv4/src/http_request/error.rs +++ b/aws/rust-runtime/aws-sigv4/src/http_request/error.rs @@ -3,8 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -use http::header::{InvalidHeaderName, InvalidHeaderValue}; -use http::uri::InvalidUri; +use http0::header::{InvalidHeaderName, InvalidHeaderValue}; +use http0::uri::InvalidUri; use std::error::Error; use std::fmt; diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs b/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs index 3c690e6ddca..787619fc364 100644 --- a/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs +++ b/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -use http::header::{AUTHORIZATION, USER_AGENT}; +use http0::header::{AUTHORIZATION, USER_AGENT}; use std::borrow::Cow; use std::time::Duration; diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs b/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs index 2cef0dbd3ce..2f27b3c4b71 100644 --- a/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs +++ b/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs @@ -14,7 +14,7 @@ use crate::sign::v4; #[cfg(feature = "sigv4a")] use crate::sign::v4a; use crate::{SignatureVersion, SigningOutput}; -use http::Uri; +use http0::Uri; use std::borrow::Cow; use std::fmt::{Debug, Formatter}; use std::str; @@ -162,10 +162,10 @@ impl SigningInstructions { #[cfg(any(feature = "http0-compat", test))] /// Applies the instructions to the given `request`. - pub fn apply_to_request_http0x(self, request: &mut http::Request) { + pub fn apply_to_request_http0x(self, request: &mut http0::Request) { let (new_headers, new_query) = self.into_parts(); for header in new_headers.into_iter() { - let mut value = http::HeaderValue::from_str(&header.value).unwrap(); + let mut value = http0::HeaderValue::from_str(&header.value).unwrap(); value.set_sensitive(header.sensitive); request.headers_mut().insert(header.key, value); } @@ -178,6 +178,34 @@ impl SigningInstructions { *request.uri_mut() = query.build_uri(); } } + + #[cfg(any(feature = "http1", test))] + /// Applies the instructions to the given `request`. + pub fn apply_to_request_http1x(self, request: &mut http::Request) { + // TODO(https://github.com/smithy-lang/smithy-rs/issues/3367): Update query writer to reduce + // allocations + let (new_headers, new_query) = self.into_parts(); + for header in new_headers.into_iter() { + let mut value = http::HeaderValue::from_str(&header.value).unwrap(); + value.set_sensitive(header.sensitive); + request.headers_mut().insert(header.key, value); + } + + if !new_query.is_empty() { + let mut query = aws_smithy_http::query_writer::QueryWriter::new_from_string( + &request.uri().to_string(), + ) + .expect("unreachable: URI is valid"); + for (name, value) in new_query { + query.insert(name, &value); + } + *request.uri_mut() = query + .build_uri() + .to_string() + .parse() + .expect("unreachable: URI is valid"); + } + } } /// Produces a signature for the given `request` and returns instructions @@ -444,7 +472,7 @@ mod tests { }; use crate::sign::v4; use aws_credential_types::Credentials; - use http::{HeaderValue, Request}; + use http0::{HeaderValue, Request}; use pretty_assertions::assert_eq; use proptest::proptest; use std::borrow::Cow; @@ -830,7 +858,7 @@ mod tests { } .into(); - let original = http::Request::builder() + let original = http0::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com") .header("some-header", HeaderValue::from_str("テスト").unwrap()) .body("") @@ -846,7 +874,7 @@ mod tests { let mut signed = original.as_http_request(); out.output.apply_to_request_http0x(&mut signed); - let expected = http::Request::builder() + let expected = http0::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com") .header("some-header", HeaderValue::from_str("テスト").unwrap()) .header( @@ -884,7 +912,7 @@ mod tests { } .into(); - let original = http::Request::builder() + let original = http0::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com") .body("") .unwrap() @@ -907,7 +935,7 @@ mod tests { .output .apply_to_request_http0x(&mut signed); - let expected = http::Request::builder() + let expected = http0::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com") .header( "x-amz-date", @@ -945,7 +973,7 @@ mod tests { } .into(); - let original = http::Request::builder() + let original = http0::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com") .header( "some-header", @@ -964,7 +992,7 @@ mod tests { let mut signed = original.as_http_request(); out.output.apply_to_request_http0x(&mut signed); - let expected = http::Request::builder() + let expected = http0::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com") .header( "some-header", @@ -1027,7 +1055,7 @@ mod tests { add_header(&mut headers, "some-other-header", "bar", false); let instructions = SigningInstructions::new(headers, vec![]); - let mut request = http::Request::builder() + let mut request = http0::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com") .body("") .unwrap(); @@ -1047,7 +1075,7 @@ mod tests { ]; let instructions = SigningInstructions::new(vec![], params); - let mut request = http::Request::builder() + let mut request = http0::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com/some/path") .body("") .unwrap(); @@ -1059,4 +1087,25 @@ mod tests { request.uri().path_and_query().unwrap().to_string() ); } + + #[test] + fn apply_signing_instructions_query_params_http_1x() { + let params = vec![ + ("some-param", Cow::Borrowed("f&o?o")), + ("some-other-param?", Cow::Borrowed("bar")), + ]; + let instructions = SigningInstructions::new(vec![], params); + + let mut request = http::Request::builder() + .uri("https://some-endpoint.some-region.amazonaws.com/some/path") + .body("") + .unwrap(); + + instructions.apply_to_request_http1x(&mut request); + + assert_eq!( + "/some/path?some-param=f%26o%3Fo&some-other-param%3F=bar", + request.uri().path_and_query().unwrap().to_string() + ); + } } diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/test.rs b/aws/rust-runtime/aws-sigv4/src/http_request/test.rs index 9d5bec6d5d0..be6c4964627 100644 --- a/aws/rust-runtime/aws-sigv4/src/http_request/test.rs +++ b/aws/rust-runtime/aws-sigv4/src/http_request/test.rs @@ -6,7 +6,7 @@ //! Functions shared between the tests of several modules. use crate::http_request::{SignableBody, SignableRequest}; -use http::{Method, Uri}; +use http0::{Method, Uri}; use std::error::Error as StdError; pub(crate) mod v4 { @@ -258,8 +258,8 @@ impl TestRequest { self.body = TestSignedBody::Signable(body); } - pub(crate) fn as_http_request(&self) -> http::Request<&'static str> { - let mut builder = http::Request::builder() + pub(crate) fn as_http_request(&self) -> http0::Request<&'static str> { + let mut builder = http0::Request::builder() .uri(&self.uri) .method(Method::from_bytes(self.method.as_bytes()).unwrap()); for (k, v) in &self.headers { @@ -269,8 +269,8 @@ impl TestRequest { } } -impl> From> for TestRequest { - fn from(value: http::Request) -> Self { +impl> From> for TestRequest { + fn from(value: http0::Request) -> Self { let invalid = value .headers() .values() diff --git a/aws/rust-runtime/aws-types/Cargo.toml b/aws/rust-runtime/aws-types/Cargo.toml index 1259261cac8..38985a1bd28 100644 --- a/aws/rust-runtime/aws-types/Cargo.toml +++ b/aws/rust-runtime/aws-types/Cargo.toml @@ -36,6 +36,7 @@ rustc_version = "0.4.0" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/aws/rust-runtime/aws-types/src/os_shim_internal.rs b/aws/rust-runtime/aws-types/src/os_shim_internal.rs index ad806bd6f2c..f3639cc7ca8 100644 --- a/aws/rust-runtime/aws-types/src/os_shim_internal.rs +++ b/aws/rust-runtime/aws-types/src/os_shim_internal.rs @@ -212,7 +212,7 @@ mod fs { /// /// Environment variables are global to a process, and, as such, are difficult to test with a multi- /// threaded test runner like Rust's. This enables loading environment variables either from the -/// actual process environment ([`std::env::var`](std::env::var)) or from a hash map. +/// actual process environment ([`std::env::var`]) or from a hash map. /// /// Process environments are cheap to clone: /// - Faked process environments are wrapped in an internal Arc @@ -257,7 +257,7 @@ impl Env { /// Create a process environment that uses the real process environment /// - /// Calls will be delegated to [`std::env::var`](std::env::var). + /// Calls will be delegated to [`std::env::var`]. pub fn real() -> Self { Self(env::Inner::Real) } diff --git a/aws/rust-runtime/aws-types/src/sdk_config.rs b/aws/rust-runtime/aws-types/src/sdk_config.rs index 4371f1d4a3a..f88f52ae3f3 100644 --- a/aws/rust-runtime/aws-types/src/sdk_config.rs +++ b/aws/rust-runtime/aws-types/src/sdk_config.rs @@ -554,7 +554,7 @@ impl Builder { self } - /// Build a [`SdkConfig`](SdkConfig) from this builder + /// Build a [`SdkConfig`] from this builder. pub fn build(self) -> SdkConfig { SdkConfig { app_name: self.app_name, diff --git a/aws/rust-runtime/build.gradle.kts b/aws/rust-runtime/build.gradle.kts index 712edb1ef21..07b1ca50952 100644 --- a/aws/rust-runtime/build.gradle.kts +++ b/aws/rust-runtime/build.gradle.kts @@ -12,6 +12,11 @@ group = "software.amazon.aws.rustruntime" version = "0.0.3" +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + tasks.jar { from("./") { include("aws-inlineable/src/*.rs") diff --git a/aws/sdk-adhoc-test/build.gradle.kts b/aws/sdk-adhoc-test/build.gradle.kts index 53460ba9ceb..22bbd647afc 100644 --- a/aws/sdk-adhoc-test/build.gradle.kts +++ b/aws/sdk-adhoc-test/build.gradle.kts @@ -12,6 +12,11 @@ plugins { id("software.amazon.smithy") } +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + val smithyVersion: String by project val defaultRustDocFlags: String by project val properties = PropertyRetriever(rootProject, project) @@ -49,14 +54,6 @@ fun baseTest(service: String, module: String, imports: List = listOf()): "includeFluentClient": false, "nullabilityCheckMode": "${getNullabilityCheckMode()}" """, - extraConfig = """ - , "customizationConfig": { - "awsSdk": { - "generateReadme": false, - "requireEndpointResolver": false - } - } - """, ) } diff --git a/aws/sdk-codegen/build.gradle.kts b/aws/sdk-codegen/build.gradle.kts index 6b255bd5a30..03343968a91 100644 --- a/aws/sdk-codegen/build.gradle.kts +++ b/aws/sdk-codegen/build.gradle.kts @@ -30,8 +30,13 @@ dependencies { implementation("software.amazon.smithy:smithy-aws-endpoints:$smithyVersion") } +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + tasks.compileKotlin { - kotlinOptions.jvmTarget = "1.8" + kotlinOptions.jvmTarget = "11" } // Reusable license copySpec @@ -67,7 +72,7 @@ if (isTestingEnabled.toBoolean()) { } tasks.compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" + kotlinOptions.jvmTarget = "11" } tasks.test { diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCargoDependency.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCargoDependency.kt index c803040f7d8..001f17984e1 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCargoDependency.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCargoDependency.kt @@ -9,15 +9,23 @@ import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.core.smithy.crateLocation -fun RuntimeConfig.awsRuntimeCrate(name: String, features: Set = setOf()): CargoDependency = - CargoDependency(name, awsRoot().crateLocation(name), features = features) +fun RuntimeConfig.awsRuntimeCrate( + name: String, + features: Set = setOf(), +): CargoDependency = CargoDependency(name, awsRoot().crateLocation(name), features = features) object AwsCargoDependency { fun awsConfig(runtimeConfig: RuntimeConfig) = runtimeConfig.awsRuntimeCrate("aws-config") + fun awsCredentialTypes(runtimeConfig: RuntimeConfig) = runtimeConfig.awsRuntimeCrate("aws-credential-types") + fun awsHttp(runtimeConfig: RuntimeConfig) = runtimeConfig.awsRuntimeCrate("aws-http") + fun awsRuntime(runtimeConfig: RuntimeConfig) = runtimeConfig.awsRuntimeCrate("aws-runtime") + fun awsRuntimeApi(runtimeConfig: RuntimeConfig) = runtimeConfig.awsRuntimeCrate("aws-runtime-api") + fun awsSigv4(runtimeConfig: RuntimeConfig) = runtimeConfig.awsRuntimeCrate("aws-sigv4") + fun awsTypes(runtimeConfig: RuntimeConfig) = runtimeConfig.awsRuntimeCrate("aws-types") } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt index 5e694c1cead..3bc616a9b8f 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt @@ -27,56 +27,55 @@ import software.amazon.smithy.rustsdk.endpoints.AwsEndpointsStdLib import software.amazon.smithy.rustsdk.endpoints.OperationInputTestDecorator import software.amazon.smithy.rustsdk.endpoints.RequireEndpointRules -val DECORATORS: List = listOf( - // General AWS Decorators +val DECORATORS: List = listOf( - CredentialsProviderDecorator(), - RegionDecorator(), - RequireEndpointRules(), - UserAgentDecorator(), - SigV4AuthDecorator(), - HttpRequestChecksumDecorator(), - HttpResponseChecksumDecorator(), - RetryClassifierDecorator(), - IntegrationTestDecorator(), - AwsFluentClientDecorator(), - CrateLicenseDecorator(), - SdkConfigDecorator(), - ServiceConfigDecorator(), - AwsPresigningDecorator(), - AwsCrateDocsDecorator(), - AwsEndpointsStdLib(), - *PromotedBuiltInsDecorators, - GenericSmithySdkConfigSettings(), - OperationInputTestDecorator(), - AwsRequestIdDecorator(), - DisabledAuthDecorator(), - RecursionDetectionDecorator(), - InvocationIdDecorator(), - RetryInformationHeaderDecorator(), - RemoveDefaultsDecorator(), - ), - - // Service specific decorators - ApiGatewayDecorator().onlyApplyTo("com.amazonaws.apigateway#BackplaneControlService"), - Ec2Decorator().onlyApplyTo("com.amazonaws.ec2#AmazonEC2"), - GlacierDecorator().onlyApplyTo("com.amazonaws.glacier#Glacier"), - Route53Decorator().onlyApplyTo("com.amazonaws.route53#AWSDnsV20130401"), - "com.amazonaws.s3#AmazonS3".applyDecorators( - S3Decorator(), - S3ExtendedRequestIdDecorator(), - ), - S3ControlDecorator().onlyApplyTo("com.amazonaws.s3control#AWSS3ControlServiceV20180820"), - STSDecorator().onlyApplyTo("com.amazonaws.sts#AWSSecurityTokenServiceV20110615"), - SSODecorator().onlyApplyTo("com.amazonaws.sso#SWBPortalService"), - TimestreamDecorator().onlyApplyTo("com.amazonaws.timestreamwrite#Timestream_20181101"), - TimestreamDecorator().onlyApplyTo("com.amazonaws.timestreamquery#Timestream_20181101"), - - // Only build docs-rs for linux to reduce load on docs.rs - listOf( - DocsRsMetadataDecorator(DocsRsMetadataSettings(targets = listOf("x86_64-unknown-linux-gnu"), allFeatures = true)), - ), -).flatten() + // General AWS Decorators + listOf( + CredentialsProviderDecorator(), + RegionDecorator(), + RequireEndpointRules(), + UserAgentDecorator(), + SigV4AuthDecorator(), + HttpRequestChecksumDecorator(), + HttpResponseChecksumDecorator(), + RetryClassifierDecorator(), + IntegrationTestDecorator(), + AwsFluentClientDecorator(), + CrateLicenseDecorator(), + SdkConfigDecorator(), + ServiceConfigDecorator(), + AwsPresigningDecorator(), + AwsCrateDocsDecorator(), + AwsEndpointsStdLib(), + *PromotedBuiltInsDecorators, + GenericSmithySdkConfigSettings(), + OperationInputTestDecorator(), + AwsRequestIdDecorator(), + DisabledAuthDecorator(), + RecursionDetectionDecorator(), + InvocationIdDecorator(), + RetryInformationHeaderDecorator(), + RemoveDefaultsDecorator(), + ), + // Service specific decorators + ApiGatewayDecorator().onlyApplyTo("com.amazonaws.apigateway#BackplaneControlService"), + Ec2Decorator().onlyApplyTo("com.amazonaws.ec2#AmazonEC2"), + GlacierDecorator().onlyApplyTo("com.amazonaws.glacier#Glacier"), + Route53Decorator().onlyApplyTo("com.amazonaws.route53#AWSDnsV20130401"), + "com.amazonaws.s3#AmazonS3".applyDecorators( + S3Decorator(), + S3ExtendedRequestIdDecorator(), + ), + S3ControlDecorator().onlyApplyTo("com.amazonaws.s3control#AWSS3ControlServiceV20180820"), + STSDecorator().onlyApplyTo("com.amazonaws.sts#AWSSecurityTokenServiceV20110615"), + SSODecorator().onlyApplyTo("com.amazonaws.sso#SWBPortalService"), + TimestreamDecorator().onlyApplyTo("com.amazonaws.timestreamwrite#Timestream_20181101"), + TimestreamDecorator().onlyApplyTo("com.amazonaws.timestreamquery#Timestream_20181101"), + // Only build docs-rs for linux to reduce load on docs.rs + listOf( + DocsRsMetadataDecorator(DocsRsMetadataSettings(targets = listOf("x86_64-unknown-linux-gnu"), allFeatures = true)), + ), + ).flatten() class AwsCodegenDecorator : CombinedClientCodegenDecorator(DECORATORS) { override val name: String = "AwsSdkCodegenDecorator" diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt index ecc52169014..2f2424eec54 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCrateDocsDecorator.kt @@ -53,28 +53,38 @@ class AwsCrateDocsDecorator : ClientCodegenDecorator { override fun libRsCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = baseCustomizations + listOf( - object : LibRsCustomization() { - override fun section(section: LibRsSection): Writable = when { - section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.ServiceDocs -> writable { - // Include README contents in crate docs if they are to be generated - if (generateReadme(codegenContext)) { - AwsCrateDocGenerator(codegenContext).generateCrateDocComment()(this) - } - } - - else -> emptySection - } - }, - ) + ): List = + baseCustomizations + + listOf( + object : LibRsCustomization() { + override fun section(section: LibRsSection): Writable = + when { + section is LibRsSection.ModuleDoc && section.subsection is ModuleDocSection.ServiceDocs -> + writable { + // Include README contents in crate docs if they are to be generated + if (generateReadme(codegenContext)) { + AwsCrateDocGenerator(codegenContext).generateCrateDocComment()(this) + } + } + + else -> emptySection + } + }, + ) - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { if (generateReadme(codegenContext)) { AwsCrateDocGenerator(codegenContext).generateReadme(rustCrate) } } - override fun clientConstructionDocs(codegenContext: ClientCodegenContext, baseDocs: Writable): Writable = + override fun clientConstructionDocs( + codegenContext: ClientCodegenContext, + baseDocs: Writable, + ): Writable = writable { val serviceName = codegenContext.serviceShape.serviceNameOrDefault("the service") docs("Client for calling $serviceName.") @@ -98,156 +108,152 @@ internal class AwsCrateDocGenerator(private val codegenContext: ClientCodegenCon ?: throw IllegalStateException("missing `awsConfigVersion` codegen setting") } - private fun RustWriter.template(asComments: Boolean, text: String, vararg args: Pair) = - when (asComments) { - true -> containerDocsTemplate(text, *args) - else -> rawTemplate(text + "\n", *args) - } + private fun RustWriter.template( + asComments: Boolean, + text: String, + vararg args: Pair, + ) = when (asComments) { + true -> containerDocsTemplate(text, *args) + else -> rawTemplate(text + "\n", *args) + } internal fun docText( includeHeader: Boolean, includeLicense: Boolean, asComments: Boolean, - ): Writable = writable { - val moduleVersion = codegenContext.settings.moduleVersion - check(moduleVersion.isNotEmpty() && moduleVersion[0].isDigit()) - - val moduleName = codegenContext.settings.moduleName - val stableVersion = !moduleVersion.startsWith("0.") - val description = normalizeDescription( - codegenContext.moduleName, - codegenContext.settings.getService(codegenContext.model).getTrait()?.value ?: "", - ) - val snakeCaseModuleName = moduleName.replace('-', '_') - val shortModuleName = moduleName.removePrefix("aws-sdk-") + ): Writable = + writable { + val moduleVersion = codegenContext.settings.moduleVersion + check(moduleVersion.isNotEmpty() && moduleVersion[0].isDigit()) + + val moduleName = codegenContext.settings.moduleName + val stableVersion = !moduleVersion.startsWith("0.") + val description = + normalizeDescription( + codegenContext.moduleName, + codegenContext.settings.getService(codegenContext.model).getTrait()?.value ?: "", + ) + val snakeCaseModuleName = moduleName.replace('-', '_') + val shortModuleName = moduleName.removePrefix("aws-sdk-") + + if (includeHeader) { + template(asComments, escape("# $moduleName\n")) + } - if (includeHeader) { - template(asComments, escape("# $moduleName\n")) - } + // TODO(PostGA): Remove warning banner conditionals. + // NOTE: when you change this, you must also change SDK_README.md.hb + if (!stableVersion) { + template( + asComments, + """ + **Please Note: The SDK is currently released as a developer preview, without support or assistance for use + on production workloads. Any use in production is at your own risk.**${"\n"} + """.trimIndent(), + ) + } + + if (description.isNotBlank()) { + template(asComments, escape("$description\n")) + } - // TODO(PostGA): Remove warning banner conditionals. - // NOTE: when you change this, you must also change SDK_README.md.hb - if (!stableVersion) { + val compileExample = AwsDocs.canRelyOnAwsConfig(codegenContext) + val exampleMode = if (compileExample) "no_run" else "ignore" template( asComments, """ - **Please Note: The SDK is currently released as a developer preview, without support or assistance for use - on production workloads. Any use in production is at your own risk.**${"\n"} - """.trimIndent(), - ) - } + #### Getting Started - if (description.isNotBlank()) { - template(asComments, escape("$description\n")) - } + > Examples are available for many services and operations, check out the + > [examples folder in GitHub](https://github.com/awslabs/aws-sdk-rust/tree/main/examples). - val compileExample = AwsDocs.canRelyOnAwsConfig(codegenContext) - val exampleMode = if (compileExample) "no_run" else "ignore" + The SDK provides one crate per AWS service. You must add [Tokio](https://crates.io/crates/tokio) + as a dependency within your Rust project to execute asynchronous code. To add `$moduleName` to + your project, add the following to your **Cargo.toml** file: - template( - asComments, - """ - #### Getting Started + ```toml + [dependencies] + aws-config = { version = "$awsConfigVersion", features = ["behavior-version-latest"] } + $moduleName = "$moduleVersion" + tokio = { version = "1", features = ["full"] } + ``` - > Examples are available for many services and operations, check out the - > [examples folder in GitHub](https://github.com/awslabs/aws-sdk-rust/tree/main/examples). + Then in code, a client can be created with the following: - The SDK provides one crate per AWS service. You must add [Tokio](https://crates.io/crates/tokio) - as a dependency within your Rust project to execute asynchronous code. To add `$moduleName` to - your project, add the following to your **Cargo.toml** file: + ```rust,$exampleMode + use $snakeCaseModuleName as $shortModuleName; - ```toml - [dependencies] - aws-config = { version = "$awsConfigVersion", features = ["behavior-version-latest"] } - $moduleName = "$moduleVersion" - tokio = { version = "1", features = ["full"] } - ``` - - Then in code, a client can be created with the following: - - ```rust,$exampleMode - use $snakeCaseModuleName as $shortModuleName; - - ##[#{tokio}::main] - async fn main() -> Result<(), $shortModuleName::Error> { - #{constructClient} - - // ... make some calls with the client - - Ok(()) - } - ``` + ##[#{tokio}::main] + async fn main() -> Result<(), $shortModuleName::Error> { + #{constructClient} - See the [client documentation](https://docs.rs/$moduleName/latest/$snakeCaseModuleName/client/struct.Client.html) - for information on what calls can be made, and the inputs and outputs for each of those calls.${"\n"} + // ... make some calls with the client + Ok(()) + } + ``` + + See the [client documentation](https://docs.rs/$moduleName/latest/$snakeCaseModuleName/client/struct.Client.html) + for information on what calls can be made, and the inputs and outputs for each of those calls.${"\n"} + """.trimIndent().trimStart(), + "tokio" to CargoDependency.Tokio.toDevDependency().toType(), + "aws_config" to + when (compileExample) { + true -> AwsCargoDependency.awsConfig(codegenContext.runtimeConfig).toDevDependency().toType() + else -> writable { rust("aws_config") } + }, + "constructClient" to AwsDocs.constructClient(codegenContext, indent = " "), + ) - """.trimIndent().trimStart(), - "tokio" to CargoDependency.Tokio.toDevDependency().toType(), - "aws_config" to when (compileExample) { - true -> AwsCargoDependency.awsConfig(codegenContext.runtimeConfig).toDevDependency().toType() - else -> writable { rust("aws_config") } - }, - "constructClient" to AwsDocs.constructClient(codegenContext, indent = " "), - ) - - template( - asComments, - """ - - """.trimIndent(), - ) - - template( - asComments, - """ - #### Using the SDK - - Until the SDK is released, we will be adding information about using the SDK to the - [Developer Guide](https://docs.aws.amazon.com/sdk-for-rust/latest/dg/welcome.html). Feel free to suggest - additional sections for the guide by opening an issue and describing what you are trying to do.${"\n"} - """.trimIndent(), - ) - - template( - asComments, - """ - #### Getting Help - - * [GitHub discussions](https://github.com/awslabs/aws-sdk-rust/discussions) - For ideas, RFCs & general questions - * [GitHub issues](https://github.com/awslabs/aws-sdk-rust/issues/new/choose) - For bug reports & feature requests - * [Generated Docs (latest version)](https://awslabs.github.io/aws-sdk-rust/) - * [Usage examples](https://github.com/awslabs/aws-sdk-rust/tree/main/examples)${"\n"} - """.trimIndent(), - ) + template( + asComments, + """ + #### Using the SDK - // important ! - // REMOVE THIS LINE WHEN THE SERDE FEATURE IS STABLIZED! - template(asComments, SerdeDecorator.SerdeInfoText.trimIndent()) + Until the SDK is released, we will be adding information about using the SDK to the + [Developer Guide](https://docs.aws.amazon.com/sdk-for-rust/latest/dg/welcome.html). Feel free to suggest + additional sections for the guide by opening an issue and describing what you are trying to do.${"\n"} + """.trimIndent(), + ) - if (includeLicense) { template( asComments, """ - #### License + #### Getting Help - This project is licensed under the Apache-2.0 License. + * [GitHub discussions](https://github.com/awslabs/aws-sdk-rust/discussions) - For ideas, RFCs & general questions + * [GitHub issues](https://github.com/awslabs/aws-sdk-rust/issues/new/choose) - For bug reports & feature requests + * [Generated Docs (latest version)](https://awslabs.github.io/aws-sdk-rust/) + * [Usage examples](https://github.com/awslabs/aws-sdk-rust/tree/main/examples)${"\n"} """.trimIndent(), ) + + if (includeLicense) { + template( + asComments, + """ + #### License + + This project is licensed under the Apache-2.0 License. + """.trimIndent(), + ) + } } - } internal fun generateCrateDocComment(): Writable = docText(includeHeader = false, includeLicense = false, asComments = true) - internal fun generateReadme(rustCrate: RustCrate) = rustCrate.withFile("README.md") { - docText(includeHeader = true, includeLicense = true, asComments = false)(this) - } + internal fun generateReadme(rustCrate: RustCrate) = + rustCrate.withFile("README.md") { + docText(includeHeader = true, includeLicense = true, asComments = false)(this) + } /** * Strips HTML from the description and makes it human-readable Markdown. */ - internal fun normalizeDescription(moduleName: String, input: String): String { + internal fun normalizeDescription( + moduleName: String, + input: String, + ): String { val doc = Jsoup.parse(input) doc.body().apply { // The order of operations here is important: @@ -296,7 +302,10 @@ internal class AwsCrateDocGenerator(private val codegenContext: ClientCodegenCon getElementsByTag("i").forEach { normalizeInlineStyleTag("_", it) } } - private fun normalizeInlineStyleTag(surround: String, tag: Element) { + private fun normalizeInlineStyleTag( + surround: String, + tag: Element, + ) { tag.replaceWith( Element("span").also { span -> span.append(surround) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsDocs.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsDocs.kt index 8452e245507..7942c28d6b3 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsDocs.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsDocs.kt @@ -26,7 +26,10 @@ object AwsDocs { ShapeId.from("com.amazonaws.sts#AWSSecurityTokenServiceV20110615"), ).contains(codegenContext.serviceShape.id) - fun constructClient(codegenContext: ClientCodegenContext, indent: String): Writable { + fun constructClient( + codegenContext: ClientCodegenContext, + indent: String, + ): Writable { val crateName = codegenContext.moduleUseName() return writable { writeCustomizationsOrElse( @@ -46,60 +49,61 @@ object AwsDocs { } } - fun clientConstructionDocs(codegenContext: ClientCodegenContext): Writable = { - if (canRelyOnAwsConfig(codegenContext)) { - val crateName = codegenContext.moduleUseName() - docsTemplate( - """ - #### Constructing a `Client` + fun clientConstructionDocs(codegenContext: ClientCodegenContext): Writable = + { + if (canRelyOnAwsConfig(codegenContext)) { + val crateName = codegenContext.moduleUseName() + docsTemplate( + """ + #### Constructing a `Client` - A [`Config`] is required to construct a client. For most use cases, the [`aws-config`] - crate should be used to automatically resolve this config using - [`aws_config::load_from_env()`], since this will resolve an [`SdkConfig`] which can be shared - across multiple different AWS SDK clients. This config resolution process can be customized - by calling [`aws_config::from_env()`] instead, which returns a [`ConfigLoader`] that uses - the [builder pattern] to customize the default config. + A [`Config`] is required to construct a client. For most use cases, the [`aws-config`] + crate should be used to automatically resolve this config using + [`aws_config::load_from_env()`], since this will resolve an [`SdkConfig`] which can be shared + across multiple different AWS SDK clients. This config resolution process can be customized + by calling [`aws_config::from_env()`] instead, which returns a [`ConfigLoader`] that uses + the [builder pattern] to customize the default config. - In the simplest case, creating a client looks as follows: - ```rust,no_run - ## async fn wrapper() { - #{constructClient} - ## } - ``` + In the simplest case, creating a client looks as follows: + ```rust,no_run + ## async fn wrapper() { + #{constructClient} + ## } + ``` - Occasionally, SDKs may have additional service-specific values that can be set on the [`Config`] that - is absent from [`SdkConfig`], or slightly different settings for a specific client may be desired. - The [`Config`] struct implements `From<&SdkConfig>`, so setting these specific settings can be - done as follows: + Occasionally, SDKs may have additional service-specific values that can be set on the [`Config`] that + is absent from [`SdkConfig`], or slightly different settings for a specific client may be desired. + The [`Config`] struct implements `From<&SdkConfig>`, so setting these specific settings can be + done as follows: - ```rust,no_run - ## async fn wrapper() { - let sdk_config = #{aws_config}::load_from_env().await; - let config = $crateName::config::Builder::from(&sdk_config) - ## /* - .some_service_specific_setting("value") - ## */ - .build(); - ## } - ``` + ```rust,no_run + ## async fn wrapper() { + let sdk_config = #{aws_config}::load_from_env().await; + let config = $crateName::config::Builder::from(&sdk_config) + ## /* + .some_service_specific_setting("value") + ## */ + .build(); + ## } + ``` - See the [`aws-config` docs] and [`Config`] for more information on customizing configuration. + See the [`aws-config` docs] and [`Config`] for more information on customizing configuration. - _Note:_ Client construction is expensive due to connection thread pool initialization, and should - be done once at application start-up. + _Note:_ Client construction is expensive due to connection thread pool initialization, and should + be done once at application start-up. - [`Config`]: crate::Config - [`ConfigLoader`]: https://docs.rs/aws-config/*/aws_config/struct.ConfigLoader.html - [`SdkConfig`]: https://docs.rs/aws-config/*/aws_config/struct.SdkConfig.html - [`aws-config` docs]: https://docs.rs/aws-config/* - [`aws-config`]: https://crates.io/crates/aws-config - [`aws_config::from_env()`]: https://docs.rs/aws-config/*/aws_config/fn.from_env.html - [`aws_config::load_from_env()`]: https://docs.rs/aws-config/*/aws_config/fn.load_from_env.html - [builder pattern]: https://rust-lang.github.io/api-guidelines/type-safety.html##builders-enable-construction-of-complex-values-c-builder - """.trimIndent(), - "aws_config" to AwsCargoDependency.awsConfig(codegenContext.runtimeConfig).toDevDependency().toType(), - "constructClient" to constructClient(codegenContext, indent = ""), - ) + [`Config`]: crate::Config + [`ConfigLoader`]: https://docs.rs/aws-config/*/aws_config/struct.ConfigLoader.html + [`SdkConfig`]: https://docs.rs/aws-config/*/aws_config/struct.SdkConfig.html + [`aws-config` docs]: https://docs.rs/aws-config/* + [`aws-config`]: https://crates.io/crates/aws-config + [`aws_config::from_env()`]: https://docs.rs/aws-config/*/aws_config/fn.from_env.html + [`aws_config::load_from_env()`]: https://docs.rs/aws-config/*/aws_config/fn.load_from_env.html + [builder pattern]: https://rust-lang.github.io/api-guidelines/type-safety.html##builders-enable-construction-of-complex-values-c-builder + """.trimIndent(), + "aws_config" to AwsCargoDependency.awsConfig(codegenContext.runtimeConfig).toDevDependency().toType(), + "constructClient" to constructClient(codegenContext, indent = ""), + ) + } } - } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsFluentClientDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsFluentClientDecorator.kt index a118823e725..4ca0fb81101 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsFluentClientDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsFluentClientDecorator.kt @@ -43,15 +43,19 @@ class AwsFluentClientDecorator : ClientCodegenDecorator { // Must run after the AwsPresigningDecorator so that the presignable trait is correctly added to operations override val order: Byte = (AwsPresigningDecorator.ORDER + 1).toByte() - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { val runtimeConfig = codegenContext.runtimeConfig val types = Types(runtimeConfig) FluentClientGenerator( codegenContext, - customizations = listOf( - AwsPresignedFluentBuilderMethod(codegenContext), - AwsFluentClientDocs(codegenContext), - ), + customizations = + listOf( + AwsPresignedFluentBuilderMethod(codegenContext), + AwsFluentClientDocs(codegenContext), + ), ).render(rustCrate, emptyList()) rustCrate.withModule(ClientRustModule.client) { AwsFluentClientExtensions(codegenContext, types).render(this) @@ -63,47 +67,52 @@ class AwsFluentClientDecorator : ClientCodegenDecorator { codegenContext: ClientCodegenContext, baseCustomizations: List, ): List { - return baseCustomizations + object : LibRsCustomization() { - override fun section(section: LibRsSection) = when (section) { - is LibRsSection.Body -> writable { - Attribute.DocInline.render(this) - rust("pub use client::Client;") - } - - else -> emptySection + return baseCustomizations + + object : LibRsCustomization() { + override fun section(section: LibRsSection) = + when (section) { + is LibRsSection.Body -> + writable { + Attribute.DocInline.render(this) + rust("pub use client::Client;") + } + + else -> emptySection + } } - } } override fun protocolTestGenerator( codegenContext: ClientCodegenContext, baseGenerator: ProtocolTestGenerator, - ): ProtocolTestGenerator = DefaultProtocolTestGenerator( - codegenContext, - baseGenerator.protocolSupport, - baseGenerator.operationShape, - renderClientCreation = { params -> - rustTemplate( - """ - let mut ${params.configBuilderName} = ${params.configBuilderName}; - ${params.configBuilderName}.set_region(Some(crate::config::Region::new("us-east-1"))); + ): ProtocolTestGenerator = + DefaultProtocolTestGenerator( + codegenContext, + baseGenerator.protocolSupport, + baseGenerator.operationShape, + renderClientCreation = { params -> + rustTemplate( + """ + let mut ${params.configBuilderName} = ${params.configBuilderName}; + ${params.configBuilderName}.set_region(Some(crate::config::Region::new("us-east-1"))); - let config = ${params.configBuilderName}.http_client(${params.httpClientName}).build(); - let ${params.clientName} = #{Client}::from_conf(config); - """, - "Client" to ClientRustModule.root.toType().resolve("Client"), - ) - }, - ) + let config = ${params.configBuilderName}.http_client(${params.httpClientName}).build(); + let ${params.clientName} = #{Client}::from_conf(config); + """, + "Client" to ClientRustModule.root.toType().resolve("Client"), + ) + }, + ) } private class AwsFluentClientExtensions(private val codegenContext: ClientCodegenContext, private val types: Types) { - private val codegenScope = arrayOf( - "Arc" to RuntimeType.Arc, - "RetryConfig" to types.retryConfig, - "TimeoutConfig" to types.timeoutConfig, - "aws_types" to types.awsTypes, - ) + private val codegenScope = + arrayOf( + "Arc" to RuntimeType.Arc, + "RetryConfig" to types.retryConfig, + "TimeoutConfig" to types.timeoutConfig, + "aws_types" to types.awsTypes, + ) fun render(writer: RustWriter) { writer.rustBlockTemplate("impl Client", *codegenScope) { @@ -134,17 +143,18 @@ private class AwsFluentClientDocs(private val codegenContext: ClientCodegenConte override fun section(section: FluentClientSection): Writable { return when (section) { - is FluentClientSection.FluentClientDocs -> writable { - rustTemplate( - """ - /// Client for $serviceName - /// - /// Client for invoking operations on $serviceName. Each operation on $serviceName is a method on this + is FluentClientSection.FluentClientDocs -> + writable { + rustTemplate( + """ + /// Client for $serviceName + /// + /// Client for invoking operations on $serviceName. Each operation on $serviceName is a method on this /// this struct. `.send()` MUST be invoked on the generated operations to dispatch the request to the service.""", - ) - AwsDocs.clientConstructionDocs(codegenContext)(this) - FluentClientDocs.clientUsageDocs(codegenContext)(this) - } + ) + AwsDocs.clientConstructionDocs(codegenContext)(this) + FluentClientDocs.clientUsageDocs(codegenContext)(this) + } else -> emptySection } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecorator.kt index 4d7e3d8bdec..5362a3c721f 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecorator.kt @@ -38,10 +38,11 @@ import software.amazon.smithy.rust.codegen.core.util.expectTrait import software.amazon.smithy.rustsdk.traits.PresignableTrait import kotlin.streams.toList -private val presigningTypes: List> = listOf( - "PresignedRequest" to AwsRuntimeType.presigning().resolve("PresignedRequest"), - "PresigningConfig" to AwsRuntimeType.presigning().resolve("PresigningConfig"), -) +private val presigningTypes: List> = + listOf( + "PresignedRequest" to AwsRuntimeType.presigning().resolve("PresignedRequest"), + "PresigningConfig" to AwsRuntimeType.presigning().resolve("PresigningConfig"), + ) internal enum class PayloadSigningType { EMPTY, @@ -68,17 +69,18 @@ internal val PRESIGNABLE_OPERATIONS by lazy { ShapeId.from("com.amazonaws.s3#PutObject") to PresignableOperation(PayloadSigningType.UNSIGNED_PAYLOAD), ShapeId.from("com.amazonaws.s3#UploadPart") to PresignableOperation(PayloadSigningType.UNSIGNED_PAYLOAD), ShapeId.from("com.amazonaws.s3#DeleteObject") to PresignableOperation(PayloadSigningType.UNSIGNED_PAYLOAD), - // Polly - SYNTHESIZE_SPEECH_OP to PresignableOperation( - PayloadSigningType.EMPTY, - // Polly's SynthesizeSpeech operation has the HTTP method overridden to GET, - // and the document members changed to query param members. - modelTransforms = listOf( - OverrideHttpMethodTransform(mapOf(SYNTHESIZE_SPEECH_OP to "GET")), - MoveDocumentMembersToQueryParamsTransform(listOf(SYNTHESIZE_SPEECH_OP)), + SYNTHESIZE_SPEECH_OP to + PresignableOperation( + PayloadSigningType.EMPTY, + // Polly's SynthesizeSpeech operation has the HTTP method overridden to GET, + // and the document members changed to query param members. + modelTransforms = + listOf( + OverrideHttpMethodTransform(mapOf(SYNTHESIZE_SPEECH_OP to "GET")), + MoveDocumentMembersToQueryParamsTransform(listOf(SYNTHESIZE_SPEECH_OP)), + ), ), - ), ) } @@ -95,25 +97,31 @@ class AwsPresigningDecorator internal constructor( /** * Adds presignable trait to known presignable operations and creates synthetic presignable shapes for codegen */ - override fun transformModel(service: ServiceShape, model: Model, settings: ClientRustSettings): Model { + override fun transformModel( + service: ServiceShape, + model: Model, + settings: ClientRustSettings, + ): Model { val modelWithSynthetics = addSyntheticOperations(model) val presignableTransforms = mutableListOf() - val intermediate = ModelTransformer.create().mapShapes(modelWithSynthetics) { shape -> - if (shape is OperationShape && presignableOperations.containsKey(shape.id)) { - presignableTransforms.addAll(presignableOperations.getValue(shape.id).modelTransforms) - shape.toBuilder().addTrait(PresignableTrait(syntheticShapeId(shape))).build() - } else { - shape + val intermediate = + ModelTransformer.create().mapShapes(modelWithSynthetics) { shape -> + if (shape is OperationShape && presignableOperations.containsKey(shape.id)) { + presignableTransforms.addAll(presignableOperations.getValue(shape.id).modelTransforms) + shape.toBuilder().addTrait(PresignableTrait(syntheticShapeId(shape))).build() + } else { + shape + } } - } // Apply operation-specific model transformations return presignableTransforms.fold(intermediate) { m, t -> t.transform(m) } } private fun addSyntheticOperations(model: Model): Model { - val presignableOps = model.shapes() - .filter { shape -> shape is OperationShape && presignableOperations.containsKey(shape.id) } - .toList() + val presignableOps = + model.shapes() + .filter { shape -> shape is OperationShape && presignableOperations.containsKey(shape.id) } + .toList() return model.toBuilder().also { builder -> for (op in presignableOps) { builder.cloneOperation(model, op, ::syntheticShapeId) @@ -126,12 +134,14 @@ class AwsPresignedFluentBuilderMethod( private val codegenContext: ClientCodegenContext, ) : FluentClientCustomization() { private val runtimeConfig = codegenContext.runtimeConfig - private val codegenScope = ( - presigningTypes + arrayOf( - *RuntimeType.preludeScope, - "Error" to AwsRuntimeType.presigning().resolve("config::Error"), - "SdkError" to RuntimeType.sdkError(runtimeConfig), - ) + private val codegenScope = + ( + presigningTypes + + arrayOf( + *RuntimeType.preludeScope, + "Error" to AwsRuntimeType.presigning().resolve("config::Error"), + "SdkError" to RuntimeType.sdkError(runtimeConfig), + ) ).toTypedArray() override fun section(section: FluentClientSection): Writable = @@ -158,11 +168,12 @@ class AwsPresignedFluentBuilderMethod( private fun RustWriter.renderPresignedMethodBody(section: FluentClientSection.FluentBuilderImpl) { val presignableOp = PRESIGNABLE_OPERATIONS.getValue(section.operationShape.id) - val operationShape = if (presignableOp.hasModelTransforms()) { - codegenContext.model.expectShape(syntheticShapeId(section.operationShape.id), OperationShape::class.java) - } else { - section.operationShape - } + val operationShape = + if (presignableOp.hasModelTransforms()) { + codegenContext.model.expectShape(syntheticShapeId(section.operationShape.id), OperationShape::class.java) + } else { + section.operationShape + } rustTemplate( """ @@ -191,52 +202,58 @@ class AwsPresignedFluentBuilderMethod( "Operation" to codegenContext.symbolProvider.toSymbol(section.operationShape), "OperationError" to section.operationErrorType, "RuntimePlugins" to RuntimeType.runtimePlugins(runtimeConfig), - "SharedInterceptor" to RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::interceptors") - .resolve("SharedInterceptor"), - "SigV4PresigningRuntimePlugin" to AwsRuntimeType.presigningInterceptor(runtimeConfig) - .resolve("SigV4PresigningRuntimePlugin"), + "SharedInterceptor" to + RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::interceptors") + .resolve("SharedInterceptor"), + "SigV4PresigningRuntimePlugin" to + AwsRuntimeType.presigningInterceptor(runtimeConfig) + .resolve("SigV4PresigningRuntimePlugin"), "StopPoint" to RuntimeType.smithyRuntime(runtimeConfig).resolve("client::orchestrator::StopPoint"), "USER_AGENT" to CargoDependency.Http.toType().resolve("header::USER_AGENT"), - "alternate_presigning_serializer" to writable { - if (presignableOp.hasModelTransforms()) { - val smithyTypes = RuntimeType.smithyTypes(codegenContext.runtimeConfig) - rustTemplate( - """ - ##[derive(::std::fmt::Debug)] - struct AlternatePresigningSerializerRuntimePlugin; - impl #{RuntimePlugin} for AlternatePresigningSerializerRuntimePlugin { - fn config(&self) -> #{Option}<#{FrozenLayer}> { - let mut cfg = #{Layer}::new("presigning_serializer"); - cfg.store_put(#{SharedRequestSerializer}::new(#{AlternateSerializer})); - #{Some}(cfg.freeze()) + "alternate_presigning_serializer" to + writable { + if (presignableOp.hasModelTransforms()) { + val smithyTypes = RuntimeType.smithyTypes(codegenContext.runtimeConfig) + rustTemplate( + """ + ##[derive(::std::fmt::Debug)] + struct AlternatePresigningSerializerRuntimePlugin; + impl #{RuntimePlugin} for AlternatePresigningSerializerRuntimePlugin { + fn config(&self) -> #{Option}<#{FrozenLayer}> { + let mut cfg = #{Layer}::new("presigning_serializer"); + cfg.store_put(#{SharedRequestSerializer}::new(#{AlternateSerializer})); + #{Some}(cfg.freeze()) + } } - } - """, - *preludeScope, - "AlternateSerializer" to alternateSerializer(operationShape), - "FrozenLayer" to smithyTypes.resolve("config_bag::FrozenLayer"), - "Layer" to smithyTypes.resolve("config_bag::Layer"), - "RuntimePlugin" to RuntimeType.runtimePlugin(codegenContext.runtimeConfig), - "SharedRequestSerializer" to RuntimeType.smithyRuntimeApiClient(codegenContext.runtimeConfig) - .resolve("client::ser_de::SharedRequestSerializer"), + """, + *preludeScope, + "AlternateSerializer" to alternateSerializer(operationShape), + "FrozenLayer" to smithyTypes.resolve("config_bag::FrozenLayer"), + "Layer" to smithyTypes.resolve("config_bag::Layer"), + "RuntimePlugin" to RuntimeType.runtimePlugin(codegenContext.runtimeConfig), + "SharedRequestSerializer" to + RuntimeType.smithyRuntimeApiClient(codegenContext.runtimeConfig) + .resolve("client::ser_de::SharedRequestSerializer"), + ) + } + }, + "alternate_presigning_serializer_registration" to + writable { + if (presignableOp.hasModelTransforms()) { + rust(".with_operation_plugin(AlternatePresigningSerializerRuntimePlugin)") + } + }, + "payload_override" to + writable { + rustTemplate( + "#{aws_sigv4}::http_request::SignableBody::" + + when (presignableOp.payloadSigningType) { + PayloadSigningType.EMPTY -> "Bytes(b\"\")" + PayloadSigningType.UNSIGNED_PAYLOAD -> "UnsignedPayload" + }, + "aws_sigv4" to AwsRuntimeType.awsSigv4(runtimeConfig), ) - } - }, - "alternate_presigning_serializer_registration" to writable { - if (presignableOp.hasModelTransforms()) { - rust(".with_operation_plugin(AlternatePresigningSerializerRuntimePlugin)") - } - }, - "payload_override" to writable { - rustTemplate( - "#{aws_sigv4}::http_request::SignableBody::" + - when (presignableOp.payloadSigningType) { - PayloadSigningType.EMPTY -> "Bytes(b\"\")" - PayloadSigningType.UNSIGNED_PAYLOAD -> "UnsignedPayload" - }, - "aws_sigv4" to AwsRuntimeType.awsSigv4(runtimeConfig), - ) - }, + }, ) } @@ -305,19 +322,21 @@ class MoveDocumentMembersToQueryParamsTransform( ) : PresignModelTransform { override fun transform(model: Model): Model { val index = HttpBindingIndex(model) - val operations = presignableOperations.map { id -> - model.expectShape(syntheticShapeId(id), OperationShape::class.java).also { shape -> - check(shape.hasTrait(HttpTrait.ID)) { - "MoveDocumentMembersToQueryParamsTransform can only be used with REST protocols" + val operations = + presignableOperations.map { id -> + model.expectShape(syntheticShapeId(id), OperationShape::class.java).also { shape -> + check(shape.hasTrait(HttpTrait.ID)) { + "MoveDocumentMembersToQueryParamsTransform can only be used with REST protocols" + } } } - } // Find document members of the presignable operations - val membersToUpdate = operations.map { operation -> - val payloadBindings = index.getRequestBindings(operation, HttpBinding.Location.DOCUMENT) - payloadBindings.map { binding -> binding.member } - }.flatten() + val membersToUpdate = + operations.map { operation -> + val payloadBindings = index.getRequestBindings(operation, HttpBinding.Location.DOCUMENT) + payloadBindings.map { binding -> binding.member } + }.flatten() // Transform found shapes for presigning return ModelTransformer.create().mapShapes(model) { shape -> @@ -331,11 +350,12 @@ class MoveDocumentMembersToQueryParamsTransform( } private fun RustWriter.documentPresignedMethod(hasConfigArg: Boolean) { - val configBlurb = if (hasConfigArg) { - "The credentials provider from the `config` will be used to generate the request's signature.\n" - } else { - "" - } + val configBlurb = + if (hasConfigArg) { + "The credentials provider from the `config` will be used to generate the request's signature.\n" + } else { + "" + } docs( """ Creates a presigned request for this operation. diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsRuntimeType.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsRuntimeType.kt index 9fea90bf893..b7042a90ee4 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsRuntimeType.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsRuntimeType.kt @@ -14,16 +14,18 @@ import java.io.File import java.nio.file.Path fun RuntimeConfig.awsRoot(): RuntimeCrateLocation { - val updatedPath = runtimeCrateLocation.path?.let { cratePath -> - val asPath = Path.of(cratePath) - val path = if (asPath.isAbsolute) { - asPath.parent.resolve("aws/rust-runtime").toAbsolutePath().toString() - } else { - cratePath + val updatedPath = + runtimeCrateLocation.path?.let { cratePath -> + val asPath = Path.of(cratePath) + val path = + if (asPath.isAbsolute) { + asPath.parent.resolve("aws/rust-runtime").toAbsolutePath().toString() + } else { + cratePath + } + check(File(path).exists()) { "$path must exist to generate a working SDK" } + path } - check(File(path).exists()) { "$path must exist to generate a working SDK" } - path - } return runtimeCrateLocation.copy( path = updatedPath, versions = runtimeCrateLocation.versions, ) @@ -32,6 +34,7 @@ fun RuntimeConfig.awsRoot(): RuntimeCrateLocation { object AwsRuntimeType { fun presigning(): RuntimeType = RuntimeType.forInlineDependency(InlineAwsDependency.forRustFile("presigning", visibility = Visibility.PUBLIC)) + fun presigningInterceptor(runtimeConfig: RuntimeConfig): RuntimeType = RuntimeType.forInlineDependency( InlineAwsDependency.forRustFile( @@ -50,8 +53,10 @@ object AwsRuntimeType { fun awsHttp(runtimeConfig: RuntimeConfig) = AwsCargoDependency.awsHttp(runtimeConfig).toType() fun awsSigv4(runtimeConfig: RuntimeConfig) = AwsCargoDependency.awsSigv4(runtimeConfig).toType() + fun awsTypes(runtimeConfig: RuntimeConfig) = AwsCargoDependency.awsTypes(runtimeConfig).toType() fun awsRuntime(runtimeConfig: RuntimeConfig) = AwsCargoDependency.awsRuntime(runtimeConfig).toType() + fun awsRuntimeApi(runtimeConfig: RuntimeConfig) = AwsCargoDependency.awsRuntimeApi(runtimeConfig).toType() } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/BaseRequestIdDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/BaseRequestIdDecorator.kt index 96d61b4f9f3..91b3a1352eb 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/BaseRequestIdDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/BaseRequestIdDecorator.kt @@ -39,7 +39,9 @@ import software.amazon.smithy.rust.codegen.core.util.hasTrait abstract class BaseRequestIdDecorator : ClientCodegenDecorator { abstract val accessorFunctionName: String abstract val fieldName: String + abstract fun accessorTrait(codegenContext: ClientCodegenContext): RuntimeType + abstract fun applyToError(codegenContext: ClientCodegenContext): RuntimeType override fun operationCustomizations( @@ -51,8 +53,7 @@ abstract class BaseRequestIdDecorator : ClientCodegenDecorator { override fun errorCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = - baseCustomizations + listOf(RequestIdErrorCustomization(codegenContext)) + ): List = baseCustomizations + listOf(RequestIdErrorCustomization(codegenContext)) override fun errorImplCustomizations( codegenContext: ClientCodegenContext, @@ -69,7 +70,10 @@ abstract class BaseRequestIdDecorator : ClientCodegenDecorator { baseCustomizations: List, ): List = baseCustomizations + listOf(RequestIdBuilderCustomization()) - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { rustCrate.withModule(ClientRustModule.Operation) { // Re-export RequestId in generated crate rust("pub use #T;", accessorTrait(codegenContext)) @@ -82,160 +86,167 @@ abstract class BaseRequestIdDecorator : ClientCodegenDecorator { private inner class RequestIdOperationCustomization(private val codegenContext: ClientCodegenContext) : OperationCustomization() { - override fun section(section: OperationSection): Writable = writable { - when (section) { - is OperationSection.PopulateErrorMetadataExtras -> { - rustTemplate( - "${section.builderName} = #{apply_to_error}(${section.builderName}, ${section.responseHeadersName});", - "apply_to_error" to applyToError(codegenContext), - ) - } + override fun section(section: OperationSection): Writable = + writable { + when (section) { + is OperationSection.PopulateErrorMetadataExtras -> { + rustTemplate( + "${section.builderName} = #{apply_to_error}(${section.builderName}, ${section.responseHeadersName});", + "apply_to_error" to applyToError(codegenContext), + ) + } - is OperationSection.MutateOutput -> { - rust( - "output._set_$fieldName(#T::$accessorFunctionName(${section.responseHeadersName}).map(str::to_string));", - accessorTrait(codegenContext), - ) - } + is OperationSection.MutateOutput -> { + rust( + "output._set_$fieldName(#T::$accessorFunctionName(${section.responseHeadersName}).map(str::to_string));", + accessorTrait(codegenContext), + ) + } - is OperationSection.BeforeParseResponse -> { - rustTemplate( - "#{tracing}::debug!($fieldName = ?#{trait}::$accessorFunctionName(${section.responseName}));", - "tracing" to RuntimeType.Tracing, - "trait" to accessorTrait(codegenContext), - ) - } + is OperationSection.BeforeParseResponse -> { + rustTemplate( + "#{tracing}::debug!($fieldName = ?#{trait}::$accessorFunctionName(${section.responseName}));", + "tracing" to RuntimeType.Tracing, + "trait" to accessorTrait(codegenContext), + ) + } - else -> {} + else -> {} + } } - } } private inner class RequestIdErrorCustomization(private val codegenContext: ClientCodegenContext) : ErrorCustomization() { - override fun section(section: ErrorSection): Writable = writable { - when (section) { - is ErrorSection.OperationErrorAdditionalTraitImpls -> { - rustTemplate( - """ - impl #{AccessorTrait} for #{error} { - fn $accessorFunctionName(&self) -> Option<&str> { - self.meta().$accessorFunctionName() + override fun section(section: ErrorSection): Writable = + writable { + when (section) { + is ErrorSection.OperationErrorAdditionalTraitImpls -> { + rustTemplate( + """ + impl #{AccessorTrait} for #{error} { + fn $accessorFunctionName(&self) -> Option<&str> { + self.meta().$accessorFunctionName() + } } - } - """, - "AccessorTrait" to accessorTrait(codegenContext), - "error" to section.errorSymbol, - ) - } + """, + "AccessorTrait" to accessorTrait(codegenContext), + "error" to section.errorSymbol, + ) + } - is ErrorSection.ServiceErrorAdditionalTraitImpls -> { - rustBlock("impl #T for Error", accessorTrait(codegenContext)) { - rustBlock("fn $accessorFunctionName(&self) -> Option<&str>") { - rustBlock("match self") { - section.allErrors.forEach { error -> - val optional = asMemberShape(error)?.let { member -> - codegenContext.symbolProvider.toSymbol(member).isOptional() - } ?: true - val wrapped = writable { - when (optional) { - false -> rustTemplate("#{Some}(e.$accessorFunctionName())", *preludeScope) - true -> rustTemplate("e.$accessorFunctionName()") - } + is ErrorSection.ServiceErrorAdditionalTraitImpls -> { + rustBlock("impl #T for Error", accessorTrait(codegenContext)) { + rustBlock("fn $accessorFunctionName(&self) -> Option<&str>") { + rustBlock("match self") { + section.allErrors.forEach { error -> + val optional = + asMemberShape(error)?.let { member -> + codegenContext.symbolProvider.toSymbol(member).isOptional() + } ?: true + val wrapped = + writable { + when (optional) { + false -> rustTemplate("#{Some}(e.$accessorFunctionName())", *preludeScope) + true -> rustTemplate("e.$accessorFunctionName()") + } + } + val sym = codegenContext.symbolProvider.toSymbol(error) + rust("Self::${sym.name}(e) => #T,", wrapped) } - val sym = codegenContext.symbolProvider.toSymbol(error) - rust("Self::${sym.name}(e) => #T,", wrapped) + rust("Self::Unhandled(e) => e.meta.$accessorFunctionName(),") } - rust("Self::Unhandled(e) => e.meta.$accessorFunctionName(),") } } } } } - } } private inner class RequestIdErrorImplCustomization(private val codegenContext: ClientCodegenContext) : ErrorImplCustomization() { - override fun section(section: ErrorImplSection): Writable = writable { - when (section) { - is ErrorImplSection.ErrorAdditionalTraitImpls -> { - rustBlock("impl #1T for #2T", accessorTrait(codegenContext), section.errorType) { - rustBlock("fn $accessorFunctionName(&self) -> Option<&str>") { - rust("use #T;", RuntimeType.provideErrorMetadataTrait(codegenContext.runtimeConfig)) - rust("self.meta().$accessorFunctionName()") + override fun section(section: ErrorImplSection): Writable = + writable { + when (section) { + is ErrorImplSection.ErrorAdditionalTraitImpls -> { + rustBlock("impl #1T for #2T", accessorTrait(codegenContext), section.errorType) { + rustBlock("fn $accessorFunctionName(&self) -> Option<&str>") { + rust("use #T;", RuntimeType.provideErrorMetadataTrait(codegenContext.runtimeConfig)) + rust("self.meta().$accessorFunctionName()") + } } } - } - else -> {} + else -> {} + } } - } } private inner class RequestIdStructureCustomization(private val codegenContext: ClientCodegenContext) : StructureCustomization() { - override fun section(section: StructureSection): Writable = writable { - if (section.shape.hasTrait()) { - when (section) { - is StructureSection.AdditionalFields -> { - rust("_$fieldName: Option,") - } + override fun section(section: StructureSection): Writable = + writable { + if (section.shape.hasTrait()) { + when (section) { + is StructureSection.AdditionalFields -> { + rust("_$fieldName: Option,") + } - is StructureSection.AdditionalTraitImpls -> { - rustTemplate( - """ - impl #{AccessorTrait} for ${section.structName} { - fn $accessorFunctionName(&self) -> Option<&str> { - self._$fieldName.as_deref() + is StructureSection.AdditionalTraitImpls -> { + rustTemplate( + """ + impl #{AccessorTrait} for ${section.structName} { + fn $accessorFunctionName(&self) -> Option<&str> { + self._$fieldName.as_deref() + } } - } - """, - "AccessorTrait" to accessorTrait(codegenContext), - ) - } + """, + "AccessorTrait" to accessorTrait(codegenContext), + ) + } - is StructureSection.AdditionalDebugFields -> { - rust("""${section.formatterName}.field("_$fieldName", &self._$fieldName);""") + is StructureSection.AdditionalDebugFields -> { + rust("""${section.formatterName}.field("_$fieldName", &self._$fieldName);""") + } } } } - } } private inner class RequestIdBuilderCustomization : BuilderCustomization() { - override fun section(section: BuilderSection): Writable = writable { - if (section.shape.hasTrait()) { - when (section) { - is BuilderSection.AdditionalFields -> { - rust("_$fieldName: Option,") - } + override fun section(section: BuilderSection): Writable = + writable { + if (section.shape.hasTrait()) { + when (section) { + is BuilderSection.AdditionalFields -> { + rust("_$fieldName: Option,") + } - is BuilderSection.AdditionalMethods -> { - rust( - """ - pub(crate) fn _$fieldName(mut self, $fieldName: impl Into) -> Self { - self._$fieldName = Some($fieldName.into()); - self - } + is BuilderSection.AdditionalMethods -> { + rust( + """ + pub(crate) fn _$fieldName(mut self, $fieldName: impl Into) -> Self { + self._$fieldName = Some($fieldName.into()); + self + } - pub(crate) fn _set_$fieldName(&mut self, $fieldName: Option) -> &mut Self { - self._$fieldName = $fieldName; - self - } - """, - ) - } + pub(crate) fn _set_$fieldName(&mut self, $fieldName: Option) -> &mut Self { + self._$fieldName = $fieldName; + self + } + """, + ) + } - is BuilderSection.AdditionalDebugFields -> { - rust("""${section.formatterName}.field("_$fieldName", &self._$fieldName);""") - } + is BuilderSection.AdditionalDebugFields -> { + rust("""${section.formatterName}.field("_$fieldName", &self._$fieldName);""") + } - is BuilderSection.AdditionalFieldsInBuild -> { - rust("_$fieldName: self._$fieldName,") + is BuilderSection.AdditionalFieldsInBuild -> { + rust("_$fieldName: self._$fieldName,") + } } } } - } } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CrateLicenseDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CrateLicenseDecorator.kt index 22ebd0ff1e4..e842d731dc0 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CrateLicenseDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CrateLicenseDecorator.kt @@ -14,7 +14,10 @@ class CrateLicenseDecorator : ClientCodegenDecorator { override val name: String = "CrateLicense" override val order: Byte = 0 - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { rustCrate.withFile("LICENSE") { val license = this::class.java.getResource("/LICENSE").readText() raw(license) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviders.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviders.kt index 331babe611a..ce8610e51ba 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviders.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviders.kt @@ -41,7 +41,10 @@ class CredentialsProviderDecorator : ClientCodegenDecorator { }, ) - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { rustCrate.mergeFeature(TestUtilFeature.copy(deps = listOf("aws-credential-types/test-util"))) rustCrate.withModule(ClientRustModule.config) { @@ -58,87 +61,94 @@ class CredentialsProviderDecorator : ClientCodegenDecorator { */ class CredentialProviderConfig(private val codegenContext: ClientCodegenContext) : ConfigCustomization() { private val runtimeConfig = codegenContext.runtimeConfig - private val codegenScope = arrayOf( - *preludeScope, - "Credentials" to configReexport(AwsRuntimeType.awsCredentialTypes(runtimeConfig).resolve("Credentials")), - "ProvideCredentials" to configReexport( - AwsRuntimeType.awsCredentialTypes(runtimeConfig) - .resolve("provider::ProvideCredentials"), - ), - "SharedCredentialsProvider" to configReexport( - AwsRuntimeType.awsCredentialTypes(runtimeConfig) - .resolve("provider::SharedCredentialsProvider"), - ), - "SIGV4A_SCHEME_ID" to AwsRuntimeType.awsRuntime(runtimeConfig) - .resolve("auth::sigv4a::SCHEME_ID"), - "SIGV4_SCHEME_ID" to AwsRuntimeType.awsRuntime(runtimeConfig) - .resolve("auth::sigv4::SCHEME_ID"), - "TestCredentials" to AwsRuntimeType.awsCredentialTypesTestUtil(runtimeConfig).resolve("Credentials"), - ) + private val codegenScope = + arrayOf( + *preludeScope, + "Credentials" to configReexport(AwsRuntimeType.awsCredentialTypes(runtimeConfig).resolve("Credentials")), + "ProvideCredentials" to + configReexport( + AwsRuntimeType.awsCredentialTypes(runtimeConfig) + .resolve("provider::ProvideCredentials"), + ), + "SharedCredentialsProvider" to + configReexport( + AwsRuntimeType.awsCredentialTypes(runtimeConfig) + .resolve("provider::SharedCredentialsProvider"), + ), + "SIGV4A_SCHEME_ID" to + AwsRuntimeType.awsRuntime(runtimeConfig) + .resolve("auth::sigv4a::SCHEME_ID"), + "SIGV4_SCHEME_ID" to + AwsRuntimeType.awsRuntime(runtimeConfig) + .resolve("auth::sigv4::SCHEME_ID"), + "TestCredentials" to AwsRuntimeType.awsCredentialTypesTestUtil(runtimeConfig).resolve("Credentials"), + ) - override fun section(section: ServiceConfig) = writable { - when (section) { - ServiceConfig.ConfigImpl -> { - rustTemplate( - """ - /// This function was intended to be removed, and has been broken since release-2023-11-15 as it always returns a `None`. Do not use. - ##[deprecated(note = "This function was intended to be removed, and has been broken since release-2023-11-15 as it always returns a `None`. Do not use.")] - pub fn credentials_provider(&self) -> Option<#{SharedCredentialsProvider}> { - #{None} - } - """, - *codegenScope, - ) - } + override fun section(section: ServiceConfig) = + writable { + when (section) { + ServiceConfig.ConfigImpl -> { + rustTemplate( + """ + /// This function was intended to be removed, and has been broken since release-2023-11-15 as it always returns a `None`. Do not use. + ##[deprecated(note = "This function was intended to be removed, and has been broken since release-2023-11-15 as it always returns a `None`. Do not use.")] + pub fn credentials_provider(&self) -> Option<#{SharedCredentialsProvider}> { + #{None} + } + """, + *codegenScope, + ) + } - ServiceConfig.BuilderImpl -> { - rustTemplate( - """ - /// Sets the credentials provider for this service - pub fn credentials_provider(mut self, credentials_provider: impl #{ProvideCredentials} + 'static) -> Self { - self.set_credentials_provider(#{Some}(#{SharedCredentialsProvider}::new(credentials_provider))); - self - } - """, - *codegenScope, - ) + ServiceConfig.BuilderImpl -> { + rustTemplate( + """ + /// Sets the credentials provider for this service + pub fn credentials_provider(mut self, credentials_provider: impl #{ProvideCredentials} + 'static) -> Self { + self.set_credentials_provider(#{Some}(#{SharedCredentialsProvider}::new(credentials_provider))); + self + } + """, + *codegenScope, + ) - rustBlockTemplate( - """ - /// Sets the credentials provider for this service - pub fn set_credentials_provider(&mut self, credentials_provider: #{Option}<#{SharedCredentialsProvider}>) -> &mut Self - """, - *codegenScope, - ) { rustBlockTemplate( """ - if let Some(credentials_provider) = credentials_provider + /// Sets the credentials provider for this service + pub fn set_credentials_provider(&mut self, credentials_provider: #{Option}<#{SharedCredentialsProvider}>) -> &mut Self """, *codegenScope, ) { - if (codegenContext.serviceShape.supportedAuthSchemes().contains("sigv4a")) { - featureGateBlock("sigv4a") { - rustTemplate( - "self.runtime_components.set_identity_resolver(#{SIGV4A_SCHEME_ID}, credentials_provider.clone());", - *codegenScope, - ) + rustBlockTemplate( + """ + if let Some(credentials_provider) = credentials_provider + """, + *codegenScope, + ) { + if (codegenContext.serviceShape.supportedAuthSchemes().contains("sigv4a")) { + featureGateBlock("sigv4a") { + rustTemplate( + "self.runtime_components.set_identity_resolver(#{SIGV4A_SCHEME_ID}, credentials_provider.clone());", + *codegenScope, + ) + } } + rustTemplate( + "self.runtime_components.set_identity_resolver(#{SIGV4_SCHEME_ID}, credentials_provider);", + *codegenScope, + ) } - rustTemplate( - "self.runtime_components.set_identity_resolver(#{SIGV4_SCHEME_ID}, credentials_provider);", - *codegenScope, - ) + rust("self") } - rust("self") } - } - is ServiceConfig.DefaultForTests -> rustTemplate( - "${section.configBuilderRef}.set_credentials_provider(Some(#{SharedCredentialsProvider}::new(#{TestCredentials}::for_tests())));", - *codegenScope, - ) + is ServiceConfig.DefaultForTests -> + rustTemplate( + "${section.configBuilderRef}.set_credentials_provider(Some(#{SharedCredentialsProvider}::new(#{TestCredentials}::for_tests())));", + *codegenScope, + ) - else -> emptySection + else -> emptySection + } } - } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointBuiltInsDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointBuiltInsDecorator.kt index 636f1951596..3a9b5815494 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointBuiltInsDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointBuiltInsDecorator.kt @@ -50,7 +50,9 @@ fun EndpointRuleSet.getBuiltIn(builtIn: String) = parameters.toList().find { it. /** load a builtIn parameter from a ruleset. The returned builtIn is the one defined in the ruleset (including latest docs, etc.) */ fun EndpointRuleSet.getBuiltIn(builtIn: Parameter) = getBuiltIn(builtIn.builtIn.orNull()!!) + fun ClientCodegenContext.getBuiltIn(builtIn: Parameter): Parameter? = getBuiltIn(builtIn.builtIn.orNull()!!) + fun ClientCodegenContext.getBuiltIn(builtIn: String): Parameter? { val idx = EndpointRulesetIndex.of(model) val rules = idx.endpointRulesForService(serviceShape) ?: return null @@ -62,24 +64,35 @@ private fun promotedBuiltins(parameter: Parameter) = parameter.builtIn == AwsBuiltIns.DUALSTACK.builtIn || parameter.builtIn == BuiltIns.SDK_ENDPOINT.builtIn -private fun configParamNewtype(parameter: Parameter, name: String, runtimeConfig: RuntimeConfig): RuntimeType { +private fun configParamNewtype( + parameter: Parameter, + name: String, + runtimeConfig: RuntimeConfig, +): RuntimeType { val type = parameter.symbol().mapRustType { t -> t.stripOuter() } return when (promotedBuiltins(parameter)) { - true -> AwsRuntimeType.awsTypes(runtimeConfig) - .resolve("endpoint_config::${name.toPascalCase()}") + true -> + AwsRuntimeType.awsTypes(runtimeConfig) + .resolve("endpoint_config::${name.toPascalCase()}") false -> configParamNewtype(name.toPascalCase(), type, runtimeConfig) } } -private fun ConfigParam.Builder.toConfigParam(parameter: Parameter, runtimeConfig: RuntimeConfig): ConfigParam = +private fun ConfigParam.Builder.toConfigParam( + parameter: Parameter, + runtimeConfig: RuntimeConfig, +): ConfigParam = this.name(this.name ?: parameter.name.rustName()) .type(parameter.symbol().mapRustType { t -> t.stripOuter() }) .newtype(configParamNewtype(parameter, this.name!!, runtimeConfig)) .setterDocs(this.setterDocs ?: parameter.documentation.orNull()?.let { writable { docs(it) } }) .build() -fun Model.loadBuiltIn(serviceId: ShapeId, builtInSrc: Parameter): Parameter? { +fun Model.loadBuiltIn( + serviceId: ShapeId, + builtInSrc: Parameter, +): Parameter? { val model = this val idx = EndpointRulesetIndex.of(model) val service = model.expectShape(serviceId, ServiceShape::class.java) @@ -96,10 +109,11 @@ fun Model.sdkConfigSetter( val builtIn = loadBuiltIn(serviceId, builtInSrc) ?: return null val fieldName = configParameterNameOverride ?: builtIn.name.rustName() - val map = when (builtIn.type!!) { - ParameterType.STRING -> writable { rust("|s|s.to_string()") } - ParameterType.BOOLEAN -> null - } + val map = + when (builtIn.type!!) { + ParameterType.STRING -> writable { rust("|s|s.to_string()") } + ParameterType.BOOLEAN -> null + } return SdkConfigCustomization.copyField(fieldName, map) } @@ -139,49 +153,59 @@ fun decoratorForBuiltIn( } } - override fun endpointCustomizations(codegenContext: ClientCodegenContext): List = listOf( - object : EndpointCustomization { - override fun loadBuiltInFromServiceConfig(parameter: Parameter, configRef: String): Writable? = - when (parameter.builtIn) { - builtIn.builtIn -> writable { - val newtype = configParamNewtype(parameter, name, codegenContext.runtimeConfig) - val symbol = parameter.symbol().mapRustType { t -> t.stripOuter() } + override fun endpointCustomizations(codegenContext: ClientCodegenContext): List = + listOf( + object : EndpointCustomization { + override fun loadBuiltInFromServiceConfig( + parameter: Parameter, + configRef: String, + ): Writable? = + when (parameter.builtIn) { + builtIn.builtIn -> + writable { + val newtype = configParamNewtype(parameter, name, codegenContext.runtimeConfig) + val symbol = parameter.symbol().mapRustType { t -> t.stripOuter() } + rustTemplate( + """$configRef.#{load_from_service_config_layer}""", + "load_from_service_config_layer" to loadFromConfigBag(symbol.name, newtype), + ) + } + + else -> null + } + + override fun setBuiltInOnServiceConfig( + name: String, + value: Node, + configBuilderRef: String, + ): Writable? { + if (name != builtIn.builtIn.get()) { + return null + } + return writable { rustTemplate( - """$configRef.#{load_from_service_config_layer}""", - "load_from_service_config_layer" to loadFromConfigBag(symbol.name, newtype), + "let $configBuilderRef = $configBuilderRef.${nameOverride ?: builtIn.name.rustName()}(#{value});", + "value" to value.toWritable(), ) } - - else -> null - } - - override fun setBuiltInOnServiceConfig(name: String, value: Node, configBuilderRef: String): Writable? { - if (name != builtIn.builtIn.get()) { - return null } - return writable { - rustTemplate( - "let $configBuilderRef = $configBuilderRef.${nameOverride ?: builtIn.name.rustName()}(#{value});", - "value" to value.toWritable(), - ) - } - } - }, - ) + }, + ) } } -private val endpointUrlDocs = writable { - rust( - """ - /// Sets the endpoint URL used to communicate with this service +private val endpointUrlDocs = + writable { + rust( + """ + /// Sets the endpoint URL used to communicate with this service - /// Note: this is used in combination with other endpoint rules, e.g. an API that applies a host-label prefix - /// will be prefixed onto this URL. To fully override the endpoint resolver, use - /// [`Builder::endpoint_resolver`]. - """.trimIndent(), - ) -} + /// Note: this is used in combination with other endpoint rules, e.g. an API that applies a host-label prefix + /// will be prefixed onto this URL. To fully override the endpoint resolver, use + /// [`Builder::endpoint_resolver`]. + """.trimIndent(), + ) + } fun Node.toWritable(): Writable { val node = this diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpRequestChecksumDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpRequestChecksumDecorator.kt index f2648ee914c..37bff546c94 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpRequestChecksumDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpRequestChecksumDecorator.kt @@ -26,19 +26,20 @@ import software.amazon.smithy.rust.codegen.core.util.getTrait import software.amazon.smithy.rust.codegen.core.util.inputShape import software.amazon.smithy.rust.codegen.core.util.orNull -private fun RuntimeConfig.awsInlineableHttpRequestChecksum() = RuntimeType.forInlineDependency( - InlineAwsDependency.forRustFile( - "http_request_checksum", visibility = Visibility.PUBCRATE, - CargoDependency.Bytes, - CargoDependency.Http, - CargoDependency.HttpBody, - CargoDependency.Tracing, - CargoDependency.smithyChecksums(this), - CargoDependency.smithyHttp(this), - CargoDependency.smithyRuntimeApiClient(this), - CargoDependency.smithyTypes(this), - ), -) +private fun RuntimeConfig.awsInlineableHttpRequestChecksum() = + RuntimeType.forInlineDependency( + InlineAwsDependency.forRustFile( + "http_request_checksum", visibility = Visibility.PUBCRATE, + CargoDependency.Bytes, + CargoDependency.Http, + CargoDependency.HttpBody, + CargoDependency.Tracing, + CargoDependency.smithyChecksums(this), + CargoDependency.smithyHttp(this), + CargoDependency.smithyRuntimeApiClient(this), + CargoDependency.smithyTypes(this), + ), + ) class HttpRequestChecksumDecorator : ClientCodegenDecorator { override val name: String = "HttpRequestChecksum" @@ -48,8 +49,7 @@ class HttpRequestChecksumDecorator : ClientCodegenDecorator { codegenContext: ClientCodegenContext, operation: OperationShape, baseCustomizations: List, - ): List = - baseCustomizations + HttpRequestChecksumCustomization(codegenContext, operation) + ): List = baseCustomizations + HttpRequestChecksumCustomization(codegenContext, operation) } private fun HttpChecksumTrait.requestAlgorithmMember( @@ -112,41 +112,44 @@ class HttpRequestChecksumCustomization( ) : OperationCustomization() { private val runtimeConfig = codegenContext.runtimeConfig - override fun section(section: OperationSection): Writable = writable { - // Get the `HttpChecksumTrait`, returning early if this `OperationShape` doesn't have one - val checksumTrait = operationShape.getTrait() ?: return@writable - val requestAlgorithmMember = checksumTrait.requestAlgorithmMember(codegenContext, operationShape) - val inputShape = codegenContext.model.expectShape(operationShape.inputShape) + override fun section(section: OperationSection): Writable = + writable { + // Get the `HttpChecksumTrait`, returning early if this `OperationShape` doesn't have one + val checksumTrait = operationShape.getTrait() ?: return@writable + val requestAlgorithmMember = checksumTrait.requestAlgorithmMember(codegenContext, operationShape) + val inputShape = codegenContext.model.expectShape(operationShape.inputShape) - when (section) { - is OperationSection.AdditionalInterceptors -> { - if (requestAlgorithmMember != null) { - section.registerInterceptor(runtimeConfig, this) { - val runtimeApi = RuntimeType.smithyRuntimeApiClient(runtimeConfig) - rustTemplate( - """ - #{RequestChecksumInterceptor}::new(|input: &#{Input}| { - let input: &#{OperationInput} = input.downcast_ref().expect("correct type"); - let checksum_algorithm = input.$requestAlgorithmMember(); - #{checksum_algorithm_to_str} - #{Result}::<_, #{BoxError}>::Ok(checksum_algorithm) - }) - """, - *preludeScope, - "BoxError" to RuntimeType.boxError(runtimeConfig), - "Input" to runtimeApi.resolve("client::interceptors::context::Input"), - "OperationInput" to codegenContext.symbolProvider.toSymbol(inputShape), - "RequestChecksumInterceptor" to runtimeConfig.awsInlineableHttpRequestChecksum() - .resolve("RequestChecksumInterceptor"), - "checksum_algorithm_to_str" to checksumTrait.checksumAlgorithmToStr( - codegenContext, - operationShape, - ), - ) + when (section) { + is OperationSection.AdditionalInterceptors -> { + if (requestAlgorithmMember != null) { + section.registerInterceptor(runtimeConfig, this) { + val runtimeApi = RuntimeType.smithyRuntimeApiClient(runtimeConfig) + rustTemplate( + """ + #{RequestChecksumInterceptor}::new(|input: &#{Input}| { + let input: &#{OperationInput} = input.downcast_ref().expect("correct type"); + let checksum_algorithm = input.$requestAlgorithmMember(); + #{checksum_algorithm_to_str} + #{Result}::<_, #{BoxError}>::Ok(checksum_algorithm) + }) + """, + *preludeScope, + "BoxError" to RuntimeType.boxError(runtimeConfig), + "Input" to runtimeApi.resolve("client::interceptors::context::Input"), + "OperationInput" to codegenContext.symbolProvider.toSymbol(inputShape), + "RequestChecksumInterceptor" to + runtimeConfig.awsInlineableHttpRequestChecksum() + .resolve("RequestChecksumInterceptor"), + "checksum_algorithm_to_str" to + checksumTrait.checksumAlgorithmToStr( + codegenContext, + operationShape, + ), + ) + } } } + else -> { } } - else -> { } } - } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpResponseChecksumDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpResponseChecksumDecorator.kt index e49e834ddd7..f5d5f67bd48 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpResponseChecksumDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/HttpResponseChecksumDecorator.kt @@ -27,19 +27,20 @@ import software.amazon.smithy.rust.codegen.core.util.inputShape import software.amazon.smithy.rust.codegen.core.util.letIf import software.amazon.smithy.rust.codegen.core.util.orNull -private fun RuntimeConfig.awsInlineableHttpResponseChecksum() = RuntimeType.forInlineDependency( - InlineAwsDependency.forRustFile( - "http_response_checksum", visibility = Visibility.PUBCRATE, - CargoDependency.Bytes, - CargoDependency.Http, - CargoDependency.HttpBody, - CargoDependency.Tracing, - CargoDependency.smithyChecksums(this), - CargoDependency.smithyHttp(this), - CargoDependency.smithyRuntimeApiClient(this), - CargoDependency.smithyTypes(this), - ), -) +private fun RuntimeConfig.awsInlineableHttpResponseChecksum() = + RuntimeType.forInlineDependency( + InlineAwsDependency.forRustFile( + "http_response_checksum", visibility = Visibility.PUBCRATE, + CargoDependency.Bytes, + CargoDependency.Http, + CargoDependency.HttpBody, + CargoDependency.Tracing, + CargoDependency.smithyChecksums(this), + CargoDependency.smithyHttp(this), + CargoDependency.smithyRuntimeApiClient(this), + CargoDependency.smithyTypes(this), + ), + ) fun HttpChecksumTrait.requestValidationModeMember( codegenContext: ClientCodegenContext, @@ -60,9 +61,10 @@ class HttpResponseChecksumDecorator : ClientCodegenDecorator { codegenContext: ClientCodegenContext, operation: OperationShape, baseCustomizations: List, - ): List = baseCustomizations.letIf(applies(operation)) { - it + HttpResponseChecksumCustomization(codegenContext, operation) - } + ): List = + baseCustomizations.letIf(applies(operation)) { + it + HttpResponseChecksumCustomization(codegenContext, operation) + } } // This generator was implemented based on this spec: @@ -71,50 +73,52 @@ class HttpResponseChecksumCustomization( private val codegenContext: ClientCodegenContext, private val operationShape: OperationShape, ) : OperationCustomization() { - override fun section(section: OperationSection): Writable = writable { - val checksumTrait = operationShape.getTrait() ?: return@writable - val requestValidationModeMember = - checksumTrait.requestValidationModeMember(codegenContext, operationShape) ?: return@writable - val requestValidationModeMemberInner = if (requestValidationModeMember.isOptional) { - codegenContext.model.expectShape(requestValidationModeMember.target) - } else { - requestValidationModeMember - } - val validationModeName = codegenContext.symbolProvider.toMemberName(requestValidationModeMember) - val inputShape = codegenContext.model.expectShape(operationShape.inputShape) + override fun section(section: OperationSection): Writable = + writable { + val checksumTrait = operationShape.getTrait() ?: return@writable + val requestValidationModeMember = + checksumTrait.requestValidationModeMember(codegenContext, operationShape) ?: return@writable + val requestValidationModeMemberInner = + if (requestValidationModeMember.isOptional) { + codegenContext.model.expectShape(requestValidationModeMember.target) + } else { + requestValidationModeMember + } + val validationModeName = codegenContext.symbolProvider.toMemberName(requestValidationModeMember) + val inputShape = codegenContext.model.expectShape(operationShape.inputShape) - when (section) { - is OperationSection.AdditionalInterceptors -> { - section.registerInterceptor(codegenContext.runtimeConfig, this) { - // CRC32, CRC32C, SHA256, SHA1 -> "crc32", "crc32c", "sha256", "sha1" - val responseAlgorithms = checksumTrait.responseAlgorithms - .map { algorithm -> algorithm.lowercase() }.joinToString(", ") { algorithm -> "\"$algorithm\"" } - val runtimeApi = RuntimeType.smithyRuntimeApiClient(codegenContext.runtimeConfig) - rustTemplate( - """ - #{ResponseChecksumInterceptor}::new( - [$responseAlgorithms].as_slice(), - |input: &#{Input}| { - ${""/* - Per [the spec](https://smithy.io/2.0/aws/aws-core.html#http-response-checksums), - we check to see if it's the `ENABLED` variant - */} - let input: &#{OperationInput} = input.downcast_ref().expect("correct type"); - matches!(input.$validationModeName(), #{Some}(#{ValidationModeShape}::Enabled)) - } + when (section) { + is OperationSection.AdditionalInterceptors -> { + section.registerInterceptor(codegenContext.runtimeConfig, this) { + // CRC32, CRC32C, SHA256, SHA1 -> "crc32", "crc32c", "sha256", "sha1" + val responseAlgorithms = + checksumTrait.responseAlgorithms + .map { algorithm -> algorithm.lowercase() }.joinToString(", ") { algorithm -> "\"$algorithm\"" } + val runtimeApi = RuntimeType.smithyRuntimeApiClient(codegenContext.runtimeConfig) + rustTemplate( + """ + #{ResponseChecksumInterceptor}::new( + [$responseAlgorithms].as_slice(), + |input: &#{Input}| { + ${""/* Per [the spec](https://smithy.io/2.0/aws/aws-core.html#http-response-checksums), + we check to see if it's the `ENABLED` variant */} + let input: &#{OperationInput} = input.downcast_ref().expect("correct type"); + matches!(input.$validationModeName(), #{Some}(#{ValidationModeShape}::Enabled)) + } + ) + """, + *preludeScope, + "ResponseChecksumInterceptor" to + codegenContext.runtimeConfig.awsInlineableHttpResponseChecksum() + .resolve("ResponseChecksumInterceptor"), + "Input" to runtimeApi.resolve("client::interceptors::context::Input"), + "OperationInput" to codegenContext.symbolProvider.toSymbol(inputShape), + "ValidationModeShape" to codegenContext.symbolProvider.toSymbol(requestValidationModeMemberInner), ) - """, - *preludeScope, - "ResponseChecksumInterceptor" to codegenContext.runtimeConfig.awsInlineableHttpResponseChecksum() - .resolve("ResponseChecksumInterceptor"), - "Input" to runtimeApi.resolve("client::interceptors::context::Input"), - "OperationInput" to codegenContext.symbolProvider.toSymbol(inputShape), - "ValidationModeShape" to codegenContext.symbolProvider.toSymbol(requestValidationModeMemberInner), - ) + } } - } - else -> {} + else -> {} + } } - } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/InlineAwsDependency.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/InlineAwsDependency.kt index 4f34f3a7503..db78816a319 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/InlineAwsDependency.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/InlineAwsDependency.kt @@ -11,10 +11,18 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustModule import software.amazon.smithy.rust.codegen.core.rustlang.Visibility object InlineAwsDependency { - fun forRustFile(file: String, visibility: Visibility = Visibility.PRIVATE, vararg additionalDependency: RustDependency): InlineDependency = - forRustFileAs(file, file, visibility, *additionalDependency) + fun forRustFile( + file: String, + visibility: Visibility = Visibility.PRIVATE, + vararg additionalDependency: RustDependency, + ): InlineDependency = forRustFileAs(file, file, visibility, *additionalDependency) - fun forRustFileAs(file: String, moduleName: String, visibility: Visibility = Visibility.PRIVATE, vararg additionalDependency: RustDependency): InlineDependency = + fun forRustFileAs( + file: String, + moduleName: String, + visibility: Visibility = Visibility.PRIVATE, + vararg additionalDependency: RustDependency, + ): InlineDependency = InlineDependency.Companion.forRustFile( RustModule.new(moduleName, visibility, documentationOverride = ""), "/aws-inlineable/src/$file.rs", diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/IntegrationTestDependencies.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/IntegrationTestDependencies.kt index ad1224546aa..a51fde33bc3 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/IntegrationTestDependencies.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/IntegrationTestDependencies.kt @@ -36,6 +36,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection import software.amazon.smithy.rust.codegen.core.testutil.testDependenciesOnly +import software.amazon.smithy.rustsdk.AwsCargoDependency.awsConfig import software.amazon.smithy.rustsdk.AwsCargoDependency.awsRuntime import java.nio.file.Files import java.nio.file.Paths @@ -60,12 +61,13 @@ class IntegrationTestDecorator : ClientCodegenDecorator { return if (Files.exists(testPackagePath) && Files.exists(testPackagePath.resolve("Cargo.toml"))) { val hasTests = Files.exists(testPackagePath.resolve("tests")) val hasBenches = Files.exists(testPackagePath.resolve("benches")) - baseCustomizations + IntegrationTestDependencies( - codegenContext, - moduleName, - hasTests, - hasBenches, - ) + baseCustomizations + + IntegrationTestDependencies( + codegenContext, + moduleName, + hasTests, + hasBenches, + ) } else { baseCustomizations } @@ -79,42 +81,48 @@ class IntegrationTestDependencies( private val hasBenches: Boolean, ) : LibRsCustomization() { private val runtimeConfig = codegenContext.runtimeConfig - override fun section(section: LibRsSection) = when (section) { - is LibRsSection.Body -> testDependenciesOnly { - if (hasTests) { - val smithyAsync = CargoDependency.smithyAsync(codegenContext.runtimeConfig) - .copy(features = setOf("test-util"), scope = DependencyScope.Dev) - val smithyTypes = CargoDependency.smithyTypes(codegenContext.runtimeConfig) - .copy(features = setOf("test-util"), scope = DependencyScope.Dev) - addDependency(awsRuntime(runtimeConfig).toDevDependency().withFeature("test-util")) - addDependency(FuturesUtil) - addDependency(SerdeJson) - addDependency(smithyAsync) - addDependency(smithyProtocolTestHelpers(codegenContext.runtimeConfig)) - addDependency(smithyRuntime(runtimeConfig).copy(features = setOf("test-util", "wire-mock"), scope = DependencyScope.Dev)) - addDependency(smithyRuntimeApiTestUtil(runtimeConfig)) - addDependency(smithyTypes) - addDependency(Tokio) - addDependency(Tracing.toDevDependency()) - addDependency(TracingSubscriber) - } - if (hasBenches) { - addDependency(Criterion) - } - for (serviceSpecific in serviceSpecificCustomizations()) { - serviceSpecific.section(section)(this) - } - } - else -> emptySection - } + override fun section(section: LibRsSection) = + when (section) { + is LibRsSection.Body -> + testDependenciesOnly { + if (hasTests) { + val smithyAsync = + CargoDependency.smithyAsync(codegenContext.runtimeConfig) + .copy(features = setOf("test-util"), scope = DependencyScope.Dev) + val smithyTypes = + CargoDependency.smithyTypes(codegenContext.runtimeConfig) + .copy(features = setOf("test-util"), scope = DependencyScope.Dev) + addDependency(awsRuntime(runtimeConfig).toDevDependency().withFeature("test-util")) + addDependency(FuturesUtil) + addDependency(SerdeJson) + addDependency(smithyAsync) + addDependency(smithyProtocolTestHelpers(codegenContext.runtimeConfig)) + addDependency(smithyRuntime(runtimeConfig).copy(features = setOf("test-util", "wire-mock"), scope = DependencyScope.Dev)) + addDependency(smithyRuntimeApiTestUtil(runtimeConfig)) + addDependency(smithyTypes) + addDependency(Tokio) + addDependency(Tracing.toDevDependency()) + addDependency(TracingSubscriber) + } + if (hasBenches) { + addDependency(Criterion) + } + for (serviceSpecific in serviceSpecificCustomizations()) { + serviceSpecific.section(section)(this) + } + } - private fun serviceSpecificCustomizations(): List = when (moduleName) { - "transcribestreaming" -> listOf(TranscribeTestDependencies()) - "s3" -> listOf(S3TestDependencies(codegenContext)) - "dynamodb" -> listOf(DynamoDbTestDependencies()) - else -> emptyList() - } + else -> emptySection + } + + private fun serviceSpecificCustomizations(): List = + when (moduleName) { + "transcribestreaming" -> listOf(TranscribeTestDependencies()) + "s3" -> listOf(S3TestDependencies(codegenContext)) + "dynamodb" -> listOf(DynamoDbTestDependencies()) + else -> emptyList() + } } class TranscribeTestDependencies : LibRsCustomization() { @@ -136,6 +144,7 @@ class DynamoDbTestDependencies : LibRsCustomization() { class S3TestDependencies(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { override fun section(section: LibRsSection): Writable = writable { + addDependency(awsConfig(codegenContext.runtimeConfig).toDevDependency().withFeature("behavior-version-latest")) addDependency(AsyncStd) addDependency(BytesUtils.toDevDependency()) addDependency(FastRand.toDevDependency()) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/InvocationIdDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/InvocationIdDecorator.kt index def448bd55d..321bedee9dd 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/InvocationIdDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/InvocationIdDecorator.kt @@ -30,8 +30,7 @@ class InvocationIdDecorator : ClientCodegenDecorator { override fun configCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = - baseCustomizations + InvocationIdConfigCustomization(codegenContext) + ): List = baseCustomizations + InvocationIdConfigCustomization(codegenContext) } private class InvocationIdRuntimePluginCustomization( @@ -39,17 +38,19 @@ private class InvocationIdRuntimePluginCustomization( ) : ServiceRuntimePluginCustomization() { private val runtimeConfig = codegenContext.runtimeConfig private val awsRuntime = AwsRuntimeType.awsRuntime(runtimeConfig) - private val codegenScope = arrayOf( - "InvocationIdInterceptor" to awsRuntime.resolve("invocation_id::InvocationIdInterceptor"), - ) + private val codegenScope = + arrayOf( + "InvocationIdInterceptor" to awsRuntime.resolve("invocation_id::InvocationIdInterceptor"), + ) - override fun section(section: ServiceRuntimePluginSection): Writable = writable { - if (section is ServiceRuntimePluginSection.RegisterRuntimeComponents) { - section.registerInterceptor(this) { - rustTemplate("#{InvocationIdInterceptor}::new()", *codegenScope) + override fun section(section: ServiceRuntimePluginSection): Writable = + writable { + if (section is ServiceRuntimePluginSection.RegisterRuntimeComponents) { + section.registerInterceptor(this) { + rustTemplate("#{InvocationIdInterceptor}::new()", *codegenScope) + } } } - } } const val GENERATOR_DOCS: String = @@ -61,51 +62,53 @@ private class InvocationIdConfigCustomization( codegenContext: ClientCodegenContext, ) : ConfigCustomization() { private val awsRuntime = AwsRuntimeType.awsRuntime(codegenContext.runtimeConfig) - private val codegenScope = arrayOf( - *preludeScope, - "InvocationIdGenerator" to awsRuntime.resolve("invocation_id::InvocationIdGenerator"), - "SharedInvocationIdGenerator" to awsRuntime.resolve("invocation_id::SharedInvocationIdGenerator"), - ) + private val codegenScope = + arrayOf( + *preludeScope, + "InvocationIdGenerator" to awsRuntime.resolve("invocation_id::InvocationIdGenerator"), + "SharedInvocationIdGenerator" to awsRuntime.resolve("invocation_id::SharedInvocationIdGenerator"), + ) - override fun section(section: ServiceConfig): Writable = writable { - when (section) { - is ServiceConfig.BuilderImpl -> { - docs("Overrides the default invocation ID generator.\n\n$GENERATOR_DOCS") - rustTemplate( - """ - pub fn invocation_id_generator(mut self, gen: impl #{InvocationIdGenerator} + 'static) -> Self { - self.set_invocation_id_generator(#{Some}(#{SharedInvocationIdGenerator}::new(gen))); - self - } - """, - *codegenScope, - ) + override fun section(section: ServiceConfig): Writable = + writable { + when (section) { + is ServiceConfig.BuilderImpl -> { + docs("Overrides the default invocation ID generator.\n\n$GENERATOR_DOCS") + rustTemplate( + """ + pub fn invocation_id_generator(mut self, gen: impl #{InvocationIdGenerator} + 'static) -> Self { + self.set_invocation_id_generator(#{Some}(#{SharedInvocationIdGenerator}::new(gen))); + self + } + """, + *codegenScope, + ) - docs("Overrides the default invocation ID generator.\n\n$GENERATOR_DOCS") - rustTemplate( - """ - pub fn set_invocation_id_generator(&mut self, gen: #{Option}<#{SharedInvocationIdGenerator}>) -> &mut Self { - self.config.store_or_unset(gen); - self - } - """, - *codegenScope, - ) - } + docs("Overrides the default invocation ID generator.\n\n$GENERATOR_DOCS") + rustTemplate( + """ + pub fn set_invocation_id_generator(&mut self, gen: #{Option}<#{SharedInvocationIdGenerator}>) -> &mut Self { + self.config.store_or_unset(gen); + self + } + """, + *codegenScope, + ) + } - is ServiceConfig.ConfigImpl -> { - docs("Returns the invocation ID generator if one was given in config.\n\n$GENERATOR_DOCS") - rustTemplate( - """ - pub fn invocation_id_generator(&self) -> #{Option}<#{SharedInvocationIdGenerator}> { - self.config.load::<#{SharedInvocationIdGenerator}>().cloned() - } - """, - *codegenScope, - ) - } + is ServiceConfig.ConfigImpl -> { + docs("Returns the invocation ID generator if one was given in config.\n\n$GENERATOR_DOCS") + rustTemplate( + """ + pub fn invocation_id_generator(&self) -> #{Option}<#{SharedInvocationIdGenerator}> { + self.config.load::<#{SharedInvocationIdGenerator}>().cloned() + } + """, + *codegenScope, + ) + } - else -> {} + else -> {} + } } - } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RecursionDetectionDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RecursionDetectionDecorator.kt index 5809d8b4b39..d56fb680d6b 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RecursionDetectionDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RecursionDetectionDecorator.kt @@ -27,15 +27,16 @@ class RecursionDetectionDecorator : ClientCodegenDecorator { private class RecursionDetectionRuntimePluginCustomization( private val codegenContext: ClientCodegenContext, ) : ServiceRuntimePluginCustomization() { - override fun section(section: ServiceRuntimePluginSection): Writable = writable { - if (section is ServiceRuntimePluginSection.RegisterRuntimeComponents) { - section.registerInterceptor(this) { - rust( - "#T::new()", - AwsRuntimeType.awsRuntime(codegenContext.runtimeConfig) - .resolve("recursion_detection::RecursionDetectionInterceptor"), - ) + override fun section(section: ServiceRuntimePluginSection): Writable = + writable { + if (section is ServiceRuntimePluginSection.RegisterRuntimeComponents) { + section.registerInterceptor(this) { + rust( + "#T::new()", + AwsRuntimeType.awsRuntime(codegenContext.runtimeConfig) + .resolve("recursion_detection::RecursionDetectionInterceptor"), + ) + } } } - } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionDecorator.kt index 4e77e1c49b6..c877d4aac54 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionDecorator.kt @@ -28,53 +28,54 @@ import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.extendIf import software.amazon.smithy.rust.codegen.core.util.thenSingletonListOf -/* Example Generated Code */ -/* -pub struct Config { - pub(crate) region: Option, -} - -impl std::fmt::Debug for Config { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut config = f.debug_struct("Config"); - config.finish() - } -} - -impl Config { - pub fn builder() -> Builder { - Builder::default() - } -} - -#[derive(Default)] -pub struct Builder { - region: Option, -} - -impl Builder { - pub fn new() -> Self { - Self::default() - } - - pub fn region(mut self, region: impl Into>) -> Self { - self.region = region.into(); - self - } - - pub fn build(self) -> Config { - Config { - region: self.region, - } - } -} - -#[test] -fn test_1() { - fn assert_send_sync() {} - assert_send_sync::(); -} - */ +// Example Generated Code +// ---------------------- +// +// pub struct Config { +// pub(crate) region: Option, +// } +// +// impl std::fmt::Debug for Config { +// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +// let mut config = f.debug_struct("Config"); +// config.finish() +// } +// } +// +// impl Config { +// pub fn builder() -> Builder { +// Builder::default() +// } +// } +// +// #[derive(Default)] +// pub struct Builder { +// region: Option, +// } +// +// impl Builder { +// pub fn new() -> Self { +// Self::default() +// } +// +// pub fn region(mut self, region: impl Into>) -> Self { +// self.region = region.into(); +// self +// } +// +// pub fn build(self) -> Config { +// Config { +// region: self.region, +// } +// } +// } +// +// #[test] +// fn test_1() { +// fn assert_send_sync() {} +// assert_send_sync::(); +// } +// class RegionDecorator : ClientCodegenDecorator { override val name: String = "Region" @@ -83,8 +84,9 @@ class RegionDecorator : ClientCodegenDecorator { // Services that have an endpoint ruleset that references the SDK::Region built in, or // that use SigV4, both need a configurable region. private fun usesRegion(codegenContext: ClientCodegenContext) = - codegenContext.getBuiltIn(AwsBuiltIns.REGION) != null || ServiceIndex.of(codegenContext.model) - .getEffectiveAuthSchemes(codegenContext.serviceShape).containsKey(SigV4Trait.ID) + codegenContext.getBuiltIn(AwsBuiltIns.REGION) != null || + ServiceIndex.of(codegenContext.model) + .getEffectiveAuthSchemes(codegenContext.serviceShape).containsKey(SigV4Trait.ID) override fun configCustomizations( codegenContext: ClientCodegenContext, @@ -114,20 +116,28 @@ class RegionDecorator : ClientCodegenDecorator { } return listOf( object : EndpointCustomization { - override fun loadBuiltInFromServiceConfig(parameter: Parameter, configRef: String): Writable? { + override fun loadBuiltInFromServiceConfig( + parameter: Parameter, + configRef: String, + ): Writable? { return when (parameter.builtIn) { - AwsBuiltIns.REGION.builtIn -> writable { - rustTemplate( - "$configRef.load::<#{Region}>().map(|r|r.as_ref().to_owned())", - "Region" to region(codegenContext.runtimeConfig).resolve("Region"), - ) - } + AwsBuiltIns.REGION.builtIn -> + writable { + rustTemplate( + "$configRef.load::<#{Region}>().map(|r|r.as_ref().to_owned())", + "Region" to region(codegenContext.runtimeConfig).resolve("Region"), + ) + } else -> null } } - override fun setBuiltInOnServiceConfig(name: String, value: Node, configBuilderRef: String): Writable? { + override fun setBuiltInOnServiceConfig( + name: String, + value: Node, + configBuilderRef: String, + ): Writable? { if (name != AwsBuiltIns.REGION.builtIn.get()) { return null } @@ -146,62 +156,64 @@ class RegionDecorator : ClientCodegenDecorator { class RegionProviderConfig(codegenContext: ClientCodegenContext) : ConfigCustomization() { private val region = region(codegenContext.runtimeConfig) private val moduleUseName = codegenContext.moduleUseName() - private val codegenScope = arrayOf( - *preludeScope, - "Region" to configReexport(region.resolve("Region")), - ) - - override fun section(section: ServiceConfig) = writable { - when (section) { - ServiceConfig.ConfigImpl -> { - rustTemplate( - """ - /// Returns the AWS region, if it was provided. - pub fn region(&self) -> #{Option}<&#{Region}> { - self.config.load::<#{Region}>() - } - """, - *codegenScope, - ) - } + private val codegenScope = + arrayOf( + *preludeScope, + "Region" to configReexport(region.resolve("Region")), + ) - ServiceConfig.BuilderImpl -> { - rustTemplate( - """ - /// Sets the AWS region to use when making requests. - /// - /// ## Examples - /// ```no_run - /// use aws_types::region::Region; - /// use $moduleUseName::config::{Builder, Config}; - /// - /// let config = $moduleUseName::Config::builder() - /// .region(Region::new("us-east-1")) - /// .build(); - /// ``` - pub fn region(mut self, region: impl #{Into}<#{Option}<#{Region}>>) -> Self { - self.set_region(region.into()); - self - } - """, - *codegenScope, - ) + override fun section(section: ServiceConfig) = + writable { + when (section) { + ServiceConfig.ConfigImpl -> { + rustTemplate( + """ + /// Returns the AWS region, if it was provided. + pub fn region(&self) -> #{Option}<&#{Region}> { + self.config.load::<#{Region}>() + } + """, + *codegenScope, + ) + } - rustTemplate( - """ - /// Sets the AWS region to use when making requests. - pub fn set_region(&mut self, region: #{Option}<#{Region}>) -> &mut Self { - self.config.store_or_unset(region); - self - } - """, - *codegenScope, - ) - } + ServiceConfig.BuilderImpl -> { + rustTemplate( + """ + /// Sets the AWS region to use when making requests. + /// + /// ## Examples + /// ```no_run + /// use aws_types::region::Region; + /// use $moduleUseName::config::{Builder, Config}; + /// + /// let config = $moduleUseName::Config::builder() + /// .region(Region::new("us-east-1")) + /// .build(); + /// ``` + pub fn region(mut self, region: impl #{Into}<#{Option}<#{Region}>>) -> Self { + self.set_region(region.into()); + self + } + """, + *codegenScope, + ) + + rustTemplate( + """ + /// Sets the AWS region to use when making requests. + pub fn set_region(&mut self, region: #{Option}<#{Region}>) -> &mut Self { + self.config.store_or_unset(region); + self + } + """, + *codegenScope, + ) + } - else -> emptySection + else -> emptySection + } } - } } fun region(runtimeConfig: RuntimeConfig) = AwsRuntimeType.awsTypes(runtimeConfig).resolve("region") diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RetryClassifierDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RetryClassifierDecorator.kt index 6b3c0185e34..1ea17d13d91 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RetryClassifierDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RetryClassifierDecorator.kt @@ -21,8 +21,9 @@ class RetryClassifierDecorator : ClientCodegenDecorator { codegenContext: ClientCodegenContext, operation: OperationShape, baseCustomizations: List, - ): List = baseCustomizations + - OperationRetryClassifiersFeature(codegenContext, operation) + ): List = + baseCustomizations + + OperationRetryClassifiersFeature(codegenContext, operation) } class OperationRetryClassifiersFeature( @@ -32,17 +33,19 @@ class OperationRetryClassifiersFeature( private val runtimeConfig = codegenContext.runtimeConfig private val symbolProvider = codegenContext.symbolProvider - override fun section(section: OperationSection) = when (section) { - is OperationSection.RetryClassifiers -> writable { - section.registerRetryClassifier(this) { - rustTemplate( - "#{AwsErrorCodeClassifier}::<#{OperationError}>::new()", - "AwsErrorCodeClassifier" to AwsRuntimeType.awsRuntime(runtimeConfig).resolve("retries::classifiers::AwsErrorCodeClassifier"), - "OperationError" to symbolProvider.symbolForOperationError(operation), - ) - } - } + override fun section(section: OperationSection) = + when (section) { + is OperationSection.RetryClassifiers -> + writable { + section.registerRetryClassifier(this) { + rustTemplate( + "#{AwsErrorCodeClassifier}::<#{OperationError}>::new()", + "AwsErrorCodeClassifier" to AwsRuntimeType.awsRuntime(runtimeConfig).resolve("retries::classifiers::AwsErrorCodeClassifier"), + "OperationError" to symbolProvider.symbolForOperationError(operation), + ) + } + } - else -> emptySection - } + else -> emptySection + } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RetryInformationHeaderDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RetryInformationHeaderDecorator.kt index 2a354327f60..4b9077af763 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RetryInformationHeaderDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RetryInformationHeaderDecorator.kt @@ -29,20 +29,21 @@ private class AddRetryInformationHeaderInterceptors(codegenContext: ClientCodege private val runtimeConfig = codegenContext.runtimeConfig private val awsRuntime = AwsRuntimeType.awsRuntime(runtimeConfig) - override fun section(section: ServiceRuntimePluginSection): Writable = writable { - if (section is ServiceRuntimePluginSection.RegisterRuntimeComponents) { - // Track the latency between client and server. - section.registerInterceptor(this) { - rust( - "#T::new()", - awsRuntime.resolve("service_clock_skew::ServiceClockSkewInterceptor"), - ) - } + override fun section(section: ServiceRuntimePluginSection): Writable = + writable { + if (section is ServiceRuntimePluginSection.RegisterRuntimeComponents) { + // Track the latency between client and server. + section.registerInterceptor(this) { + rust( + "#T::new()", + awsRuntime.resolve("service_clock_skew::ServiceClockSkewInterceptor"), + ) + } - // Add request metadata to outgoing requests. Sets a header. - section.registerInterceptor(this) { - rust("#T::new()", awsRuntime.resolve("request_info::RequestInfoInterceptor")) + // Add request metadata to outgoing requests. Sets a header. + section.registerInterceptor(this) { + rust("#T::new()", awsRuntime.resolve("request_info::RequestInfoInterceptor")) + } } } - } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SdkConfigDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SdkConfigDecorator.kt index 69a1299d738..f071835fc4e 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SdkConfigDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SdkConfigDecorator.kt @@ -49,14 +49,16 @@ object SdkConfigCustomization { * SdkConfigCustomization.copyField("some_string_field") { rust("|s|s.to_to_string()") } * ``` */ - fun copyField(fieldName: String, map: Writable?) = - adhocCustomization { section -> - val mapBlock = map?.let { writable { rust(".map(#W)", it) } } ?: writable { } - rustTemplate( - "${section.serviceConfigBuilder}.set_$fieldName(${section.sdkConfig}.$fieldName()#{map});", - "map" to mapBlock, - ) - } + fun copyField( + fieldName: String, + map: Writable?, + ) = adhocCustomization { section -> + val mapBlock = map?.let { writable { rust(".map(#W)", it) } } ?: writable { } + rustTemplate( + "${section.serviceConfigBuilder}.set_$fieldName(${section.sdkConfig}.$fieldName()#{map});", + "map" to mapBlock, + ) + } } /** @@ -110,10 +112,14 @@ class SdkConfigDecorator : ClientCodegenDecorator { return baseCustomizations + NewFromShared(codegenContext.runtimeConfig) } - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { - val codegenScope = arrayOf( - "SdkConfig" to AwsRuntimeType.awsTypes(codegenContext.runtimeConfig).resolve("sdk_config::SdkConfig"), - ) + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { + val codegenScope = + arrayOf( + "SdkConfig" to AwsRuntimeType.awsTypes(codegenContext.runtimeConfig).resolve("sdk_config::SdkConfig"), + ) rustCrate.withModule(ClientRustModule.config) { rustTemplate( @@ -133,15 +139,16 @@ class SdkConfigDecorator : ClientCodegenDecorator { } } """, - "augmentBuilder" to writable { - writeCustomizations( - codegenContext.rootDecorator.extraSections(codegenContext), - SdkConfigSection.CopySdkConfigToClientConfig( - sdkConfig = "input", - serviceConfigBuilder = "builder", - ), - ) - }, + "augmentBuilder" to + writable { + writeCustomizations( + codegenContext.rootDecorator.extraSections(codegenContext), + SdkConfigSection.CopySdkConfigToClientConfig( + sdkConfig = "input", + serviceConfigBuilder = "builder", + ), + ) + }, *codegenScope, ) } @@ -149,23 +156,25 @@ class SdkConfigDecorator : ClientCodegenDecorator { } class NewFromShared(runtimeConfig: RuntimeConfig) : ConfigCustomization() { - private val codegenScope = arrayOf( - "SdkConfig" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("sdk_config::SdkConfig"), - ) + private val codegenScope = + arrayOf( + "SdkConfig" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("sdk_config::SdkConfig"), + ) override fun section(section: ServiceConfig): Writable { return when (section) { - ServiceConfig.ConfigImpl -> writable { - rustTemplate( - """ - /// Creates a new [service config](crate::Config) from a [shared `config`](#{SdkConfig}). - pub fn new(config: &#{SdkConfig}) -> Self { - Builder::from(config).build() - } - """, - *codegenScope, - ) - } + ServiceConfig.ConfigImpl -> + writable { + rustTemplate( + """ + /// Creates a new [service config](crate::Config) from a [shared `config`](#{SdkConfig}). + pub fn new(config: &#{SdkConfig}) -> Self { + Builder::from(config).build() + } + """, + *codegenScope, + ) + } else -> emptySection } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SdkSettings.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SdkSettings.kt index 62bb927a041..6623d676190 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SdkSettings.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SdkSettings.kt @@ -10,14 +10,56 @@ import software.amazon.smithy.rust.codegen.core.smithy.CoreRustSettings import software.amazon.smithy.rust.codegen.core.util.orNull import java.nio.file.Path import java.nio.file.Paths +import java.util.logging.Logger /** * SDK-specific settings within the Rust codegen `customizationConfig.awsSdk` object. */ class SdkSettings private constructor(private val awsSdk: ObjectNode?) { + private fun warnOnUnusedProperties() { + if (awsSdk == null) { + return + } + val logger = Logger.getLogger("SdkSettings") + if (awsSdk.getMember("generateReadme").isPresent) { + logger.warning( + "`generateReadme` parameter is now ignored. Readmes are now only generated when " + + "`awsSdkBuild` is set to `true`. You can use `suppressReadme` to explicitly suppress the readme in that case.", + ) + } + + if (awsSdk.getMember("requireEndpointResolver").isPresent) { + logger.warning( + "`requireEndpointResolver` is no a no-op and you may remove it from your configuration. " + + "An endpoint resolver is only required when `awsSdkBuild` is set to true.", + ) + } + } + companion object { - fun from(coreRustSettings: CoreRustSettings): SdkSettings = - SdkSettings(coreRustSettings.customizationConfig?.getObjectMember("awsSdk")?.orNull()) + fun from(coreRustSettings: CoreRustSettings): SdkSettings { + val settings = SdkSettings(coreRustSettings.customizationConfig?.getObjectMember("awsSdk")?.orNull()) + if (shouldPrintWarning()) { + settings.warnOnUnusedProperties() + warningPrinted() + } + return settings + } + + @Volatile + var warningPrinted = false + + private fun warningPrinted() { + synchronized(this) { + this.warningPrinted = true + } + } + + private fun shouldPrintWarning(): Boolean { + synchronized(this) { + return !this.warningPrinted + } + } } /** Path to the `sdk-default-configuration.json` config file */ @@ -25,33 +67,30 @@ class SdkSettings private constructor(private val awsSdk: ObjectNode?) { get() = awsSdk?.getStringMember("defaultConfigPath")?.orNull()?.value.let { Paths.get(it) } - /** Path to the `sdk-endpoints.json` configuration */ - val endpointsConfigPath: Path? - get() = - awsSdk?.getStringMember("endpointsConfigPath")?.orNull()?.value?.let { Paths.get(it) } - /** Path to the `default-partitions.json` configuration */ val partitionsConfigPath: Path? get() = awsSdk?.getStringMember("partitionsConfigPath")?.orNull()?.value?.let { Paths.get(it) } + val awsSdkBuild: Boolean + get() = awsSdk?.getBooleanMember("awsSdkBuild")?.orNull()?.value ?: false + /** Path to AWS SDK integration tests */ val integrationTestPath: String get() = awsSdk?.getStringMember("integrationTestPath")?.orNull()?.value ?: "aws/sdk/integration-tests" - /** Version number of the `aws-config` crate */ + /** Version number of the `aws-config` crate. This is used to set the dev-dependency when generating readme's */ val awsConfigVersion: String? get() = awsSdk?.getStringMember("awsConfigVersion")?.orNull()?.value /** Whether to generate a README */ val generateReadme: Boolean - get() = - awsSdk?.getBooleanMember("generateReadme")?.orNull()?.value ?: false + get() = awsSdkBuild && !(awsSdk?.getBooleanMember("suppressReadme")?.orNull()?.value ?: false) val requireEndpointResolver: Boolean - get() = awsSdk?.getBooleanMember("requireEndpointResolver")?.orNull()?.value ?: true + get() = awsSdkBuild } fun ClientCodegenContext.sdkSettings() = SdkSettings.from(this.settings) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt index a6a0bc7b80e..fb1385bdc62 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt @@ -43,29 +43,33 @@ class SigV4AuthDecorator : ClientCodegenDecorator { private val sigv4a = "sigv4a" - private fun sigv4(runtimeConfig: RuntimeConfig) = writable { - val awsRuntimeAuthModule = AwsRuntimeType.awsRuntime(runtimeConfig).resolve("auth") - rust("#T", awsRuntimeAuthModule.resolve("sigv4::SCHEME_ID")) - } + private fun sigv4(runtimeConfig: RuntimeConfig) = + writable { + val awsRuntimeAuthModule = AwsRuntimeType.awsRuntime(runtimeConfig).resolve("auth") + rust("#T", awsRuntimeAuthModule.resolve("sigv4::SCHEME_ID")) + } - private fun sigv4a(runtimeConfig: RuntimeConfig) = writable { - val awsRuntimeAuthModule = AwsRuntimeType.awsRuntime(runtimeConfig).resolve("auth") - featureGateBlock(sigv4a) { - rust("#T", awsRuntimeAuthModule.resolve("sigv4a::SCHEME_ID")) + private fun sigv4a(runtimeConfig: RuntimeConfig) = + writable { + val awsRuntimeAuthModule = AwsRuntimeType.awsRuntime(runtimeConfig).resolve("auth") + featureGateBlock(sigv4a) { + rust("#T", awsRuntimeAuthModule.resolve("sigv4a::SCHEME_ID")) + } } - } override fun authOptions( codegenContext: ClientCodegenContext, operationShape: OperationShape, baseAuthSchemeOptions: List, ): List { - val supportsSigV4a = codegenContext.serviceShape.supportedAuthSchemes().contains(sigv4a) - .thenSingletonListOf { sigv4a(codegenContext.runtimeConfig) } - return baseAuthSchemeOptions + AuthSchemeOption.StaticAuthSchemeOption( - SigV4Trait.ID, - listOf(sigv4(codegenContext.runtimeConfig)) + supportsSigV4a, - ) + val supportsSigV4a = + codegenContext.serviceShape.supportedAuthSchemes().contains(sigv4a) + .thenSingletonListOf { sigv4a(codegenContext.runtimeConfig) } + return baseAuthSchemeOptions + + AuthSchemeOption.StaticAuthSchemeOption( + SigV4Trait.ID, + listOf(sigv4(codegenContext.runtimeConfig)) + supportsSigV4a, + ) } override fun serviceRuntimePluginCustomizations( @@ -86,7 +90,10 @@ class SigV4AuthDecorator : ClientCodegenDecorator { ): List = baseCustomizations + SigV4SigningConfig(codegenContext.runtimeConfig, codegenContext.serviceShape.getTrait()) - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { if (codegenContext.serviceShape.supportedAuthSchemes().contains("sigv4a")) { // Add optional feature for SigV4a support rustCrate.mergeFeature(Feature("sigv4a", true, listOf("aws-runtime/sigv4a"))) @@ -98,55 +105,57 @@ private class SigV4SigningConfig( runtimeConfig: RuntimeConfig, private val sigV4Trait: SigV4Trait?, ) : ConfigCustomization() { - private val codegenScope = arrayOf( - "Region" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("region::Region"), - "SigningName" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("SigningName"), - "SigningRegion" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("region::SigningRegion"), - ) + private val codegenScope = + arrayOf( + "Region" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("region::Region"), + "SigningName" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("SigningName"), + "SigningRegion" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("region::SigningRegion"), + ) - override fun section(section: ServiceConfig): Writable = writable { - if (sigV4Trait != null) { - when (section) { - ServiceConfig.ConfigImpl -> { - rust( - """ - /// The signature version 4 service signing name to use in the credential scope when signing requests. - /// - /// The signing service may be overridden by the `Endpoint`, or by specifying a custom - /// [`SigningName`](aws_types::SigningName) during operation construction - pub fn signing_name(&self) -> &'static str { - ${sigV4Trait.name.dq()} - } - """, - ) - } + override fun section(section: ServiceConfig): Writable = + writable { + if (sigV4Trait != null) { + when (section) { + ServiceConfig.ConfigImpl -> { + rust( + """ + /// The signature version 4 service signing name to use in the credential scope when signing requests. + /// + /// The signing service may be overridden by the `Endpoint`, or by specifying a custom + /// [`SigningName`](aws_types::SigningName) during operation construction + pub fn signing_name(&self) -> &'static str { + ${sigV4Trait.name.dq()} + } + """, + ) + } - ServiceConfig.BuilderBuild -> { - rustTemplate( - """ - layer.store_put(#{SigningName}::from_static(${sigV4Trait.name.dq()})); - layer.load::<#{Region}>().cloned().map(|r| layer.store_put(#{SigningRegion}::from(r))); - """, - *codegenScope, - ) - } + ServiceConfig.BuilderBuild -> { + rustTemplate( + """ + layer.store_put(#{SigningName}::from_static(${sigV4Trait.name.dq()})); + layer.load::<#{Region}>().cloned().map(|r| layer.store_put(#{SigningRegion}::from(r))); + """, + *codegenScope, + ) + } - is ServiceConfig.OperationConfigOverride -> { - rustTemplate( - """ - resolver.config_mut() - .load::<#{Region}>() - .cloned() - .map(|r| resolver.config_mut().store_put(#{SigningRegion}::from(r))); - """, - *codegenScope, - ) - } + is ServiceConfig.OperationConfigOverride -> { + rustTemplate( + """ + resolver.config_mut() + .load::<#{Region}>() + .cloned() + .map(|r| resolver.config_mut().store_put(#{SigningRegion}::from(r))); + """, + *codegenScope, + ) + } - else -> {} + else -> {} + } } } - } } private class AuthServiceRuntimePluginCustomization(private val codegenContext: ClientCodegenContext) : @@ -161,49 +170,53 @@ private class AuthServiceRuntimePluginCustomization(private val codegenContext: ) } - override fun section(section: ServiceRuntimePluginSection): Writable = writable { - when (section) { - is ServiceRuntimePluginSection.RegisterRuntimeComponents -> { - val serviceHasEventStream = codegenContext.serviceShape.hasEventStreamOperations(codegenContext.model) - if (serviceHasEventStream) { - // enable the aws-runtime `sign-eventstream` feature - addDependency( - AwsCargoDependency.awsRuntime(runtimeConfig).withFeature("event-stream").toType().toSymbol(), - ) - } - section.registerAuthScheme(this) { - rustTemplate("#{SharedAuthScheme}::new(#{SigV4AuthScheme}::new())", *codegenScope) - } + override fun section(section: ServiceRuntimePluginSection): Writable = + writable { + when (section) { + is ServiceRuntimePluginSection.RegisterRuntimeComponents -> { + val serviceHasEventStream = codegenContext.serviceShape.hasEventStreamOperations(codegenContext.model) + if (serviceHasEventStream) { + // enable the aws-runtime `sign-eventstream` feature + addDependency( + AwsCargoDependency.awsRuntime(runtimeConfig).withFeature("event-stream").toType().toSymbol(), + ) + } + section.registerAuthScheme(this) { + rustTemplate("#{SharedAuthScheme}::new(#{SigV4AuthScheme}::new())", *codegenScope) + } - if (codegenContext.serviceShape.supportedAuthSchemes().contains("sigv4a")) { - featureGateBlock("sigv4a") { - section.registerAuthScheme(this) { - rustTemplate("#{SharedAuthScheme}::new(#{SigV4aAuthScheme}::new())", *codegenScope) + if (codegenContext.serviceShape.supportedAuthSchemes().contains("sigv4a")) { + featureGateBlock("sigv4a") { + section.registerAuthScheme(this) { + rustTemplate("#{SharedAuthScheme}::new(#{SigV4aAuthScheme}::new())", *codegenScope) + } } } } - } - else -> {} + else -> {} + } } - } } -fun needsAmzSha256(service: ServiceShape) = when (service.id) { - ShapeId.from("com.amazonaws.s3#AmazonS3") -> true - ShapeId.from("com.amazonaws.s3control#AWSS3ControlServiceV20180820") -> true - else -> false -} +fun needsAmzSha256(service: ServiceShape) = + when (service.id) { + ShapeId.from("com.amazonaws.s3#AmazonS3") -> true + ShapeId.from("com.amazonaws.s3control#AWSS3ControlServiceV20180820") -> true + else -> false + } -fun disableDoubleEncode(service: ServiceShape) = when (service.id) { - ShapeId.from("com.amazonaws.s3#AmazonS3") -> true - else -> false -} +fun disableDoubleEncode(service: ServiceShape) = + when (service.id) { + ShapeId.from("com.amazonaws.s3#AmazonS3") -> true + else -> false + } -fun disableUriPathNormalization(service: ServiceShape) = when (service.id) { - ShapeId.from("com.amazonaws.s3#AmazonS3") -> true - else -> false -} +fun disableUriPathNormalization(service: ServiceShape) = + when (service.id) { + ShapeId.from("com.amazonaws.s3#AmazonS3") -> true + else -> false + } private class AuthOperationCustomization(private val codegenContext: ClientCodegenContext) : OperationCustomization() { private val runtimeConfig = codegenContext.runtimeConfig @@ -218,45 +231,47 @@ private class AuthOperationCustomization(private val codegenContext: ClientCodeg } private val serviceIndex = ServiceIndex.of(codegenContext.model) - override fun section(section: OperationSection): Writable = writable { - when (section) { - is OperationSection.AdditionalRuntimePluginConfig -> { - val authSchemes = - serviceIndex.getEffectiveAuthSchemes(codegenContext.serviceShape, section.operationShape) - if (authSchemes.containsKey(SigV4Trait.ID)) { - val unsignedPayload = section.operationShape.hasTrait() - val doubleUriEncode = unsignedPayload || !disableDoubleEncode(codegenContext.serviceShape) - val contentSha256Header = needsAmzSha256(codegenContext.serviceShape) || unsignedPayload - val normalizeUrlPath = !disableUriPathNormalization(codegenContext.serviceShape) - rustTemplate( - """ - let mut signing_options = #{SigningOptions}::default(); - signing_options.double_uri_encode = $doubleUriEncode; - signing_options.content_sha256_header = $contentSha256Header; - signing_options.normalize_uri_path = $normalizeUrlPath; - signing_options.payload_override = #{payload_override}; + override fun section(section: OperationSection): Writable = + writable { + when (section) { + is OperationSection.AdditionalRuntimePluginConfig -> { + val authSchemes = + serviceIndex.getEffectiveAuthSchemes(codegenContext.serviceShape, section.operationShape) + if (authSchemes.containsKey(SigV4Trait.ID)) { + val unsignedPayload = section.operationShape.hasTrait() + val doubleUriEncode = unsignedPayload || !disableDoubleEncode(codegenContext.serviceShape) + val contentSha256Header = needsAmzSha256(codegenContext.serviceShape) || unsignedPayload + val normalizeUrlPath = !disableUriPathNormalization(codegenContext.serviceShape) + rustTemplate( + """ + let mut signing_options = #{SigningOptions}::default(); + signing_options.double_uri_encode = $doubleUriEncode; + signing_options.content_sha256_header = $contentSha256Header; + signing_options.normalize_uri_path = $normalizeUrlPath; + signing_options.payload_override = #{payload_override}; - ${section.newLayerName}.store_put(#{SigV4OperationSigningConfig} { - signing_options, - ..#{Default}::default() - }); - """, - *codegenScope, - "payload_override" to writable { - if (unsignedPayload) { - rustTemplate("Some(#{SignableBody}::UnsignedPayload)", *codegenScope) - } else if (section.operationShape.isInputEventStream(codegenContext.model)) { - // TODO(EventStream): Is this actually correct for all Event Stream operations? - rustTemplate("Some(#{SignableBody}::Bytes(&[]))", *codegenScope) - } else { - rust("None") - } - }, - ) + ${section.newLayerName}.store_put(#{SigV4OperationSigningConfig} { + signing_options, + ..#{Default}::default() + }); + """, + *codegenScope, + "payload_override" to + writable { + if (unsignedPayload) { + rustTemplate("Some(#{SignableBody}::UnsignedPayload)", *codegenScope) + } else if (section.operationShape.isInputEventStream(codegenContext.model)) { + // TODO(EventStream): Is this actually correct for all Event Stream operations? + rustTemplate("Some(#{SignableBody}::Bytes(&[]))", *codegenScope) + } else { + rust("None") + } + }, + ) + } } - } - else -> {} + else -> {} + } } - } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/UserAgentDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/UserAgentDecorator.kt index 058acab9cce..b8b69f275cf 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/UserAgentDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/UserAgentDecorator.kt @@ -42,8 +42,7 @@ class UserAgentDecorator : ClientCodegenDecorator { override fun serviceRuntimePluginCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = - baseCustomizations + AddApiMetadataIntoConfigBag(codegenContext) + ): List = baseCustomizations + AddApiMetadataIntoConfigBag(codegenContext) override fun extraSections(codegenContext: ClientCodegenContext): List { return listOf( @@ -56,7 +55,10 @@ class UserAgentDecorator : ClientCodegenDecorator { /** * Adds a static `API_METADATA` variable to the crate `config` containing the serviceId & the version of the crate for this individual service */ - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { val runtimeConfig = codegenContext.runtimeConfig // We are generating an AWS SDK, the service needs to have the AWS service trait @@ -88,85 +90,91 @@ class UserAgentDecorator : ClientCodegenDecorator { private val runtimeConfig = codegenContext.runtimeConfig private val awsRuntime = AwsRuntimeType.awsRuntime(runtimeConfig) - override fun section(section: ServiceRuntimePluginSection): Writable = writable { - when (section) { - is ServiceRuntimePluginSection.RegisterRuntimeComponents -> { - section.registerInterceptor(this) { - rust("#T::new()", awsRuntime.resolve("user_agent::UserAgentInterceptor")) + override fun section(section: ServiceRuntimePluginSection): Writable = + writable { + when (section) { + is ServiceRuntimePluginSection.RegisterRuntimeComponents -> { + section.registerInterceptor(this) { + rust("#T::new()", awsRuntime.resolve("user_agent::UserAgentInterceptor")) + } } + else -> emptySection } - else -> emptySection } - } } private class AppNameCustomization(codegenContext: ClientCodegenContext) : ConfigCustomization() { private val runtimeConfig = codegenContext.runtimeConfig - private val codegenScope = arrayOf( - *preludeScope, - "AppName" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("app_name::AppName"), - "AwsUserAgent" to AwsRuntimeType.awsHttp(runtimeConfig).resolve("user_agent::AwsUserAgent"), - ) + private val codegenScope = + arrayOf( + *preludeScope, + "AppName" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("app_name::AppName"), + "AwsUserAgent" to AwsRuntimeType.awsHttp(runtimeConfig).resolve("user_agent::AwsUserAgent"), + ) override fun section(section: ServiceConfig): Writable = when (section) { - is ServiceConfig.BuilderImpl -> writable { - rustTemplate( - """ - /// Sets the name of the app that is using the client. - /// - /// This _optional_ name is used to identify the application in the user agent that - /// gets sent along with requests. - pub fn app_name(mut self, app_name: #{AppName}) -> Self { - self.set_app_name(Some(app_name)); - self - } - """, - *codegenScope, - ) - - rustTemplate( - """ - /// Sets the name of the app that is using the client. - /// - /// This _optional_ name is used to identify the application in the user agent that - /// gets sent along with requests. - pub fn set_app_name(&mut self, app_name: #{Option}<#{AppName}>) -> &mut Self { - self.config.store_or_unset(app_name); - self - } - """, - *codegenScope, - ) - } + is ServiceConfig.BuilderImpl -> + writable { + rustTemplate( + """ + /// Sets the name of the app that is using the client. + /// + /// This _optional_ name is used to identify the application in the user agent that + /// gets sent along with requests. + pub fn app_name(mut self, app_name: #{AppName}) -> Self { + self.set_app_name(Some(app_name)); + self + } + """, + *codegenScope, + ) + + rustTemplate( + """ + /// Sets the name of the app that is using the client. + /// + /// This _optional_ name is used to identify the application in the user agent that + /// gets sent along with requests. + pub fn set_app_name(&mut self, app_name: #{Option}<#{AppName}>) -> &mut Self { + self.config.store_or_unset(app_name); + self + } + """, + *codegenScope, + ) + } - is ServiceConfig.BuilderBuild -> writable { - rust("layer.store_put(#T.clone());", ClientRustModule.Meta.toType().resolve("API_METADATA")) - } + is ServiceConfig.BuilderBuild -> + writable { + rust("layer.store_put(#T.clone());", ClientRustModule.Meta.toType().resolve("API_METADATA")) + } - is ServiceConfig.ConfigImpl -> writable { - rustTemplate( - """ - /// Returns the name of the app that is using the client, if it was provided. - /// - /// This _optional_ name is used to identify the application in the user agent that - /// gets sent along with requests. - pub fn app_name(&self) -> #{Option}<&#{AppName}> { - self.config.load::<#{AppName}>() - } - """, - *codegenScope, - ) - } + is ServiceConfig.ConfigImpl -> + writable { + rustTemplate( + """ + /// Returns the name of the app that is using the client, if it was provided. + /// + /// This _optional_ name is used to identify the application in the user agent that + /// gets sent along with requests. + pub fn app_name(&self) -> #{Option}<&#{AppName}> { + self.config.load::<#{AppName}>() + } + """, + *codegenScope, + ) + } - is ServiceConfig.DefaultForTests -> writable { - rustTemplate( - """ - self.config.store_put(#{AwsUserAgent}::for_tests()); - """, - *codegenScope, - ) - } + is ServiceConfig.DefaultForTests -> + writable { + rustTemplate( + """ + self.config.store_put(#{AwsUserAgent}::for_tests()); + """, + *codegenScope, + ) + } else -> emptySection } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/DisabledAuthDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/DisabledAuthDecorator.kt index 4dfc75c30be..b9c319df128 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/DisabledAuthDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/DisabledAuthDecorator.kt @@ -28,10 +28,13 @@ class DisabledAuthDecorator : ClientCodegenDecorator { ), ) - private fun applies(service: ServiceShape) = - optionalAuth.containsKey(service.id) + private fun applies(service: ServiceShape) = optionalAuth.containsKey(service.id) - override fun transformModel(service: ServiceShape, model: Model, settings: ClientRustSettings): Model { + override fun transformModel( + service: ServiceShape, + model: Model, + settings: ClientRustSettings, + ): Model { if (!applies(service)) { return model } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/RemoveDefaults.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/RemoveDefaults.kt index 45bf8bc1987..e12c1ba8aa9 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/RemoveDefaults.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/RemoveDefaults.kt @@ -24,15 +24,19 @@ import java.util.logging.Logger object RemoveDefaults { private val logger: Logger = Logger.getLogger(javaClass.name) - fun processModel(model: Model, removeDefaultsFrom: Set): Model { + fun processModel( + model: Model, + removeDefaultsFrom: Set, + ): Model { val removedRootDefaults: MutableSet = HashSet() - val removedRootDefaultsModel = ModelTransformer.create().mapShapes(model) { shape -> - shape.letIf(shouldRemoveRootDefault(shape, removeDefaultsFrom)) { - logger.info("Removing default trait from root $shape") - removedRootDefaults.add(shape.id) - removeDefault(shape) + val removedRootDefaultsModel = + ModelTransformer.create().mapShapes(model) { shape -> + shape.letIf(shouldRemoveRootDefault(shape, removeDefaultsFrom)) { + logger.info("Removing default trait from root $shape") + removedRootDefaults.add(shape.id) + removeDefault(shape) + } } - } return ModelTransformer.create().mapShapes(removedRootDefaultsModel) { shape -> shape.letIf(shouldRemoveMemberDefault(shape, removedRootDefaults, removeDefaultsFrom)) { @@ -42,7 +46,10 @@ object RemoveDefaults { } } - private fun shouldRemoveRootDefault(shape: Shape, removeDefaultsFrom: Set): Boolean { + private fun shouldRemoveRootDefault( + shape: Shape, + removeDefaultsFrom: Set, + ): Boolean { return shape !is MemberShape && removeDefaultsFrom.contains(shape.id) && shape.hasTrait() } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/RemoveDefaultsDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/RemoveDefaultsDecorator.kt index 1e1e205f45e..88b1ada994c 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/RemoveDefaultsDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/RemoveDefaultsDecorator.kt @@ -25,56 +25,68 @@ class RemoveDefaultsDecorator : ClientCodegenDecorator { // Service shape id -> Shape id of each root shape to remove the default from. // TODO(https://github.com/smithy-lang/smithy-rs/issues/3220): Remove this customization after model updates. - private val removeDefaults: Map> = mapOf( - "com.amazonaws.amplifyuibuilder#AmplifyUIBuilder" to setOf( - "com.amazonaws.amplifyuibuilder#ListComponentsLimit", - "com.amazonaws.amplifyuibuilder#ListFormsLimit", - "com.amazonaws.amplifyuibuilder#ListThemesLimit", - ), - "com.amazonaws.drs#ElasticDisasterRecoveryService" to setOf( - "com.amazonaws.drs#Validity", - "com.amazonaws.drs#CostOptimizationConfiguration\$burstBalanceThreshold", - "com.amazonaws.drs#CostOptimizationConfiguration\$burstBalanceDeltaThreshold", - "com.amazonaws.drs.synthetic#ListStagingAccountsInput\$maxResults", - "com.amazonaws.drs#StrictlyPositiveInteger", - "com.amazonaws.drs#MaxResultsType", - "com.amazonaws.drs#MaxResultsReplicatingSourceServers", - "com.amazonaws.drs#LaunchActionOrder", - ), - "com.amazonaws.evidently#Evidently" to setOf( - "com.amazonaws.evidently#ResultsPeriod", - ), - "com.amazonaws.location#LocationService" to setOf( - "com.amazonaws.location.synthetic#ListPlaceIndexesInput\$MaxResults", - "com.amazonaws.location.synthetic#SearchPlaceIndexForSuggestionsInput\$MaxResults", - "com.amazonaws.location#PlaceIndexSearchResultLimit", - ), - "com.amazonaws.paymentcryptographydata#PaymentCryptographyDataPlane" to setOf( - "com.amazonaws.paymentcryptographydata#IntegerRangeBetween4And12", - ), - "com.amazonaws.emrserverless#AwsToledoWebService" to setOf( - "com.amazonaws.emrserverless#WorkerCounts", - ), - "com.amazonaws.s3control#AWSS3ControlServiceV20180820" to setOf( - "com.amazonaws.s3control#PublicAccessBlockConfiguration\$BlockPublicAcls", - "com.amazonaws.s3control#PublicAccessBlockConfiguration\$IgnorePublicAcls", - "com.amazonaws.s3control#PublicAccessBlockConfiguration\$BlockPublicPolicy", - "com.amazonaws.s3control#PublicAccessBlockConfiguration\$RestrictPublicBuckets", - ), - "com.amazonaws.iot#AWSIotService" to setOf( - "com.amazonaws.iot#ThingConnectivity\$connected", - "com.amazonaws.iot.synthetic#UpdateProvisioningTemplateInput\$enabled", - "com.amazonaws.iot.synthetic#CreateProvisioningTemplateInput\$enabled", - "com.amazonaws.iot.synthetic#DescribeProvisioningTemplateOutput\$enabled", - "com.amazonaws.iot.synthetic#DescribeProvisioningTemplateOutput\$enabled", - "com.amazonaws.iot#ProvisioningTemplateSummary\$enabled", - ), - ).map { (k, v) -> k.shapeId() to v.map { it.shapeId() }.toSet() }.toMap() + private val removeDefaults: Map> = + mapOf( + "com.amazonaws.amplifyuibuilder#AmplifyUIBuilder" to + setOf( + "com.amazonaws.amplifyuibuilder#ListComponentsLimit", + "com.amazonaws.amplifyuibuilder#ListFormsLimit", + "com.amazonaws.amplifyuibuilder#ListThemesLimit", + ), + "com.amazonaws.drs#ElasticDisasterRecoveryService" to + setOf( + "com.amazonaws.drs#Validity", + "com.amazonaws.drs#CostOptimizationConfiguration\$burstBalanceThreshold", + "com.amazonaws.drs#CostOptimizationConfiguration\$burstBalanceDeltaThreshold", + "com.amazonaws.drs.synthetic#ListStagingAccountsInput\$maxResults", + "com.amazonaws.drs#StrictlyPositiveInteger", + "com.amazonaws.drs#MaxResultsType", + "com.amazonaws.drs#MaxResultsReplicatingSourceServers", + "com.amazonaws.drs#LaunchActionOrder", + ), + "com.amazonaws.evidently#Evidently" to + setOf( + "com.amazonaws.evidently#ResultsPeriod", + ), + "com.amazonaws.location#LocationService" to + setOf( + "com.amazonaws.location.synthetic#ListPlaceIndexesInput\$MaxResults", + "com.amazonaws.location.synthetic#SearchPlaceIndexForSuggestionsInput\$MaxResults", + "com.amazonaws.location#PlaceIndexSearchResultLimit", + ), + "com.amazonaws.paymentcryptographydata#PaymentCryptographyDataPlane" to + setOf( + "com.amazonaws.paymentcryptographydata#IntegerRangeBetween4And12", + ), + "com.amazonaws.emrserverless#AwsToledoWebService" to + setOf( + "com.amazonaws.emrserverless#WorkerCounts", + ), + "com.amazonaws.s3control#AWSS3ControlServiceV20180820" to + setOf( + "com.amazonaws.s3control#PublicAccessBlockConfiguration\$BlockPublicAcls", + "com.amazonaws.s3control#PublicAccessBlockConfiguration\$IgnorePublicAcls", + "com.amazonaws.s3control#PublicAccessBlockConfiguration\$BlockPublicPolicy", + "com.amazonaws.s3control#PublicAccessBlockConfiguration\$RestrictPublicBuckets", + ), + "com.amazonaws.iot#AWSIotService" to + setOf( + "com.amazonaws.iot#ThingConnectivity\$connected", + "com.amazonaws.iot.synthetic#UpdateProvisioningTemplateInput\$enabled", + "com.amazonaws.iot.synthetic#CreateProvisioningTemplateInput\$enabled", + "com.amazonaws.iot.synthetic#DescribeProvisioningTemplateOutput\$enabled", + "com.amazonaws.iot.synthetic#DescribeProvisioningTemplateOutput\$enabled", + "com.amazonaws.iot#ProvisioningTemplateSummary\$enabled", + ), + ).map { (k, v) -> k.shapeId() to v.map { it.shapeId() }.toSet() }.toMap() - private fun applies(service: ServiceShape) = - removeDefaults.containsKey(service.id) + private fun applies(service: ServiceShape) = removeDefaults.containsKey(service.id) - override fun transformModel(service: ServiceShape, model: Model, settings: ClientRustSettings): Model { + override fun transformModel( + service: ServiceShape, + model: Model, + settings: ClientRustSettings, + ): Model { if (!applies(service)) { return model } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ServiceSpecificDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ServiceSpecificDecorator.kt index 4850d299efb..7a493f702d1 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ServiceSpecificDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ServiceSpecificDecorator.kt @@ -50,7 +50,10 @@ class ServiceSpecificDecorator( /** Decorator order */ override val order: Byte = 0, ) : ClientCodegenDecorator { - private fun T.maybeApply(serviceId: ToShapeId, delegatedValue: () -> T): T = + private fun T.maybeApply( + serviceId: ToShapeId, + delegatedValue: () -> T, + ): T = if (appliesToServiceId == serviceId.toShapeId()) { delegatedValue() } else { @@ -64,23 +67,26 @@ class ServiceSpecificDecorator( codegenContext: ClientCodegenContext, operationShape: OperationShape, baseAuthSchemeOptions: List, - ): List = baseAuthSchemeOptions.maybeApply(codegenContext.serviceShape) { - delegateTo.authOptions(codegenContext, operationShape, baseAuthSchemeOptions) - } + ): List = + baseAuthSchemeOptions.maybeApply(codegenContext.serviceShape) { + delegateTo.authOptions(codegenContext, operationShape, baseAuthSchemeOptions) + } override fun builderCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.builderCustomizations(codegenContext, baseCustomizations) - } + ): List = + baseCustomizations.maybeApply(codegenContext.serviceShape) { + delegateTo.builderCustomizations(codegenContext, baseCustomizations) + } override fun configCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.configCustomizations(codegenContext, baseCustomizations) - } + ): List = + baseCustomizations.maybeApply(codegenContext.serviceShape) { + delegateTo.configCustomizations(codegenContext, baseCustomizations) + } override fun crateManifestCustomizations(codegenContext: ClientCodegenContext): ManifestCustomizations = emptyMap().maybeApply(codegenContext.serviceShape) { @@ -95,18 +101,23 @@ class ServiceSpecificDecorator( override fun errorCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.errorCustomizations(codegenContext, baseCustomizations) - } + ): List = + baseCustomizations.maybeApply(codegenContext.serviceShape) { + delegateTo.errorCustomizations(codegenContext, baseCustomizations) + } override fun errorImplCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.errorImplCustomizations(codegenContext, baseCustomizations) - } + ): List = + baseCustomizations.maybeApply(codegenContext.serviceShape) { + delegateTo.errorImplCustomizations(codegenContext, baseCustomizations) + } - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { maybeApply(codegenContext.serviceShape) { delegateTo.extras(codegenContext, rustCrate) } @@ -115,19 +126,24 @@ class ServiceSpecificDecorator( override fun libRsCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.libRsCustomizations(codegenContext, baseCustomizations) - } + ): List = + baseCustomizations.maybeApply(codegenContext.serviceShape) { + delegateTo.libRsCustomizations(codegenContext, baseCustomizations) + } override fun operationCustomizations( codegenContext: ClientCodegenContext, operation: OperationShape, baseCustomizations: List, - ): List = baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.operationCustomizations(codegenContext, operation, baseCustomizations) - } + ): List = + baseCustomizations.maybeApply(codegenContext.serviceShape) { + delegateTo.operationCustomizations(codegenContext, operation, baseCustomizations) + } - override fun protocols(serviceId: ShapeId, currentProtocols: ClientProtocolMap): ClientProtocolMap = + override fun protocols( + serviceId: ShapeId, + currentProtocols: ClientProtocolMap, + ): ClientProtocolMap = currentProtocols.maybeApply(serviceId) { delegateTo.protocols(serviceId, currentProtocols) } @@ -135,11 +151,16 @@ class ServiceSpecificDecorator( override fun structureCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.structureCustomizations(codegenContext, baseCustomizations) - } + ): List = + baseCustomizations.maybeApply(codegenContext.serviceShape) { + delegateTo.structureCustomizations(codegenContext, baseCustomizations) + } - override fun transformModel(service: ServiceShape, model: Model, settings: ClientRustSettings): Model = + override fun transformModel( + service: ServiceShape, + model: Model, + settings: ClientRustSettings, + ): Model = model.maybeApply(service) { delegateTo.transformModel(service, model, settings) } @@ -147,16 +168,18 @@ class ServiceSpecificDecorator( override fun serviceRuntimePluginCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = baseCustomizations.maybeApply(codegenContext.serviceShape) { - delegateTo.serviceRuntimePluginCustomizations(codegenContext, baseCustomizations) - } + ): List = + baseCustomizations.maybeApply(codegenContext.serviceShape) { + delegateTo.serviceRuntimePluginCustomizations(codegenContext, baseCustomizations) + } override fun protocolTestGenerator( codegenContext: ClientCodegenContext, baseGenerator: ProtocolTestGenerator, - ): ProtocolTestGenerator = baseGenerator.maybeApply(codegenContext.serviceShape) { - delegateTo.protocolTestGenerator(codegenContext, baseGenerator) - } + ): ProtocolTestGenerator = + baseGenerator.maybeApply(codegenContext.serviceShape) { + delegateTo.protocolTestGenerator(codegenContext, baseGenerator) + } override fun extraSections(codegenContext: ClientCodegenContext): List = listOf().maybeApply(codegenContext.serviceShape) { diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/apigateway/ApiGatewayDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/apigateway/ApiGatewayDecorator.kt index 4b9cc3616aa..7d13d1bf759 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/apigateway/ApiGatewayDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/apigateway/ApiGatewayDecorator.kt @@ -29,21 +29,24 @@ class ApiGatewayDecorator : ClientCodegenDecorator { private class ApiGatewayAcceptHeaderInterceptorCustomization(private val codegenContext: ClientCodegenContext) : ServiceRuntimePluginCustomization() { - override fun section(section: ServiceRuntimePluginSection): Writable = writable { - if (section is ServiceRuntimePluginSection.RegisterRuntimeComponents) { - section.registerInterceptor(this) { - rustTemplate( - "#{Interceptor}::default()", - "Interceptor" to RuntimeType.forInlineDependency( - InlineAwsDependency.forRustFile( - "apigateway_interceptors", - additionalDependency = arrayOf( - CargoDependency.smithyRuntimeApiClient(codegenContext.runtimeConfig), - ), - ), - ).resolve("AcceptHeaderInterceptor"), - ) + override fun section(section: ServiceRuntimePluginSection): Writable = + writable { + if (section is ServiceRuntimePluginSection.RegisterRuntimeComponents) { + section.registerInterceptor(this) { + rustTemplate( + "#{Interceptor}::default()", + "Interceptor" to + RuntimeType.forInlineDependency( + InlineAwsDependency.forRustFile( + "apigateway_interceptors", + additionalDependency = + arrayOf( + CargoDependency.smithyRuntimeApiClient(codegenContext.runtimeConfig), + ), + ), + ).resolve("AcceptHeaderInterceptor"), + ) + } } } - } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ec2/Ec2Decorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ec2/Ec2Decorator.kt index 693b2b572d9..9d7e9e8b9bd 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ec2/Ec2Decorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/ec2/Ec2Decorator.kt @@ -16,6 +16,9 @@ class Ec2Decorator : ClientCodegenDecorator { // EC2 incorrectly models primitive shapes as unboxed when they actually // need to be boxed for the API to work properly - override fun transformModel(service: ServiceShape, model: Model, settings: ClientRustSettings): Model = - EC2MakePrimitivesOptional.processModel(model) + override fun transformModel( + service: ServiceShape, + model: Model, + settings: ClientRustSettings, + ): Model = EC2MakePrimitivesOptional.processModel(model) } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/glacier/GlacierDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/glacier/GlacierDecorator.kt index 364faa8c6a5..9b4a79172ef 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/glacier/GlacierDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/glacier/GlacierDecorator.kt @@ -64,37 +64,39 @@ class GlacierDecorator : ClientCodegenDecorator { /** Implements the `GlacierAccountId` trait for inputs that have an `account_id` field */ private class GlacierAccountIdCustomization(private val codegenContext: ClientCodegenContext) : StructureCustomization() { - override fun section(section: StructureSection): Writable = writable { - if (section is StructureSection.AdditionalTraitImpls && section.shape.inputWithAccountId()) { - val inlineModule = inlineModule(codegenContext.runtimeConfig) - rustTemplate( - """ - impl #{GlacierAccountId} for ${section.structName} { - fn account_id_mut(&mut self) -> &mut Option { - &mut self.account_id + override fun section(section: StructureSection): Writable = + writable { + if (section is StructureSection.AdditionalTraitImpls && section.shape.inputWithAccountId()) { + val inlineModule = inlineModule(codegenContext.runtimeConfig) + rustTemplate( + """ + impl #{GlacierAccountId} for ${section.structName} { + fn account_id_mut(&mut self) -> &mut Option { + &mut self.account_id + } } - } - """, - "GlacierAccountId" to inlineModule.resolve("GlacierAccountId"), - ) + """, + "GlacierAccountId" to inlineModule.resolve("GlacierAccountId"), + ) + } } - } } /** Adds the `x-amz-glacier-version` header to all requests */ private class GlacierApiVersionCustomization(private val codegenContext: ClientCodegenContext) : ServiceRuntimePluginCustomization() { - override fun section(section: ServiceRuntimePluginSection): Writable = writable { - if (section is ServiceRuntimePluginSection.RegisterRuntimeComponents) { - val apiVersion = codegenContext.serviceShape.version - section.registerInterceptor(this) { - rustTemplate( - "#{Interceptor}::new(${apiVersion.dq()})", - "Interceptor" to inlineModule(codegenContext.runtimeConfig).resolve("GlacierApiVersionInterceptor"), - ) + override fun section(section: ServiceRuntimePluginSection): Writable = + writable { + if (section is ServiceRuntimePluginSection.RegisterRuntimeComponents) { + val apiVersion = codegenContext.serviceShape.version + section.registerInterceptor(this) { + rustTemplate( + "#{Interceptor}::new(${apiVersion.dq()})", + "Interceptor" to inlineModule(codegenContext.runtimeConfig).resolve("GlacierApiVersionInterceptor"), + ) + } } } - } } /** @@ -105,29 +107,30 @@ private class GlacierApiVersionCustomization(private val codegenContext: ClientC */ private class GlacierOperationInterceptorsCustomization(private val codegenContext: ClientCodegenContext) : OperationCustomization() { - override fun section(section: OperationSection): Writable = writable { - if (section is OperationSection.AdditionalInterceptors) { - val inputShape = codegenContext.model.expectShape(section.operationShape.inputShape) as StructureShape - val inlineModule = inlineModule(codegenContext.runtimeConfig) - if (inputShape.inputWithAccountId()) { - section.registerInterceptor(codegenContext.runtimeConfig, this) { - rustTemplate( - "#{Interceptor}::<#{Input}>::new()", - "Interceptor" to inlineModule.resolve("GlacierAccountIdAutofillInterceptor"), - "Input" to codegenContext.symbolProvider.toSymbol(inputShape), - ) + override fun section(section: OperationSection): Writable = + writable { + if (section is OperationSection.AdditionalInterceptors) { + val inputShape = codegenContext.model.expectShape(section.operationShape.inputShape) as StructureShape + val inlineModule = inlineModule(codegenContext.runtimeConfig) + if (inputShape.inputWithAccountId()) { + section.registerInterceptor(codegenContext.runtimeConfig, this) { + rustTemplate( + "#{Interceptor}::<#{Input}>::new()", + "Interceptor" to inlineModule.resolve("GlacierAccountIdAutofillInterceptor"), + "Input" to codegenContext.symbolProvider.toSymbol(inputShape), + ) + } } - } - if (section.operationShape.requiresTreeHashHeader()) { - section.registerInterceptor(codegenContext.runtimeConfig, this) { - rustTemplate( - "#{Interceptor}::default()", - "Interceptor" to inlineModule.resolve("GlacierTreeHashHeaderInterceptor"), - ) + if (section.operationShape.requiresTreeHashHeader()) { + section.registerInterceptor(codegenContext.runtimeConfig, this) { + rustTemplate( + "#{Interceptor}::default()", + "Interceptor" to inlineModule.resolve("GlacierTreeHashHeaderInterceptor"), + ) + } } } } - } } /** True when the operation requires tree hash headers */ @@ -138,19 +141,21 @@ private fun OperationShape.requiresTreeHashHeader(): Boolean = private fun StructureShape.inputWithAccountId(): Boolean = hasTrait() && members().any { it.memberName.lowercase() == "accountid" } -private fun inlineModule(runtimeConfig: RuntimeConfig) = RuntimeType.forInlineDependency( - InlineAwsDependency.forRustFile( - "glacier_interceptors", - additionalDependency = glacierInterceptorDependencies(runtimeConfig).toTypedArray(), - ), -) +private fun inlineModule(runtimeConfig: RuntimeConfig) = + RuntimeType.forInlineDependency( + InlineAwsDependency.forRustFile( + "glacier_interceptors", + additionalDependency = glacierInterceptorDependencies(runtimeConfig).toTypedArray(), + ), + ) -private fun glacierInterceptorDependencies(runtimeConfig: RuntimeConfig) = listOf( - AwsCargoDependency.awsRuntime(runtimeConfig), - AwsCargoDependency.awsSigv4(runtimeConfig), - CargoDependency.Bytes, - CargoDependency.Hex, - CargoDependency.Ring, - CargoDependency.smithyHttp(runtimeConfig), - CargoDependency.smithyRuntimeApiClient(runtimeConfig), -) +private fun glacierInterceptorDependencies(runtimeConfig: RuntimeConfig) = + listOf( + AwsCargoDependency.awsRuntime(runtimeConfig), + AwsCargoDependency.awsSigv4(runtimeConfig), + CargoDependency.Bytes, + CargoDependency.Hex, + CargoDependency.Ring, + CargoDependency.smithyHttp(runtimeConfig), + CargoDependency.smithyRuntimeApiClient(runtimeConfig), + ) diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/Route53Decorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/Route53Decorator.kt index d4aa5bf78e2..19dd0e5e57e 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/Route53Decorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/route53/Route53Decorator.kt @@ -32,9 +32,14 @@ class Route53Decorator : ClientCodegenDecorator { override val name: String = "Route53" override val order: Byte = 0 private val logger: Logger = Logger.getLogger(javaClass.name) - private val resourceShapes = setOf(ShapeId.from("com.amazonaws.route53#ResourceId"), ShapeId.from("com.amazonaws.route53#ChangeId")) + private val resourceShapes = + setOf(ShapeId.from("com.amazonaws.route53#ResourceId"), ShapeId.from("com.amazonaws.route53#ChangeId")) - override fun transformModel(service: ServiceShape, model: Model, settings: ClientRustSettings): Model = + override fun transformModel( + service: ServiceShape, + model: Model, + settings: ClientRustSettings, + ): Model = ModelTransformer.create().mapShapes(model) { shape -> shape.letIf(isResourceId(shape)) { logger.info("Adding TrimResourceId trait to $shape") @@ -50,11 +55,12 @@ class Route53Decorator : ClientCodegenDecorator { val inputShape = operation.inputShape(codegenContext.model) val hostedZoneMember = inputShape.members().find { it.hasTrait() } return if (hostedZoneMember != null) { - baseCustomizations + TrimResourceIdCustomization( - codegenContext, - inputShape, - codegenContext.symbolProvider.toMemberName(hostedZoneMember), - ) + baseCustomizations + + TrimResourceIdCustomization( + codegenContext, + inputShape, + codegenContext.symbolProvider.toMemberName(hostedZoneMember), + ) } else { baseCustomizations } @@ -70,29 +76,29 @@ class TrimResourceIdCustomization( private val inputShape: StructureShape, private val fieldName: String, ) : OperationCustomization() { - - override fun section(section: OperationSection): Writable = writable { - when (section) { - is OperationSection.AdditionalInterceptors -> { - section.registerInterceptor(codegenContext.runtimeConfig, this) { - val smithyRuntimeApi = RuntimeType.smithyRuntimeApiClient(codegenContext.runtimeConfig) - val interceptor = - RuntimeType.forInlineDependency( - InlineAwsDependency.forRustFile("route53_resource_id_preprocessor"), - ).resolve("Route53ResourceIdInterceptor") - rustTemplate( - """ - #{Route53ResourceIdInterceptor}::new(|input: &mut #{Input}| { - &mut input.$fieldName - }) - """, - "Input" to codegenContext.symbolProvider.toSymbol(inputShape), - "Route53ResourceIdInterceptor" to interceptor, - "SharedInterceptor" to smithyRuntimeApi.resolve("client::interceptors::SharedInterceptor"), - ) + override fun section(section: OperationSection): Writable = + writable { + when (section) { + is OperationSection.AdditionalInterceptors -> { + section.registerInterceptor(codegenContext.runtimeConfig, this) { + val smithyRuntimeApi = RuntimeType.smithyRuntimeApiClient(codegenContext.runtimeConfig) + val interceptor = + RuntimeType.forInlineDependency( + InlineAwsDependency.forRustFile("route53_resource_id_preprocessor"), + ).resolve("Route53ResourceIdInterceptor") + rustTemplate( + """ + #{Route53ResourceIdInterceptor}::new(|input: &mut #{Input}| { + &mut input.$fieldName + }) + """, + "Input" to codegenContext.symbolProvider.toSymbol(inputShape), + "Route53ResourceIdInterceptor" to interceptor, + "SharedInterceptor" to smithyRuntimeApi.resolve("client::interceptors::SharedInterceptor"), + ) + } } + else -> {} } - else -> {} } - } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt index 3a003398111..5c91ead09ae 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt @@ -50,21 +50,29 @@ class S3Decorator : ClientCodegenDecorator { override val name: String = "S3" override val order: Byte = 0 private val logger: Logger = Logger.getLogger(javaClass.name) - private val invalidXmlRootAllowList = setOf( - // API returns GetObjectAttributes_Response_ instead of Output - ShapeId.from("com.amazonaws.s3#GetObjectAttributesOutput"), - ) + private val invalidXmlRootAllowList = + setOf( + // API returns GetObjectAttributes_Response_ instead of Output + ShapeId.from("com.amazonaws.s3#GetObjectAttributesOutput"), + ) override fun protocols( serviceId: ShapeId, currentProtocols: ProtocolMap, - ): ProtocolMap = currentProtocols + mapOf( - RestXmlTrait.ID to ClientRestXmlFactory { protocolConfig -> - S3ProtocolOverride(protocolConfig) - }, - ) + ): ProtocolMap = + currentProtocols + + mapOf( + RestXmlTrait.ID to + ClientRestXmlFactory { protocolConfig -> + S3ProtocolOverride(protocolConfig) + }, + ) - override fun transformModel(service: ServiceShape, model: Model, settings: ClientRustSettings): Model = + override fun transformModel( + service: ServiceShape, + model: Model, + settings: ClientRustSettings, + ): Model = ModelTransformer.create().mapShapes(model) { shape -> shape.letIf(isInInvalidXmlRootAllowList(shape)) { logger.info("Adding AllowInvalidXmlRoot trait to $it") @@ -93,7 +101,11 @@ class S3Decorator : ClientCodegenDecorator { override fun endpointCustomizations(codegenContext: ClientCodegenContext): List { return listOf( object : EndpointCustomization { - override fun setBuiltInOnServiceConfig(name: String, value: Node, configBuilderRef: String): Writable? { + override fun setBuiltInOnServiceConfig( + name: String, + value: Node, + configBuilderRef: String, + ): Writable? { if (!name.startsWith("AWS::S3")) { return null } @@ -114,27 +126,28 @@ class S3Decorator : ClientCodegenDecorator { operation: OperationShape, baseCustomizations: List, ): List { - return baseCustomizations + object : OperationCustomization() { - override fun section(section: OperationSection): Writable { - return writable { - when (section) { - is OperationSection.BeforeParseResponse -> { - section.body?.also { body -> - rustTemplate( - """ - if matches!(#{errors}::body_is_error($body), Ok(true)) { - ${section.forceError} = true; - } - """, - "errors" to RuntimeType.unwrappedXmlErrors(codegenContext.runtimeConfig), - ) + return baseCustomizations + + object : OperationCustomization() { + override fun section(section: OperationSection): Writable { + return writable { + when (section) { + is OperationSection.BeforeParseResponse -> { + section.body?.also { body -> + rustTemplate( + """ + if matches!(#{errors}::body_is_error($body), Ok(true)) { + ${section.forceError} = true; + } + """, + "errors" to RuntimeType.unwrappedXmlErrors(codegenContext.runtimeConfig), + ) + } } + else -> {} } - else -> {} } } } - } } private fun isInInvalidXmlRootAllowList(shape: Shape): Boolean { @@ -154,41 +167,45 @@ class FilterEndpointTests( } } - fun transform(model: Model): Model = ModelTransformer.create().mapTraits(model) { _, trait -> - when (trait) { - is EndpointTestsTrait -> EndpointTestsTrait.builder().testCases(updateEndpointTests(trait.testCases)) - .version(trait.version).build() + fun transform(model: Model): Model = + ModelTransformer.create().mapTraits(model) { _, trait -> + when (trait) { + is EndpointTestsTrait -> + EndpointTestsTrait.builder().testCases(updateEndpointTests(trait.testCases)) + .version(trait.version).build() - else -> trait + else -> trait + } } - } } // TODO(P96049742): This model transform may need to change depending on if and how the S3 model is updated. private class AddOptionalAuth { - fun transform(model: Model): Model = ModelTransformer.create().mapShapes(model) { shape -> - // Add @optionalAuth to all S3 operations - if (shape is OperationShape && !shape.hasTrait()) { - shape.toBuilder() - .addTrait(OptionalAuthTrait()) - .build() - } else { - shape + fun transform(model: Model): Model = + ModelTransformer.create().mapShapes(model) { shape -> + // Add @optionalAuth to all S3 operations + if (shape is OperationShape && !shape.hasTrait()) { + shape.toBuilder() + .addTrait(OptionalAuthTrait()) + .build() + } else { + shape + } } - } } class S3ProtocolOverride(codegenContext: CodegenContext) : RestXml(codegenContext) { private val runtimeConfig = codegenContext.runtimeConfig - private val errorScope = arrayOf( - *RuntimeType.preludeScope, - "Bytes" to RuntimeType.Bytes, - "ErrorMetadata" to RuntimeType.errorMetadata(runtimeConfig), - "ErrorBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), - "Headers" to RuntimeType.headers(runtimeConfig), - "XmlDecodeError" to RuntimeType.smithyXml(runtimeConfig).resolve("decode::XmlDecodeError"), - "base_errors" to restXmlErrors, - ) + private val errorScope = + arrayOf( + *RuntimeType.preludeScope, + "Bytes" to RuntimeType.Bytes, + "ErrorMetadata" to RuntimeType.errorMetadata(runtimeConfig), + "ErrorBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), + "Headers" to RuntimeType.headers(runtimeConfig), + "XmlDecodeError" to RuntimeType.smithyXml(runtimeConfig).resolve("decode::XmlDecodeError"), + "base_errors" to restXmlErrors, + ) override fun parseHttpErrorMetadata(operationShape: OperationShape): RuntimeType { return ProtocolFunctions.crossOperationFn("parse_http_error_metadata") { fnName -> diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/StripBucketFromPath.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/StripBucketFromPath.kt index f2559b05c72..8b6de837b91 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/StripBucketFromPath.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/StripBucketFromPath.kt @@ -14,18 +14,20 @@ import software.amazon.smithy.rust.codegen.core.util.letIf class StripBucketFromHttpPath { private val transformer = ModelTransformer.create() + fun transform(model: Model): Model { // Remove `/{Bucket}` from the path (http trait) // The endpoints 2.0 rules handle either placing the bucket into the virtual host or adding it to the path return transformer.mapTraits(model) { shape, trait -> when (trait) { is HttpTrait -> { - val appliedToOperation = shape - .asOperationShape() - .map { operation -> - model.expectShape(operation.inputShape, StructureShape::class.java) - .getMember("Bucket").isPresent - }.orElse(false) + val appliedToOperation = + shape + .asOperationShape() + .map { operation -> + model.expectShape(operation.inputShape, StructureShape::class.java) + .getMember("Bucket").isPresent + }.orElse(false) trait.letIf(appliedToOperation) { it.toBuilder().uri(UriPattern.parse(transformUri(trait.uri.toString()))).build() } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3control/S3ControlDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3control/S3ControlDecorator.kt index ce96a33b827..6246eb1e524 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3control/S3ControlDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3control/S3ControlDecorator.kt @@ -24,24 +24,32 @@ class S3ControlDecorator : ClientCodegenDecorator { override val name: String = "S3Control" override val order: Byte = 0 - override fun transformModel(service: ServiceShape, model: Model, settings: ClientRustSettings): Model = - stripEndpointTrait("AccountId")(model) + override fun transformModel( + service: ServiceShape, + model: Model, + settings: ClientRustSettings, + ): Model = stripEndpointTrait("AccountId")(model) override fun endpointCustomizations(codegenContext: ClientCodegenContext): List { - return listOf(object : EndpointCustomization { - override fun setBuiltInOnServiceConfig(name: String, value: Node, configBuilderRef: String): Writable? { - if (!name.startsWith("AWS::S3Control")) { - return null + return listOf( + object : EndpointCustomization { + override fun setBuiltInOnServiceConfig( + name: String, + value: Node, + configBuilderRef: String, + ): Writable? { + if (!name.startsWith("AWS::S3Control")) { + return null + } + val builtIn = codegenContext.getBuiltIn(name) ?: return null + return writable { + rustTemplate( + "let $configBuilderRef = $configBuilderRef.${builtIn.name.rustName()}(#{value});", + "value" to value.toWritable(), + ) + } } - val builtIn = codegenContext.getBuiltIn(name) ?: return null - return writable { - rustTemplate( - "let $configBuilderRef = $configBuilderRef.${builtIn.name.rustName()}(#{value});", - "value" to value.toWritable(), - ) - } - } - }, + }, ) } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/sso/SSODecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/sso/SSODecorator.kt index 8ead07d3bce..db13a1bd86b 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/sso/SSODecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/sso/SSODecorator.kt @@ -24,7 +24,11 @@ class SSODecorator : ClientCodegenDecorator { private fun isAwsCredentials(shape: Shape): Boolean = shape.id == ShapeId.from("com.amazonaws.sso#RoleCredentials") - override fun transformModel(service: ServiceShape, model: Model, settings: ClientRustSettings): Model = + override fun transformModel( + service: ServiceShape, + model: Model, + settings: ClientRustSettings, + ): Model = ModelTransformer.create().mapShapes(model) { shape -> shape.letIf(isAwsCredentials(shape)) { (shape as StructureShape).toBuilder().addTrait(SensitiveTrait()).build() diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/sts/STSDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/sts/STSDecorator.kt index ed23c99d8f9..c4c0f06ff88 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/sts/STSDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/sts/STSDecorator.kt @@ -30,7 +30,11 @@ class STSDecorator : ClientCodegenDecorator { private fun isAwsCredentials(shape: Shape): Boolean = shape.id == ShapeId.from("com.amazonaws.sts#Credentials") - override fun transformModel(service: ServiceShape, model: Model, settings: ClientRustSettings): Model = + override fun transformModel( + service: ServiceShape, + model: Model, + settings: ClientRustSettings, + ): Model = ModelTransformer.create().mapShapes(model) { shape -> shape.letIf(isIdpCommunicationError(shape)) { logger.info("Adding @retryable trait to $shape and setting its error type to 'server'") diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/timestream/TimestreamDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/timestream/TimestreamDecorator.kt index eca18011871..3e4705a743f 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/timestream/TimestreamDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/timestream/TimestreamDecorator.kt @@ -31,26 +31,31 @@ class TimestreamDecorator : ClientCodegenDecorator { override val name: String = "Timestream" override val order: Byte = -1 - override fun extraSections(codegenContext: ClientCodegenContext): List = listOf( - adhocCustomization { - addDependency(AwsCargoDependency.awsConfig(codegenContext.runtimeConfig).toDevDependency()) - rustTemplate( - """ - let config = aws_config::load_from_env().await; - // You MUST call `with_endpoint_discovery_enabled` to produce a working client for this service. - let ${it.clientName} = ${it.crateName}::Client::new(&config).with_endpoint_discovery_enabled().await; - """.replaceIndent(it.indent), - ) - }, - ) - - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { - val endpointDiscovery = InlineAwsDependency.forRustFile( - "endpoint_discovery", - Visibility.PUBLIC, - CargoDependency.Tokio.copy(scope = DependencyScope.Compile, features = setOf("sync")), - CargoDependency.smithyAsync(codegenContext.runtimeConfig).toDevDependency().withFeature("test-util"), + override fun extraSections(codegenContext: ClientCodegenContext): List = + listOf( + adhocCustomization { + addDependency(AwsCargoDependency.awsConfig(codegenContext.runtimeConfig).toDevDependency()) + rustTemplate( + """ + let config = aws_config::load_from_env().await; + // You MUST call `with_endpoint_discovery_enabled` to produce a working client for this service. + let ${it.clientName} = ${it.crateName}::Client::new(&config).with_endpoint_discovery_enabled().await; + """.replaceIndent(it.indent), + ) + }, ) + + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { + val endpointDiscovery = + InlineAwsDependency.forRustFile( + "endpoint_discovery", + Visibility.PUBLIC, + CargoDependency.Tokio.copy(scope = DependencyScope.Compile, features = setOf("sync")), + CargoDependency.smithyAsync(codegenContext.runtimeConfig).toDevDependency().withFeature("test-util"), + ) rustCrate.withModule(ClientRustModule.client) { // helper function to resolve an endpoint given a base client rustTemplate( diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/AwsEndpointsStdLib.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/AwsEndpointsStdLib.kt index 5d3fb010f9e..f96e54102e3 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/AwsEndpointsStdLib.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/AwsEndpointsStdLib.kt @@ -12,6 +12,7 @@ import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegen import software.amazon.smithy.rust.codegen.client.smithy.endpoint.EndpointCustomization import software.amazon.smithy.rust.codegen.client.smithy.endpoint.generators.CustomRuntimeFunction import software.amazon.smithy.rust.codegen.client.smithy.endpoint.rulesgen.awsStandardLib +import software.amazon.smithy.rust.codegen.core.util.PANIC import software.amazon.smithy.rustsdk.SdkSettings import kotlin.io.path.readText @@ -29,14 +30,20 @@ class AwsEndpointsStdLib() : ClientCodegenDecorator { private fun partitionMetadata(sdkSettings: SdkSettings): ObjectNode { if (partitionsCache == null) { - val partitionsJson = when (val path = sdkSettings.partitionsConfigPath) { - null -> ( - javaClass.getResource("/default-partitions.json") - ?: throw IllegalStateException("Failed to find default-partitions.json in the JAR") - ).readText() + val partitionsJson = + when (val path = sdkSettings.partitionsConfigPath) { + null -> { + if (sdkSettings.awsSdkBuild) { + PANIC("cannot use hardcoded partitions in AWS SDK build") + } + ( + javaClass.getResource("/default-partitions.json") + ?: throw IllegalStateException("Failed to find default-partitions.json in the JAR") + ).readText() + } - else -> path.readText() - } + else -> path.readText() + } partitionsCache = Node.parse(partitionsJson).expectObjectNode() } return partitionsCache!! diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt index b11236dfd14..5bcc870ae5b 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt @@ -41,16 +41,20 @@ class OperationInputTestDecorator : ClientCodegenDecorator { override val name: String = "OperationInputTest" override val order: Byte = 0 - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { val endpointTests = EndpointTypesGenerator.fromContext(codegenContext).tests.orNullIfEmpty() ?: return rustCrate.integrationTest("endpoint_tests") { Attribute(Attribute.cfg(Attribute.feature("test-util"))).render(this, AttributeKind.Inner) - val tests = endpointTests.flatMap { test -> - val generator = OperationInputTestGenerator(codegenContext, test) - test.operationInputs.filterNot { usesDeprecatedBuiltIns(it) }.map { operationInput -> - generator.generateInput(operationInput) + val tests = + endpointTests.flatMap { test -> + val generator = OperationInputTestGenerator(codegenContext, test) + test.operationInputs.filterNot { usesDeprecatedBuiltIns(it) }.map { operationInput -> + generator.generateInput(operationInput) + } } - } tests.join("\n")(this) } } @@ -122,89 +126,94 @@ class OperationInputTestGenerator(_ctx: ClientCodegenContext, private val test: private val model = ctx.model private val instantiator = ClientInstantiator(ctx) - fun generateInput(testOperationInput: EndpointTestOperationInput) = writable { - val operationName = testOperationInput.operationName.toSnakeCase() - tokioTest(safeName("operation_input_test_$operationName")) { - rustTemplate( - """ - /* builtIns: ${escape(Node.prettyPrintJson(testOperationInput.builtInParams))} */ - /* clientParams: ${escape(Node.prettyPrintJson(testOperationInput.clientParams))} */ - let (http_client, rcvr) = #{capture_request}(None); - let conf = #{conf}; - let client = $moduleName::Client::from_conf(conf); - let _result = dbg!(#{invoke_operation}); - #{assertion} - """, - "capture_request" to RuntimeType.captureRequest(runtimeConfig), - "conf" to config(testOperationInput), - "invoke_operation" to operationInvocation(testOperationInput), - "assertion" to writable { - test.expect.endpoint.ifPresent { endpoint -> - val uri = escape(endpoint.url) - rustTemplate( - """ - let req = rcvr.expect_request(); - let uri = req.uri().to_string(); - assert!(uri.starts_with(${uri.dq()}), "expected URI to start with `$uri` but it was `{}`", uri); - """, - ) - } - test.expect.error.ifPresent { error -> - val expectedError = - escape("expected error: $error [${test.documentation.orNull() ?: "no docs"}]") - val escapedError = escape(error) - rustTemplate( - """ - rcvr.expect_no_request(); - let error = _result.expect_err(${expectedError.dq()}); - assert!( - format!("{:?}", error).contains(${escapedError.dq()}), - "expected error to contain `$escapedError` but it was {:?}", error - ); - """, - ) - } - }, - ) + fun generateInput(testOperationInput: EndpointTestOperationInput) = + writable { + val operationName = testOperationInput.operationName.toSnakeCase() + tokioTest(safeName("operation_input_test_$operationName")) { + rustTemplate( + """ + /* builtIns: ${escape(Node.prettyPrintJson(testOperationInput.builtInParams))} */ + /* clientParams: ${escape(Node.prettyPrintJson(testOperationInput.clientParams))} */ + let (http_client, rcvr) = #{capture_request}(None); + let conf = #{conf}; + let client = $moduleName::Client::from_conf(conf); + let _result = dbg!(#{invoke_operation}); + #{assertion} + """, + "capture_request" to RuntimeType.captureRequest(runtimeConfig), + "conf" to config(testOperationInput), + "invoke_operation" to operationInvocation(testOperationInput), + "assertion" to + writable { + test.expect.endpoint.ifPresent { endpoint -> + val uri = escape(endpoint.url) + rustTemplate( + """ + let req = rcvr.expect_request(); + let uri = req.uri().to_string(); + assert!(uri.starts_with(${uri.dq()}), "expected URI to start with `$uri` but it was `{}`", uri); + """, + ) + } + test.expect.error.ifPresent { error -> + val expectedError = + escape("expected error: $error [${test.documentation.orNull() ?: "no docs"}]") + val escapedError = escape(error) + rustTemplate( + """ + rcvr.expect_no_request(); + let error = _result.expect_err(${expectedError.dq()}); + assert!( + format!("{:?}", error).contains(${escapedError.dq()}), + "expected error to contain `$escapedError` but it was {:?}", error + ); + """, + ) + } + }, + ) + } } - } - private fun operationInvocation(testOperationInput: EndpointTestOperationInput) = writable { - rust("client.${testOperationInput.operationName.toSnakeCase()}()") - val operationInput = - model.expectShape(ctx.operationId(testOperationInput), OperationShape::class.java).inputShape(model) - testOperationInput.operationParams.members.forEach { (key, value) -> - val member = operationInput.expectMember(key.value) - rustTemplate( - ".${member.setterName()}(#{value})", - "value" to instantiator.generate(member, value), - ) + private fun operationInvocation(testOperationInput: EndpointTestOperationInput) = + writable { + rust("client.${testOperationInput.operationName.toSnakeCase()}()") + val operationInput = + model.expectShape(ctx.operationId(testOperationInput), OperationShape::class.java).inputShape(model) + testOperationInput.operationParams.members.forEach { (key, value) -> + val member = operationInput.expectMember(key.value) + rustTemplate( + ".${member.setterName()}(#{value})", + "value" to instantiator.generate(member, value), + ) + } + rust(".send().await") } - rust(".send().await") - } /** initialize service config for test */ - private fun config(operationInput: EndpointTestOperationInput) = writable { - rustBlock("") { - Attribute.AllowUnusedMut.render(this) - rust("let mut builder = $moduleName::Config::builder().with_test_defaults().http_client(http_client);") - operationInput.builtInParams.members.forEach { (builtIn, value) -> - val setter = endpointCustomizations.firstNotNullOfOrNull { - it.setBuiltInOnServiceConfig( - builtIn.value, - value, - "builder", - ) - } - if (setter != null) { - setter(this) - } else { - Logger.getLogger("OperationTestGenerator").warning("No provider for ${builtIn.value}") + private fun config(operationInput: EndpointTestOperationInput) = + writable { + rustBlock("") { + Attribute.AllowUnusedMut.render(this) + rust("let mut builder = $moduleName::Config::builder().with_test_defaults().http_client(http_client);") + operationInput.builtInParams.members.forEach { (builtIn, value) -> + val setter = + endpointCustomizations.firstNotNullOfOrNull { + it.setBuiltInOnServiceConfig( + builtIn.value, + value, + "builder", + ) + } + if (setter != null) { + setter(this) + } else { + Logger.getLogger("OperationTestGenerator").warning("No provider for ${builtIn.value}") + } } + rust("builder.build()") } - rust("builder.build()") } - } } fun ClientCodegenContext.operationId(testOperationInput: EndpointTestOperationInput): ShapeId = diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/RequireEndpointRules.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/RequireEndpointRules.kt index 3b3b81aeccf..f0aed0add0e 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/RequireEndpointRules.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/RequireEndpointRules.kt @@ -15,7 +15,11 @@ import software.amazon.smithy.rustsdk.sdkSettings class RequireEndpointRules : ClientCodegenDecorator { override val name: String = "RequireEndpointRules" override val order: Byte = 100 - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { if (!codegenContext.sdkSettings().requireEndpointResolver) { return } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/StripEndpointTrait.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/StripEndpointTrait.kt index 6dccf3f6b3f..9fd6f40822f 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/StripEndpointTrait.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/StripEndpointTrait.kt @@ -13,9 +13,10 @@ fun stripEndpointTrait(hostPrefix: String): (Model) -> Model { return { model: Model -> ModelTransformer.create() .removeTraitsIf(model) { _, trait -> - trait is EndpointTrait && trait.hostPrefix.labels.any { - it.isLabel && it.content == hostPrefix - } + trait is EndpointTrait && + trait.hostPrefix.labels.any { + it.isLabel && it.content == hostPrefix + } } } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/traits/PresignableTrait.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/traits/PresignableTrait.kt index ea3c2db0663..84cc95dbbd6 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/traits/PresignableTrait.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/traits/PresignableTrait.kt @@ -9,8 +9,9 @@ import software.amazon.smithy.model.node.Node import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.traits.AnnotationTrait -/** Synthetic trait that indicates an operation is presignable. */ // TODO(https://github.com/awslabs/smithy/pull/897) this can be replaced when the trait is added to Smithy. + +/** Synthetic trait that indicates an operation is presignable. */ class PresignableTrait(val syntheticOperationId: ShapeId) : AnnotationTrait(ID, Node.objectNode()) { companion object { val ID = ShapeId.from("smithy.api.aws.internal#presignable") diff --git a/aws/sdk-codegen/src/main/resources/default-partitions.json b/aws/sdk-codegen/src/main/resources/default-partitions.json deleted file mode 100644 index ad0872be3a1..00000000000 --- a/aws/sdk-codegen/src/main/resources/default-partitions.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "version": "1.1", - "partitions": [ - { - "id": "aws", - "regionRegex": "^(us|eu|ap|sa|ca|me|af)-\\w+-\\d+$", - "regions": { - "af-south-1": {}, - "ap-east-1": {}, - "ap-northeast-1": {}, - "ap-northeast-2": {}, - "ap-northeast-3": {}, - "ap-south-1": {}, - "ap-southeast-1": {}, - "ap-southeast-2": {}, - "ap-southeast-3": {}, - "ca-central-1": {}, - "eu-central-1": {}, - "eu-north-1": {}, - "eu-south-1": {}, - "eu-west-1": {}, - "eu-west-2": {}, - "eu-west-3": {}, - "me-central-1": {}, - "me-south-1": {}, - "sa-east-1": {}, - "us-east-1": {}, - "us-east-2": {}, - "us-west-1": {}, - "us-west-2": {}, - "aws-global": {} - }, - "outputs": { - "name": "aws", - "dnsSuffix": "amazonaws.com", - "dualStackDnsSuffix": "api.aws", - "supportsFIPS": true, - "supportsDualStack": true - } - }, - { - "id": "aws-us-gov", - "regionRegex": "^us\\-gov\\-\\w+\\-\\d+$", - "regions": { - "us-gov-west-1": {}, - "us-gov-east-1": {}, - "aws-us-gov-global": {} - }, - "outputs": { - "name": "aws-us-gov", - "dnsSuffix": "amazonaws.com", - "dualStackDnsSuffix": "api.aws", - "supportsFIPS": true, - "supportsDualStack": true - } - }, - { - "id": "aws-cn", - "regionRegex": "^cn\\-\\w+\\-\\d+$", - "regions": { - "cn-north-1": {}, - "cn-northwest-1": {}, - "aws-cn-global": {} - }, - "outputs": { - "name": "aws-cn", - "dnsSuffix": "amazonaws.com.cn", - "dualStackDnsSuffix": "api.amazonwebservices.com.cn", - "supportsFIPS": true, - "supportsDualStack": true - } - }, - { - "id": "aws-iso", - "regionRegex": "^us\\-iso\\-\\w+\\-\\d+$", - "outputs": { - "name": "aws-iso", - "dnsSuffix": "c2s.ic.gov", - "supportsFIPS": true, - "supportsDualStack": false, - "dualStackDnsSuffix": "c2s.ic.gov" - }, - "regions": { - "us-iso-east-1": {}, - "us-iso-west-1": {}, - "aws-iso-global": {} - } - }, - { - "id": "aws-iso-b", - "regionRegex": "^us\\-isob\\-\\w+\\-\\d+$", - "outputs": { - "name": "aws-iso-b", - "dnsSuffix": "sc2s.sgov.gov", - "supportsFIPS": true, - "supportsDualStack": false, - "dualStackDnsSuffix": "sc2s.sgov.gov" - }, - "regions": { - "us-isob-east-1": {}, - "aws-iso-b-global": {} - } - } - ] -} diff --git a/aws/sdk-codegen/src/main/resources/default-partitions.json b/aws/sdk-codegen/src/main/resources/default-partitions.json new file mode 120000 index 00000000000..39f6aaa6b45 --- /dev/null +++ b/aws/sdk-codegen/src/main/resources/default-partitions.json @@ -0,0 +1 @@ +../../../../sdk/aws-models/sdk-partitions.json \ No newline at end of file diff --git a/aws/sdk-codegen/src/main/resources/default-sdk-endpoints.json b/aws/sdk-codegen/src/main/resources/default-sdk-endpoints.json deleted file mode 100644 index 3b3278a0c9a..00000000000 --- a/aws/sdk-codegen/src/main/resources/default-sdk-endpoints.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "partitions" : [ - { - "defaults": { - "hostname": "{service}.{region}.{dnsSuffix}", - "protocols": [ - "https" - ], - "signatureVersions": [ - "v4" - ], - "variants": [ - { - "dnsSuffix": "amazonaws.com", - "hostname": "{service}-fips.{region}.{dnsSuffix}", - "tags": [ - "fips" - ] - }, - { - "dnsSuffix": "api.aws", - "hostname": "{service}-fips.{region}.{dnsSuffix}", - "tags": [ - "dualstack", - "fips" - ] - }, - { - "dnsSuffix": "api.aws", - "hostname": "{service}.{region}.{dnsSuffix}", - "tags": [ - "dualstack" - ] - } - ] - }, - "dnsSuffix": "amazonaws.com", - "partition": "aws", - "partitionName": "AWS Standard", - "regionRegex": "^(us|eu|ap|sa|ca|me|af)\\-\\w+\\-\\d+$" - } - ], - "version" : 3 -} diff --git a/aws/sdk-codegen/src/test/kotlin/AwsCrateDocsDecoratorTest.kt b/aws/sdk-codegen/src/test/kotlin/AwsCrateDocsDecoratorTest.kt index 7cd935e381d..bd8fc889a21 100644 --- a/aws/sdk-codegen/src/test/kotlin/AwsCrateDocsDecoratorTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/AwsCrateDocsDecoratorTest.kt @@ -120,43 +120,47 @@ class AwsCrateDocsDecoratorTest { fun warningBanner() { val context = { version: String -> testClientCodegenContext( - model = """ + model = + """ namespace test service Foobaz { } - """.asSmithyModel(), - settings = testClientRustSettings( - moduleVersion = version, - service = ShapeId.from("test#Foobaz"), - runtimeConfig = AwsTestRuntimeConfig, - customizationConfig = - ObjectNode.parse( - """ - { "awsSdk": { - "awsConfigVersion": "dontcare" } } - """, - ) as ObjectNode, - ), + """.asSmithyModel(), + settings = + testClientRustSettings( + moduleVersion = version, + service = ShapeId.from("test#Foobaz"), + runtimeConfig = AwsTestRuntimeConfig, + customizationConfig = + ObjectNode.parse( + """ + { "awsSdk": { + "awsConfigVersion": "dontcare" } } + """, + ) as ObjectNode, + ), ) } // Test unstable versions first var codegenContext = context("0.36.0") - var result = AwsCrateDocGenerator(codegenContext).docText(includeHeader = false, includeLicense = false, asComments = true).let { writable -> - val writer = RustWriter.root() - writable(writer) - writer.toString() - } + var result = + AwsCrateDocGenerator(codegenContext).docText(includeHeader = false, includeLicense = false, asComments = true).let { writable -> + val writer = RustWriter.root() + writable(writer) + writer.toString() + } assertTrue(result.contains("The SDK is currently released as a developer preview")) // And now stable versions codegenContext = context("1.0.0") - result = AwsCrateDocGenerator(codegenContext).docText(includeHeader = false, includeLicense = false, asComments = true).let { writable -> - val writer = RustWriter.root() - writable(writer) - writer.toString() - } + result = + AwsCrateDocGenerator(codegenContext).docText(includeHeader = false, includeLicense = false, asComments = true).let { writable -> + val writer = RustWriter.root() + writable(writer) + writer.toString() + } assertFalse(result.contains("The SDK is currently released as a developer preview")) } } diff --git a/aws/sdk-codegen/src/test/kotlin/SdkCodegenIntegrationTest.kt b/aws/sdk-codegen/src/test/kotlin/SdkCodegenIntegrationTest.kt index d4bd5e9ab11..998674bf917 100644 --- a/aws/sdk-codegen/src/test/kotlin/SdkCodegenIntegrationTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/SdkCodegenIntegrationTest.kt @@ -12,7 +12,8 @@ import software.amazon.smithy.rustsdk.awsSdkIntegrationTest class SdkCodegenIntegrationTest { companion object { - val model = """ + val model = + """ namespace test use aws.api#service @@ -46,12 +47,14 @@ class SdkCodegenIntegrationTest { operation SomeOperation { output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() } @Test fun smokeTestSdkCodegen() { - awsSdkIntegrationTest(model) { _, _ -> /* it should compile */ } + awsSdkIntegrationTest(model) { _, _ -> + // it should compile + } } // TODO(PostGA): Remove warning banner conditionals. diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecoratorTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecoratorTest.kt index 0435e742594..c04a4ce5714 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecoratorTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/AwsPresigningDecoratorTest.kt @@ -27,7 +27,11 @@ class AwsPresigningDecoratorTest { testTransform("com.amazonaws.s3", "GetObject", presignable = true) } - private fun testTransform(namespace: String, name: String, presignable: Boolean) { + private fun testTransform( + namespace: String, + name: String, + presignable: Boolean, + ) { val settings = testClientRustSettings() val decorator = AwsPresigningDecorator() val model = testOperation(namespace, name) @@ -35,7 +39,11 @@ class AwsPresigningDecoratorTest { hasPresignableTrait(transformed, namespace, name) shouldBe presignable } - private fun hasPresignableTrait(model: Model, namespace: String, name: String): Boolean = + private fun hasPresignableTrait( + model: Model, + namespace: String, + name: String, + ): Boolean = model.shapes().filter { shape -> shape is OperationShape && shape.id == ShapeId.fromParts(namespace, name) } .findFirst() .orNull()!! @@ -44,7 +52,10 @@ class AwsPresigningDecoratorTest { private fun serviceShape(model: Model): ServiceShape = model.shapes().filter { shape -> shape is ServiceShape }.findFirst().orNull()!! as ServiceShape - private fun testOperation(namespace: String, name: String): Model = + private fun testOperation( + namespace: String, + name: String, + ): Model = """ namespace $namespace use aws.protocols#restJson1 @@ -68,7 +79,8 @@ class OverrideHttpMethodTransformTest { @Test fun `it should override the HTTP method for the listed operations`() { val settings = testClientRustSettings() - val model = """ + val model = + """ namespace test use aws.protocols#restJson1 @@ -89,26 +101,28 @@ class OverrideHttpMethodTransformTest { @http(uri: "/three", method: "POST") operation Three { input: TestInput, output: TestOutput } - """.asSmithyModel() + """.asSmithyModel() val serviceShape = model.expectShape(ShapeId.from("test#TestService"), ServiceShape::class.java) - val presignableOp = PresignableOperation( - PayloadSigningType.EMPTY, - listOf( - OverrideHttpMethodTransform( - mapOf( - ShapeId.from("test#One") to "GET", - ShapeId.from("test#Two") to "POST", + val presignableOp = + PresignableOperation( + PayloadSigningType.EMPTY, + listOf( + OverrideHttpMethodTransform( + mapOf( + ShapeId.from("test#One") to "GET", + ShapeId.from("test#Two") to "POST", + ), ), ), - ), - ) - val transformed = AwsPresigningDecorator( - mapOf( - ShapeId.from("test#One") to presignableOp, - ShapeId.from("test#Two") to presignableOp, - ), - ).transformModel(serviceShape, model, settings) + ) + val transformed = + AwsPresigningDecorator( + mapOf( + ShapeId.from("test#One") to presignableOp, + ShapeId.from("test#Two") to presignableOp, + ), + ).transformModel(serviceShape, model, settings) val synthNamespace = "test.synthetic.aws.presigned" transformed.expectShape(ShapeId.from("$synthNamespace#One")).expectTrait().method shouldBe "GET" @@ -118,11 +132,11 @@ class OverrideHttpMethodTransformTest { } class MoveDocumentMembersToQueryParamsTransformTest { - @Test fun `it should move document members to query parameters for the listed operations`() { val settings = testClientRustSettings() - val model = """ + val model = + """ namespace test use aws.protocols#restJson1 @@ -156,39 +170,43 @@ class MoveDocumentMembersToQueryParamsTransformTest { @http(uri: "/two", method: "POST") operation Two { input: TwoInputOutput, output: TwoInputOutput } - """.asSmithyModel() + """.asSmithyModel() val serviceShape = model.expectShape(ShapeId.from("test#TestService"), ServiceShape::class.java) - val presignableOp = PresignableOperation( - PayloadSigningType.EMPTY, - listOf( - MoveDocumentMembersToQueryParamsTransform( - listOf(ShapeId.from("test#One")), + val presignableOp = + PresignableOperation( + PayloadSigningType.EMPTY, + listOf( + MoveDocumentMembersToQueryParamsTransform( + listOf(ShapeId.from("test#One")), + ), ), - ), - ) - val transformed = AwsPresigningDecorator( - mapOf(ShapeId.from("test#One") to presignableOp), - ).transformModel(serviceShape, model, settings) + ) + val transformed = + AwsPresigningDecorator( + mapOf(ShapeId.from("test#One") to presignableOp), + ).transformModel(serviceShape, model, settings) val index = HttpBindingIndex(transformed) index.getRequestBindings(ShapeId.from("test.synthetic.aws.presigned#One")).map { (key, value) -> key to value.location - }.toMap() shouldBe mapOf( - "one" to HttpBinding.Location.HEADER, - "two" to HttpBinding.Location.QUERY, - "three" to HttpBinding.Location.QUERY, - "four" to HttpBinding.Location.QUERY, - ) + }.toMap() shouldBe + mapOf( + "one" to HttpBinding.Location.HEADER, + "two" to HttpBinding.Location.QUERY, + "three" to HttpBinding.Location.QUERY, + "four" to HttpBinding.Location.QUERY, + ) transformed.getShape(ShapeId.from("test.synthetic.aws.presigned#Two")).orNull() shouldBe null index.getRequestBindings(ShapeId.from("test#Two")).map { (key, value) -> key to value.location - }.toMap() shouldBe mapOf( - "one" to HttpBinding.Location.HEADER, - "two" to HttpBinding.Location.QUERY, - "three" to HttpBinding.Location.DOCUMENT, - "four" to HttpBinding.Location.DOCUMENT, - ) + }.toMap() shouldBe + mapOf( + "one" to HttpBinding.Location.HEADER, + "two" to HttpBinding.Location.QUERY, + "three" to HttpBinding.Location.DOCUMENT, + "four" to HttpBinding.Location.DOCUMENT, + ) } } diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfigTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfigTest.kt index aec0806d06f..eb759fe3af7 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfigTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/CredentialProviderConfigTest.kt @@ -17,13 +17,15 @@ internal class CredentialProviderConfigTest { fun `configuring credentials provider at operation level should work`() { awsSdkIntegrationTest(SdkCodegenIntegrationTest.model) { ctx, rustCrate -> val rc = ctx.runtimeConfig - val codegenScope = arrayOf( - *RuntimeType.preludeScope, - "capture_request" to RuntimeType.captureRequest(rc), - "Credentials" to AwsRuntimeType.awsCredentialTypesTestUtil(rc) - .resolve("Credentials"), - "Region" to AwsRuntimeType.awsTypes(rc).resolve("region::Region"), - ) + val codegenScope = + arrayOf( + *RuntimeType.preludeScope, + "capture_request" to RuntimeType.captureRequest(rc), + "Credentials" to + AwsRuntimeType.awsCredentialTypesTestUtil(rc) + .resolve("Credentials"), + "Region" to AwsRuntimeType.awsTypes(rc).resolve("region::Region"), + ) rustCrate.integrationTest("credentials_provider") { // per https://github.com/awslabs/aws-sdk-rust/issues/901 tokioTest("configuring_credentials_provider_at_operation_level_should_work") { @@ -67,16 +69,19 @@ internal class CredentialProviderConfigTest { fun `configuring credentials provider on builder should replace what was previously set`() { awsSdkIntegrationTest(SdkCodegenIntegrationTest.model) { ctx, rustCrate -> val rc = ctx.runtimeConfig - val codegenScope = arrayOf( - *RuntimeType.preludeScope, - "capture_request" to RuntimeType.captureRequest(rc), - "Credentials" to AwsRuntimeType.awsCredentialTypesTestUtil(rc) - .resolve("Credentials"), - "Region" to AwsRuntimeType.awsTypes(rc).resolve("region::Region"), - "SdkConfig" to AwsRuntimeType.awsTypes(rc).resolve("sdk_config::SdkConfig"), - "SharedCredentialsProvider" to AwsRuntimeType.awsCredentialTypes(rc) - .resolve("provider::SharedCredentialsProvider"), - ) + val codegenScope = + arrayOf( + *RuntimeType.preludeScope, + "capture_request" to RuntimeType.captureRequest(rc), + "Credentials" to + AwsRuntimeType.awsCredentialTypesTestUtil(rc) + .resolve("Credentials"), + "Region" to AwsRuntimeType.awsTypes(rc).resolve("region::Region"), + "SdkConfig" to AwsRuntimeType.awsTypes(rc).resolve("sdk_config::SdkConfig"), + "SharedCredentialsProvider" to + AwsRuntimeType.awsCredentialTypes(rc) + .resolve("provider::SharedCredentialsProvider"), + ) rustCrate.integrationTest("credentials_provider") { // per https://github.com/awslabs/aws-sdk-rust/issues/973 tokioTest("configuring_credentials_provider_on_builder_should_replace_what_was_previously_set") { diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/EndpointBuiltInsDecoratorTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/EndpointBuiltInsDecoratorTest.kt index 68bfab92fef..c5dd5581600 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/EndpointBuiltInsDecoratorTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/EndpointBuiltInsDecoratorTest.kt @@ -13,7 +13,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.integrationTest class EndpointBuiltInsDecoratorTest { - private val endpointUrlModel = """ + private val endpointUrlModel = + """ namespace test use aws.api#service @@ -74,7 +75,7 @@ class EndpointBuiltInsDecoratorTest { operation SomeOperation { output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() @Test fun endpointUrlBuiltInWorksEndToEnd() { @@ -107,10 +108,12 @@ class EndpointBuiltInsDecoratorTest { } """, "tokio" to CargoDependency.Tokio.toDevDependency().withFeature("rt").withFeature("macros").toType(), - "StaticReplayClient" to CargoDependency.smithyRuntimeTestUtil(codegenContext.runtimeConfig).toType() - .resolve("client::http::test_util::StaticReplayClient"), - "ReplayEvent" to CargoDependency.smithyRuntimeTestUtil(codegenContext.runtimeConfig).toType() - .resolve("client::http::test_util::ReplayEvent"), + "StaticReplayClient" to + CargoDependency.smithyRuntimeTestUtil(codegenContext.runtimeConfig).toType() + .resolve("client::http::test_util::StaticReplayClient"), + "ReplayEvent" to + CargoDependency.smithyRuntimeTestUtil(codegenContext.runtimeConfig).toType() + .resolve("client::http::test_util::ReplayEvent"), "SdkBody" to RuntimeType.sdkBody(codegenContext.runtimeConfig), ) } diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/EndpointsCredentialsTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/EndpointsCredentialsTest.kt index 21494c8d58c..0beb50db35d 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/EndpointsCredentialsTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/EndpointsCredentialsTest.kt @@ -21,7 +21,8 @@ class EndpointsCredentialsTest { // 1. A rule that sets no authentication scheme—in this case, we should be using the default from the service // 2. A rule that sets a custom authentication scheme and that configures signing // The chosen path is controlled by static context parameters set on the operation - private val model = """ + private val model = + """ namespace aws.fooBaz use aws.api#service @@ -73,7 +74,7 @@ class EndpointsCredentialsTest { @http(uri: "/custom", method: "GET") @staticContextParams({ AuthMode: { value: "custom-auth" } }) operation CustomAuth { } - """.asSmithyModel() + """.asSmithyModel() @Test fun `endpoint rules configure auth in default and non-default case`() { @@ -97,8 +98,9 @@ class EndpointsCredentialsTest { assert!(auth_header.contains("/us-west-2/foobaz/aws4_request"), "{}", auth_header); """, "capture_request" to RuntimeType.captureRequest(context.runtimeConfig), - "Credentials" to AwsRuntimeType.awsCredentialTypesTestUtil(context.runtimeConfig) - .resolve("Credentials"), + "Credentials" to + AwsRuntimeType.awsCredentialTypesTestUtil(context.runtimeConfig) + .resolve("Credentials"), "Region" to AwsRuntimeType.awsTypes(context.runtimeConfig).resolve("region::Region"), ) } @@ -120,8 +122,9 @@ class EndpointsCredentialsTest { assert!(auth_header.contains("/region-custom-auth/name-custom-auth/aws4_request"), "{}", auth_header); """, "capture_request" to RuntimeType.captureRequest(context.runtimeConfig), - "Credentials" to AwsRuntimeType.awsCredentialTypesTestUtil(context.runtimeConfig) - .resolve("Credentials"), + "Credentials" to + AwsRuntimeType.awsCredentialTypesTestUtil(context.runtimeConfig) + .resolve("Credentials"), "Region" to AwsRuntimeType.awsTypes(context.runtimeConfig).resolve("region::Region"), ) } diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/InvocationIdDecoratorTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/InvocationIdDecoratorTest.kt index be0861a045b..849db468525 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/InvocationIdDecoratorTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/InvocationIdDecoratorTest.kt @@ -48,10 +48,12 @@ class InvocationIdDecoratorTest { """, *preludeScope, "tokio" to CargoDependency.Tokio.toType(), - "InvocationIdGenerator" to AwsRuntimeType.awsRuntime(rc) - .resolve("invocation_id::InvocationIdGenerator"), - "InvocationId" to AwsRuntimeType.awsRuntime(rc) - .resolve("invocation_id::InvocationId"), + "InvocationIdGenerator" to + AwsRuntimeType.awsRuntime(rc) + .resolve("invocation_id::InvocationIdGenerator"), + "InvocationId" to + AwsRuntimeType.awsRuntime(rc) + .resolve("invocation_id::InvocationId"), "BoxError" to RuntimeType.boxError(rc), "capture_request" to RuntimeType.captureRequest(rc), ) diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/OperationInputTestGeneratorTests.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/OperationInputTestGeneratorTests.kt index 91c7f6be91a..472d8159956 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/OperationInputTestGeneratorTests.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/OperationInputTestGeneratorTests.kt @@ -18,13 +18,15 @@ class OperationInputTestGeneratorTests { @Test fun `finds operation shape by name`() { val prefix = "\$version: \"2\"" - val operationModel = """ + val operationModel = + """ $prefix namespace operations operation Ping {} - """.trimIndent() - val serviceModel = """ + """.trimIndent() + val serviceModel = + """ $prefix namespace service @@ -33,19 +35,21 @@ class OperationInputTestGeneratorTests { service MyService { operations: [Ping] } - """.trimIndent() + """.trimIndent() - val model = Model.assembler() - .discoverModels() - .addUnparsedModel("operation.smithy", operationModel) - .addUnparsedModel("main.smithy", serviceModel) - .assemble() - .unwrap() + val model = + Model.assembler() + .discoverModels() + .addUnparsedModel("operation.smithy", operationModel) + .addUnparsedModel("main.smithy", serviceModel) + .assemble() + .unwrap() val context = testClientCodegenContext(model) - val testOperationInput = EndpointTestOperationInput.builder() - .operationName("Ping") - .build() + val testOperationInput = + EndpointTestOperationInput.builder() + .operationName("Ping") + .build() val operationId = context.operationId(testOperationInput) assertEquals("operations#Ping", operationId.toString()) @@ -53,18 +57,20 @@ class OperationInputTestGeneratorTests { @Test fun `fails for operation name not found`() { - val model = """ + val model = + """ namespace test operation Ping {} service MyService { operations: [Ping] } - """.trimIndent().asSmithyModel() + """.trimIndent().asSmithyModel() val context = testClientCodegenContext(model) - val testOperationInput = EndpointTestOperationInput.builder() - .operationName("Pong") - .build() + val testOperationInput = + EndpointTestOperationInput.builder() + .operationName("Pong") + .build() assertThrows { context.operationId(testOperationInput) } } diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/RegionDecoratorTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/RegionDecoratorTest.kt index cc003fc0864..61362caea7b 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/RegionDecoratorTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/RegionDecoratorTest.kt @@ -11,7 +11,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import kotlin.io.path.readText class RegionDecoratorTest { - private val modelWithoutRegionParamOrSigV4AuthScheme = """ + private val modelWithoutRegionParamOrSigV4AuthScheme = + """ namespace test use aws.api#service @@ -28,9 +29,10 @@ class RegionDecoratorTest { service TestService { version: "2023-01-01", operations: [SomeOperation] } structure SomeOutput { something: String } operation SomeOperation { output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() - private val modelWithRegionParam = """ + private val modelWithRegionParam = + """ namespace test use aws.api#service @@ -49,9 +51,10 @@ class RegionDecoratorTest { service TestService { version: "2023-01-01", operations: [SomeOperation] } structure SomeOutput { something: String } operation SomeOperation { output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() - private val modelWithSigV4AuthScheme = """ + private val modelWithSigV4AuthScheme = + """ namespace test use aws.auth#sigv4 @@ -71,31 +74,34 @@ class RegionDecoratorTest { service TestService { version: "2023-01-01", operations: [SomeOperation] } structure SomeOutput { something: String } operation SomeOperation { output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() @Test fun `models without region built-in params or SigV4 should not have configurable regions`() { - val path = awsSdkIntegrationTest(modelWithoutRegionParamOrSigV4AuthScheme) { _, _ -> - // it should generate and compile successfully - } + val path = + awsSdkIntegrationTest(modelWithoutRegionParamOrSigV4AuthScheme) { _, _ -> + // it should generate and compile successfully + } val configContents = path.resolve("src/config.rs").readText() assertFalse(configContents.contains("fn set_region(")) } @Test fun `models with region built-in params should have configurable regions`() { - val path = awsSdkIntegrationTest(modelWithRegionParam) { _, _ -> - // it should generate and compile successfully - } + val path = + awsSdkIntegrationTest(modelWithRegionParam) { _, _ -> + // it should generate and compile successfully + } val configContents = path.resolve("src/config.rs").readText() assertTrue(configContents.contains("fn set_region(")) } @Test fun `models with SigV4 should have configurable regions`() { - val path = awsSdkIntegrationTest(modelWithSigV4AuthScheme) { _, _ -> - // it should generate and compile successfully - } + val path = + awsSdkIntegrationTest(modelWithSigV4AuthScheme) { _, _ -> + // it should generate and compile successfully + } val configContents = path.resolve("src/config.rs").readText() assertTrue(configContents.contains("fn set_region(")) } diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/RegionProviderConfigTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/RegionProviderConfigTest.kt index 62312b3ae01..a0c12525533 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/RegionProviderConfigTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/RegionProviderConfigTest.kt @@ -13,7 +13,7 @@ import software.amazon.smithy.rust.codegen.core.testutil.unitTest internal class RegionProviderConfigTest { @Test fun `generates a valid config`() { - awsSdkIntegrationTest(SdkCodegenIntegrationTest.model) { _ctx, crate -> + awsSdkIntegrationTest(SdkCodegenIntegrationTest.model) { _, crate -> crate.unitTest { rustTemplate("let conf: Option = None; let _reg: Option = conf.and_then(|c|c.region().cloned());") } diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecoratorTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecoratorTest.kt index 64f35d197fa..5183d4051a2 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecoratorTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecoratorTest.kt @@ -8,7 +8,8 @@ import org.junit.jupiter.api.Test import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel class SigV4AuthDecoratorTest { - private val modelWithSigV4AuthScheme = """ + private val modelWithSigV4AuthScheme = + """ namespace test use aws.auth#sigv4 @@ -55,7 +56,7 @@ class SigV4AuthDecoratorTest { @unsignedPayload @http(uri: "/", method: "POST") operation SomeOperation { input: SomeInput, output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() @Test fun unsignedPayloadSetsCorrectHeader() { diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/TestUtil.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/TestUtil.kt index ad08e25aebf..0da78519c07 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/TestUtil.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/TestUtil.kt @@ -21,50 +21,57 @@ import java.io.File // In aws-sdk-codegen, the working dir when gradle runs tests is actually `./aws`. So, to find the smithy runtime, we need // to go up one more level -val AwsTestRuntimeConfig = TestRuntimeConfig.copy( - runtimeCrateLocation = run { - val path = File("../../rust-runtime") - check(path.exists()) { "$path must exist to generate a working SDK" } - RuntimeCrateLocation.Path(path.absolutePath) - }, -) - -fun awsTestCodegenContext(model: Model? = null, settings: ClientRustSettings? = null) = - testClientCodegenContext( - model ?: "namespace test".asSmithyModel(), - settings = settings ?: testClientRustSettings(runtimeConfig = AwsTestRuntimeConfig), +val AwsTestRuntimeConfig = + TestRuntimeConfig.copy( + runtimeCrateLocation = + run { + val path = File("../../rust-runtime") + check(path.exists()) { "$path must exist to generate a working SDK" } + RuntimeCrateLocation.path(path.absolutePath) + }, ) +fun awsTestCodegenContext( + model: Model? = null, + settings: ClientRustSettings? = null, +) = testClientCodegenContext( + model ?: "namespace test".asSmithyModel(), + settings = settings ?: testClientRustSettings(runtimeConfig = AwsTestRuntimeConfig), +) + fun awsSdkIntegrationTest( model: Model, params: IntegrationTestParams = awsIntegrationTestParams(), test: (ClientCodegenContext, RustCrate) -> Unit = { _, _ -> }, -) = - clientIntegrationTest( - model, - awsIntegrationTestParams(), - test = test, - ) +) = clientIntegrationTest( + model, + params, + test = test, +) -fun awsIntegrationTestParams() = IntegrationTestParams( - cargoCommand = "cargo test --features test-util behavior-version-latest", - runtimeConfig = AwsTestRuntimeConfig, - additionalSettings = ObjectNode.builder().withMember( - "customizationConfig", - ObjectNode.builder() - .withMember( - "awsSdk", +fun awsIntegrationTestParams() = + IntegrationTestParams( + cargoCommand = "cargo test --features test-util behavior-version-latest", + runtimeConfig = AwsTestRuntimeConfig, + additionalSettings = + ObjectNode.builder().withMember( + "customizationConfig", ObjectNode.builder() - .withMember("generateReadme", false) - .withMember("integrationTestPath", "../sdk/integration-tests") - .build(), - ).build(), + .withMember( + "awsSdk", + ObjectNode.builder() + .withMember("awsSdkBuild", true) + .withMember("suppressReadme", true) + .withMember("integrationTestPath", "../sdk/integration-tests") + .withMember("partitionsConfigPath", "../sdk/aws-models/sdk-partitions.json") + .build(), + ).build(), + ) + .withMember( + "codegen", + ObjectNode.builder() + .withMember("includeFluentClient", false) + .withMember("includeEndpointUrlConfig", false) + .build(), + ).build(), ) - .withMember( - "codegen", - ObjectNode.builder() - .withMember("includeFluentClient", false) - .withMember("includeEndpointUrlConfig", false) - .build(), - ).build(), -) diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/customize/RemoveDefaultsTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/customize/RemoveDefaultsTest.kt index 1ecc0e650e2..1443b5c3457 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/customize/RemoveDefaultsTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/customize/RemoveDefaultsTest.kt @@ -18,11 +18,13 @@ import software.amazon.smithy.rust.codegen.core.util.shapeId internal class RemoveDefaultsTest { @Test fun `defaults should be removed`() { - val removeDefaults = setOf( - "test#Bar".shapeId(), - "test#Foo\$baz".shapeId(), - ) - val baseModel = """ + val removeDefaults = + setOf( + "test#Bar".shapeId(), + "test#Foo\$baz".shapeId(), + ) + val baseModel = + """ namespace test structure Foo { @@ -33,7 +35,7 @@ internal class RemoveDefaultsTest { @default(0) integer Bar - """.asSmithyModel(smithyVersion = "2.0") + """.asSmithyModel(smithyVersion = "2.0") val model = RemoveDefaults.processModel(baseModel, removeDefaults) val barMember = model.lookup("test#Foo\$bar") barMember.hasTrait() shouldBe false diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/customize/ec2/EC2MakePrimitivesOptionalTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/customize/ec2/EC2MakePrimitivesOptionalTest.kt index ae919497f0f..9a6510e6c01 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/customize/ec2/EC2MakePrimitivesOptionalTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/customize/ec2/EC2MakePrimitivesOptionalTest.kt @@ -22,7 +22,8 @@ internal class EC2MakePrimitivesOptionalTest { "CLIENT_ZERO_VALUE_V1_NO_INPUT", ) fun `primitive shapes are boxed`(nullabilityCheckMode: NullableIndex.CheckMode) { - val baseModel = """ + val baseModel = + """ namespace test structure Primitives { int: PrimitiveInteger, @@ -38,7 +39,7 @@ internal class EC2MakePrimitivesOptionalTest { structure Other {} - """.asSmithyModel() + """.asSmithyModel() val model = EC2MakePrimitivesOptional.processModel(baseModel) val nullableIndex = NullableIndex(model) val struct = model.lookup("test#Primitives") diff --git a/aws/sdk/aws-models/bedrock-runtime.json b/aws/sdk/aws-models/bedrock-runtime.json index 571e87e4eb4..001c0cdde17 100644 --- a/aws/sdk/aws-models/bedrock-runtime.json +++ b/aws/sdk/aws-models/bedrock-runtime.json @@ -786,7 +786,7 @@ "min": 1, "max": 2048 }, - "smithy.api#pattern": "^(arn:aws(-[^:]+)?:bedrock:[a-z0-9-]{1,20}:(([0-9]{12}:custom-model/[a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}/[a-z0-9]{12})|(:foundation-model/[a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}([.]?[a-z0-9-]{1,63}))|([0-9]{12}:provisioned-model/[a-z0-9]{12})))|([a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}([.]?[a-z0-9-]{1,63}))|(([0-9a-zA-Z][_-]?)+)$" + "smithy.api#pattern": "^(arn:aws(-[^:]+)?:bedrock:[a-z0-9-]{1,20}:(([0-9]{12}:custom-model/[a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}/[a-z0-9]{12})|(:foundation-model/[a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}([.:]?[a-z0-9-]{1,63}))|([0-9]{12}:provisioned-model/[a-z0-9]{12})))|([a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}([.:]?[a-z0-9-]{1,63}))|(([0-9a-zA-Z][_-]?)+)$" } }, "com.amazonaws.bedrockruntime#InvokeModelRequest": { diff --git a/aws/sdk/aws-models/config.json b/aws/sdk/aws-models/config.json index 386955ec097..7ab3db4e379 100644 --- a/aws/sdk/aws-models/config.json +++ b/aws/sdk/aws-models/config.json @@ -13782,6 +13782,108 @@ "traits": { "smithy.api#enumValue": "AWS::Batch::SchedulingPolicy" } + }, + "ACMPCACertificateAuthorityActivation": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::ACMPCA::CertificateAuthorityActivation" + } + }, + "AppMeshGatewayRoute": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::AppMesh::GatewayRoute" + } + }, + "AppMeshMesh": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::AppMesh::Mesh" + } + }, + "ConnectInstance": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::Connect::Instance" + } + }, + "ConnectQuickConnect": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::Connect::QuickConnect" + } + }, + "EC2CarrierGateway": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::EC2::CarrierGateway" + } + }, + "EC2IPAMPool": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::EC2::IPAMPool" + } + }, + "EC2TransitGatewayConnect": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::EC2::TransitGatewayConnect" + } + }, + "EC2TransitGatewayMulticastDomain": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::EC2::TransitGatewayMulticastDomain" + } + }, + "ECSCapacityProvider": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::ECS::CapacityProvider" + } + }, + "IAMInstanceProfile": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::IAM::InstanceProfile" + } + }, + "IoTCACertificate": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::IoT::CACertificate" + } + }, + "IoTTwinMakerSyncJob": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::IoTTwinMaker::SyncJob" + } + }, + "KafkaConnectConnector": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::KafkaConnect::Connector" + } + }, + "LambdaCodeSigningConfig": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::Lambda::CodeSigningConfig" + } + }, + "NetworkManagerConnectPeer": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::NetworkManager::ConnectPeer" + } + }, + "ResourceExplorer2Index": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AWS::ResourceExplorer2::Index" + } } } }, diff --git a/aws/sdk/aws-models/ec2.json b/aws/sdk/aws-models/ec2.json index 6afa836ebbf..79ce1e574cd 100644 --- a/aws/sdk/aws-models/ec2.json +++ b/aws/sdk/aws-models/ec2.json @@ -76,10 +76,10 @@ "com.amazonaws.ec2#AcceleratorManufacturer": { "type": "enum", "members": { - "NVIDIA": { + "AMAZON_WEB_SERVICES": { "target": "smithy.api#Unit", "traits": { - "smithy.api#enumValue": "nvidia" + "smithy.api#enumValue": "amazon-web-services" } }, "AMD": { @@ -88,10 +88,10 @@ "smithy.api#enumValue": "amd" } }, - "AMAZON_WEB_SERVICES": { + "NVIDIA": { "target": "smithy.api#Unit", "traits": { - "smithy.api#enumValue": "amazon-web-services" + "smithy.api#enumValue": "nvidia" } }, "XILINX": { @@ -120,22 +120,22 @@ "smithy.api#enumValue": "a100" } }, - "V100": { + "INFERENTIA": { "target": "smithy.api#Unit", "traits": { - "smithy.api#enumValue": "v100" + "smithy.api#enumValue": "inferentia" } }, - "K80": { + "K520": { "target": "smithy.api#Unit", "traits": { - "smithy.api#enumValue": "k80" + "smithy.api#enumValue": "k520" } }, - "T4": { + "K80": { "target": "smithy.api#Unit", "traits": { - "smithy.api#enumValue": "t4" + "smithy.api#enumValue": "k80" } }, "M60": { @@ -150,22 +150,22 @@ "smithy.api#enumValue": "radeon-pro-v520" } }, - "VU9P": { + "T4": { "target": "smithy.api#Unit", "traits": { - "smithy.api#enumValue": "vu9p" + "smithy.api#enumValue": "t4" } }, - "INFERENTIA": { + "VU9P": { "target": "smithy.api#Unit", "traits": { - "smithy.api#enumValue": "inferentia" + "smithy.api#enumValue": "vu9p" } }, - "K520": { + "V100": { "target": "smithy.api#Unit", "traits": { - "smithy.api#enumValue": "k520" + "smithy.api#enumValue": "v100" } } } @@ -1449,6 +1449,12 @@ "smithy.api#required": {} } }, + "Asn": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#documentation": "

The public 2-byte or 4-byte ASN that you want to advertise.

" + } + }, "DryRun": { "target": "com.amazonaws.ec2#Boolean", "traits": { @@ -1820,6 +1826,13 @@ "smithy.api#documentation": "

A preview of the next available CIDR in a pool.

" } }, + "AllowedCidrs": { + "target": "com.amazonaws.ec2#IpamPoolAllocationAllowedCidrs", + "traits": { + "smithy.api#documentation": "

Include a particular CIDR range that can be returned by the pool. Allowed CIDRs are only allowed if using netmask length for allocation.

", + "smithy.api#xmlName": "AllowedCidr" + } + }, "DisallowedCidrs": { "target": "com.amazonaws.ec2#IpamPoolAllocationDisallowedCidrs", "traits": { @@ -2155,6 +2168,9 @@ { "target": "com.amazonaws.ec2#AssociateInstanceEventWindow" }, + { + "target": "com.amazonaws.ec2#AssociateIpamByoasn" + }, { "target": "com.amazonaws.ec2#AssociateIpamResourceDiscovery" }, @@ -2725,6 +2741,9 @@ { "target": "com.amazonaws.ec2#DeprovisionByoipCidr" }, + { + "target": "com.amazonaws.ec2#DeprovisionIpamByoasn" + }, { "target": "com.amazonaws.ec2#DeprovisionIpamPoolCidr" }, @@ -2770,6 +2789,9 @@ { "target": "com.amazonaws.ec2#DescribeByoipCidrs" }, + { + "target": "com.amazonaws.ec2#DescribeCapacityBlockOfferings" + }, { "target": "com.amazonaws.ec2#DescribeCapacityReservationFleets" }, @@ -2896,6 +2918,9 @@ { "target": "com.amazonaws.ec2#DescribeInstanceStatus" }, + { + "target": "com.amazonaws.ec2#DescribeInstanceTopology" + }, { "target": "com.amazonaws.ec2#DescribeInstanceTypeOfferings" }, @@ -2905,6 +2930,9 @@ { "target": "com.amazonaws.ec2#DescribeInternetGateways" }, + { + "target": "com.amazonaws.ec2#DescribeIpamByoasn" + }, { "target": "com.amazonaws.ec2#DescribeIpamPools" }, @@ -2950,6 +2978,9 @@ { "target": "com.amazonaws.ec2#DescribeLocalGatewayVirtualInterfaces" }, + { + "target": "com.amazonaws.ec2#DescribeLockedSnapshots" + }, { "target": "com.amazonaws.ec2#DescribeManagedPrefixLists" }, @@ -3226,6 +3257,9 @@ { "target": "com.amazonaws.ec2#DisableSerialConsoleAccess" }, + { + "target": "com.amazonaws.ec2#DisableSnapshotBlockPublicAccess" + }, { "target": "com.amazonaws.ec2#DisableTransitGatewayRouteTablePropagation" }, @@ -3253,6 +3287,9 @@ { "target": "com.amazonaws.ec2#DisassociateInstanceEventWindow" }, + { + "target": "com.amazonaws.ec2#DisassociateIpamByoasn" + }, { "target": "com.amazonaws.ec2#DisassociateIpamResourceDiscovery" }, @@ -3313,6 +3350,9 @@ { "target": "com.amazonaws.ec2#EnableSerialConsoleAccess" }, + { + "target": "com.amazonaws.ec2#EnableSnapshotBlockPublicAccess" + }, { "target": "com.amazonaws.ec2#EnableTransitGatewayRouteTablePropagation" }, @@ -3394,6 +3434,9 @@ { "target": "com.amazonaws.ec2#GetIpamDiscoveredAccounts" }, + { + "target": "com.amazonaws.ec2#GetIpamDiscoveredPublicAddresses" + }, { "target": "com.amazonaws.ec2#GetIpamDiscoveredResourceCidrs" }, @@ -3433,6 +3476,9 @@ { "target": "com.amazonaws.ec2#GetSerialConsoleAccessStatus" }, + { + "target": "com.amazonaws.ec2#GetSnapshotBlockPublicAccessState" + }, { "target": "com.amazonaws.ec2#GetSpotPlacementScores" }, @@ -3499,6 +3545,9 @@ { "target": "com.amazonaws.ec2#ListSnapshotsInRecycleBin" }, + { + "target": "com.amazonaws.ec2#LockSnapshot" + }, { "target": "com.amazonaws.ec2#ModifyAddressAttribute" }, @@ -3703,12 +3752,18 @@ { "target": "com.amazonaws.ec2#ProvisionByoipCidr" }, + { + "target": "com.amazonaws.ec2#ProvisionIpamByoasn" + }, { "target": "com.amazonaws.ec2#ProvisionIpamPoolCidr" }, { "target": "com.amazonaws.ec2#ProvisionPublicIpv4PoolCidr" }, + { + "target": "com.amazonaws.ec2#PurchaseCapacityBlock" + }, { "target": "com.amazonaws.ec2#PurchaseHostReservation" }, @@ -3880,6 +3935,9 @@ { "target": "com.amazonaws.ec2#UnassignPrivateNatGatewayAddress" }, + { + "target": "com.amazonaws.ec2#UnlockSnapshot" + }, { "target": "com.amazonaws.ec2#UnmonitorInstances" }, @@ -5606,6 +5664,161 @@ } } }, + "com.amazonaws.ec2#AsnAssociation": { + "type": "structure", + "members": { + "Asn": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "Asn", + "smithy.api#documentation": "

The association's ASN.

", + "smithy.api#xmlName": "asn" + } + }, + "Cidr": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "Cidr", + "smithy.api#documentation": "

The association's CIDR.

", + "smithy.api#xmlName": "cidr" + } + }, + "StatusMessage": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "StatusMessage", + "smithy.api#documentation": "

The association's status message.

", + "smithy.api#xmlName": "statusMessage" + } + }, + "State": { + "target": "com.amazonaws.ec2#AsnAssociationState", + "traits": { + "aws.protocols#ec2QueryName": "State", + "smithy.api#documentation": "

The association's state.

", + "smithy.api#xmlName": "state" + } + } + }, + "traits": { + "smithy.api#documentation": "

An Autonomous System Number (ASN) and BYOIP CIDR association.

" + } + }, + "com.amazonaws.ec2#AsnAssociationSet": { + "type": "list", + "member": { + "target": "com.amazonaws.ec2#AsnAssociation", + "traits": { + "smithy.api#xmlName": "item" + } + } + }, + "com.amazonaws.ec2#AsnAssociationState": { + "type": "enum", + "members": { + "disassociated": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "disassociated" + } + }, + "failed_disassociation": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "failed-disassociation" + } + }, + "failed_association": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "failed-association" + } + }, + "pending_disassociation": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "pending-disassociation" + } + }, + "pending_association": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "pending-association" + } + }, + "associated": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "associated" + } + } + } + }, + "com.amazonaws.ec2#AsnAuthorizationContext": { + "type": "structure", + "members": { + "Message": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The authorization context's message.

", + "smithy.api#required": {} + } + }, + "Signature": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The authorization context's signature.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#documentation": "
" + } + }, + "com.amazonaws.ec2#AsnState": { + "type": "enum", + "members": { + "deprovisioned": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "deprovisioned" + } + }, + "failed_deprovision": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "failed-deprovision" + } + }, + "failed_provision": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "failed-provision" + } + }, + "pending_deprovision": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "pending-deprovision" + } + }, + "pending_provision": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "pending-provision" + } + }, + "provisioned": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "provisioned" + } + } + } + }, "com.amazonaws.ec2#AssetId": { "type": "string" }, @@ -6347,6 +6560,64 @@ "smithy.api#output": {} } }, + "com.amazonaws.ec2#AssociateIpamByoasn": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#AssociateIpamByoasnRequest" + }, + "output": { + "target": "com.amazonaws.ec2#AssociateIpamByoasnResult" + }, + "traits": { + "smithy.api#documentation": "

Associates your Autonomous System Number (ASN) with a BYOIP CIDR that you own in the same Amazon Web Services Region. \n For more information, see Tutorial: Bring your ASN to IPAM in the Amazon VPC IPAM guide.

\n

After the association succeeds, the ASN is eligible for \n advertisement. You can view the association with DescribeByoipCidrs. You can advertise the CIDR with AdvertiseByoipCidr.

" + } + }, + "com.amazonaws.ec2#AssociateIpamByoasnRequest": { + "type": "structure", + "members": { + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, \n and provides an error response. If you have the required permissions, the error response is DryRunOperation. \n Otherwise, it is UnauthorizedOperation.

" + } + }, + "Asn": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

A public 2-byte or 4-byte ASN.

", + "smithy.api#required": {} + } + }, + "Cidr": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The BYOIP CIDR you want to associate with an ASN.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#AssociateIpamByoasnResult": { + "type": "structure", + "members": { + "AsnAssociation": { + "target": "com.amazonaws.ec2#AsnAssociation", + "traits": { + "aws.protocols#ec2QueryName": "AsnAssociation", + "smithy.api#documentation": "

The ASN and BYOIP CIDR association.

", + "smithy.api#xmlName": "asnAssociation" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#AssociateIpamResourceDiscovery": { "type": "operation", "input": { @@ -6591,7 +6862,7 @@ "target": "com.amazonaws.ec2#AssociateSubnetCidrBlockResult" }, "traits": { - "smithy.api#documentation": "

Associates a CIDR block with your subnet. You can only associate a single IPv6 CIDR\n block with your subnet. An IPv6 CIDR block must have a prefix length of /64.

" + "smithy.api#documentation": "

Associates a CIDR block with your subnet. You can only associate a single IPv6 CIDR\n block with your subnet.

" } }, "com.amazonaws.ec2#AssociateSubnetCidrBlockRequest": { @@ -6601,9 +6872,7 @@ "target": "com.amazonaws.ec2#String", "traits": { "aws.protocols#ec2QueryName": "Ipv6CidrBlock", - "smithy.api#clientOptional": {}, - "smithy.api#documentation": "

The IPv6 CIDR block for your subnet. The subnet must have a /64 prefix\n length.

", - "smithy.api#required": {}, + "smithy.api#documentation": "

The IPv6 CIDR block for your subnet.

", "smithy.api#xmlName": "ipv6CidrBlock" } }, @@ -6616,6 +6885,18 @@ "smithy.api#required": {}, "smithy.api#xmlName": "subnetId" } + }, + "Ipv6IpamPoolId": { + "target": "com.amazonaws.ec2#IpamPoolId", + "traits": { + "smithy.api#documentation": "

An IPv6 IPAM pool ID.

" + } + }, + "Ipv6NetmaskLength": { + "target": "com.amazonaws.ec2#NetmaskLength", + "traits": { + "smithy.api#documentation": "

An IPv6 netmask length.

" + } } }, "traits": { @@ -6837,7 +7118,7 @@ "target": "com.amazonaws.ec2#AssociateTrunkInterfaceResult" }, "traits": { - "smithy.api#documentation": "\n

This API action is currently in limited preview only. \n If you are interested in using this feature, contact your account manager.

\n
\n

Associates a branch network interface with a trunk network interface.

\n

Before you create the association, run the create-network-interface command and set\n --interface-type to trunk. You must also create a network interface for each branch network interface that you want to associate with the trunk network interface.

" + "smithy.api#documentation": "

Associates a branch network interface with a trunk network interface.

\n

Before you create the association, run the create-network-interface command and set\n --interface-type to trunk. You must also create a network interface for each branch network interface that you want to associate with the trunk network interface.

" } }, "com.amazonaws.ec2#AssociateTrunkInterfaceRequest": { @@ -6922,7 +7203,7 @@ "target": "com.amazonaws.ec2#AssociateVpcCidrBlockResult" }, "traits": { - "smithy.api#documentation": "

Associates a CIDR block with your VPC. You can associate a secondary IPv4 CIDR block,\n an Amazon-provided IPv6 CIDR block, or an IPv6 CIDR block from an IPv6 address pool that\n you provisioned through bring your own IP addresses (BYOIP). The IPv6 CIDR block size is fixed\n at /56.

\n

You must specify one of the following in the request: an IPv4 CIDR block, an IPv6\n pool, or an Amazon-provided IPv6 CIDR block.

\n

For more information about associating CIDR blocks with your VPC and applicable\n restrictions, see IP addressing for your VPCs and subnets \n in the Amazon VPC User Guide.

" + "smithy.api#documentation": "

Associates a CIDR block with your VPC. You can associate a secondary IPv4 CIDR block,\n an Amazon-provided IPv6 CIDR block, or an IPv6 CIDR block from an IPv6 address pool that\n you provisioned through bring your own IP addresses (BYOIP).

\n

You must specify one of the following in the request: an IPv4 CIDR block, an IPv6\n pool, or an Amazon-provided IPv6 CIDR block.

\n

For more information about associating CIDR blocks with your VPC and applicable\n restrictions, see IP addressing for your VPCs and subnets \n in the Amazon VPC User Guide.

" } }, "com.amazonaws.ec2#AssociateVpcCidrBlockRequest": { @@ -6932,7 +7213,7 @@ "target": "com.amazonaws.ec2#Boolean", "traits": { "aws.protocols#ec2QueryName": "AmazonProvidedIpv6CidrBlock", - "smithy.api#documentation": "

Requests an Amazon-provided IPv6 CIDR block with a /56 prefix length for the VPC. You cannot specify the range of IPv6 addresses, or the size of the CIDR block.

", + "smithy.api#documentation": "

Requests an Amazon-provided IPv6 CIDR block with a /56 prefix length for the VPC. You\n cannot specify the range of IPv6 addresses or the size of the CIDR block.

", "smithy.api#xmlName": "amazonProvidedIpv6CidrBlock" } }, @@ -7540,7 +7821,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessTrustProvider", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessTrustProvider", - "smithy.api#documentation": "

The ID of the Verified Access trust provider.

", + "smithy.api#documentation": "

Details about the Verified Access trust provider.

", "smithy.api#xmlName": "verifiedAccessTrustProvider" } }, @@ -7548,7 +7829,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessInstance", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessInstance", - "smithy.api#documentation": "

The ID of the Verified Access instance.

", + "smithy.api#documentation": "

Details about the Verified Access instance.

", "smithy.api#xmlName": "verifiedAccessInstance" } } @@ -7696,7 +7977,7 @@ "target": "com.amazonaws.ec2#Boolean", "traits": { "aws.protocols#ec2QueryName": "EnaSrdEnabled", - "smithy.api#documentation": "

Indicates whether ENA Express is enabled for the network interface that's attached to the\n\t\t\tinstance.

", + "smithy.api#documentation": "

Indicates whether ENA Express is enabled for the network interface.

", "smithy.api#xmlName": "enaSrdEnabled" } }, @@ -7704,13 +7985,13 @@ "target": "com.amazonaws.ec2#AttachmentEnaSrdUdpSpecification", "traits": { "aws.protocols#ec2QueryName": "EnaSrdUdpSpecification", - "smithy.api#documentation": "

ENA Express configuration for UDP network traffic.

", + "smithy.api#documentation": "

Configures ENA Express for UDP network traffic.

", "smithy.api#xmlName": "enaSrdUdpSpecification" } } }, "traits": { - "smithy.api#documentation": "

Describes the ENA Express configuration for the network interface that's attached to the instance.

" + "smithy.api#documentation": "

ENA Express uses Amazon Web Services Scalable Reliable Datagram (SRD) technology to increase the\n\t\t\tmaximum bandwidth used per stream and minimize tail latency of network traffic between EC2 instances.\n\t\t\tWith ENA Express, you can communicate between two EC2 instances in the same subnet within the same\n\t\t\taccount, or in different accounts. Both sending and receiving instances must have ENA Express enabled.

\n

To improve the reliability of network packet delivery, ENA Express reorders network packets on the\n\t\t\treceiving end by default. However, some UDP-based applications are designed to handle network packets\n\t\t\tthat are out of order to reduce the overhead for packet delivery at the network layer. When ENA Express\n\t\t\tis enabled, you can specify whether UDP network traffic uses it.

" } }, "com.amazonaws.ec2#AttachmentEnaSrdUdpSpecification": { @@ -7720,13 +8001,13 @@ "target": "com.amazonaws.ec2#Boolean", "traits": { "aws.protocols#ec2QueryName": "EnaSrdUdpEnabled", - "smithy.api#documentation": "

Indicates whether UDP traffic to and from the instance uses ENA Express. To specify this setting, \n\t\t\tyou must first enable ENA Express.

", + "smithy.api#documentation": "

Indicates whether UDP traffic to and from the instance uses ENA Express. To specify this setting,\n\t\t\tyou must first enable ENA Express.

", "smithy.api#xmlName": "enaSrdUdpEnabled" } } }, "traits": { - "smithy.api#documentation": "

Describes the ENA Express configuration for UDP traffic on the network interface that's attached to \n\t\t\tthe instance.

" + "smithy.api#documentation": "

ENA Express is compatible with both TCP and UDP transport protocols. When it's enabled, TCP traffic\n\t\t\tautomatically uses it. However, some UDP-based applications are designed to handle network packets that are\n\t\t\tout of order, without a need for retransmission, such as live video broadcasting or other near-real-time\n\t\t\tapplications. For UDP traffic, you can specify whether to use ENA Express, based on your application\n\t\t\tenvironment needs.

" } }, "com.amazonaws.ec2#AttachmentStatus": { @@ -7947,7 +8228,7 @@ "target": "com.amazonaws.ec2#AuthorizeSecurityGroupEgressResult" }, "traits": { - "smithy.api#documentation": "

Adds the specified outbound (egress) rules to a security group for use with a VPC.

\n

An outbound rule permits instances to send traffic to the specified IPv4 or IPv6 CIDR\n address ranges, or to the instances that are associated with the specified source\n security groups. When specifying an outbound rule for your security group in a VPC, the\n IpPermissions must include a destination for the traffic.

\n

You specify a protocol for each rule (for example, TCP). \n For the TCP and UDP protocols, you must also specify the destination port or port range. \n For the ICMP protocol, you must also specify the ICMP type and code. \n You can use -1 for the type or code to mean all types or all codes.

\n

Rule changes are propagated to affected instances as quickly as possible. However, a small delay might occur.

\n

For information about VPC security group quotas, see Amazon VPC quotas.

", + "smithy.api#documentation": "

Adds the specified outbound (egress) rules to a security group for use with a VPC.

\n

An outbound rule permits instances to send traffic to the specified IPv4 or IPv6 CIDR\n address ranges, or to the instances that are associated with the specified source\n security groups. When specifying an outbound rule for your security group in a VPC, the\n IpPermissions must include a destination for the traffic.

\n

You specify a protocol for each rule (for example, TCP). \n For the TCP and UDP protocols, you must also specify the destination port or port range. \n For the ICMP protocol, you must also specify the ICMP type and code. \n You can use -1 for the type or code to mean all types or all codes.

\n

Rule changes are propagated to affected instances as quickly as possible. However, a small delay might occur.

\n

For information about VPC security group quotas, see Amazon VPC quotas.

\n \n

If you want to reference a security group across VPCs attached to a transit gateway using the\n security group\n referencing feature, note that you can only reference security groups\n for ingress rules. You cannot reference a security group for egress rules.

\n
", "smithy.api#examples": [ { "title": "To add a rule that allows outbound traffic to a specific address range", @@ -9040,6 +9321,55 @@ "com.amazonaws.ec2#BurstablePerformanceFlag": { "type": "boolean" }, + "com.amazonaws.ec2#Byoasn": { + "type": "structure", + "members": { + "Asn": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "Asn", + "smithy.api#documentation": "

A public 2-byte or 4-byte ASN.

", + "smithy.api#xmlName": "asn" + } + }, + "IpamId": { + "target": "com.amazonaws.ec2#IpamId", + "traits": { + "aws.protocols#ec2QueryName": "IpamId", + "smithy.api#documentation": "

An IPAM ID.

", + "smithy.api#xmlName": "ipamId" + } + }, + "StatusMessage": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "StatusMessage", + "smithy.api#documentation": "

The status message.

", + "smithy.api#xmlName": "statusMessage" + } + }, + "State": { + "target": "com.amazonaws.ec2#AsnState", + "traits": { + "aws.protocols#ec2QueryName": "State", + "smithy.api#documentation": "

The provisioning state of the BYOASN.

", + "smithy.api#xmlName": "state" + } + } + }, + "traits": { + "smithy.api#documentation": "

The Autonomous System Number (ASN) and BYOIP CIDR association.

" + } + }, + "com.amazonaws.ec2#ByoasnSet": { + "type": "list", + "member": { + "target": "com.amazonaws.ec2#Byoasn", + "traits": { + "smithy.api#xmlName": "item" + } + } + }, "com.amazonaws.ec2#ByoipCidr": { "type": "structure", "members": { @@ -9059,6 +9389,14 @@ "smithy.api#xmlName": "description" } }, + "AsnAssociations": { + "target": "com.amazonaws.ec2#AsnAssociationSet", + "traits": { + "aws.protocols#ec2QueryName": "AsnAssociationSet", + "smithy.api#documentation": "

The BYOIP CIDR associations with ASNs.

", + "smithy.api#xmlName": "asnAssociationSet" + } + }, "StatusMessage": { "target": "com.amazonaws.ec2#String", "traits": { @@ -9976,6 +10314,103 @@ } } }, + "com.amazonaws.ec2#CapacityBlockOffering": { + "type": "structure", + "members": { + "CapacityBlockOfferingId": { + "target": "com.amazonaws.ec2#OfferingId", + "traits": { + "aws.protocols#ec2QueryName": "CapacityBlockOfferingId", + "smithy.api#documentation": "

The ID of the Capacity Block offering.

", + "smithy.api#xmlName": "capacityBlockOfferingId" + } + }, + "InstanceType": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "InstanceType", + "smithy.api#documentation": "

The instance type of the Capacity Block offering.

", + "smithy.api#xmlName": "instanceType" + } + }, + "AvailabilityZone": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "AvailabilityZone", + "smithy.api#documentation": "

The Availability Zone of the Capacity Block offering.

", + "smithy.api#xmlName": "availabilityZone" + } + }, + "InstanceCount": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "aws.protocols#ec2QueryName": "InstanceCount", + "smithy.api#documentation": "

The number of instances in the Capacity Block offering.

", + "smithy.api#xmlName": "instanceCount" + } + }, + "StartDate": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "aws.protocols#ec2QueryName": "StartDate", + "smithy.api#documentation": "

The start date of the Capacity Block offering.

", + "smithy.api#xmlName": "startDate" + } + }, + "EndDate": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "aws.protocols#ec2QueryName": "EndDate", + "smithy.api#documentation": "

The end date of the Capacity Block offering.

", + "smithy.api#xmlName": "endDate" + } + }, + "CapacityBlockDurationHours": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "aws.protocols#ec2QueryName": "CapacityBlockDurationHours", + "smithy.api#documentation": "

The amount of time of the Capacity Block reservation in hours.

", + "smithy.api#xmlName": "capacityBlockDurationHours" + } + }, + "UpfrontFee": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "UpfrontFee", + "smithy.api#documentation": "

The total price to be paid up front.

", + "smithy.api#xmlName": "upfrontFee" + } + }, + "CurrencyCode": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "CurrencyCode", + "smithy.api#documentation": "

The currency of the payment for the Capacity Block.

", + "smithy.api#xmlName": "currencyCode" + } + }, + "Tenancy": { + "target": "com.amazonaws.ec2#CapacityReservationTenancy", + "traits": { + "aws.protocols#ec2QueryName": "Tenancy", + "smithy.api#documentation": "

The tenancy of the Capacity Block.

", + "smithy.api#xmlName": "tenancy" + } + } + }, + "traits": { + "smithy.api#documentation": "

The recommended Capacity Block that fits your search requirements.

" + } + }, + "com.amazonaws.ec2#CapacityBlockOfferingSet": { + "type": "list", + "member": { + "target": "com.amazonaws.ec2#CapacityBlockOffering", + "traits": { + "smithy.api#xmlName": "item" + } + } + }, "com.amazonaws.ec2#CapacityReservation": { "type": "structure", "members": { @@ -10162,6 +10597,14 @@ "smithy.api#documentation": "

Information about instance capacity usage.

", "smithy.api#xmlName": "capacityAllocationSet" } + }, + "ReservationType": { + "target": "com.amazonaws.ec2#CapacityReservationType", + "traits": { + "aws.protocols#ec2QueryName": "ReservationType", + "smithy.api#documentation": "

The type of Capacity Reservation.

", + "smithy.api#xmlName": "reservationType" + } } }, "traits": { @@ -10683,6 +11126,24 @@ "traits": { "smithy.api#enumValue": "failed" } + }, + "scheduled": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "scheduled" + } + }, + "payment_pending": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "payment-pending" + } + }, + "payment_failed": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "payment-failed" + } } } }, @@ -10747,6 +11208,23 @@ } } }, + "com.amazonaws.ec2#CapacityReservationType": { + "type": "enum", + "members": { + "DEFAULT": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "default" + } + }, + "CAPACITY_BLOCK": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "capacity-block" + } + } + } + }, "com.amazonaws.ec2#CarrierGateway": { "type": "structure", "members": { @@ -11240,9 +11718,6 @@ "smithy.api#sensitive": {} } }, - "com.amazonaws.ec2#ClientVpnAssociationId": { - "type": "string" - }, "com.amazonaws.ec2#ClientVpnAuthentication": { "type": "structure", "members": { @@ -12502,6 +12977,128 @@ } } }, + "com.amazonaws.ec2#ConnectionTrackingConfiguration": { + "type": "structure", + "members": { + "TcpEstablishedTimeout": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "aws.protocols#ec2QueryName": "TcpEstablishedTimeout", + "smithy.api#documentation": "

Timeout (in seconds) for idle TCP\n\t\t\t\t\t\tconnections in an established state. Min: 60 seconds. Max: 432000 seconds (5\n\t\t\t\t\t\tdays). Default: 432000 seconds. Recommended: Less than 432000 seconds.

", + "smithy.api#xmlName": "tcpEstablishedTimeout" + } + }, + "UdpStreamTimeout": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "aws.protocols#ec2QueryName": "UdpStreamTimeout", + "smithy.api#documentation": "

Timeout (in seconds) for idle UDP\n\t\t\t\t\t\tflows classified as streams which have seen more than one request-response\n\t\t\t\t\t\ttransaction. Min: 60 seconds. Max: 180 seconds (3 minutes). Default: 180\n\t\t\t\t\t\tseconds.

", + "smithy.api#xmlName": "udpStreamTimeout" + } + }, + "UdpTimeout": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "aws.protocols#ec2QueryName": "UdpTimeout", + "smithy.api#documentation": "

Timeout (in seconds) for idle UDP flows that\n\t\t\t\t\t\thave seen traffic only in a single direction or a single request-response\n\t\t\t\t\t\ttransaction. Min: 30 seconds. Max: 60 seconds. Default: 30 seconds.

", + "smithy.api#xmlName": "udpTimeout" + } + } + }, + "traits": { + "smithy.api#documentation": "

A security group connection tracking configuration that enables you to set the idle timeout for connection tracking on an Elastic network interface. For more information, see Connection tracking timeouts in the Amazon Elastic Compute Cloud User Guide.

" + } + }, + "com.amazonaws.ec2#ConnectionTrackingSpecification": { + "type": "structure", + "members": { + "TcpEstablishedTimeout": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "aws.protocols#ec2QueryName": "TcpEstablishedTimeout", + "smithy.api#documentation": "

Timeout (in seconds) for idle TCP\n\t\t\t\t\t\tconnections in an established state. Min: 60 seconds. Max: 432000 seconds (5\n\t\t\t\t\t\tdays). Default: 432000 seconds. Recommended: Less than 432000 seconds.

", + "smithy.api#xmlName": "tcpEstablishedTimeout" + } + }, + "UdpTimeout": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "aws.protocols#ec2QueryName": "UdpTimeout", + "smithy.api#documentation": "

Timeout (in seconds) for idle UDP flows that\n\t\t\t\t\t\thave seen traffic only in a single direction or a single request-response\n\t\t\t\t\t\ttransaction. Min: 30 seconds. Max: 60 seconds. Default: 30 seconds.

", + "smithy.api#xmlName": "udpTimeout" + } + }, + "UdpStreamTimeout": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "aws.protocols#ec2QueryName": "UdpStreamTimeout", + "smithy.api#documentation": "

Timeout (in seconds) for idle UDP\n\t\t\t\t\t\tflows classified as streams which have seen more than one request-response\n\t\t\t\t\t\ttransaction. Min: 60 seconds. Max: 180 seconds (3 minutes). Default: 180\n\t\t\t\t\t\tseconds.

", + "smithy.api#xmlName": "udpStreamTimeout" + } + } + }, + "traits": { + "smithy.api#documentation": "

A security group connection tracking specification that enables you to set the idle timeout for connection tracking on an Elastic network interface. For more information, see Connection tracking timeouts in the Amazon Elastic Compute Cloud User Guide.

" + } + }, + "com.amazonaws.ec2#ConnectionTrackingSpecificationRequest": { + "type": "structure", + "members": { + "TcpEstablishedTimeout": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "smithy.api#documentation": "

Timeout (in seconds) for idle TCP\n\t\t\t\t\t\tconnections in an established state. Min: 60 seconds. Max: 432000 seconds (5\n\t\t\t\t\t\tdays). Default: 432000 seconds. Recommended: Less than 432000 seconds.

" + } + }, + "UdpStreamTimeout": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "smithy.api#documentation": "

Timeout (in seconds) for idle UDP\n\t\t\t\t\t\tflows classified as streams which have seen more than one request-response\n\t\t\t\t\t\ttransaction. Min: 60 seconds. Max: 180 seconds (3 minutes). Default: 180\n\t\t\t\t\t\tseconds.

" + } + }, + "UdpTimeout": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "smithy.api#documentation": "

Timeout (in seconds) for idle UDP flows that\n\t\t\t\t\t\thave seen traffic only in a single direction or a single request-response\n\t\t\t\t\t\ttransaction. Min: 30 seconds. Max: 60 seconds. Default: 30 seconds.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

A security group connection tracking specification request that enables you to set the idle timeout for connection tracking on an Elastic network interface. For more information, see Connection tracking timeouts in the Amazon Elastic Compute Cloud User Guide.

" + } + }, + "com.amazonaws.ec2#ConnectionTrackingSpecificationResponse": { + "type": "structure", + "members": { + "TcpEstablishedTimeout": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "aws.protocols#ec2QueryName": "TcpEstablishedTimeout", + "smithy.api#documentation": "

Timeout (in seconds) for idle TCP\n\t\t\t\t\t\tconnections in an established state. Min: 60 seconds. Max: 432000 seconds (5\n\t\t\t\t\t\tdays). Default: 432000 seconds. Recommended: Less than 432000 seconds.

", + "smithy.api#xmlName": "tcpEstablishedTimeout" + } + }, + "UdpStreamTimeout": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "aws.protocols#ec2QueryName": "UdpStreamTimeout", + "smithy.api#documentation": "

Timeout (in seconds) for idle UDP\n\t\t\t\t\t\tflows classified as streams which have seen more than one request-response\n\t\t\t\t\t\ttransaction. Min: 60 seconds. Max: 180 seconds (3 minutes). Default: 180\n\t\t\t\t\t\tseconds.

", + "smithy.api#xmlName": "udpStreamTimeout" + } + }, + "UdpTimeout": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "aws.protocols#ec2QueryName": "UdpTimeout", + "smithy.api#documentation": "

Timeout (in seconds) for idle UDP flows that\n\t\t\t\t\t\thave seen traffic only in a single direction or a single request-response\n\t\t\t\t\t\ttransaction. Min: 30 seconds. Max: 60 seconds. Default: 30 seconds.

", + "smithy.api#xmlName": "udpTimeout" + } + } + }, + "traits": { + "smithy.api#documentation": "

A security group connection tracking specification response that enables you to set the idle timeout for connection tracking on an Elastic network interface. For more information, see Connection tracking timeouts in the Amazon Elastic Compute Cloud User Guide.

" + } + }, "com.amazonaws.ec2#ConnectivityType": { "type": "enum", "members": { @@ -12635,6 +13232,18 @@ } } }, + "com.amazonaws.ec2#CoolOffPeriodRequestHours": { + "type": "integer", + "traits": { + "smithy.api#range": { + "min": 1, + "max": 72 + } + } + }, + "com.amazonaws.ec2#CoolOffPeriodResponseHours": { + "type": "integer" + }, "com.amazonaws.ec2#CopyFpgaImage": { "type": "operation", "input": { @@ -14710,7 +15319,7 @@ "target": "com.amazonaws.ec2#BlockDeviceMappingRequestList", "traits": { "aws.protocols#ec2QueryName": "BlockDeviceMapping", - "smithy.api#documentation": "

The block device mappings. This parameter cannot be used to modify the encryption \n \t\tstatus of existing volumes or snapshots. To create an AMI with encrypted snapshots, \n \t\tuse the CopyImage action.

", + "smithy.api#documentation": "

The block device mappings.

\n

When using the CreateImage action:

\n
    \n
  • \n

    You can't change the volume size using the VolumeSize parameter. If you want a\n different volume size, you must first change the volume size of the source\n instance.

    \n
  • \n
  • \n

    You can't modify the encryption status of existing volumes or snapshots. To create an\n AMI with volumes or snapshots that have a different encryption status (for example, where\n the source volume and snapshots are unencrypted, and you want to create an AMI with\n encrypted volumes or snapshots), use the CopyImage action.

    \n
  • \n
  • \n

    The only option that can be changed for existing mappings or snapshots is\n DeleteOnTermination.

    \n
  • \n
", "smithy.api#xmlName": "blockDeviceMapping" } }, @@ -15213,6 +15822,12 @@ "traits": { "smithy.api#documentation": "

The IP address source for pools in the public scope. Only used for provisioning IP address CIDRs to pools in the public scope. Default is byoip. For more information, see Create IPv6 pools in the Amazon VPC IPAM User Guide. \n By default, you can add only one Amazon-provided IPv6 CIDR block to a top-level IPv6 pool if PublicIpSource is amazon. For information on increasing the default limit, see Quotas for your IPAM in the Amazon VPC IPAM User Guide.

" } + }, + "SourceResource": { + "target": "com.amazonaws.ec2#IpamPoolSourceResourceRequest", + "traits": { + "smithy.api#documentation": "

The resource used to provision CIDRs to a resource planning pool.

" + } } }, "traits": { @@ -15270,6 +15885,12 @@ "smithy.api#documentation": "

A unique, case-sensitive identifier that you provide to ensure the idempotency of the request. For more information, see Ensuring Idempotency.

", "smithy.api#idempotencyToken": {} } + }, + "Tier": { + "target": "com.amazonaws.ec2#IpamTier", + "traits": { + "smithy.api#documentation": "

IPAM is offered in a Free Tier and an Advanced Tier. For more information about the features available in each tier and the costs associated with the tiers, see Amazon VPC pricing > IPAM tab.

" + } } }, "traits": { @@ -16869,6 +17490,12 @@ "traits": { "smithy.api#documentation": "

If you’re creating a network interface in a dual-stack or IPv6-only subnet, you have\n the option to assign a primary IPv6 IP address. A primary IPv6 address is an IPv6 GUA\n address associated with an ENI that you have enabled to use a primary IPv6 address. Use this option if the instance that\n this ENI will be attached to relies on its IPv6 address not changing. Amazon Web Services\n will automatically assign an IPv6 address associated with the ENI attached to your\n instance to be the primary IPv6 address. Once you enable an IPv6 GUA address to be a\n primary IPv6, you cannot disable it. When you enable an IPv6 GUA address to be a primary\n IPv6, the first IPv6 GUA will be made the primary IPv6 address until the instance is\n terminated or the network interface is detached. If you have multiple IPv6 addresses\n associated with an ENI attached to your instance and you enable a primary IPv6 address,\n the first IPv6 GUA address associated with the ENI becomes the primary IPv6\n address.

" } + }, + "ConnectionTrackingSpecification": { + "target": "com.amazonaws.ec2#ConnectionTrackingSpecificationRequest", + "traits": { + "smithy.api#documentation": "

A connection tracking specification for the network interface.

" + } } }, "traits": { @@ -17922,7 +18549,7 @@ "target": "com.amazonaws.ec2#CreateSubnetResult" }, "traits": { - "smithy.api#documentation": "

Creates a subnet in the specified VPC. For an IPv4 only subnet, specify an IPv4 CIDR block.\n If the VPC has an IPv6 CIDR block, you can create an IPv6 only subnet or a dual stack subnet instead.\n For an IPv6 only subnet, specify an IPv6 CIDR block. For a dual stack subnet, specify both\n an IPv4 CIDR block and an IPv6 CIDR block.

\n

A subnet CIDR block must not overlap the CIDR block of an existing subnet in the VPC.\n After you create a subnet, you can't change its CIDR block.

\n

The allowed size for an IPv4 subnet is between a /28 netmask (16 IP addresses) and \n a /16 netmask (65,536 IP addresses). Amazon Web Services reserves both the first four and \n the last IPv4 address in each subnet's CIDR block. They're not available for your use.

\n

If you've associated an IPv6 CIDR block with your VPC, you can associate an IPv6 CIDR block \n with a subnet when you create it. The allowed block size for an IPv6 subnet is a /64 netmask.

\n

If you add more than one subnet to a VPC, they're set up in a star topology with a\n logical router in the middle.

\n

When you stop an instance in a subnet, it retains its private IPv4 address. It's\n therefore possible to have a subnet with no running instances (they're all stopped), but\n no remaining IP addresses available.

\n

For more information, see Subnets in the Amazon VPC User Guide.

", + "smithy.api#documentation": "

Creates a subnet in the specified VPC. For an IPv4 only subnet, specify an IPv4 CIDR block.\n If the VPC has an IPv6 CIDR block, you can create an IPv6 only subnet or a dual stack subnet instead.\n For an IPv6 only subnet, specify an IPv6 CIDR block. For a dual stack subnet, specify both\n an IPv4 CIDR block and an IPv6 CIDR block.

\n

A subnet CIDR block must not overlap the CIDR block of an existing subnet in the VPC.\n After you create a subnet, you can't change its CIDR block.

\n

The allowed size for an IPv4 subnet is between a /28 netmask (16 IP addresses) and \n a /16 netmask (65,536 IP addresses). Amazon Web Services reserves both the first four and \n the last IPv4 address in each subnet's CIDR block. They're not available for your use.

\n

If you've associated an IPv6 CIDR block with your VPC, you can associate an IPv6 CIDR\n block with a subnet when you create it.

\n

If you add more than one subnet to a VPC, they're set up in a star topology with a\n logical router in the middle.

\n

When you stop an instance in a subnet, it retains its private IPv4 address. It's\n therefore possible to have a subnet with no running instances (they're all stopped), but\n no remaining IP addresses available.

\n

For more information, see Subnets in the Amazon VPC User Guide.

", "smithy.api#examples": [ { "title": "To create a subnet", @@ -18055,7 +18682,7 @@ "Ipv6CidrBlock": { "target": "com.amazonaws.ec2#String", "traits": { - "smithy.api#documentation": "

The IPv6 network range for the subnet, in CIDR notation. The subnet size must use a\n /64 prefix length.

\n

This parameter is required for an IPv6 only subnet.

" + "smithy.api#documentation": "

The IPv6 network range for the subnet, in CIDR notation. This parameter is required\n for an IPv6 only subnet.

" } }, "OutpostArn": { @@ -18085,6 +18712,30 @@ "traits": { "smithy.api#documentation": "

Indicates whether to create an IPv6 only subnet.

" } + }, + "Ipv4IpamPoolId": { + "target": "com.amazonaws.ec2#IpamPoolId", + "traits": { + "smithy.api#documentation": "

An IPv4 IPAM pool ID for the subnet.

" + } + }, + "Ipv4NetmaskLength": { + "target": "com.amazonaws.ec2#NetmaskLength", + "traits": { + "smithy.api#documentation": "

An IPv4 netmask length for the subnet.

" + } + }, + "Ipv6IpamPoolId": { + "target": "com.amazonaws.ec2#IpamPoolId", + "traits": { + "smithy.api#documentation": "

An IPv6 IPAM pool ID for the subnet.

" + } + }, + "Ipv6NetmaskLength": { + "target": "com.amazonaws.ec2#NetmaskLength", + "traits": { + "smithy.api#documentation": "

An IPv6 netmask length for the subnet.

" + } } }, "traits": { @@ -19376,6 +20027,12 @@ "smithy.api#documentation": "

Enable or disable DNS support. The default is enable.

" } }, + "SecurityGroupReferencingSupport": { + "target": "com.amazonaws.ec2#SecurityGroupReferencingSupportValue", + "traits": { + "smithy.api#documentation": "

Enables you to reference a security group across VPCs attached to a transit gateway (TGW). Use this option to simplify security group management and control of instance-to-instance traffic across VPCs that are connected by transit gateway. You can also use this option to migrate from VPC peering (which was the only option that supported security group referencing) to transit gateways (which now also support security group referencing). This option is disabled by default and there are no additional costs to use this feature.

\n

If you don't enable or disable SecurityGroupReferencingSupport in the request, the\n attachment will inherit the security group referencing support setting on the transit\n gateway.

\n

For important information about this feature, see Create a transit gateway attachment to a VPC in the Amazon Web Services Transit Gateway Guide.

" + } + }, "Ipv6Support": { "target": "com.amazonaws.ec2#Ipv6SupportValue", "traits": { @@ -19534,7 +20191,7 @@ "SecurityGroupIds": { "target": "com.amazonaws.ec2#SecurityGroupIdList", "traits": { - "smithy.api#documentation": "

The IDs of the security groups to associate with the Verified Access endpoint.

", + "smithy.api#documentation": "

The IDs of the security groups to associate with the Verified Access endpoint. Required if AttachmentType is set to vpc.

", "smithy.api#xmlName": "SecurityGroupId" } }, @@ -19585,7 +20242,7 @@ "SseSpecification": { "target": "com.amazonaws.ec2#VerifiedAccessSseSpecificationRequest", "traits": { - "smithy.api#documentation": "

\n Options for server side encryption.\n

" + "smithy.api#documentation": "

The options for server side encryption.

" } } }, @@ -19600,7 +20257,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessEndpoint", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessEndpoint", - "smithy.api#documentation": "

The ID of the Verified Access endpoint.

", + "smithy.api#documentation": "

Details about the Verified Access endpoint.

", "smithy.api#xmlName": "verifiedAccessEndpoint" } } @@ -19676,7 +20333,7 @@ "SseSpecification": { "target": "com.amazonaws.ec2#VerifiedAccessSseSpecificationRequest", "traits": { - "smithy.api#documentation": "

\n Options for server side encryption.\n

" + "smithy.api#documentation": "

The options for server side encryption.

" } } }, @@ -19691,7 +20348,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessGroup", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessGroup", - "smithy.api#documentation": "

The ID of the Verified Access group.

", + "smithy.api#documentation": "

Details about the Verified Access group.

", "smithy.api#xmlName": "verifiedAccessGroup" } } @@ -19759,7 +20416,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessInstance", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessInstance", - "smithy.api#documentation": "

The ID of the Verified Access instance.

", + "smithy.api#documentation": "

Details about the Verified Access instance.

", "smithy.api#xmlName": "verifiedAccessInstance" } } @@ -19788,6 +20445,12 @@ "traits": { "smithy.api#documentation": "

The ID of the tenant application with the device-identity provider.

" } + }, + "PublicSigningKeyUrl": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#documentation": "

\n The URL Amazon Web Services Verified Access will use to verify the authenticity of the device tokens.\n

" + } } }, "traits": { @@ -19916,7 +20579,7 @@ "SseSpecification": { "target": "com.amazonaws.ec2#VerifiedAccessSseSpecificationRequest", "traits": { - "smithy.api#documentation": "

\n Options for server side encryption.\n

" + "smithy.api#documentation": "

The options for server side encryption.

" } } }, @@ -19931,7 +20594,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessTrustProvider", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessTrustProvider", - "smithy.api#documentation": "

The ID of the Verified Access trust provider.

", + "smithy.api#documentation": "

Details about the Verified Access trust provider.

", "smithy.api#xmlName": "verifiedAccessTrustProvider" } } @@ -20049,7 +20712,7 @@ "Iops": { "target": "com.amazonaws.ec2#Integer", "traits": { - "smithy.api#documentation": "

The number of I/O operations per second (IOPS). For gp3, io1, and io2 volumes, this represents \n the number of IOPS that are provisioned for the volume. For gp2 volumes, this represents the baseline \n performance of the volume and the rate at which the volume accumulates I/O credits for bursting.

\n

The following are the supported values for each volume type:

\n
    \n
  • \n

    \n gp3: 3,000-16,000 IOPS

    \n
  • \n
  • \n

    \n io1: 100-64,000 IOPS

    \n
  • \n
  • \n

    \n io2: 100-64,000 IOPS

    \n
  • \n
\n

\n io1 and io2 volumes support up to 64,000 IOPS only on \n Instances built on the Nitro System. Other instance families support performance \n up to 32,000 IOPS.

\n

This parameter is required for io1 and io2 volumes.\n The default for gp3 volumes is 3,000 IOPS.\n This parameter is not supported for gp2, st1, sc1, or standard volumes.

" + "smithy.api#documentation": "

The number of I/O operations per second (IOPS). For gp3, io1, and io2 volumes, this represents \n the number of IOPS that are provisioned for the volume. For gp2 volumes, this represents the baseline \n performance of the volume and the rate at which the volume accumulates I/O credits for bursting.

\n

The following are the supported values for each volume type:

\n
    \n
  • \n

    \n gp3: 3,000 - 16,000 IOPS

    \n
  • \n
  • \n

    \n io1: 100 - 64,000 IOPS

    \n
  • \n
  • \n

    \n io2: 100 - 256,000 IOPS

    \n
  • \n
\n

For io2 volumes, you can achieve up to 256,000 IOPS on \ninstances \nbuilt on the Nitro System. On other instances, you can achieve performance up to 32,000 IOPS.

\n

This parameter is required for io1 and io2 volumes. The default for gp3 volumes is 3,000 IOPS.\n This parameter is not supported for gp2, st1, sc1, or standard volumes.

" } }, "KmsKeyId": { @@ -20067,7 +20730,7 @@ "Size": { "target": "com.amazonaws.ec2#Integer", "traits": { - "smithy.api#documentation": "

The size of the volume, in GiBs. You must specify either a snapshot ID or a volume size.\n If you specify a snapshot, the default is the snapshot size. You can specify a volume \n size that is equal to or larger than the snapshot size.

\n

The following are the supported volumes sizes for each volume type:

\n
    \n
  • \n

    \n gp2 and gp3: 1-16,384

    \n
  • \n
  • \n

    \n io1 and io2: 4-16,384

    \n
  • \n
  • \n

    \n st1 and sc1: 125-16,384

    \n
  • \n
  • \n

    \n standard: 1-1,024

    \n
  • \n
" + "smithy.api#documentation": "

The size of the volume, in GiBs. You must specify either a snapshot ID or a volume size.\n If you specify a snapshot, the default is the snapshot size. You can specify a volume \n size that is equal to or larger than the snapshot size.

\n

The following are the supported volumes sizes for each volume type:

\n
    \n
  • \n

    \n gp2 and gp3: 1 - 16,384 GiB

    \n
  • \n
  • \n

    \n io1: 4 - 16,384 GiB

    \n
  • \n
  • \n

    \n io2: 4 - 65,536 GiB

    \n
  • \n
  • \n

    \n st1 and sc1: 125 - 16,384 GiB

    \n
  • \n
  • \n

    \n standard: 1 - 1024 GiB

    \n
  • \n
" } }, "SnapshotId": { @@ -20130,7 +20793,7 @@ "target": "com.amazonaws.ec2#CreateVpcResult" }, "traits": { - "smithy.api#documentation": "

Creates a VPC with the specified CIDR blocks. For more information, see IP addressing for your VPCs and subnets in the \n Amazon VPC User Guide.

\n

You can optionally request an IPv6 CIDR block for the VPC. You can request an Amazon-provided \n IPv6 CIDR block from Amazon's pool of IPv6 addresses, or an IPv6 CIDR block from an IPv6 address \n pool that you provisioned through bring your own IP addresses (BYOIP).

\n

By default, each instance that you launch in the VPC has the default DHCP options, which\n\t\t\tinclude only a default DNS server that we provide (AmazonProvidedDNS). For more\n\t\t\tinformation, see DHCP option sets in the Amazon VPC User Guide.

\n

You can specify the instance tenancy value for the VPC when you create it. You can't change\n this value for the VPC after you create it. For more information, see Dedicated Instances in the\n Amazon EC2 User Guide.

", + "smithy.api#documentation": "

Creates a VPC with the specified CIDR blocks. For more information, see IP addressing for your VPCs and subnets in the \n Amazon VPC User Guide.

\n

You can optionally request an IPv6 CIDR block for the VPC. You can request an\n Amazon-provided IPv6 CIDR block from Amazon's pool of IPv6 addresses or an IPv6 CIDR\n block from an IPv6 address pool that you provisioned through bring your own IP addresses\n (BYOIP).

\n

By default, each instance that you launch in the VPC has the default DHCP options, which\n\t\t\tinclude only a default DNS server that we provide (AmazonProvidedDNS). For more\n\t\t\tinformation, see DHCP option sets in the Amazon VPC User Guide.

\n

You can specify the instance tenancy value for the VPC when you create it. You can't change\n this value for the VPC after you create it. For more information, see Dedicated Instances in the\n Amazon EC2 User Guide.

", "smithy.api#examples": [ { "title": "To create a VPC", @@ -21219,6 +21882,12 @@ "traits": { "smithy.api#enumValue": "on-demand" } + }, + "CAPACITY_BLOCK": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "capacity-block" + } } } }, @@ -22127,6 +22796,12 @@ "smithy.api#documentation": "

The ID of the pool to delete.

", "smithy.api#required": {} } + }, + "Cascade": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Enables you to quickly delete an IPAM pool and all resources within that pool, including\n provisioned CIDRs, allocations, and other pools.

\n \n

You can only use this option to delete pools in the private scope or pools in the public scope with a source resource. A source resource is a resource used to provision CIDRs to a resource planning pool.

\n
" + } } }, "traits": { @@ -24808,7 +25483,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessEndpoint", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessEndpoint", - "smithy.api#documentation": "

The ID of the Verified Access endpoint.

", + "smithy.api#documentation": "

Details about the Verified Access endpoint.

", "smithy.api#xmlName": "verifiedAccessEndpoint" } } @@ -24865,7 +25540,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessGroup", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessGroup", - "smithy.api#documentation": "

The ID of the Verified Access group.

", + "smithy.api#documentation": "

Details about the Verified Access group.

", "smithy.api#xmlName": "verifiedAccessGroup" } } @@ -24922,7 +25597,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessInstance", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessInstance", - "smithy.api#documentation": "

The ID of the Verified Access instance.

", + "smithy.api#documentation": "

Details about the Verified Access instance.

", "smithy.api#xmlName": "verifiedAccessInstance" } } @@ -24979,7 +25654,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessTrustProvider", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessTrustProvider", - "smithy.api#documentation": "

The ID of the Verified Access trust provider.

", + "smithy.api#documentation": "

Details about the Verified Access trust provider.

", "smithy.api#xmlName": "verifiedAccessTrustProvider" } } @@ -25217,7 +25892,7 @@ "target": "com.amazonaws.ec2#DeleteVpcPeeringConnectionResult" }, "traits": { - "smithy.api#documentation": "

Deletes a VPC peering connection. Either the owner of the requester VPC or the owner\n of the accepter VPC can delete the VPC peering connection if it's in the\n active state. The owner of the requester VPC can delete a VPC peering\n connection in the pending-acceptance state. You cannot delete a VPC peering\n connection that's in the failed state.

" + "smithy.api#documentation": "

Deletes a VPC peering connection. Either the owner of the requester VPC or the owner\n of the accepter VPC can delete the VPC peering connection if it's in the\n active state. The owner of the requester VPC can delete a VPC peering\n connection in the pending-acceptance state. You cannot delete a VPC peering\n connection that's in the failed or rejected state.

" } }, "com.amazonaws.ec2#DeleteVpcPeeringConnectionRequest": { @@ -25447,6 +26122,64 @@ "smithy.api#output": {} } }, + "com.amazonaws.ec2#DeprovisionIpamByoasn": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#DeprovisionIpamByoasnRequest" + }, + "output": { + "target": "com.amazonaws.ec2#DeprovisionIpamByoasnResult" + }, + "traits": { + "smithy.api#documentation": "

Deprovisions your Autonomous System Number (ASN) from your Amazon Web Services account. This action can only be called after any BYOIP CIDR associations are removed from your Amazon Web Services account with DisassociateIpamByoasn.\n For more information, see Tutorial: Bring your ASN to IPAM in the Amazon VPC IPAM guide.

" + } + }, + "com.amazonaws.ec2#DeprovisionIpamByoasnRequest": { + "type": "structure", + "members": { + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, \n and provides an error response. If you have the required permissions, the error response is DryRunOperation. \n Otherwise, it is UnauthorizedOperation.

" + } + }, + "IpamId": { + "target": "com.amazonaws.ec2#IpamId", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The IPAM ID.

", + "smithy.api#required": {} + } + }, + "Asn": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

An ASN.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#DeprovisionIpamByoasnResult": { + "type": "structure", + "members": { + "Byoasn": { + "target": "com.amazonaws.ec2#Byoasn", + "traits": { + "aws.protocols#ec2QueryName": "Byoasn", + "smithy.api#documentation": "

An ASN and BYOIP CIDR association.

", + "smithy.api#xmlName": "byoasn" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#DeprovisionIpamPoolCidr": { "type": "operation", "input": { @@ -26533,6 +27266,119 @@ "smithy.api#output": {} } }, + "com.amazonaws.ec2#DescribeCapacityBlockOfferings": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#DescribeCapacityBlockOfferingsRequest" + }, + "output": { + "target": "com.amazonaws.ec2#DescribeCapacityBlockOfferingsResult" + }, + "traits": { + "smithy.api#documentation": "

Describes Capacity Block offerings available for purchase. With Capacity Blocks, you purchase a specific instance type for a period of time.

", + "smithy.api#paginated": { + "inputToken": "NextToken", + "outputToken": "NextToken", + "items": "CapacityBlockOfferings", + "pageSize": "MaxResults" + } + } + }, + "com.amazonaws.ec2#DescribeCapacityBlockOfferingsMaxResults": { + "type": "integer", + "traits": { + "smithy.api#range": { + "min": 1, + "max": 1000 + } + } + }, + "com.amazonaws.ec2#DescribeCapacityBlockOfferingsRequest": { + "type": "structure", + "members": { + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. If you have the required permissions, the error response is DryRunOperation. Otherwise, it is UnauthorizedOperation.

" + } + }, + "InstanceType": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The type of instance for which the Capacity Block offering reserves capacity.

", + "smithy.api#required": {} + } + }, + "InstanceCount": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The number of instances for which to reserve capacity.

", + "smithy.api#required": {} + } + }, + "StartDateRange": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "smithy.api#documentation": "

The earliest start date for the Capacity Block offering.

" + } + }, + "EndDateRange": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "smithy.api#documentation": "

The latest end date for the Capacity Block offering.

" + } + }, + "CapacityDurationHours": { + "target": "com.amazonaws.ec2#Integer", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The number of hours for which to reserve Capacity Block.

", + "smithy.api#required": {} + } + }, + "NextToken": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#documentation": "

The token to use to retrieve the next page of results.

" + } + }, + "MaxResults": { + "target": "com.amazonaws.ec2#DescribeCapacityBlockOfferingsMaxResults", + "traits": { + "smithy.api#documentation": "

The maximum number of results to return for the request in a single page. The remaining results can be seen by sending another request with the returned nextToken value. This value can be between 5 and 500. If maxResults is given a larger value than 500, you receive an error.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#DescribeCapacityBlockOfferingsResult": { + "type": "structure", + "members": { + "CapacityBlockOfferings": { + "target": "com.amazonaws.ec2#CapacityBlockOfferingSet", + "traits": { + "aws.protocols#ec2QueryName": "CapacityBlockOfferingSet", + "smithy.api#documentation": "

The recommended Capacity Block offering for the dates specified.

", + "smithy.api#xmlName": "capacityBlockOfferingSet" + } + }, + "NextToken": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "NextToken", + "smithy.api#documentation": "

The token to use to retrieve the next page of results. This value is null when there are no more results to return.

", + "smithy.api#xmlName": "nextToken" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#DescribeCapacityReservationFleets": { "type": "operation", "input": { @@ -28179,7 +29025,7 @@ "target": "com.amazonaws.ec2#DescribeFastLaunchImagesResult" }, "traits": { - "smithy.api#documentation": "

Describe details for Windows AMIs that are configured for faster launching.

", + "smithy.api#documentation": "

Describe details for Windows AMIs that are configured for Windows fast launch.

", "smithy.api#paginated": { "inputToken": "NextToken", "outputToken": "NextToken", @@ -28194,14 +29040,14 @@ "ImageIds": { "target": "com.amazonaws.ec2#FastLaunchImageIdList", "traits": { - "smithy.api#documentation": "

Details for one or more Windows AMI image IDs.

", + "smithy.api#documentation": "

Specify one or more Windows AMI image IDs for the request.

", "smithy.api#xmlName": "ImageId" } }, "Filters": { "target": "com.amazonaws.ec2#FilterList", "traits": { - "smithy.api#documentation": "

Use the following filters to streamline results.

\n
    \n
  • \n

    \n resource-type - The resource type for pre-provisioning.

    \n
  • \n
  • \n

    \n launch-template - The launch template that is associated with the pre-provisioned Windows AMI.

    \n
  • \n
  • \n

    \n owner-id - The owner ID for the pre-provisioning resource.

    \n
  • \n
  • \n

    \n state - The current state of fast launching for the Windows AMI.

    \n
  • \n
", + "smithy.api#documentation": "

Use the following filters to streamline results.

\n
    \n
  • \n

    \n resource-type - The resource type for pre-provisioning.

    \n
  • \n
  • \n

    \n owner-id - The owner ID for the pre-provisioning resource.

    \n
  • \n
  • \n

    \n state - The current state of fast launching for the Windows AMI.

    \n
  • \n
", "smithy.api#xmlName": "Filter" } }, @@ -28268,7 +29114,7 @@ "target": "com.amazonaws.ec2#ImageId", "traits": { "aws.protocols#ec2QueryName": "ImageId", - "smithy.api#documentation": "

The image ID that identifies the fast-launch enabled Windows image.

", + "smithy.api#documentation": "

The image ID that identifies the Windows fast launch enabled image.

", "smithy.api#xmlName": "imageId" } }, @@ -28276,7 +29122,7 @@ "target": "com.amazonaws.ec2#FastLaunchResourceType", "traits": { "aws.protocols#ec2QueryName": "ResourceType", - "smithy.api#documentation": "

The resource type that is used for pre-provisioning the Windows AMI. Supported values \n\t\t\tinclude: snapshot.

", + "smithy.api#documentation": "

The resource type that Amazon EC2 uses for pre-provisioning the Windows AMI. Supported values \n\t\t\tinclude: snapshot.

", "smithy.api#xmlName": "resourceType" } }, @@ -28292,7 +29138,7 @@ "target": "com.amazonaws.ec2#FastLaunchLaunchTemplateSpecificationResponse", "traits": { "aws.protocols#ec2QueryName": "LaunchTemplate", - "smithy.api#documentation": "

The launch template that the fast-launch enabled Windows AMI uses when it launches \n\t\t\tWindows instances from pre-provisioned snapshots.

", + "smithy.api#documentation": "

The launch template that the Windows fast launch enabled AMI uses when it launches \n\t\t\tWindows instances from pre-provisioned snapshots.

", "smithy.api#xmlName": "launchTemplate" } }, @@ -28300,7 +29146,7 @@ "target": "com.amazonaws.ec2#Integer", "traits": { "aws.protocols#ec2QueryName": "MaxParallelLaunches", - "smithy.api#documentation": "

The maximum number of instances that Amazon EC2 can launch at the same time to create \n\t\t\tpre-provisioned snapshots for Windows faster launching.

", + "smithy.api#documentation": "

The maximum number of instances that Amazon EC2 can launch at the same time to create \n\t\t\tpre-provisioned snapshots for Windows fast launch.

", "smithy.api#xmlName": "maxParallelLaunches" } }, @@ -28308,7 +29154,7 @@ "target": "com.amazonaws.ec2#String", "traits": { "aws.protocols#ec2QueryName": "OwnerId", - "smithy.api#documentation": "

The owner ID for the fast-launch enabled Windows AMI.

", + "smithy.api#documentation": "

The owner ID for the Windows fast launch enabled AMI.

", "smithy.api#xmlName": "ownerId" } }, @@ -28316,7 +29162,7 @@ "target": "com.amazonaws.ec2#FastLaunchStateCode", "traits": { "aws.protocols#ec2QueryName": "State", - "smithy.api#documentation": "

The current state of faster launching for the specified Windows AMI.

", + "smithy.api#documentation": "

The current state of Windows fast launch for the specified Windows AMI.

", "smithy.api#xmlName": "state" } }, @@ -28324,7 +29170,7 @@ "target": "com.amazonaws.ec2#String", "traits": { "aws.protocols#ec2QueryName": "StateTransitionReason", - "smithy.api#documentation": "

The reason that faster launching for the Windows AMI changed to the current state.

", + "smithy.api#documentation": "

The reason that Windows fast launch for the AMI changed to the current state.

", "smithy.api#xmlName": "stateTransitionReason" } }, @@ -28332,13 +29178,13 @@ "target": "com.amazonaws.ec2#MillisecondDateTime", "traits": { "aws.protocols#ec2QueryName": "StateTransitionTime", - "smithy.api#documentation": "

The time that faster launching for the Windows AMI changed to the current state.

", + "smithy.api#documentation": "

The time that Windows fast launch for the AMI changed to the current state.

", "smithy.api#xmlName": "stateTransitionTime" } } }, "traits": { - "smithy.api#documentation": "

Describe details about a fast-launch enabled Windows image that meets the requested \n\t\t\tcriteria. Criteria are defined by the DescribeFastLaunchImages action filters.

" + "smithy.api#documentation": "

Describe details about a Windows image with Windows fast launch enabled that meets the requested \n\t\t\tcriteria. Criteria are defined by the DescribeFastLaunchImages action filters.

" } }, "com.amazonaws.ec2#DescribeFastLaunchImagesSuccessSet": { @@ -30606,6 +31452,116 @@ "smithy.api#output": {} } }, + "com.amazonaws.ec2#DescribeInstanceTopology": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#DescribeInstanceTopologyRequest" + }, + "output": { + "target": "com.amazonaws.ec2#DescribeInstanceTopologyResult" + }, + "traits": { + "smithy.api#documentation": "

Describes a tree-based hierarchy that represents the physical host placement of your\n EC2 instances within an Availability Zone or Local Zone. You can use this information to\n determine the relative proximity of your EC2 instances within the Amazon Web Services network to\n support your tightly coupled workloads.

\n

\n Limitations\n

\n
    \n
  • \n

    Supported zones

    \n
      \n
    • \n

      Availability Zone

      \n
    • \n
    • \n

      Local Zone

      \n
    • \n
    \n
  • \n
  • \n

    Supported instance types

    \n
      \n
    • \n

      \n hpc6a.48xlarge | hpc6id.32xlarge |\n hpc7a.12xlarge | hpc7a.24xlarge |\n hpc7a.48xlarge | hpc7a.96xlarge |\n hpc7g.4xlarge | hpc7g.8xlarge |\n hpc7g.16xlarge\n

      \n
    • \n
    • \n

      \n p3dn.24xlarge | p4d.24xlarge |\n p4de.24xlarge | p5.48xlarge\n

      \n
    • \n
    • \n

      \n trn1.2xlarge | trn1.32xlarge |\n trn1n.32xlarge\n

      \n
    • \n
    \n
  • \n
\n

For more information, see Amazon EC2 instance\n topology in the Amazon EC2 User Guide.

", + "smithy.api#paginated": { + "inputToken": "NextToken", + "outputToken": "NextToken", + "items": "Instances", + "pageSize": "MaxResults" + } + } + }, + "com.amazonaws.ec2#DescribeInstanceTopologyGroupNameSet": { + "type": "list", + "member": { + "target": "com.amazonaws.ec2#PlacementGroupName" + } + }, + "com.amazonaws.ec2#DescribeInstanceTopologyInstanceIdSet": { + "type": "list", + "member": { + "target": "com.amazonaws.ec2#InstanceId" + } + }, + "com.amazonaws.ec2#DescribeInstanceTopologyMaxResults": { + "type": "integer", + "traits": { + "smithy.api#range": { + "min": 1, + "max": 100 + } + } + }, + "com.amazonaws.ec2#DescribeInstanceTopologyRequest": { + "type": "structure", + "members": { + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, \n and provides an error response. If you have the required permissions, the error response is DryRunOperation. \n Otherwise, it is UnauthorizedOperation.

" + } + }, + "NextToken": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#documentation": "

The token returned from a previous paginated request. Pagination continues from the end of the items returned by the previous request.

" + } + }, + "MaxResults": { + "target": "com.amazonaws.ec2#DescribeInstanceTopologyMaxResults", + "traits": { + "smithy.api#documentation": "

The maximum number of items to return for this request.\n To get the next page of items, make another request with the token returned in the output.\n\t For more information, see Pagination.

\n

You can't specify this parameter and the instance IDs parameter in the same request.

\n

Default: 20\n

" + } + }, + "InstanceIds": { + "target": "com.amazonaws.ec2#DescribeInstanceTopologyInstanceIdSet", + "traits": { + "smithy.api#documentation": "

The instance IDs.

\n

Default: Describes all your instances.

\n

Constraints: Maximum 100 explicitly specified instance IDs.

", + "smithy.api#xmlName": "InstanceId" + } + }, + "GroupNames": { + "target": "com.amazonaws.ec2#DescribeInstanceTopologyGroupNameSet", + "traits": { + "smithy.api#documentation": "

The name of the placement group that each instance is in.

\n

Constraints: Maximum 100 explicitly specified placement group names.

", + "smithy.api#xmlName": "GroupName" + } + }, + "Filters": { + "target": "com.amazonaws.ec2#FilterList", + "traits": { + "smithy.api#documentation": "

The filters.

\n
    \n
  • \n

    \n availability-zone - The name of the Availability Zone (for\n example, us-west-2a) or Local Zone (for example,\n us-west-2-lax-1b) that the instance is in.

    \n
  • \n
  • \n

    \n instance-type - The instance type (for example,\n p4d.24xlarge) or instance family (for example,\n p4d*). You can use the * wildcard to match zero or\n more characters, or the ? wildcard to match zero or one\n character.

    \n
  • \n
  • \n

    \n zone-id - The ID of the Availability Zone (for example,\n usw2-az2) or Local Zone (for example,\n usw2-lax1-az1) that the instance is in.

    \n
  • \n
", + "smithy.api#xmlName": "Filter" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#DescribeInstanceTopologyResult": { + "type": "structure", + "members": { + "Instances": { + "target": "com.amazonaws.ec2#InstanceSet", + "traits": { + "aws.protocols#ec2QueryName": "InstanceSet", + "smithy.api#documentation": "

Information about the topology of each instance.

", + "smithy.api#xmlName": "instanceSet" + } + }, + "NextToken": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "NextToken", + "smithy.api#documentation": "

The token to include in another request to get the next page of items. This value is null when there\n are no more items to return.

", + "smithy.api#xmlName": "nextToken" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#DescribeInstanceTypeOfferings": { "type": "operation", "input": { @@ -30952,7 +31908,7 @@ "Filters": { "target": "com.amazonaws.ec2#FilterList", "traits": { - "smithy.api#documentation": "

The filters.

\n
    \n
  • \n

    \n affinity - The affinity setting for an instance running on a\n Dedicated Host (default | host).

    \n
  • \n
  • \n

    \n architecture - The instance architecture (i386 |\n x86_64 | arm64).

    \n
  • \n
  • \n

    \n availability-zone - The Availability Zone of the instance.

    \n
  • \n
  • \n

    \n block-device-mapping.attach-time - The attach time for an EBS\n volume mapped to the instance, for example,\n 2022-09-15T17:15:20.000Z.

    \n
  • \n
  • \n

    \n block-device-mapping.delete-on-termination - A Boolean that\n indicates whether the EBS volume is deleted on instance termination.

    \n
  • \n
  • \n

    \n block-device-mapping.device-name - The device name specified in\n the block device mapping (for example, /dev/sdh or\n xvdh).

    \n
  • \n
  • \n

    \n block-device-mapping.status - The status for the EBS volume\n (attaching | attached | detaching |\n detached).

    \n
  • \n
  • \n

    \n block-device-mapping.volume-id - The volume ID of the EBS\n volume.

    \n
  • \n
  • \n

    \n boot-mode - The boot mode that was specified by the AMI\n (legacy-bios | uefi |\n uefi-preferred).

    \n
  • \n
  • \n

    \n capacity-reservation-id - The ID of the Capacity Reservation into which the\n instance was launched.

    \n
  • \n
  • \n

    \n capacity-reservation-specification.capacity-reservation-preference\n - The instance's Capacity Reservation preference (open | none).

    \n
  • \n
  • \n

    \n capacity-reservation-specification.capacity-reservation-target.capacity-reservation-id\n - The ID of the targeted Capacity Reservation.

    \n
  • \n
  • \n

    \n capacity-reservation-specification.capacity-reservation-target.capacity-reservation-resource-group-arn\n - The ARN of the targeted Capacity Reservation group.

    \n
  • \n
  • \n

    \n client-token - The idempotency token you provided when you\n launched the instance.

    \n
  • \n
  • \n

    \n current-instance-boot-mode - The boot mode that is used to launch\n the instance at launch or start (legacy-bios |\n uefi).

    \n
  • \n
  • \n

    \n dns-name - The public DNS name of the instance.

    \n
  • \n
  • \n

    \n ebs-optimized - A Boolean that indicates whether the instance is\n optimized for Amazon EBS I/O.

    \n
  • \n
  • \n

    \n ena-support - A Boolean that indicates whether the instance is\n enabled for enhanced networking with ENA.

    \n
  • \n
  • \n

    \n enclave-options.enabled - A Boolean that indicates whether the\n instance is enabled for Amazon Web Services Nitro Enclaves.

    \n
  • \n
  • \n

    \n hibernation-options.configured - A Boolean that indicates whether\n the instance is enabled for hibernation. A value of true means that\n the instance is enabled for hibernation.

    \n
  • \n
  • \n

    \n host-id - The ID of the Dedicated Host on which the instance is\n running, if applicable.

    \n
  • \n
  • \n

    \n hypervisor - The hypervisor type of the instance\n (ovm | xen). The value xen is used\n for both Xen and Nitro hypervisors.

    \n
  • \n
  • \n

    \n iam-instance-profile.arn - The instance profile associated with\n the instance. Specified as an ARN.

    \n
  • \n
  • \n

    \n iam-instance-profile.id - The instance profile associated with\n the instance. Specified as an ID.

    \n
  • \n
  • \n

    \n iam-instance-profile.name - The instance profile associated with\n the instance. Specified as an name.

    \n
  • \n
  • \n

    \n image-id - The ID of the image used to launch the\n instance.

    \n
  • \n
  • \n

    \n instance-id - The ID of the instance.

    \n
  • \n
  • \n

    \n instance-lifecycle - Indicates whether this is a Spot Instance or\n a Scheduled Instance (spot | scheduled).

    \n
  • \n
  • \n

    \n instance-state-code - The state of the instance, as a 16-bit\n unsigned integer. The high byte is used for internal purposes and should be\n ignored. The low byte is set based on the state represented. The valid values\n are: 0 (pending), 16 (running), 32 (shutting-down), 48 (terminated), 64\n (stopping), and 80 (stopped).

    \n
  • \n
  • \n

    \n instance-state-name - The state of the instance\n (pending | running | shutting-down |\n terminated | stopping |\n stopped).

    \n
  • \n
  • \n

    \n instance-type - The type of instance (for example,\n t2.micro).

    \n
  • \n
  • \n

    \n instance.group-id - The ID of the security group for the\n instance.

    \n
  • \n
  • \n

    \n instance.group-name - The name of the security group for the\n instance.

    \n
  • \n
  • \n

    \n ip-address - The public IPv4 address of the instance.

    \n
  • \n
  • \n

    \n ipv6-address - The IPv6 address of the instance.

    \n
  • \n
  • \n

    \n kernel-id - The kernel ID.

    \n
  • \n
  • \n

    \n key-name - The name of the key pair used when the instance was\n launched.

    \n
  • \n
  • \n

    \n launch-index - When launching multiple instances, this is the\n index for the instance in the launch group (for example, 0, 1, 2, and so on).\n

    \n
  • \n
  • \n

    \n launch-time - The time when the instance was launched, in the ISO\n 8601 format in the UTC time zone (YYYY-MM-DDThh:mm:ss.sssZ), for example,\n 2021-09-29T11:04:43.305Z. You can use a wildcard\n (*), for example, 2021-09-29T*, which matches an\n entire day.

    \n
  • \n
  • \n

    \n maintenance-options.auto-recovery - The current automatic\n recovery behavior of the instance (disabled | default).

    \n
  • \n
  • \n

    \n metadata-options.http-endpoint - The status of access to the HTTP\n metadata endpoint on your instance (enabled |\n disabled)

    \n
  • \n
  • \n

    \n metadata-options.http-protocol-ipv4 - Indicates whether the IPv4\n endpoint is enabled (disabled | enabled).

    \n
  • \n
  • \n

    \n metadata-options.http-protocol-ipv6 - Indicates whether the IPv6\n endpoint is enabled (disabled | enabled).

    \n
  • \n
  • \n

    \n metadata-options.http-put-response-hop-limit - The HTTP metadata\n request put response hop limit (integer, possible values 1 to\n 64)

    \n
  • \n
  • \n

    \n metadata-options.http-tokens - The metadata request authorization\n state (optional | required)

    \n
  • \n
  • \n

    \n metadata-options.instance-metadata-tags - The status of access to\n instance tags from the instance metadata (enabled |\n disabled)

    \n
  • \n
  • \n

    \n metadata-options.state - The state of the metadata option changes\n (pending | applied).

    \n
  • \n
  • \n

    \n monitoring-state - Indicates whether detailed monitoring is\n enabled (disabled | enabled).

    \n
  • \n
  • \n

    \n network-interface.addresses.association.allocation-id - The allocation ID.

    \n
  • \n
  • \n

    \n network-interface.addresses.association.association-id - The association ID.

    \n
  • \n
  • \n

    \n network-interface.addresses.association.carrier-ip - The carrier IP address.

    \n
  • \n
  • \n

    \n network-interface.addresses.association.customer-owned-ip - The customer-owned IP address.

    \n
  • \n
  • \n

    \n network-interface.addresses.association.ip-owner-id - The owner\n ID of the private IPv4 address associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.addresses.association.public-dns-name - The public DNS name.

    \n
  • \n
  • \n

    \n network-interface.addresses.association.public-ip - The ID of the\n association of an Elastic IP address (IPv4) with a network interface.

    \n
  • \n
  • \n

    \n network-interface.addresses.primary - Specifies whether the IPv4\n address of the network interface is the primary private IPv4 address.

    \n
  • \n
  • \n

    \n network-interface.addresses.private-dns-name - The private DNS name.

    \n
  • \n
  • \n

    \n network-interface.addresses.private-ip-address - The private IPv4\n address associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.association.allocation-id - The allocation ID\n returned when you allocated the Elastic IP address (IPv4) for your network\n interface.

    \n
  • \n
  • \n

    \n network-interface.association.association-id - The association ID\n returned when the network interface was associated with an IPv4 address.

    \n
  • \n
  • \n

    \n network-interface.association.carrier-ip - The customer-owned IP address.

    \n
  • \n
  • \n

    \n network-interface.association.customer-owned-ip - The customer-owned IP address.

    \n
  • \n
  • \n

    \n network-interface.association.ip-owner-id - The owner of the\n Elastic IP address (IPv4) associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.association.public-dns-name - The public DNS name.

    \n
  • \n
  • \n

    \n network-interface.association.public-ip - The address of the\n Elastic IP address (IPv4) bound to the network interface.

    \n
  • \n
  • \n

    \n network-interface.attachment.attach-time - The time that the\n network interface was attached to an instance.

    \n
  • \n
  • \n

    \n network-interface.attachment.attachment-id - The ID of the\n interface attachment.

    \n
  • \n
  • \n

    \n network-interface.attachment.delete-on-termination - Specifies\n whether the attachment is deleted when an instance is terminated.

    \n
  • \n
  • \n

    \n network-interface.attachment.device-index - The device index to\n which the network interface is attached.

    \n
  • \n
  • \n

    \n network-interface.attachment.instance-id - The ID of the instance\n to which the network interface is attached.

    \n
  • \n
  • \n

    \n network-interface.attachment.instance-owner-id - The owner ID of\n the instance to which the network interface is attached.

    \n
  • \n
  • \n

    \n network-interface.attachment.network-card-index - The index of the network card.

    \n
  • \n
  • \n

    \n network-interface.attachment.status - The status of the\n attachment (attaching | attached |\n detaching | detached).

    \n
  • \n
  • \n

    \n network-interface.availability-zone - The Availability Zone for\n the network interface.

    \n
  • \n
  • \n

    \n network-interface.deny-all-igw-traffic - A Boolean that indicates whether \n a network interface with an IPv6 address is unreachable from the public internet.

    \n
  • \n
  • \n

    \n network-interface.description - The description of the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.group-id - The ID of a security group\n associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.group-name - The name of a security group\n associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.ipv4-prefixes.ipv4-prefix - The IPv4 prefixes that are assigned to the network interface.

    \n
  • \n
  • \n

    \n network-interface.ipv6-address - The IPv6 address associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.ipv6-addresses.ipv6-address - The IPv6 address\n associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.ipv6-addresses.is-primary-ipv6 - A Boolean that indicates whether this\n is the primary IPv6 address.

    \n
  • \n
  • \n

    \n network-interface.ipv6-native - A Boolean that indicates whether this is\n an IPv6 only network interface.

    \n
  • \n
  • \n

    \n network-interface.ipv6-prefixes.ipv6-prefix - The IPv6 prefix assigned to the network interface.

    \n
  • \n
  • \n

    \n network-interface.mac-address - The MAC address of the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.network-interface-id - The ID of the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.outpost-arn - The ARN of the Outpost.

    \n
  • \n
  • \n

    \n network-interface.owner-id - The ID of the owner of the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.private-dns-name - The private DNS name of the\n network interface.

    \n
  • \n
  • \n

    \n network-interface.private-ip-address - The private IPv4 address.

    \n
  • \n
  • \n

    \n network-interface.public-dns-name - The public DNS name.

    \n
  • \n
  • \n

    \n network-interface.requester-id - The requester ID for the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.requester-managed - Indicates whether the\n network interface is being managed by Amazon Web Services.

    \n
  • \n
  • \n

    \n network-interface.status - The status of the network interface\n (available) | in-use).

    \n
  • \n
  • \n

    \n network-interface.source-dest-check - Whether the network\n interface performs source/destination checking. A value of true\n means that checking is enabled, and false means that checking is\n disabled. The value must be false for the network interface to\n perform network address translation (NAT) in your VPC.

    \n
  • \n
  • \n

    \n network-interface.subnet-id - The ID of the subnet for the\n network interface.

    \n
  • \n
  • \n

    \n network-interface.tag-key - The key of a tag assigned to the network interface.

    \n
  • \n
  • \n

    \n network-interface.tag-value - The value of a tag assigned to the network interface.

    \n
  • \n
  • \n

    \n network-interface.vpc-id - The ID of the VPC for the network\n interface.

    \n
  • \n
  • \n

    \n outpost-arn - The Amazon Resource Name (ARN) of the\n Outpost.

    \n
  • \n
  • \n

    \n owner-id - The Amazon Web Services account ID of the instance\n owner.

    \n
  • \n
  • \n

    \n placement-group-name - The name of the placement group for the\n instance.

    \n
  • \n
  • \n

    \n placement-partition-number - The partition in which the instance is\n located.

    \n
  • \n
  • \n

    \n platform - The platform. To list only Windows instances, use\n windows.

    \n
  • \n
  • \n

    \n platform-details - The platform (Linux/UNIX |\n Red Hat BYOL Linux | Red Hat Enterprise Linux |\n Red Hat Enterprise Linux with HA | Red Hat Enterprise\n Linux with SQL Server Standard and HA | Red Hat Enterprise\n Linux with SQL Server Enterprise and HA | Red Hat Enterprise\n Linux with SQL Server Standard | Red Hat Enterprise Linux with\n SQL Server Web | Red Hat Enterprise Linux with SQL Server\n Enterprise | SQL Server Enterprise | SQL Server\n Standard | SQL Server Web | SUSE Linux |\n Ubuntu Pro | Windows | Windows BYOL |\n Windows with SQL Server Enterprise | Windows with SQL\n Server Standard | Windows with SQL Server Web).

    \n
  • \n
  • \n

    \n private-dns-name - The private IPv4 DNS name of the\n instance.

    \n
  • \n
  • \n

    \n private-dns-name-options.enable-resource-name-dns-a-record - A\n Boolean that indicates whether to respond to DNS queries for instance hostnames\n with DNS A records.

    \n
  • \n
  • \n

    \n private-dns-name-options.enable-resource-name-dns-aaaa-record - A\n Boolean that indicates whether to respond to DNS queries for instance hostnames\n with DNS AAAA records.

    \n
  • \n
  • \n

    \n private-dns-name-options.hostname-type - The type of hostname\n (ip-name | resource-name).

    \n
  • \n
  • \n

    \n private-ip-address - The private IPv4 address of the\n instance.

    \n
  • \n
  • \n

    \n product-code - The product code associated with the AMI used to\n launch the instance.

    \n
  • \n
  • \n

    \n product-code.type - The type of product code (devpay\n | marketplace).

    \n
  • \n
  • \n

    \n ramdisk-id - The RAM disk ID.

    \n
  • \n
  • \n

    \n reason - The reason for the current state of the instance (for\n example, shows \"User Initiated [date]\" when you stop or terminate the instance).\n Similar to the state-reason-code filter.

    \n
  • \n
  • \n

    \n requester-id - The ID of the entity that launched the instance on\n your behalf (for example, Amazon Web Services Management Console, Auto Scaling, and so\n on).

    \n
  • \n
  • \n

    \n reservation-id - The ID of the instance's reservation. A\n reservation ID is created any time you launch an instance. A reservation ID has\n a one-to-one relationship with an instance launch request, but can be associated\n with more than one instance if you launch multiple instances using the same\n launch request. For example, if you launch one instance, you get one reservation\n ID. If you launch ten instances using the same launch request, you also get one\n reservation ID.

    \n
  • \n
  • \n

    \n root-device-name - The device name of the root device volume (for\n example, /dev/sda1).

    \n
  • \n
  • \n

    \n root-device-type - The type of the root device volume\n (ebs | instance-store).

    \n
  • \n
  • \n

    \n source-dest-check - Indicates whether the instance performs\n source/destination checking. A value of true means that checking is\n enabled, and false means that checking is disabled. The value must\n be false for the instance to perform network address translation\n (NAT) in your VPC.

    \n
  • \n
  • \n

    \n spot-instance-request-id - The ID of the Spot Instance\n request.

    \n
  • \n
  • \n

    \n state-reason-code - The reason code for the state change.

    \n
  • \n
  • \n

    \n state-reason-message - A message that describes the state\n change.

    \n
  • \n
  • \n

    \n subnet-id - The ID of the subnet for the instance.

    \n
  • \n
  • \n

    \n tag: - The key/value combination of a tag assigned to the resource. Use the tag key in the filter name and the tag value as the filter value.\n For example, to find all resources that have a tag with the key Owner and the value TeamA, specify tag:Owner for the filter name and TeamA for the filter value.

    \n
  • \n
  • \n

    \n tag-key - The key of a tag assigned to the resource. Use this filter to find all resources that have a tag with a specific key, regardless of the tag value.

    \n
  • \n
  • \n

    \n tenancy - The tenancy of an instance (dedicated |\n default | host).

    \n
  • \n
  • \n

    \n tpm-support - Indicates if the instance is configured for\n NitroTPM support (v2.0).

    \n
  • \n
  • \n

    \n usage-operation - The usage operation value for the instance\n (RunInstances | RunInstances:00g0 |\n RunInstances:0010 | RunInstances:1010 |\n RunInstances:1014 | RunInstances:1110 |\n RunInstances:0014 | RunInstances:0210 |\n RunInstances:0110 | RunInstances:0100 |\n RunInstances:0004 | RunInstances:0200 |\n RunInstances:000g | RunInstances:0g00 |\n RunInstances:0002 | RunInstances:0800 |\n RunInstances:0102 | RunInstances:0006 |\n RunInstances:0202).

    \n
  • \n
  • \n

    \n usage-operation-update-time - The time that the usage operation\n was last updated, for example, 2022-09-15T17:15:20.000Z.

    \n
  • \n
  • \n

    \n virtualization-type - The virtualization type of the instance\n (paravirtual | hvm).

    \n
  • \n
  • \n

    \n vpc-id - The ID of the VPC that the instance is running in.

    \n
  • \n
", + "smithy.api#documentation": "

The filters.

\n
    \n
  • \n

    \n affinity - The affinity setting for an instance running on a\n Dedicated Host (default | host).

    \n
  • \n
  • \n

    \n architecture - The instance architecture (i386 |\n x86_64 | arm64).

    \n
  • \n
  • \n

    \n availability-zone - The Availability Zone of the instance.

    \n
  • \n
  • \n

    \n block-device-mapping.attach-time - The attach time for an EBS\n volume mapped to the instance, for example,\n 2022-09-15T17:15:20.000Z.

    \n
  • \n
  • \n

    \n block-device-mapping.delete-on-termination - A Boolean that\n indicates whether the EBS volume is deleted on instance termination.

    \n
  • \n
  • \n

    \n block-device-mapping.device-name - The device name specified in\n the block device mapping (for example, /dev/sdh or\n xvdh).

    \n
  • \n
  • \n

    \n block-device-mapping.status - The status for the EBS volume\n (attaching | attached | detaching |\n detached).

    \n
  • \n
  • \n

    \n block-device-mapping.volume-id - The volume ID of the EBS\n volume.

    \n
  • \n
  • \n

    \n boot-mode - The boot mode that was specified by the AMI\n (legacy-bios | uefi |\n uefi-preferred).

    \n
  • \n
  • \n

    \n capacity-reservation-id - The ID of the Capacity Reservation into which the\n instance was launched.

    \n
  • \n
  • \n

    \n capacity-reservation-specification.capacity-reservation-preference\n - The instance's Capacity Reservation preference (open | none).

    \n
  • \n
  • \n

    \n capacity-reservation-specification.capacity-reservation-target.capacity-reservation-id\n - The ID of the targeted Capacity Reservation.

    \n
  • \n
  • \n

    \n capacity-reservation-specification.capacity-reservation-target.capacity-reservation-resource-group-arn\n - The ARN of the targeted Capacity Reservation group.

    \n
  • \n
  • \n

    \n client-token - The idempotency token you provided when you\n launched the instance.

    \n
  • \n
  • \n

    \n current-instance-boot-mode - The boot mode that is used to launch\n the instance at launch or start (legacy-bios |\n uefi).

    \n
  • \n
  • \n

    \n dns-name - The public DNS name of the instance.

    \n
  • \n
  • \n

    \n ebs-optimized - A Boolean that indicates whether the instance is\n optimized for Amazon EBS I/O.

    \n
  • \n
  • \n

    \n ena-support - A Boolean that indicates whether the instance is\n enabled for enhanced networking with ENA.

    \n
  • \n
  • \n

    \n enclave-options.enabled - A Boolean that indicates whether the\n instance is enabled for Amazon Web Services Nitro Enclaves.

    \n
  • \n
  • \n

    \n hibernation-options.configured - A Boolean that indicates whether\n the instance is enabled for hibernation. A value of true means that\n the instance is enabled for hibernation.

    \n
  • \n
  • \n

    \n host-id - The ID of the Dedicated Host on which the instance is\n running, if applicable.

    \n
  • \n
  • \n

    \n hypervisor - The hypervisor type of the instance\n (ovm | xen). The value xen is used\n for both Xen and Nitro hypervisors.

    \n
  • \n
  • \n

    \n iam-instance-profile.arn - The instance profile associated with\n the instance. Specified as an ARN.

    \n
  • \n
  • \n

    \n iam-instance-profile.id - The instance profile associated with\n the instance. Specified as an ID.

    \n
  • \n
  • \n

    \n iam-instance-profile.name - The instance profile associated with\n the instance. Specified as an name.

    \n
  • \n
  • \n

    \n image-id - The ID of the image used to launch the\n instance.

    \n
  • \n
  • \n

    \n instance-id - The ID of the instance.

    \n
  • \n
  • \n

    \n instance-lifecycle - Indicates whether this is a Spot Instance, a Scheduled Instance, or\n a Capacity Block (spot | scheduled | capacity-block).

    \n
  • \n
  • \n

    \n instance-state-code - The state of the instance, as a 16-bit\n unsigned integer. The high byte is used for internal purposes and should be\n ignored. The low byte is set based on the state represented. The valid values\n are: 0 (pending), 16 (running), 32 (shutting-down), 48 (terminated), 64\n (stopping), and 80 (stopped).

    \n
  • \n
  • \n

    \n instance-state-name - The state of the instance\n (pending | running | shutting-down |\n terminated | stopping |\n stopped).

    \n
  • \n
  • \n

    \n instance-type - The type of instance (for example,\n t2.micro).

    \n
  • \n
  • \n

    \n instance.group-id - The ID of the security group for the\n instance.

    \n
  • \n
  • \n

    \n instance.group-name - The name of the security group for the\n instance.

    \n
  • \n
  • \n

    \n ip-address - The public IPv4 address of the instance.

    \n
  • \n
  • \n

    \n ipv6-address - The IPv6 address of the instance.

    \n
  • \n
  • \n

    \n kernel-id - The kernel ID.

    \n
  • \n
  • \n

    \n key-name - The name of the key pair used when the instance was\n launched.

    \n
  • \n
  • \n

    \n launch-index - When launching multiple instances, this is the\n index for the instance in the launch group (for example, 0, 1, 2, and so on).\n

    \n
  • \n
  • \n

    \n launch-time - The time when the instance was launched, in the ISO\n 8601 format in the UTC time zone (YYYY-MM-DDThh:mm:ss.sssZ), for example,\n 2021-09-29T11:04:43.305Z. You can use a wildcard\n (*), for example, 2021-09-29T*, which matches an\n entire day.

    \n
  • \n
  • \n

    \n maintenance-options.auto-recovery - The current automatic\n recovery behavior of the instance (disabled | default).

    \n
  • \n
  • \n

    \n metadata-options.http-endpoint - The status of access to the HTTP\n metadata endpoint on your instance (enabled |\n disabled)

    \n
  • \n
  • \n

    \n metadata-options.http-protocol-ipv4 - Indicates whether the IPv4\n endpoint is enabled (disabled | enabled).

    \n
  • \n
  • \n

    \n metadata-options.http-protocol-ipv6 - Indicates whether the IPv6\n endpoint is enabled (disabled | enabled).

    \n
  • \n
  • \n

    \n metadata-options.http-put-response-hop-limit - The HTTP metadata\n request put response hop limit (integer, possible values 1 to\n 64)

    \n
  • \n
  • \n

    \n metadata-options.http-tokens - The metadata request authorization\n state (optional | required)

    \n
  • \n
  • \n

    \n metadata-options.instance-metadata-tags - The status of access to\n instance tags from the instance metadata (enabled |\n disabled)

    \n
  • \n
  • \n

    \n metadata-options.state - The state of the metadata option changes\n (pending | applied).

    \n
  • \n
  • \n

    \n monitoring-state - Indicates whether detailed monitoring is\n enabled (disabled | enabled).

    \n
  • \n
  • \n

    \n network-interface.addresses.association.allocation-id - The allocation ID.

    \n
  • \n
  • \n

    \n network-interface.addresses.association.association-id - The association ID.

    \n
  • \n
  • \n

    \n network-interface.addresses.association.carrier-ip - The carrier IP address.

    \n
  • \n
  • \n

    \n network-interface.addresses.association.customer-owned-ip - The customer-owned IP address.

    \n
  • \n
  • \n

    \n network-interface.addresses.association.ip-owner-id - The owner\n ID of the private IPv4 address associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.addresses.association.public-dns-name - The public DNS name.

    \n
  • \n
  • \n

    \n network-interface.addresses.association.public-ip - The ID of the\n association of an Elastic IP address (IPv4) with a network interface.

    \n
  • \n
  • \n

    \n network-interface.addresses.primary - Specifies whether the IPv4\n address of the network interface is the primary private IPv4 address.

    \n
  • \n
  • \n

    \n network-interface.addresses.private-dns-name - The private DNS name.

    \n
  • \n
  • \n

    \n network-interface.addresses.private-ip-address - The private IPv4\n address associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.association.allocation-id - The allocation ID\n returned when you allocated the Elastic IP address (IPv4) for your network\n interface.

    \n
  • \n
  • \n

    \n network-interface.association.association-id - The association ID\n returned when the network interface was associated with an IPv4 address.

    \n
  • \n
  • \n

    \n network-interface.association.carrier-ip - The customer-owned IP address.

    \n
  • \n
  • \n

    \n network-interface.association.customer-owned-ip - The customer-owned IP address.

    \n
  • \n
  • \n

    \n network-interface.association.ip-owner-id - The owner of the\n Elastic IP address (IPv4) associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.association.public-dns-name - The public DNS name.

    \n
  • \n
  • \n

    \n network-interface.association.public-ip - The address of the\n Elastic IP address (IPv4) bound to the network interface.

    \n
  • \n
  • \n

    \n network-interface.attachment.attach-time - The time that the\n network interface was attached to an instance.

    \n
  • \n
  • \n

    \n network-interface.attachment.attachment-id - The ID of the\n interface attachment.

    \n
  • \n
  • \n

    \n network-interface.attachment.delete-on-termination - Specifies\n whether the attachment is deleted when an instance is terminated.

    \n
  • \n
  • \n

    \n network-interface.attachment.device-index - The device index to\n which the network interface is attached.

    \n
  • \n
  • \n

    \n network-interface.attachment.instance-id - The ID of the instance\n to which the network interface is attached.

    \n
  • \n
  • \n

    \n network-interface.attachment.instance-owner-id - The owner ID of\n the instance to which the network interface is attached.

    \n
  • \n
  • \n

    \n network-interface.attachment.network-card-index - The index of the network card.

    \n
  • \n
  • \n

    \n network-interface.attachment.status - The status of the\n attachment (attaching | attached |\n detaching | detached).

    \n
  • \n
  • \n

    \n network-interface.availability-zone - The Availability Zone for\n the network interface.

    \n
  • \n
  • \n

    \n network-interface.deny-all-igw-traffic - A Boolean that indicates whether \n a network interface with an IPv6 address is unreachable from the public internet.

    \n
  • \n
  • \n

    \n network-interface.description - The description of the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.group-id - The ID of a security group\n associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.group-name - The name of a security group\n associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.ipv4-prefixes.ipv4-prefix - The IPv4 prefixes that are assigned to the network interface.

    \n
  • \n
  • \n

    \n network-interface.ipv6-address - The IPv6 address associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.ipv6-addresses.ipv6-address - The IPv6 address\n associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.ipv6-addresses.is-primary-ipv6 - A Boolean that indicates whether this\n is the primary IPv6 address.

    \n
  • \n
  • \n

    \n network-interface.ipv6-native - A Boolean that indicates whether this is\n an IPv6 only network interface.

    \n
  • \n
  • \n

    \n network-interface.ipv6-prefixes.ipv6-prefix - The IPv6 prefix assigned to the network interface.

    \n
  • \n
  • \n

    \n network-interface.mac-address - The MAC address of the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.network-interface-id - The ID of the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.outpost-arn - The ARN of the Outpost.

    \n
  • \n
  • \n

    \n network-interface.owner-id - The ID of the owner of the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.private-dns-name - The private DNS name of the\n network interface.

    \n
  • \n
  • \n

    \n network-interface.private-ip-address - The private IPv4 address.

    \n
  • \n
  • \n

    \n network-interface.public-dns-name - The public DNS name.

    \n
  • \n
  • \n

    \n network-interface.requester-id - The requester ID for the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.requester-managed - Indicates whether the\n network interface is being managed by Amazon Web Services.

    \n
  • \n
  • \n

    \n network-interface.status - The status of the network interface\n (available) | in-use).

    \n
  • \n
  • \n

    \n network-interface.source-dest-check - Whether the network\n interface performs source/destination checking. A value of true\n means that checking is enabled, and false means that checking is\n disabled. The value must be false for the network interface to\n perform network address translation (NAT) in your VPC.

    \n
  • \n
  • \n

    \n network-interface.subnet-id - The ID of the subnet for the\n network interface.

    \n
  • \n
  • \n

    \n network-interface.tag-key - The key of a tag assigned to the network interface.

    \n
  • \n
  • \n

    \n network-interface.tag-value - The value of a tag assigned to the network interface.

    \n
  • \n
  • \n

    \n network-interface.vpc-id - The ID of the VPC for the network\n interface.

    \n
  • \n
  • \n

    \n outpost-arn - The Amazon Resource Name (ARN) of the\n Outpost.

    \n
  • \n
  • \n

    \n owner-id - The Amazon Web Services account ID of the instance\n owner.

    \n
  • \n
  • \n

    \n placement-group-name - The name of the placement group for the\n instance.

    \n
  • \n
  • \n

    \n placement-partition-number - The partition in which the instance is\n located.

    \n
  • \n
  • \n

    \n platform - The platform. To list only Windows instances, use\n windows.

    \n
  • \n
  • \n

    \n platform-details - The platform (Linux/UNIX |\n Red Hat BYOL Linux | Red Hat Enterprise Linux |\n Red Hat Enterprise Linux with HA | Red Hat Enterprise\n Linux with SQL Server Standard and HA | Red Hat Enterprise\n Linux with SQL Server Enterprise and HA | Red Hat Enterprise\n Linux with SQL Server Standard | Red Hat Enterprise Linux with\n SQL Server Web | Red Hat Enterprise Linux with SQL Server\n Enterprise | SQL Server Enterprise | SQL Server\n Standard | SQL Server Web | SUSE Linux |\n Ubuntu Pro | Windows | Windows BYOL |\n Windows with SQL Server Enterprise | Windows with SQL\n Server Standard | Windows with SQL Server Web).

    \n
  • \n
  • \n

    \n private-dns-name - The private IPv4 DNS name of the\n instance.

    \n
  • \n
  • \n

    \n private-dns-name-options.enable-resource-name-dns-a-record - A\n Boolean that indicates whether to respond to DNS queries for instance hostnames\n with DNS A records.

    \n
  • \n
  • \n

    \n private-dns-name-options.enable-resource-name-dns-aaaa-record - A\n Boolean that indicates whether to respond to DNS queries for instance hostnames\n with DNS AAAA records.

    \n
  • \n
  • \n

    \n private-dns-name-options.hostname-type - The type of hostname\n (ip-name | resource-name).

    \n
  • \n
  • \n

    \n private-ip-address - The private IPv4 address of the\n instance.

    \n
  • \n
  • \n

    \n product-code - The product code associated with the AMI used to\n launch the instance.

    \n
  • \n
  • \n

    \n product-code.type - The type of product code (devpay\n | marketplace).

    \n
  • \n
  • \n

    \n ramdisk-id - The RAM disk ID.

    \n
  • \n
  • \n

    \n reason - The reason for the current state of the instance (for\n example, shows \"User Initiated [date]\" when you stop or terminate the instance).\n Similar to the state-reason-code filter.

    \n
  • \n
  • \n

    \n requester-id - The ID of the entity that launched the instance on\n your behalf (for example, Amazon Web Services Management Console, Auto Scaling, and so\n on).

    \n
  • \n
  • \n

    \n reservation-id - The ID of the instance's reservation. A\n reservation ID is created any time you launch an instance. A reservation ID has\n a one-to-one relationship with an instance launch request, but can be associated\n with more than one instance if you launch multiple instances using the same\n launch request. For example, if you launch one instance, you get one reservation\n ID. If you launch ten instances using the same launch request, you also get one\n reservation ID.

    \n
  • \n
  • \n

    \n root-device-name - The device name of the root device volume (for\n example, /dev/sda1).

    \n
  • \n
  • \n

    \n root-device-type - The type of the root device volume\n (ebs | instance-store).

    \n
  • \n
  • \n

    \n source-dest-check - Indicates whether the instance performs\n source/destination checking. A value of true means that checking is\n enabled, and false means that checking is disabled. The value must\n be false for the instance to perform network address translation\n (NAT) in your VPC.

    \n
  • \n
  • \n

    \n spot-instance-request-id - The ID of the Spot Instance\n request.

    \n
  • \n
  • \n

    \n state-reason-code - The reason code for the state change.

    \n
  • \n
  • \n

    \n state-reason-message - A message that describes the state\n change.

    \n
  • \n
  • \n

    \n subnet-id - The ID of the subnet for the instance.

    \n
  • \n
  • \n

    \n tag: - The key/value combination of a tag assigned to the resource. Use the tag key in the filter name and the tag value as the filter value.\n For example, to find all resources that have a tag with the key Owner and the value TeamA, specify tag:Owner for the filter name and TeamA for the filter value.

    \n
  • \n
  • \n

    \n tag-key - The key of a tag assigned to the resource. Use this filter to find all resources that have a tag with a specific key, regardless of the tag value.

    \n
  • \n
  • \n

    \n tenancy - The tenancy of an instance (dedicated |\n default | host).

    \n
  • \n
  • \n

    \n tpm-support - Indicates if the instance is configured for\n NitroTPM support (v2.0).

    \n
  • \n
  • \n

    \n usage-operation - The usage operation value for the instance\n (RunInstances | RunInstances:00g0 |\n RunInstances:0010 | RunInstances:1010 |\n RunInstances:1014 | RunInstances:1110 |\n RunInstances:0014 | RunInstances:0210 |\n RunInstances:0110 | RunInstances:0100 |\n RunInstances:0004 | RunInstances:0200 |\n RunInstances:000g | RunInstances:0g00 |\n RunInstances:0002 | RunInstances:0800 |\n RunInstances:0102 | RunInstances:0006 |\n RunInstances:0202).

    \n
  • \n
  • \n

    \n usage-operation-update-time - The time that the usage operation\n was last updated, for example, 2022-09-15T17:15:20.000Z.

    \n
  • \n
  • \n

    \n virtualization-type - The virtualization type of the instance\n (paravirtual | hvm).

    \n
  • \n
  • \n

    \n vpc-id - The ID of the VPC that the instance is running in.

    \n
  • \n
", "smithy.api#xmlName": "Filter" } }, @@ -31166,6 +32122,77 @@ "smithy.api#output": {} } }, + "com.amazonaws.ec2#DescribeIpamByoasn": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#DescribeIpamByoasnRequest" + }, + "output": { + "target": "com.amazonaws.ec2#DescribeIpamByoasnResult" + }, + "traits": { + "smithy.api#documentation": "

Describes your Autonomous System Numbers (ASNs), their provisioning statuses, and the BYOIP CIDRs with which they are associated. For more information, see Tutorial: Bring your ASN to IPAM in the Amazon VPC IPAM guide.

" + } + }, + "com.amazonaws.ec2#DescribeIpamByoasnMaxResults": { + "type": "integer", + "traits": { + "smithy.api#range": { + "min": 1, + "max": 100 + } + } + }, + "com.amazonaws.ec2#DescribeIpamByoasnRequest": { + "type": "structure", + "members": { + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, \n and provides an error response. If you have the required permissions, the error response is DryRunOperation. \n Otherwise, it is UnauthorizedOperation.

" + } + }, + "MaxResults": { + "target": "com.amazonaws.ec2#DescribeIpamByoasnMaxResults", + "traits": { + "smithy.api#documentation": "

The maximum number of results to return with a single call.\n\tTo retrieve the remaining results, make another call with the returned nextToken value.

" + } + }, + "NextToken": { + "target": "com.amazonaws.ec2#NextToken", + "traits": { + "smithy.api#documentation": "

The token for the next page of results.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#DescribeIpamByoasnResult": { + "type": "structure", + "members": { + "Byoasns": { + "target": "com.amazonaws.ec2#ByoasnSet", + "traits": { + "aws.protocols#ec2QueryName": "ByoasnSet", + "smithy.api#documentation": "

ASN and BYOIP CIDR associations.

", + "smithy.api#xmlName": "byoasnSet" + } + }, + "NextToken": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "NextToken", + "smithy.api#documentation": "

The token to use to retrieve the next page of results. This value is null when there are no more results to return.

", + "smithy.api#xmlName": "nextToken" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#DescribeIpamPools": { "type": "operation", "input": { @@ -32559,6 +33586,91 @@ "smithy.api#output": {} } }, + "com.amazonaws.ec2#DescribeLockedSnapshots": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#DescribeLockedSnapshotsRequest" + }, + "output": { + "target": "com.amazonaws.ec2#DescribeLockedSnapshotsResult" + }, + "traits": { + "smithy.api#documentation": "

Describes the lock status for a snapshot.

" + } + }, + "com.amazonaws.ec2#DescribeLockedSnapshotsMaxResults": { + "type": "integer", + "traits": { + "smithy.api#range": { + "min": 5, + "max": 1000 + } + } + }, + "com.amazonaws.ec2#DescribeLockedSnapshotsRequest": { + "type": "structure", + "members": { + "Filters": { + "target": "com.amazonaws.ec2#FilterList", + "traits": { + "smithy.api#documentation": "

The filters.

\n
    \n
  • \n

    \n lock-state - The state of the snapshot lock (compliance-cooloff | \n governance | compliance | expired).

    \n
  • \n
", + "smithy.api#xmlName": "Filter" + } + }, + "MaxResults": { + "target": "com.amazonaws.ec2#DescribeLockedSnapshotsMaxResults", + "traits": { + "smithy.api#documentation": "

The maximum number of items to return for this request.\n\tTo get the next page of items, make another request with the token returned in the output. \n\tFor more information, see Pagination.

" + } + }, + "NextToken": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#documentation": "

The token returned from a previous paginated request.\n Pagination continues from the end of the items returned by the previous request.

" + } + }, + "SnapshotIds": { + "target": "com.amazonaws.ec2#SnapshotIdStringList", + "traits": { + "smithy.api#documentation": "

The IDs of the snapshots for which to view the lock status.

", + "smithy.api#xmlName": "SnapshotId" + } + }, + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, \n and provides an error response. If you have the required permissions, the error response is DryRunOperation. \n Otherwise, it is UnauthorizedOperation.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#DescribeLockedSnapshotsResult": { + "type": "structure", + "members": { + "Snapshots": { + "target": "com.amazonaws.ec2#LockedSnapshotsInfoList", + "traits": { + "aws.protocols#ec2QueryName": "SnapshotSet", + "smithy.api#documentation": "

Information about the snapshots.

", + "smithy.api#xmlName": "snapshotSet" + } + }, + "NextToken": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "NextToken", + "smithy.api#documentation": "

The token to include in another request to get the next page of items. \n This value is null when there are no more items to return.

", + "smithy.api#xmlName": "nextToken" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#DescribeManagedPrefixLists": { "type": "operation", "input": { @@ -35068,7 +36180,7 @@ "target": "com.amazonaws.ec2#DescribeSecurityGroupReferencesResult" }, "traits": { - "smithy.api#documentation": "

Describes the VPCs on the other side of a VPC peering connection that are referencing the security groups you've specified in this request.

", + "smithy.api#documentation": "

Describes the VPCs on the other side of a VPC peering connection or the VPCs attached to a transit gateway that are referencing the security groups you've specified in this request.

", "smithy.api#examples": [ { "title": "To describe security group references", @@ -36321,7 +37433,7 @@ "Filters": { "target": "com.amazonaws.ec2#FilterList", "traits": { - "smithy.api#documentation": "

The filters.

\n
    \n
  • \n

    \n availability-zone-group - The Availability Zone group.

    \n
  • \n
  • \n

    \n create-time - The time stamp when the Spot Instance request was\n created.

    \n
  • \n
  • \n

    \n fault-code - The fault code related to the request.

    \n
  • \n
  • \n

    \n fault-message - The fault message related to the request.

    \n
  • \n
  • \n

    \n instance-id - The ID of the instance that fulfilled the\n request.

    \n
  • \n
  • \n

    \n launch-group - The Spot Instance launch group.

    \n
  • \n
  • \n

    \n launch.block-device-mapping.delete-on-termination - Indicates\n whether the EBS volume is deleted on instance termination.

    \n
  • \n
  • \n

    \n launch.block-device-mapping.device-name - The device name for the\n volume in the block device mapping (for example, /dev/sdh or\n xvdh).

    \n
  • \n
  • \n

    \n launch.block-device-mapping.snapshot-id - The ID of the snapshot\n for the EBS volume.

    \n
  • \n
  • \n

    \n launch.block-device-mapping.volume-size - The size of the EBS\n volume, in GiB.

    \n
  • \n
  • \n

    \n launch.block-device-mapping.volume-type - The type of EBS volume:\n gp2 for General Purpose SSD, io1 or\n io2 for Provisioned IOPS SSD, st1 for Throughput\n Optimized HDD, sc1for Cold HDD, or standard for\n Magnetic.

    \n
  • \n
  • \n

    \n launch.group-id - The ID of the security group for the\n instance.

    \n
  • \n
  • \n

    \n launch.group-name - The name of the security group for the\n instance.

    \n
  • \n
  • \n

    \n launch.image-id - The ID of the AMI.

    \n
  • \n
  • \n

    \n launch.instance-type - The type of instance (for example,\n m3.medium).

    \n
  • \n
  • \n

    \n launch.kernel-id - The kernel ID.

    \n
  • \n
  • \n

    \n launch.key-name - The name of the key pair the instance launched\n with.

    \n
  • \n
  • \n

    \n launch.monitoring-enabled - Whether detailed monitoring is\n enabled for the Spot Instance.

    \n
  • \n
  • \n

    \n launch.ramdisk-id - The RAM disk ID.

    \n
  • \n
  • \n

    \n launched-availability-zone - The Availability Zone in which the\n request is launched.

    \n
  • \n
  • \n

    \n network-interface.addresses.primary - Indicates whether the IP\n address is the primary private IP address.

    \n
  • \n
  • \n

    \n network-interface.delete-on-termination - Indicates whether the\n network interface is deleted when the instance is terminated.

    \n
  • \n
  • \n

    \n network-interface.description - A description of the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.device-index - The index of the device for the\n network interface attachment on the instance.

    \n
  • \n
  • \n

    \n network-interface.group-id - The ID of the security group\n associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.network-interface-id - The ID of the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.private-ip-address - The primary private IP\n address of the network interface.

    \n
  • \n
  • \n

    \n network-interface.subnet-id - The ID of the subnet for the\n instance.

    \n
  • \n
  • \n

    \n product-description - The product description associated with the\n instance (Linux/UNIX | Windows).

    \n
  • \n
  • \n

    \n spot-instance-request-id - The Spot Instance request ID.

    \n
  • \n
  • \n

    \n spot-price - The maximum hourly price for any Spot Instance\n launched to fulfill the request.

    \n
  • \n
  • \n

    \n state - The state of the Spot Instance request (open\n | active | closed | cancelled |\n failed). Spot request status information can help you track\n your Amazon EC2 Spot Instance requests. For more information, see Spot\n request status in the Amazon EC2 User Guide for Linux Instances.

    \n
  • \n
  • \n

    \n status-code - The short code describing the most recent\n evaluation of your Spot Instance request.

    \n
  • \n
  • \n

    \n status-message - The message explaining the status of the Spot\n Instance request.

    \n
  • \n
  • \n

    \n tag: - The key/value combination of a tag assigned to the resource. Use the tag key in the filter name and the tag value as the filter value.\n For example, to find all resources that have a tag with the key Owner and the value TeamA, specify tag:Owner for the filter name and TeamA for the filter value.

    \n
  • \n
  • \n

    \n tag-key - The key of a tag assigned to the resource. Use this filter to find all resources assigned a tag with a specific key, regardless of the tag value.

    \n
  • \n
  • \n

    \n type - The type of Spot Instance request (one-time |\n persistent).

    \n
  • \n
  • \n

    \n valid-from - The start date of the request.

    \n
  • \n
  • \n

    \n valid-until - The end date of the request.

    \n
  • \n
", + "smithy.api#documentation": "

The filters.

\n
    \n
  • \n

    \n availability-zone-group - The Availability Zone group.

    \n
  • \n
  • \n

    \n create-time - The time stamp when the Spot Instance request was\n created.

    \n
  • \n
  • \n

    \n fault-code - The fault code related to the request.

    \n
  • \n
  • \n

    \n fault-message - The fault message related to the request.

    \n
  • \n
  • \n

    \n instance-id - The ID of the instance that fulfilled the\n request.

    \n
  • \n
  • \n

    \n launch-group - The Spot Instance launch group.

    \n
  • \n
  • \n

    \n launch.block-device-mapping.delete-on-termination - Indicates\n whether the EBS volume is deleted on instance termination.

    \n
  • \n
  • \n

    \n launch.block-device-mapping.device-name - The device name for the\n volume in the block device mapping (for example, /dev/sdh or\n xvdh).

    \n
  • \n
  • \n

    \n launch.block-device-mapping.snapshot-id - The ID of the snapshot\n for the EBS volume.

    \n
  • \n
  • \n

    \n launch.block-device-mapping.volume-size - The size of the EBS\n volume, in GiB.

    \n
  • \n
  • \n

    \n launch.block-device-mapping.volume-type - The type of EBS volume:\n gp2 or gp3 for General Purpose SSD, io1 \n or io2 for Provisioned IOPS SSD, st1 for Throughput\n Optimized HDD, sc1 for Cold HDD, or standard for\n Magnetic.

    \n
  • \n
  • \n

    \n launch.group-id - The ID of the security group for the\n instance.

    \n
  • \n
  • \n

    \n launch.group-name - The name of the security group for the\n instance.

    \n
  • \n
  • \n

    \n launch.image-id - The ID of the AMI.

    \n
  • \n
  • \n

    \n launch.instance-type - The type of instance (for example,\n m3.medium).

    \n
  • \n
  • \n

    \n launch.kernel-id - The kernel ID.

    \n
  • \n
  • \n

    \n launch.key-name - The name of the key pair the instance launched\n with.

    \n
  • \n
  • \n

    \n launch.monitoring-enabled - Whether detailed monitoring is\n enabled for the Spot Instance.

    \n
  • \n
  • \n

    \n launch.ramdisk-id - The RAM disk ID.

    \n
  • \n
  • \n

    \n launched-availability-zone - The Availability Zone in which the\n request is launched.

    \n
  • \n
  • \n

    \n network-interface.addresses.primary - Indicates whether the IP\n address is the primary private IP address.

    \n
  • \n
  • \n

    \n network-interface.delete-on-termination - Indicates whether the\n network interface is deleted when the instance is terminated.

    \n
  • \n
  • \n

    \n network-interface.description - A description of the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.device-index - The index of the device for the\n network interface attachment on the instance.

    \n
  • \n
  • \n

    \n network-interface.group-id - The ID of the security group\n associated with the network interface.

    \n
  • \n
  • \n

    \n network-interface.network-interface-id - The ID of the network\n interface.

    \n
  • \n
  • \n

    \n network-interface.private-ip-address - The primary private IP\n address of the network interface.

    \n
  • \n
  • \n

    \n network-interface.subnet-id - The ID of the subnet for the\n instance.

    \n
  • \n
  • \n

    \n product-description - The product description associated with the\n instance (Linux/UNIX | Windows).

    \n
  • \n
  • \n

    \n spot-instance-request-id - The Spot Instance request ID.

    \n
  • \n
  • \n

    \n spot-price - The maximum hourly price for any Spot Instance\n launched to fulfill the request.

    \n
  • \n
  • \n

    \n state - The state of the Spot Instance request (open\n | active | closed | cancelled |\n failed). Spot request status information can help you track\n your Amazon EC2 Spot Instance requests. For more information, see Spot\n request status in the Amazon EC2 User Guide for Linux Instances.

    \n
  • \n
  • \n

    \n status-code - The short code describing the most recent\n evaluation of your Spot Instance request.

    \n
  • \n
  • \n

    \n status-message - The message explaining the status of the Spot\n Instance request.

    \n
  • \n
  • \n

    \n tag: - The key/value combination of a tag assigned to the resource. Use the tag key in the filter name and the tag value as the filter value.\n For example, to find all resources that have a tag with the key Owner and the value TeamA, specify tag:Owner for the filter name and TeamA for the filter value.

    \n
  • \n
  • \n

    \n tag-key - The key of a tag assigned to the resource. Use this filter to find all resources assigned a tag with a specific key, regardless of the tag value.

    \n
  • \n
  • \n

    \n type - The type of Spot Instance request (one-time |\n persistent).

    \n
  • \n
  • \n

    \n valid-from - The start date of the request.

    \n
  • \n
  • \n

    \n valid-until - The end date of the request.

    \n
  • \n
", "smithy.api#xmlName": "Filter" } }, @@ -36547,7 +37659,7 @@ "target": "com.amazonaws.ec2#DescribeStaleSecurityGroupsResult" }, "traits": { - "smithy.api#documentation": "

Describes the stale security group rules for security groups in a specified VPC. \n Rules are stale when they reference a deleted security group in the same VPC or in a peer VPC, \n or if they reference a security group in a peer VPC for which the VPC peering connection has \n been deleted.

", + "smithy.api#documentation": "

Describes the stale security group rules for security groups in a specified VPC. \n Rules are stale when they reference a deleted security group in the same VPC, peered VPC, or in separate VPCs attached to a transit gateway (with security group referencing support enabled). Rules can also be stale if they reference a security group in a peer VPC for which the VPC peering connection has \n been deleted or if they reference a security group in a VPC that has been detached from a transit gateway.

", "smithy.api#paginated": { "inputToken": "NextToken", "outputToken": "NextToken", @@ -38078,7 +39190,7 @@ "target": "com.amazonaws.ec2#DescribeTrunkInterfaceAssociationsResult" }, "traits": { - "smithy.api#documentation": "\n

This API action is currently in limited preview only. \n If you are interested in using this feature, contact your account manager.

\n
\n

Describes one or more network interface trunk associations.

", + "smithy.api#documentation": "

Describes one or more network interface trunk associations.

", "smithy.api#paginated": { "inputToken": "NextToken", "outputToken": "NextToken", @@ -38246,7 +39358,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessEndpointList", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessEndpointSet", - "smithy.api#documentation": "

The ID of the Verified Access endpoint.

", + "smithy.api#documentation": "

Details about the Verified Access endpoints.

", "smithy.api#xmlName": "verifiedAccessEndpointSet" } }, @@ -38343,7 +39455,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessGroupList", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessGroupSet", - "smithy.api#documentation": "

The ID of the Verified Access group.

", + "smithy.api#documentation": "

Details about the Verified Access groups.

", "smithy.api#xmlName": "verifiedAccessGroupSet" } }, @@ -38434,7 +39546,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessInstanceLoggingConfigurationList", "traits": { "aws.protocols#ec2QueryName": "LoggingConfigurationSet", - "smithy.api#documentation": "

The current logging configuration for the Verified Access instances.

", + "smithy.api#documentation": "

The logging configuration for the Verified Access instances.

", "smithy.api#xmlName": "loggingConfigurationSet" } }, @@ -38525,7 +39637,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessInstanceList", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessInstanceSet", - "smithy.api#documentation": "

The IDs of the Verified Access instances.

", + "smithy.api#documentation": "

Details about the Verified Access instances.

", "smithy.api#xmlName": "verifiedAccessInstanceSet" } }, @@ -38616,7 +39728,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessTrustProviderList", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessTrustProviderSet", - "smithy.api#documentation": "

The IDs of the Verified Access trust providers.

", + "smithy.api#documentation": "

Details about the Verified Access trust providers.

", "smithy.api#xmlName": "verifiedAccessTrustProviderSet" } }, @@ -40641,7 +41753,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessTrustProvider", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessTrustProvider", - "smithy.api#documentation": "

The ID of the Verified Access trust provider.

", + "smithy.api#documentation": "

Details about the Verified Access trust provider.

", "smithy.api#xmlName": "verifiedAccessTrustProvider" } }, @@ -40649,7 +41761,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessInstance", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessInstance", - "smithy.api#documentation": "

The ID of the Verified Access instance.

", + "smithy.api#documentation": "

Details about the Verified Access instance.

", "smithy.api#xmlName": "verifiedAccessInstance" } } @@ -40783,6 +41895,14 @@ "smithy.api#documentation": "

The ID of the tenant application with the device-identity provider.

", "smithy.api#xmlName": "tenantId" } + }, + "PublicSigningKeyUrl": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "PublicSigningKeyUrl", + "smithy.api#documentation": "

\n The URL Amazon Web Services Verified Access will use to verify the authenticity of the device tokens.\n

", + "smithy.api#xmlName": "publicSigningKeyUrl" + } } }, "traits": { @@ -40803,6 +41923,12 @@ "traits": { "smithy.api#enumValue": "crowdstrike" } + }, + "jumpcloud": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "jumpcloud" + } } } }, @@ -41123,7 +42249,7 @@ "target": "com.amazonaws.ec2#DisableFastLaunchResult" }, "traits": { - "smithy.api#documentation": "

Discontinue faster launching for a Windows AMI, and clean up existing pre-provisioned snapshots. \n\t\t\tWhen you disable faster launching, the AMI uses the standard launch process for each \n\t\t\tinstance. All pre-provisioned snapshots must be removed before you can enable faster launching again.

\n \n

To change these settings, you must own the AMI.

\n
" + "smithy.api#documentation": "

Discontinue Windows fast launch for a Windows AMI, and clean up existing pre-provisioned snapshots. \n\t\t\tAfter you disable Windows fast launch, the AMI uses the standard launch process for each \n\t\t\tnew instance. Amazon EC2 must remove all pre-provisioned snapshots before you can enable Windows fast launch again.

\n \n

You can only change these settings for Windows AMIs that you own or that have been shared with you.

\n
" } }, "com.amazonaws.ec2#DisableFastLaunchRequest": { @@ -41133,14 +42259,14 @@ "target": "com.amazonaws.ec2#ImageId", "traits": { "smithy.api#clientOptional": {}, - "smithy.api#documentation": "

The ID of the image for which you’re turning off faster launching, and removing pre-provisioned snapshots.

", + "smithy.api#documentation": "

Specify the ID of the image for which to disable Windows fast launch.

", "smithy.api#required": {} } }, "Force": { "target": "com.amazonaws.ec2#Boolean", "traits": { - "smithy.api#documentation": "

Forces the image settings to turn off faster launching for your Windows AMI. This parameter overrides \n\t\t\tany errors that are encountered while cleaning up resources in your account.

" + "smithy.api#documentation": "

Forces the image settings to turn off Windows fast launch for your Windows AMI. This parameter overrides \n\t\t\tany errors that are encountered while cleaning up resources in your account.

" } }, "DryRun": { @@ -41161,7 +42287,7 @@ "target": "com.amazonaws.ec2#ImageId", "traits": { "aws.protocols#ec2QueryName": "ImageId", - "smithy.api#documentation": "

The ID of the image for which faster-launching has been turned off.

", + "smithy.api#documentation": "

The ID of the image for which Windows fast launch was disabled.

", "smithy.api#xmlName": "imageId" } }, @@ -41169,7 +42295,7 @@ "target": "com.amazonaws.ec2#FastLaunchResourceType", "traits": { "aws.protocols#ec2QueryName": "ResourceType", - "smithy.api#documentation": "

The pre-provisioning resource type that must be cleaned after turning off faster launching \n\t\t\tfor the Windows AMI. Supported values include: snapshot.

", + "smithy.api#documentation": "

The pre-provisioning resource type that must be cleaned after turning off Windows fast launch \n\t\t\tfor the Windows AMI. Supported values include: snapshot.

", "smithy.api#xmlName": "resourceType" } }, @@ -41177,7 +42303,7 @@ "target": "com.amazonaws.ec2#FastLaunchSnapshotConfigurationResponse", "traits": { "aws.protocols#ec2QueryName": "SnapshotConfiguration", - "smithy.api#documentation": "

Parameters that were used for faster launching for the Windows AMI before \n\t\t\tfaster launching was turned off. This informs the clean-up process.

", + "smithy.api#documentation": "

Parameters that were used for Windows fast launch for the Windows AMI before \n\t\t\tWindows fast launch was disabled. This informs the clean-up process.

", "smithy.api#xmlName": "snapshotConfiguration" } }, @@ -41193,7 +42319,7 @@ "target": "com.amazonaws.ec2#Integer", "traits": { "aws.protocols#ec2QueryName": "MaxParallelLaunches", - "smithy.api#documentation": "

The maximum number of instances that Amazon EC2 can launch at the same time to \n\t\t\tcreate pre-provisioned snapshots for Windows faster launching.

", + "smithy.api#documentation": "

The maximum number of instances that Amazon EC2 can launch at the same time to \n\t\t\tcreate pre-provisioned snapshots for Windows fast launch.

", "smithy.api#xmlName": "maxParallelLaunches" } }, @@ -41201,7 +42327,7 @@ "target": "com.amazonaws.ec2#String", "traits": { "aws.protocols#ec2QueryName": "OwnerId", - "smithy.api#documentation": "

The owner of the Windows AMI for which faster launching was turned off.

", + "smithy.api#documentation": "

The owner of the Windows AMI for which Windows fast launch was disabled.

", "smithy.api#xmlName": "ownerId" } }, @@ -41209,7 +42335,7 @@ "target": "com.amazonaws.ec2#FastLaunchStateCode", "traits": { "aws.protocols#ec2QueryName": "State", - "smithy.api#documentation": "

The current state of faster launching for the specified Windows AMI.

", + "smithy.api#documentation": "

The current state of Windows fast launch for the specified Windows AMI.

", "smithy.api#xmlName": "state" } }, @@ -41217,7 +42343,7 @@ "target": "com.amazonaws.ec2#String", "traits": { "aws.protocols#ec2QueryName": "StateTransitionReason", - "smithy.api#documentation": "

The reason that the state changed for faster launching for the Windows AMI.

", + "smithy.api#documentation": "

The reason that the state changed for Windows fast launch for the Windows AMI.

", "smithy.api#xmlName": "stateTransitionReason" } }, @@ -41225,7 +42351,7 @@ "target": "com.amazonaws.ec2#MillisecondDateTime", "traits": { "aws.protocols#ec2QueryName": "StateTransitionTime", - "smithy.api#documentation": "

The time that the state changed for faster launching for the Windows AMI.

", + "smithy.api#documentation": "

The time that the state changed for Windows fast launch for the Windows AMI.

", "smithy.api#xmlName": "stateTransitionTime" } } @@ -41506,7 +42632,7 @@ "target": "com.amazonaws.ec2#DisableImageResult" }, "traits": { - "smithy.api#documentation": "

Sets the AMI state to disabled and removes all launch permissions from the\n AMI. A disabled AMI can't be used for instance launches.

\n

A disabled AMI can't be shared. If a public or shared AMI was previously shared, it is\n made private. If an AMI was shared with an Amazon Web Services account, organization, or Organizational\n Unit, they lose access to the disabled AMI.

\n

A disabled AMI does not appear in DescribeImages API calls by\n default.

\n

Only the AMI owner can disable an AMI.

\n

You can re-enable a disabled AMI using EnableImage.

\n

For more information, see Disable an AMI in the\n Amazon EC2 User Guide.

" + "smithy.api#documentation": "

Sets the AMI state to disabled and removes all launch permissions from the\n AMI. A disabled AMI can't be used for instance launches.

\n

A disabled AMI can't be shared. If an AMI was public or previously shared, it is made\n private. If an AMI was shared with an Amazon Web Services account, organization, or Organizational Unit,\n they lose access to the disabled AMI.

\n

A disabled AMI does not appear in DescribeImages API calls by\n default.

\n

Only the AMI owner can disable an AMI.

\n

You can re-enable a disabled AMI using EnableImage.

\n

For more information, see Disable an AMI in the\n Amazon EC2 User Guide.

" } }, "com.amazonaws.ec2#DisableImageBlockPublicAccess": { @@ -41731,6 +42857,48 @@ "smithy.api#output": {} } }, + "com.amazonaws.ec2#DisableSnapshotBlockPublicAccess": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#DisableSnapshotBlockPublicAccessRequest" + }, + "output": { + "target": "com.amazonaws.ec2#DisableSnapshotBlockPublicAccessResult" + }, + "traits": { + "smithy.api#documentation": "

Disables the block public access for snapshots setting at \n the account level for the specified Amazon Web Services Region. After you disable block public \n access for snapshots in a Region, users can publicly share snapshots in that Region.

\n

If block public access is enabled in block-all-sharing mode, and \n you disable block public access, all snapshots that were previously publicly shared \n are no longer treated as private and they become publicly accessible again.

\n

For more information, see \n Block public access for snapshots in the Amazon Elastic Compute Cloud User Guide .

\n

" + } + }, + "com.amazonaws.ec2#DisableSnapshotBlockPublicAccessRequest": { + "type": "structure", + "members": { + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, \n and provides an error response. If you have the required permissions, the error response is DryRunOperation. \n Otherwise, it is UnauthorizedOperation.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#DisableSnapshotBlockPublicAccessResult": { + "type": "structure", + "members": { + "State": { + "target": "com.amazonaws.ec2#SnapshotBlockPublicAccessState", + "traits": { + "aws.protocols#ec2QueryName": "State", + "smithy.api#documentation": "

Returns unblocked if the request succeeds.

", + "smithy.api#xmlName": "state" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#DisableTransitGatewayRouteTablePropagation": { "type": "operation", "input": { @@ -42016,7 +43184,7 @@ } }, "AssociationId": { - "target": "com.amazonaws.ec2#ClientVpnAssociationId", + "target": "com.amazonaws.ec2#String", "traits": { "smithy.api#clientOptional": {}, "smithy.api#documentation": "

The ID of the target network association.

", @@ -42238,6 +43406,64 @@ "smithy.api#output": {} } }, + "com.amazonaws.ec2#DisassociateIpamByoasn": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#DisassociateIpamByoasnRequest" + }, + "output": { + "target": "com.amazonaws.ec2#DisassociateIpamByoasnResult" + }, + "traits": { + "smithy.api#documentation": "

Remove the association between your Autonomous System Number (ASN) and your BYOIP CIDR. You may want to use this action to disassociate an ASN from a CIDR or if you want to swap ASNs. \n For more information, see Tutorial: Bring your ASN to IPAM in the Amazon VPC IPAM guide.

" + } + }, + "com.amazonaws.ec2#DisassociateIpamByoasnRequest": { + "type": "structure", + "members": { + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, \n and provides an error response. If you have the required permissions, the error response is DryRunOperation. \n Otherwise, it is UnauthorizedOperation.

" + } + }, + "Asn": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

A public 2-byte or 4-byte ASN.

", + "smithy.api#required": {} + } + }, + "Cidr": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

A BYOIP CIDR.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#DisassociateIpamByoasnResult": { + "type": "structure", + "members": { + "AsnAssociation": { + "target": "com.amazonaws.ec2#AsnAssociation", + "traits": { + "aws.protocols#ec2QueryName": "AsnAssociation", + "smithy.api#documentation": "

An ASN and BYOIP CIDR association.

", + "smithy.api#xmlName": "asnAssociation" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#DisassociateIpamResourceDiscovery": { "type": "operation", "input": { @@ -42653,7 +43879,7 @@ "target": "com.amazonaws.ec2#DisassociateTrunkInterfaceResult" }, "traits": { - "smithy.api#documentation": "\n

This API action is currently in limited preview only. \n If you are interested in using this feature, contact your account manager.

\n
\n

Removes an association between a branch network interface with a trunk network interface.

" + "smithy.api#documentation": "

Removes an association between a branch network interface with a trunk network interface.

" } }, "com.amazonaws.ec2#DisassociateTrunkInterfaceRequest": { @@ -43228,7 +44454,7 @@ "target": "com.amazonaws.ec2#Integer", "traits": { "aws.protocols#ec2QueryName": "Iops", - "smithy.api#documentation": "

The number of I/O operations per second (IOPS). For gp3, io1, and io2 volumes,\n this represents the number of IOPS that are provisioned for the volume. For gp2\n volumes, this represents the baseline performance of the volume and the rate at which\n the volume accumulates I/O credits for bursting.

\n

The following are the supported values for each volume type:

\n
    \n
  • \n

    \n gp3: 3,000-16,000 IOPS

    \n
  • \n
  • \n

    \n io1: 100-64,000 IOPS

    \n
  • \n
  • \n

    \n io2: 100-64,000 IOPS

    \n
  • \n
\n

For io1 and io2 volumes, we guarantee 64,000 IOPS only for\n Instances built on the\n Nitro System. Other instance families guarantee performance up to\n 32,000 IOPS.

\n

This parameter is required for io1 and io2 volumes. The default for gp3 volumes\n is 3,000 IOPS. This parameter is not supported for gp2, st1, sc1, or standard\n volumes.

", + "smithy.api#documentation": "

The number of I/O operations per second (IOPS). For gp3, io1, and io2 volumes,\n this represents the number of IOPS that are provisioned for the volume. For gp2\n volumes, this represents the baseline performance of the volume and the rate at which\n the volume accumulates I/O credits for bursting.

\n

The following are the supported values for each volume type:

\n
    \n
  • \n

    \n gp3: 3,000 - 16,000 IOPS

    \n
  • \n
  • \n

    \n io1: 100 - 64,000 IOPS

    \n
  • \n
  • \n

    \n io2: 100 - 256,000 IOPS

    \n
  • \n
\n

For io2 volumes, you can achieve up to 256,000 IOPS on \ninstances \nbuilt on the Nitro System. On other instances, you can achieve performance up to 32,000 IOPS.

\n

This parameter is required for io1 and io2 volumes. The default for gp3 volumes\n is 3,000 IOPS.

", "smithy.api#xmlName": "iops" } }, @@ -43244,7 +44470,7 @@ "target": "com.amazonaws.ec2#Integer", "traits": { "aws.protocols#ec2QueryName": "VolumeSize", - "smithy.api#documentation": "

The size of the volume, in GiBs. You must specify either a snapshot ID or a volume\n size. If you specify a snapshot, the default is the snapshot size. You can specify a\n volume size that is equal to or larger than the snapshot size.

\n

The following are the supported volumes sizes for each volume type:

\n
    \n
  • \n

    \n gp2 and gp3:1-16,384

    \n
  • \n
  • \n

    \n io1 and io2: 4-16,384

    \n
  • \n
  • \n

    \n st1 and sc1: 125-16,384

    \n
  • \n
  • \n

    \n standard: 1-1,024

    \n
  • \n
", + "smithy.api#documentation": "

The size of the volume, in GiBs. You must specify either a snapshot ID or a volume\n size. If you specify a snapshot, the default is the snapshot size. You can specify a\n volume size that is equal to or larger than the snapshot size.

\n

The following are the supported sizes for each volume type:

\n
    \n
  • \n

    \n gp2 and gp3: 1 - 16,384 GiB

    \n
  • \n
  • \n

    \n io1: 4 - 16,384 GiB

    \n
  • \n
  • \n

    \n io2: 4 - 65,536 GiB

    \n
  • \n
  • \n

    \n st1 and sc1: 125 - 16,384 GiB

    \n
  • \n
  • \n

    \n standard: 1 - 1024 GiB

    \n
  • \n
", "smithy.api#xmlName": "volumeSize" } }, @@ -43252,7 +44478,7 @@ "target": "com.amazonaws.ec2#VolumeType", "traits": { "aws.protocols#ec2QueryName": "VolumeType", - "smithy.api#documentation": "

The volume type. For more information, see Amazon EBS volume types in the\n Amazon EC2 User Guide. If the volume type is io1 or\n io2, you must specify the IOPS that the volume supports.

", + "smithy.api#documentation": "

The volume type. For more information, see Amazon EBS volume types in the\n Amazon EC2 User Guide.

", "smithy.api#xmlName": "volumeType" } }, @@ -44114,7 +45340,27 @@ } }, "traits": { - "smithy.api#documentation": "

ENA Express uses Amazon Web Services Scalable Reliable Datagram (SRD) technology to increase the \n\t\t\tmaximum bandwidth used per stream and minimize tail latency of network traffic between EC2 instances. \n\t\t\tWith ENA Express, you can communicate between two EC2 instances in the same subnet within the same \n\t\t\taccount, or in different accounts. Both sending and receiving instances must have ENA Express enabled.

\n

To improve the reliability of network packet delivery, ENA Express reorders network packets on the \n\t\t\treceiving end by default. However, some UDP-based applications are designed to handle network packets \n\t\t\tthat are out of order to reduce the overhead for packet delivery at the network layer. When ENA Express \n\t\t\tis enabled, you can specify whether UDP network traffic uses it.

" + "smithy.api#documentation": "

ENA Express uses Amazon Web Services Scalable Reliable Datagram (SRD) technology to increase the\n\t\t\tmaximum bandwidth used per stream and minimize tail latency of network traffic between EC2 instances.\n\t\t\tWith ENA Express, you can communicate between two EC2 instances in the same subnet within the same\n\t\t\taccount, or in different accounts. Both sending and receiving instances must have ENA Express enabled.

\n

To improve the reliability of network packet delivery, ENA Express reorders network packets on the\n\t\t\treceiving end by default. However, some UDP-based applications are designed to handle network packets\n\t\t\tthat are out of order to reduce the overhead for packet delivery at the network layer. When ENA Express\n\t\t\tis enabled, you can specify whether UDP network traffic uses it.

" + } + }, + "com.amazonaws.ec2#EnaSrdSpecificationRequest": { + "type": "structure", + "members": { + "EnaSrdEnabled": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Specifies whether ENA Express is enabled for the network interface when you \n\t\t\tlaunch an instance from your launch template.

" + } + }, + "EnaSrdUdpSpecification": { + "target": "com.amazonaws.ec2#EnaSrdUdpSpecificationRequest", + "traits": { + "smithy.api#documentation": "

Contains ENA Express settings for UDP network traffic in your launch template.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Launch instances with ENA Express settings configured \n\t\t\tfrom your launch template.

" } }, "com.amazonaws.ec2#EnaSrdSupported": { @@ -44126,12 +45372,26 @@ "EnaSrdUdpEnabled": { "target": "com.amazonaws.ec2#Boolean", "traits": { - "smithy.api#documentation": "

Indicates whether UDP traffic uses ENA Express. To specify this setting, you must first enable ENA Express.

" + "smithy.api#documentation": "

Indicates whether UDP traffic to and from the instance uses ENA Express. To specify this setting,\n\t\t\tyou must first enable ENA Express.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

ENA Express is compatible with both TCP and UDP transport protocols. When it's enabled, TCP traffic\n\t\t\tautomatically uses it. However, some UDP-based applications are designed to handle network packets that are\n\t\t\tout of order, without a need for retransmission, such as live video broadcasting or other near-real-time\n\t\t\tapplications. For UDP traffic, you can specify whether to use ENA Express, based on your application\n\t\t\tenvironment needs.

" + } + }, + "com.amazonaws.ec2#EnaSrdUdpSpecificationRequest": { + "type": "structure", + "members": { + "EnaSrdUdpEnabled": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Indicates whether UDP traffic uses ENA Express for your instance. To ensure that \n\t\t\tUDP traffic can use ENA Express when you launch an instance, you must also set \n\t\t\tEnaSrdEnabled in the EnaSrdSpecificationRequest to true in your \n\t\t\tlaunch template.

" } } }, "traits": { - "smithy.api#documentation": "

ENA Express is compatible with both TCP and UDP transport protocols. When it’s enabled, TCP traffic \n\t\t\tautomatically uses it. However, some UDP-based applications are designed to handle network packets that are \n\t\t\tout of order, without a need for retransmission, such as live video broadcasting or other near-real-time \n\t\t\tapplications. For UDP traffic, you can specify whether to use ENA Express, based on your application \n\t\t\tenvironment needs.

" + "smithy.api#documentation": "

Configures ENA Express for UDP network traffic from your launch template.

" } }, "com.amazonaws.ec2#EnaSupport": { @@ -44332,7 +45592,7 @@ "target": "com.amazonaws.ec2#EnableFastLaunchResult" }, "traits": { - "smithy.api#documentation": "

When you enable faster launching for a Windows AMI, images are pre-provisioned, \n\t\t\tusing snapshots to launch instances up to 65% faster. To create the optimized Windows \n\t\t\timage, Amazon EC2 launches an instance and runs through Sysprep steps, rebooting as required. \n\t\t\tThen it creates a set of reserved snapshots that are used for subsequent launches. The \n\t\t\treserved snapshots are automatically replenished as they are used, depending on your \n\t\t\tsettings for launch frequency.

\n \n

To change these settings, you must own the AMI.

\n
" + "smithy.api#documentation": "

When you enable Windows fast launch for a Windows AMI, images are pre-provisioned, \n\t\t\tusing snapshots to launch instances up to 65% faster. To create the optimized Windows \n\t\t\timage, Amazon EC2 launches an instance and runs through Sysprep steps, rebooting as required. \n\t\t\tThen it creates a set of reserved snapshots that are used for subsequent launches. The \n\t\t\treserved snapshots are automatically replenished as they are used, depending on your \n\t\t\tsettings for launch frequency.

\n \n

You can only change these settings for Windows AMIs that you own or that have been shared with you.

\n
" } }, "com.amazonaws.ec2#EnableFastLaunchRequest": { @@ -44342,20 +45602,20 @@ "target": "com.amazonaws.ec2#ImageId", "traits": { "smithy.api#clientOptional": {}, - "smithy.api#documentation": "

The ID of the image for which you’re enabling faster launching.

", + "smithy.api#documentation": "

Specify the ID of the image for which to enable Windows fast launch.

", "smithy.api#required": {} } }, "ResourceType": { "target": "com.amazonaws.ec2#String", "traits": { - "smithy.api#documentation": "

The type of resource to use for pre-provisioning the Windows AMI for faster launching. \n\t\t\tSupported values include: snapshot, which is the default value.

" + "smithy.api#documentation": "

The type of resource to use for pre-provisioning the AMI for Windows fast launch. \n\t\t\tSupported values include: snapshot, which is the default value.

" } }, "SnapshotConfiguration": { "target": "com.amazonaws.ec2#FastLaunchSnapshotConfigurationRequest", "traits": { - "smithy.api#documentation": "

Configuration settings for creating and managing the snapshots that are used for \n\t\t\tpre-provisioning the Windows AMI for faster launching. The associated ResourceType \n\t\t\tmust be snapshot.

" + "smithy.api#documentation": "

Configuration settings for creating and managing the snapshots that are used for \n\t\t\tpre-provisioning the AMI for Windows fast launch. The associated ResourceType \n\t\t\tmust be snapshot.

" } }, "LaunchTemplate": { @@ -44367,7 +45627,7 @@ "MaxParallelLaunches": { "target": "com.amazonaws.ec2#Integer", "traits": { - "smithy.api#documentation": "

The maximum number of instances that Amazon EC2 can launch at the same time to create \n\t\t\tpre-provisioned snapshots for Windows faster launching. Value must be \n\t\t\t6 or greater.

" + "smithy.api#documentation": "

The maximum number of instances that Amazon EC2 can launch at the same time to create \n\t\t\tpre-provisioned snapshots for Windows fast launch. Value must be \n\t\t\t6 or greater.

" } }, "DryRun": { @@ -44388,7 +45648,7 @@ "target": "com.amazonaws.ec2#ImageId", "traits": { "aws.protocols#ec2QueryName": "ImageId", - "smithy.api#documentation": "

The image ID that identifies the Windows AMI for which faster launching was enabled.

", + "smithy.api#documentation": "

The image ID that identifies the AMI for which Windows fast launch was enabled.

", "smithy.api#xmlName": "imageId" } }, @@ -44396,7 +45656,7 @@ "target": "com.amazonaws.ec2#FastLaunchResourceType", "traits": { "aws.protocols#ec2QueryName": "ResourceType", - "smithy.api#documentation": "

The type of resource that was defined for pre-provisioning the Windows AMI for faster launching.

", + "smithy.api#documentation": "

The type of resource that was defined for pre-provisioning the AMI for Windows fast launch.

", "smithy.api#xmlName": "resourceType" } }, @@ -44420,7 +45680,7 @@ "target": "com.amazonaws.ec2#Integer", "traits": { "aws.protocols#ec2QueryName": "MaxParallelLaunches", - "smithy.api#documentation": "

The maximum number of instances that Amazon EC2 can launch at the same time to \n\t\t\tcreate pre-provisioned snapshots for Windows faster launching.

", + "smithy.api#documentation": "

The maximum number of instances that Amazon EC2 can launch at the same time to \n\t\t\tcreate pre-provisioned snapshots for Windows fast launch.

", "smithy.api#xmlName": "maxParallelLaunches" } }, @@ -44428,7 +45688,7 @@ "target": "com.amazonaws.ec2#String", "traits": { "aws.protocols#ec2QueryName": "OwnerId", - "smithy.api#documentation": "

The owner ID for the Windows AMI for which faster launching was enabled.

", + "smithy.api#documentation": "

The owner ID for the AMI for which Windows fast launch was enabled.

", "smithy.api#xmlName": "ownerId" } }, @@ -44436,7 +45696,7 @@ "target": "com.amazonaws.ec2#FastLaunchStateCode", "traits": { "aws.protocols#ec2QueryName": "State", - "smithy.api#documentation": "

The current state of faster launching for the specified Windows AMI.

", + "smithy.api#documentation": "

The current state of Windows fast launch for the specified AMI.

", "smithy.api#xmlName": "state" } }, @@ -44444,7 +45704,7 @@ "target": "com.amazonaws.ec2#String", "traits": { "aws.protocols#ec2QueryName": "StateTransitionReason", - "smithy.api#documentation": "

The reason that the state changed for faster launching for the Windows AMI.

", + "smithy.api#documentation": "

The reason that the state changed for Windows fast launch for the AMI.

", "smithy.api#xmlName": "stateTransitionReason" } }, @@ -44452,7 +45712,7 @@ "target": "com.amazonaws.ec2#MillisecondDateTime", "traits": { "aws.protocols#ec2QueryName": "StateTransitionTime", - "smithy.api#documentation": "

The time that the state changed for faster launching for the Windows AMI.

", + "smithy.api#documentation": "

The time that the state changed for Windows fast launch for the AMI.

", "smithy.api#xmlName": "stateTransitionTime" } } @@ -45016,6 +46276,56 @@ "smithy.api#output": {} } }, + "com.amazonaws.ec2#EnableSnapshotBlockPublicAccess": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#EnableSnapshotBlockPublicAccessRequest" + }, + "output": { + "target": "com.amazonaws.ec2#EnableSnapshotBlockPublicAccessResult" + }, + "traits": { + "smithy.api#documentation": "

Enables or modifies the block public access for snapshots \n setting at the account level for the specified Amazon Web Services Region. After you enable block \n public access for snapshots in a Region, users can no longer request public sharing \n for snapshots in that Region. Snapshots that are already publicly shared are either \n treated as private or they remain publicly shared, depending on the \n State that you specify.

\n

If block public access is enabled in block-all-sharing mode, and \n you change the mode to block-new-sharing, all snapshots that were \n previously publicly shared are no longer treated as private and they become publicly \n accessible again.

\n

For more information, see \n Block public access for snapshots in the Amazon Elastic Compute Cloud User Guide.

" + } + }, + "com.amazonaws.ec2#EnableSnapshotBlockPublicAccessRequest": { + "type": "structure", + "members": { + "State": { + "target": "com.amazonaws.ec2#SnapshotBlockPublicAccessState", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The mode in which to enable block public access for snapshots for the Region. \n Specify one of the following values:

\n
    \n
  • \n

    \n block-all-sharing - Prevents all public sharing of snapshots in \n the Region. Users in the account will no longer be able to request new public \n sharing. Additionally, snapshots that are already publicly shared are treated as \n private and they are no longer publicly available.

    \n \n

    If you enable block public access for snapshots in block-all-sharing \n mode, it does not change the permissions for snapshots that are already publicly shared. \n Instead, it prevents these snapshots from be publicly visible and publicly accessible. \n Therefore, the attributes for these snapshots still indicate that they are publicly \n shared, even though they are not publicly available.

    \n
    \n
  • \n
  • \n

    \n block-new-sharing - Prevents only new public sharing of snapshots \n in the Region. Users in the account will no longer be able to request new public \n sharing. However, snapshots that are already publicly shared, remain publicly \n available.

    \n
  • \n
", + "smithy.api#required": {} + } + }, + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, \n and provides an error response. If you have the required permissions, the error response is DryRunOperation. \n Otherwise, it is UnauthorizedOperation.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#EnableSnapshotBlockPublicAccessResult": { + "type": "structure", + "members": { + "State": { + "target": "com.amazonaws.ec2#SnapshotBlockPublicAccessState", + "traits": { + "aws.protocols#ec2QueryName": "State", + "smithy.api#documentation": "

The state of block public access for snapshots for the account and Region. Returns \n either block-all-sharing or block-new-sharing if the request \n succeeds.

", + "smithy.api#xmlName": "state" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#EnableTransitGatewayRouteTablePropagation": { "type": "operation", "input": { @@ -46731,26 +48041,26 @@ "LaunchTemplateId": { "target": "com.amazonaws.ec2#LaunchTemplateId", "traits": { - "smithy.api#documentation": "

The ID of the launch template to use for faster launching for a Windows AMI.

" + "smithy.api#documentation": "

Specify the ID of the launch template that the AMI should use for Windows fast launch.

" } }, "LaunchTemplateName": { "target": "com.amazonaws.ec2#String", "traits": { - "smithy.api#documentation": "

The name of the launch template to use for faster launching for a Windows AMI.

" + "smithy.api#documentation": "

Specify the name of the launch template that the AMI should use for Windows fast launch.

" } }, "Version": { "target": "com.amazonaws.ec2#String", "traits": { "smithy.api#clientOptional": {}, - "smithy.api#documentation": "

The version of the launch template to use for faster launching for a Windows AMI.

", + "smithy.api#documentation": "

Specify the version of the launch template that the AMI should use for Windows fast launch.

", "smithy.api#required": {} } } }, "traits": { - "smithy.api#documentation": "

Request to create a launch template for a fast-launch enabled Windows AMI.

\n \n

Note - You can specify either the LaunchTemplateName or the \n\t\t\t\tLaunchTemplateId, but not both.

\n
" + "smithy.api#documentation": "

Request to create a launch template for a Windows fast launch enabled AMI.

\n \n

Note - You can specify either the LaunchTemplateName or the \n\t\t\t\tLaunchTemplateId, but not both.

\n
" } }, "com.amazonaws.ec2#FastLaunchLaunchTemplateSpecificationResponse": { @@ -46760,7 +48070,7 @@ "target": "com.amazonaws.ec2#LaunchTemplateId", "traits": { "aws.protocols#ec2QueryName": "LaunchTemplateId", - "smithy.api#documentation": "

The ID of the launch template for faster launching of the associated Windows AMI.

", + "smithy.api#documentation": "

The ID of the launch template that the AMI uses for Windows fast launch.

", "smithy.api#xmlName": "launchTemplateId" } }, @@ -46768,7 +48078,7 @@ "target": "com.amazonaws.ec2#String", "traits": { "aws.protocols#ec2QueryName": "LaunchTemplateName", - "smithy.api#documentation": "

The name of the launch template for faster launching of the associated Windows AMI.

", + "smithy.api#documentation": "

The name of the launch template that the AMI uses for Windows fast launch.

", "smithy.api#xmlName": "launchTemplateName" } }, @@ -46776,13 +48086,13 @@ "target": "com.amazonaws.ec2#String", "traits": { "aws.protocols#ec2QueryName": "Version", - "smithy.api#documentation": "

The version of the launch template for faster launching of the associated Windows AMI.

", + "smithy.api#documentation": "

The version of the launch template that the AMI uses for Windows fast launch.

", "smithy.api#xmlName": "version" } } }, "traits": { - "smithy.api#documentation": "

Identifies the launch template to use for faster launching of the Windows AMI.

" + "smithy.api#documentation": "

Identifies the launch template that the AMI uses for Windows fast launch.

" } }, "com.amazonaws.ec2#FastLaunchResourceType": { @@ -46802,12 +48112,12 @@ "TargetResourceCount": { "target": "com.amazonaws.ec2#Integer", "traits": { - "smithy.api#documentation": "

The number of pre-provisioned snapshots to keep on hand for a fast-launch enabled Windows AMI.

" + "smithy.api#documentation": "

The number of pre-provisioned snapshots to keep on hand for a Windows fast launch \n\t\t\tenabled AMI.

" } } }, "traits": { - "smithy.api#documentation": "

Configuration settings for creating and managing pre-provisioned snapshots for a fast-launch enabled Windows AMI.

" + "smithy.api#documentation": "

Configuration settings for creating and managing pre-provisioned snapshots for a Windows fast launch \n\t\t\tenabled AMI.

" } }, "com.amazonaws.ec2#FastLaunchSnapshotConfigurationResponse": { @@ -46817,13 +48127,13 @@ "target": "com.amazonaws.ec2#Integer", "traits": { "aws.protocols#ec2QueryName": "TargetResourceCount", - "smithy.api#documentation": "

The number of pre-provisioned snapshots requested to keep on hand for a fast-launch enabled Windows AMI.

", + "smithy.api#documentation": "

The number of pre-provisioned snapshots requested to keep on hand for a Windows fast launch \n\t\t\tenabled AMI.

", "smithy.api#xmlName": "targetResourceCount" } } }, "traits": { - "smithy.api#documentation": "

Configuration settings for creating and managing pre-provisioned snapshots for a fast-launch enabled Windows AMI.

" + "smithy.api#documentation": "

Configuration settings for creating and managing pre-provisioned snapshots for a Windows fast launch \n\t\t\tenabled Windows AMI.

" } }, "com.amazonaws.ec2#FastLaunchStateCode": { @@ -49087,6 +50397,14 @@ "smithy.api#documentation": "

The ID of the local gateway route table.

", "smithy.api#xmlName": "localGatewayRouteTableId" } + }, + "NextToken": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "NextToken", + "smithy.api#documentation": "

The token to use to retrieve the next page of results. This value is null when there are no more results to return.

", + "smithy.api#xmlName": "nextToken" + } } }, "traits": { @@ -50003,6 +51321,99 @@ "smithy.api#output": {} } }, + "com.amazonaws.ec2#GetIpamDiscoveredPublicAddresses": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#GetIpamDiscoveredPublicAddressesRequest" + }, + "output": { + "target": "com.amazonaws.ec2#GetIpamDiscoveredPublicAddressesResult" + }, + "traits": { + "smithy.api#documentation": "

Gets the public IP addresses that have been discovered by IPAM.

" + } + }, + "com.amazonaws.ec2#GetIpamDiscoveredPublicAddressesRequest": { + "type": "structure", + "members": { + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

A check for whether you have the required permissions for the action without actually making the request \n and provides an error response. If you have the required permissions, the error response is DryRunOperation. \n Otherwise, it is UnauthorizedOperation.

" + } + }, + "IpamResourceDiscoveryId": { + "target": "com.amazonaws.ec2#IpamResourceDiscoveryId", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

An IPAM resource discovery ID.

", + "smithy.api#required": {} + } + }, + "AddressRegion": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The Amazon Web Services Region for the IP address.

", + "smithy.api#required": {} + } + }, + "Filters": { + "target": "com.amazonaws.ec2#FilterList", + "traits": { + "smithy.api#documentation": "

Filters.

", + "smithy.api#xmlName": "Filter" + } + }, + "NextToken": { + "target": "com.amazonaws.ec2#NextToken", + "traits": { + "smithy.api#documentation": "

The token for the next page of results.

" + } + }, + "MaxResults": { + "target": "com.amazonaws.ec2#IpamMaxResults", + "traits": { + "smithy.api#documentation": "

The maximum number of IPAM discovered public addresses to return in one page of results.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#GetIpamDiscoveredPublicAddressesResult": { + "type": "structure", + "members": { + "IpamDiscoveredPublicAddresses": { + "target": "com.amazonaws.ec2#IpamDiscoveredPublicAddressSet", + "traits": { + "aws.protocols#ec2QueryName": "IpamDiscoveredPublicAddressSet", + "smithy.api#documentation": "

IPAM discovered public addresses.

", + "smithy.api#xmlName": "ipamDiscoveredPublicAddressSet" + } + }, + "OldestSampleTime": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "aws.protocols#ec2QueryName": "OldestSampleTime", + "smithy.api#documentation": "

The oldest successful resource discovery time.

", + "smithy.api#xmlName": "oldestSampleTime" + } + }, + "NextToken": { + "target": "com.amazonaws.ec2#NextToken", + "traits": { + "aws.protocols#ec2QueryName": "NextToken", + "smithy.api#documentation": "

The token to use to retrieve the next page of results. This value is null when there are no more results to return.

", + "smithy.api#xmlName": "nextToken" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#GetIpamDiscoveredResourceCidrs": { "type": "operation", "input": { @@ -51149,6 +52560,48 @@ "smithy.api#output": {} } }, + "com.amazonaws.ec2#GetSnapshotBlockPublicAccessState": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#GetSnapshotBlockPublicAccessStateRequest" + }, + "output": { + "target": "com.amazonaws.ec2#GetSnapshotBlockPublicAccessStateResult" + }, + "traits": { + "smithy.api#documentation": "

Gets the current state of block public access for snapshots setting \n for the account and Region.

\n

For more information, see \n Block public access for snapshots in the Amazon Elastic Compute Cloud User Guide.

" + } + }, + "com.amazonaws.ec2#GetSnapshotBlockPublicAccessStateRequest": { + "type": "structure", + "members": { + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, \n and provides an error response. If you have the required permissions, the error response is DryRunOperation. \n Otherwise, it is UnauthorizedOperation.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#GetSnapshotBlockPublicAccessStateResult": { + "type": "structure", + "members": { + "State": { + "target": "com.amazonaws.ec2#SnapshotBlockPublicAccessState", + "traits": { + "aws.protocols#ec2QueryName": "State", + "smithy.api#documentation": "

The current state of block public access for snapshots. Possible values include:

\n
    \n
  • \n

    \n block-all-sharing - All public sharing of snapshots is blocked. Users in \n the account can't request new public sharing. Additionally, snapshots that were already \n publicly shared are treated as private and are not publicly available.

    \n
  • \n
  • \n

    \n block-new-sharing - Only new public sharing of snapshots is blocked. \n Users in the account can't request new public sharing. However, snapshots that were \n already publicly shared, remain publicly available.

    \n
  • \n
  • \n

    \n unblocked - Public sharing is not blocked. Users can publicly share \n snapshots.

    \n
  • \n
", + "smithy.api#xmlName": "state" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#GetSpotPlacementScores": { "type": "operation", "input": { @@ -55507,7 +56960,7 @@ "target": "com.amazonaws.ec2#PlatformValues", "traits": { "aws.protocols#ec2QueryName": "Platform", - "smithy.api#documentation": "

The value is Windows for Windows instances; otherwise blank.

", + "smithy.api#documentation": "

The platform. This value is windows for Windows instances; otherwise, it is empty.

", "smithy.api#xmlName": "platform" } }, @@ -55892,6 +57345,46 @@ "smithy.api#documentation": "

Describes an instance.

" } }, + "com.amazonaws.ec2#InstanceAttachmentEnaSrdSpecification": { + "type": "structure", + "members": { + "EnaSrdEnabled": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "aws.protocols#ec2QueryName": "EnaSrdEnabled", + "smithy.api#documentation": "

Indicates whether ENA Express is enabled for the network interface.

", + "smithy.api#xmlName": "enaSrdEnabled" + } + }, + "EnaSrdUdpSpecification": { + "target": "com.amazonaws.ec2#InstanceAttachmentEnaSrdUdpSpecification", + "traits": { + "aws.protocols#ec2QueryName": "EnaSrdUdpSpecification", + "smithy.api#documentation": "

Configures ENA Express for UDP network traffic.

", + "smithy.api#xmlName": "enaSrdUdpSpecification" + } + } + }, + "traits": { + "smithy.api#documentation": "

ENA Express uses Amazon Web Services Scalable Reliable Datagram (SRD) technology to increase the\n\t\t\tmaximum bandwidth used per stream and minimize tail latency of network traffic between EC2 instances.\n\t\t\tWith ENA Express, you can communicate between two EC2 instances in the same subnet within the same\n\t\t\taccount, or in different accounts. Both sending and receiving instances must have ENA Express enabled.

\n

To improve the reliability of network packet delivery, ENA Express reorders network packets on the\n\t\t\treceiving end by default. However, some UDP-based applications are designed to handle network packets\n\t\t\tthat are out of order to reduce the overhead for packet delivery at the network layer. When ENA Express\n\t\t\tis enabled, you can specify whether UDP network traffic uses it.

" + } + }, + "com.amazonaws.ec2#InstanceAttachmentEnaSrdUdpSpecification": { + "type": "structure", + "members": { + "EnaSrdUdpEnabled": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "aws.protocols#ec2QueryName": "EnaSrdUdpEnabled", + "smithy.api#documentation": "

Indicates whether UDP traffic to and from the instance uses ENA Express. To specify this setting,\n\t\t\tyou must first enable ENA Express.

", + "smithy.api#xmlName": "enaSrdUdpEnabled" + } + } + }, + "traits": { + "smithy.api#documentation": "

ENA Express is compatible with both TCP and UDP transport protocols. When it's enabled, TCP traffic\n\t\t\tautomatically uses it. However, some UDP-based applications are designed to handle network packets that are\n\t\t\tout of order, without a need for retransmission, such as live video broadcasting or other near-real-time\n\t\t\tapplications. For UDP traffic, you can specify whether to use ENA Express, based on your application\n\t\t\tenvironment needs.

" + } + }, "com.amazonaws.ec2#InstanceAttribute": { "type": "structure", "members": { @@ -57020,6 +58513,12 @@ "traits": { "smithy.api#enumValue": "scheduled" } + }, + "capacity_block": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "capacity-block" + } } } }, @@ -57440,6 +58939,14 @@ "smithy.api#documentation": "

The IPv6 delegated prefixes that are assigned to the network interface.

", "smithy.api#xmlName": "ipv6PrefixSet" } + }, + "ConnectionTrackingConfiguration": { + "target": "com.amazonaws.ec2#ConnectionTrackingSpecificationResponse", + "traits": { + "aws.protocols#ec2QueryName": "ConnectionTrackingConfiguration", + "smithy.api#documentation": "

A security group connection tracking configuration that enables you to set the timeout for connection tracking on an Elastic network interface. For more information, see Connection tracking timeouts in the Amazon Elastic Compute Cloud User Guide.

", + "smithy.api#xmlName": "connectionTrackingConfiguration" + } } }, "traits": { @@ -57544,6 +59051,14 @@ "smithy.api#documentation": "

The index of the network card.

", "smithy.api#xmlName": "networkCardIndex" } + }, + "EnaSrdSpecification": { + "target": "com.amazonaws.ec2#InstanceAttachmentEnaSrdSpecification", + "traits": { + "aws.protocols#ec2QueryName": "EnaSrdSpecification", + "smithy.api#documentation": "

Contains the ENA Express settings for the network interface that's attached\n\t\t\tto the instance.

", + "smithy.api#xmlName": "enaSrdSpecification" + } } }, "traits": { @@ -57706,6 +59221,18 @@ "traits": { "smithy.api#documentation": "

The primary IPv6 address of the network interface. When you enable an IPv6 GUA address to be a primary IPv6, the first IPv6 GUA will be made the primary IPv6 address until the instance is terminated or the network interface is detached. For more information about primary IPv6 addresses, see RunInstances.

" } + }, + "EnaSrdSpecification": { + "target": "com.amazonaws.ec2#EnaSrdSpecificationRequest", + "traits": { + "smithy.api#documentation": "

Specifies the ENA Express settings for the network interface that's attached to\n\t\t\tthe instance.

" + } + }, + "ConnectionTrackingSpecification": { + "target": "com.amazonaws.ec2#ConnectionTrackingSpecificationRequest", + "traits": { + "smithy.api#documentation": "

A security group connection tracking specification that enables you to set the timeout for connection tracking on an Elastic network interface. For more information, see Connection tracking timeouts in the Amazon Elastic Compute Cloud User Guide.

" + } } }, "traits": { @@ -57959,7 +59486,7 @@ } }, "traits": { - "smithy.api#documentation": "

The attributes for the instance types. When you specify instance attributes, Amazon EC2 will\n identify instance types with these attributes.

\n

You must specify VCpuCount and MemoryMiB. All other attributes\n are optional. Any unspecified optional attribute is set to its default.

\n

When you specify multiple attributes, you get instance types that satisfy all of the\n specified attributes. If you specify multiple values for an attribute, you get instance\n types that satisfy any of the specified values.

\n

To limit the list of instance types from which Amazon EC2 can identify matching instance types, \n you can use one of the following parameters, but not both in the same request:

\n
    \n
  • \n

    \n AllowedInstanceTypes - The instance types to include in the list. All \n other instance types are ignored, even if they match your specified attributes.

    \n
  • \n
  • \n

    \n ExcludedInstanceTypes - The instance types to exclude from the list, \n even if they match your specified attributes.

    \n
  • \n
\n \n

If you specify InstanceRequirements, you can't specify\n InstanceType.

\n

Attribute-based instance type selection is only supported when using Auto Scaling\n groups, EC2 Fleet, and Spot Fleet to launch instances. If you plan to use the launch template in\n the launch instance\n wizard or with the RunInstances API, you\n can't specify InstanceRequirements.

\n
\n

For more information, see Attribute-based instance type selection for EC2 Fleet, Attribute-based instance type selection for Spot Fleet, and Spot\n placement score in the Amazon EC2 User Guide.

" + "smithy.api#documentation": "

The attributes for the instance types. When you specify instance attributes, Amazon EC2 will\n identify instance types with these attributes.

\n

You must specify VCpuCount and MemoryMiB. All other attributes\n are optional. Any unspecified optional attribute is set to its default.

\n

When you specify multiple attributes, you get instance types that satisfy all of the\n specified attributes. If you specify multiple values for an attribute, you get instance\n types that satisfy any of the specified values.

\n

To limit the list of instance types from which Amazon EC2 can identify matching instance types, \n you can use one of the following parameters, but not both in the same request:

\n
    \n
  • \n

    \n AllowedInstanceTypes - The instance types to include in the list. All \n other instance types are ignored, even if they match your specified attributes.

    \n
  • \n
  • \n

    \n ExcludedInstanceTypes - The instance types to exclude from the list, \n even if they match your specified attributes.

    \n
  • \n
\n \n

If you specify InstanceRequirements, you can't specify\n InstanceType.

\n

Attribute-based instance type selection is only supported when using Auto Scaling\n groups, EC2 Fleet, and Spot Fleet to launch instances. If you plan to use the launch template in\n the launch instance\n wizard or with the RunInstances API, you\n can't specify InstanceRequirements.

\n
\n

For more information, see Create a mixed instances group using attribute-based instance type selection in\n the Amazon EC2 Auto Scaling User Guide, and also Attribute-based instance type selection for EC2 Fleet, Attribute-based instance type selection for Spot Fleet, and Spot\n placement score in the Amazon EC2 User Guide.

" } }, "com.amazonaws.ec2#InstanceRequirementsRequest": { @@ -58148,6 +59675,15 @@ "smithy.api#documentation": "

The architecture type, virtualization type, and other attributes for the instance types.\n When you specify instance attributes, Amazon EC2 will identify instance types with those\n attributes.

\n

If you specify InstanceRequirementsWithMetadataRequest, you can't specify\n InstanceTypes.

" } }, + "com.amazonaws.ec2#InstanceSet": { + "type": "list", + "member": { + "target": "com.amazonaws.ec2#InstanceTopology", + "traits": { + "smithy.api#xmlName": "item" + } + } + }, "com.amazonaws.ec2#InstanceSpecification": { "type": "structure", "members": { @@ -58579,6 +60115,62 @@ "smithy.api#documentation": "

Describes the registered tag keys for the current Region.

" } }, + "com.amazonaws.ec2#InstanceTopology": { + "type": "structure", + "members": { + "InstanceId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "InstanceId", + "smithy.api#documentation": "

The instance ID.

", + "smithy.api#xmlName": "instanceId" + } + }, + "InstanceType": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "InstanceType", + "smithy.api#documentation": "

The instance type.

", + "smithy.api#xmlName": "instanceType" + } + }, + "GroupName": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "GroupName", + "smithy.api#documentation": "

The name of the placement group that the instance is in.

", + "smithy.api#xmlName": "groupName" + } + }, + "NetworkNodes": { + "target": "com.amazonaws.ec2#NetworkNodesList", + "traits": { + "aws.protocols#ec2QueryName": "NetworkNodeSet", + "smithy.api#documentation": "

The network nodes. The nodes are hashed based on your account. Instances from\n different accounts running under the same droplet will return a different hashed list of\n strings.

", + "smithy.api#xmlName": "networkNodeSet" + } + }, + "AvailabilityZone": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "AvailabilityZone", + "smithy.api#documentation": "

The name of the Availability Zone or Local Zone that the instance is in.

", + "smithy.api#xmlName": "availabilityZone" + } + }, + "ZoneId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "ZoneId", + "smithy.api#documentation": "

The ID of the Availability Zone or Local Zone that the instance is in.

", + "smithy.api#xmlName": "zoneId" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about the instance topology.

" + } + }, "com.amazonaws.ec2#InstanceType": { "type": "enum", "members": { @@ -63207,6 +64799,12 @@ "traits": { "smithy.api#enumValue": "r7i.48xlarge" } + }, + "dl2q_24xlarge": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "dl2q.24xlarge" + } } } }, @@ -64029,6 +65627,22 @@ "smithy.api#documentation": "

The IPAM's resource discovery association count.

", "smithy.api#xmlName": "resourceDiscoveryAssociationCount" } + }, + "StateMessage": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "StateMessage", + "smithy.api#documentation": "

The state message.

", + "smithy.api#xmlName": "stateMessage" + } + }, + "Tier": { + "target": "com.amazonaws.ec2#IpamTier", + "traits": { + "aws.protocols#ec2QueryName": "Tier", + "smithy.api#documentation": "

IPAM is offered in a Free Tier and an Advanced Tier. For more information about the features available in each tier and the costs associated with the tiers, see Amazon VPC pricing > IPAM tab.

", + "smithy.api#xmlName": "tier" + } } }, "traits": { @@ -64307,6 +65921,175 @@ } } }, + "com.amazonaws.ec2#IpamDiscoveredPublicAddress": { + "type": "structure", + "members": { + "IpamResourceDiscoveryId": { + "target": "com.amazonaws.ec2#IpamResourceDiscoveryId", + "traits": { + "aws.protocols#ec2QueryName": "IpamResourceDiscoveryId", + "smithy.api#documentation": "

The resource discovery ID.

", + "smithy.api#xmlName": "ipamResourceDiscoveryId" + } + }, + "AddressRegion": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "AddressRegion", + "smithy.api#documentation": "

The Region of the resource the IP address is assigned to.

", + "smithy.api#xmlName": "addressRegion" + } + }, + "Address": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "Address", + "smithy.api#documentation": "

The IP address.

", + "smithy.api#xmlName": "address" + } + }, + "AddressOwnerId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "AddressOwnerId", + "smithy.api#documentation": "

The ID of the owner of the resource the IP address is assigned to.

", + "smithy.api#xmlName": "addressOwnerId" + } + }, + "AddressAllocationId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "AddressAllocationId", + "smithy.api#documentation": "

The allocation ID of the resource the IP address is assigned to.

", + "smithy.api#xmlName": "addressAllocationId" + } + }, + "AssociationStatus": { + "target": "com.amazonaws.ec2#IpamPublicAddressAssociationStatus", + "traits": { + "aws.protocols#ec2QueryName": "AssociationStatus", + "smithy.api#documentation": "

The association status.

", + "smithy.api#xmlName": "associationStatus" + } + }, + "AddressType": { + "target": "com.amazonaws.ec2#IpamPublicAddressType", + "traits": { + "aws.protocols#ec2QueryName": "AddressType", + "smithy.api#documentation": "

The IP address type.

", + "smithy.api#xmlName": "addressType" + } + }, + "Service": { + "target": "com.amazonaws.ec2#IpamPublicAddressAwsService", + "traits": { + "aws.protocols#ec2QueryName": "Service", + "smithy.api#documentation": "

The Amazon Web Services service associated with the IP address.

", + "smithy.api#xmlName": "service" + } + }, + "ServiceResource": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "ServiceResource", + "smithy.api#documentation": "

The resource ARN or ID.

", + "smithy.api#xmlName": "serviceResource" + } + }, + "VpcId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "VpcId", + "smithy.api#documentation": "

The ID of the VPC that the resource with the assigned IP address is in.

", + "smithy.api#xmlName": "vpcId" + } + }, + "SubnetId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "SubnetId", + "smithy.api#documentation": "

The ID of the subnet that the resource with the assigned IP address is in.

", + "smithy.api#xmlName": "subnetId" + } + }, + "PublicIpv4PoolId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "PublicIpv4PoolId", + "smithy.api#documentation": "

The ID of the public IPv4 pool that the resource with the assigned IP address is from.

", + "smithy.api#xmlName": "publicIpv4PoolId" + } + }, + "NetworkInterfaceId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "NetworkInterfaceId", + "smithy.api#documentation": "

The network interface ID of the resource with the assigned IP address.

", + "smithy.api#xmlName": "networkInterfaceId" + } + }, + "NetworkInterfaceDescription": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "NetworkInterfaceDescription", + "smithy.api#documentation": "

The description of the network interface that IP address is assigned to.

", + "smithy.api#xmlName": "networkInterfaceDescription" + } + }, + "InstanceId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "InstanceId", + "smithy.api#documentation": "

The instance ID of the instance the assigned IP address is assigned to.

", + "smithy.api#xmlName": "instanceId" + } + }, + "Tags": { + "target": "com.amazonaws.ec2#IpamPublicAddressTags", + "traits": { + "aws.protocols#ec2QueryName": "Tags", + "smithy.api#documentation": "

Tags associated with the IP address.

", + "smithy.api#xmlName": "tags" + } + }, + "NetworkBorderGroup": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "NetworkBorderGroup", + "smithy.api#documentation": "

The network border group that the resource that the IP address is assigned to is in.

", + "smithy.api#xmlName": "networkBorderGroup" + } + }, + "SecurityGroups": { + "target": "com.amazonaws.ec2#IpamPublicAddressSecurityGroupList", + "traits": { + "aws.protocols#ec2QueryName": "SecurityGroupSet", + "smithy.api#documentation": "

Security groups associated with the resource that the IP address is assigned to.

", + "smithy.api#xmlName": "securityGroupSet" + } + }, + "SampleTime": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "aws.protocols#ec2QueryName": "SampleTime", + "smithy.api#documentation": "

The last successful resource discovery time.

", + "smithy.api#xmlName": "sampleTime" + } + } + }, + "traits": { + "smithy.api#documentation": "

A public IP Address discovered by IPAM.

" + } + }, + "com.amazonaws.ec2#IpamDiscoveredPublicAddressSet": { + "type": "list", + "member": { + "target": "com.amazonaws.ec2#IpamDiscoveredPublicAddress", + "traits": { + "smithy.api#xmlName": "item" + } + } + }, "com.amazonaws.ec2#IpamDiscoveredResourceCidr": { "type": "structure", "members": { @@ -64638,7 +66421,7 @@ "target": "com.amazonaws.ec2#String", "traits": { "aws.protocols#ec2QueryName": "StateMessage", - "smithy.api#documentation": "

A message related to the failed creation of an IPAM pool.

", + "smithy.api#documentation": "

The state message.

", "smithy.api#xmlName": "stateMessage" } }, @@ -64729,6 +66512,13 @@ "smithy.api#documentation": "

The IP address source for pools in the public scope. Only used for provisioning IP address CIDRs to pools in the public scope. Default is BYOIP. For more information, see Create IPv6 pools in the Amazon VPC IPAM User Guide. \n By default, you can add only one Amazon-provided IPv6 CIDR block to a top-level IPv6 pool. For information on increasing the default limit, see Quotas for your IPAM in the Amazon VPC IPAM User Guide.

", "smithy.api#xmlName": "publicIpSource" } + }, + "SourceResource": { + "target": "com.amazonaws.ec2#IpamPoolSourceResource", + "traits": { + "aws.protocols#ec2QueryName": "SourceResource", + "smithy.api#xmlName": "sourceResource" + } } }, "traits": { @@ -64799,6 +66589,15 @@ "smithy.api#documentation": "

In IPAM, an allocation is a CIDR assignment from an IPAM pool to another IPAM pool or to a resource.

" } }, + "com.amazonaws.ec2#IpamPoolAllocationAllowedCidrs": { + "type": "list", + "member": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#xmlName": "item" + } + } + }, "com.amazonaws.ec2#IpamPoolAllocationDisallowedCidrs": { "type": "list", "member": { @@ -64837,6 +66636,12 @@ "traits": { "smithy.api#enumValue": "custom" } + }, + "subnet": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "subnet" + } } } }, @@ -65043,6 +66848,89 @@ } } }, + "com.amazonaws.ec2#IpamPoolSourceResource": { + "type": "structure", + "members": { + "ResourceId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "ResourceId", + "smithy.api#documentation": "

The source resource ID.

", + "smithy.api#xmlName": "resourceId" + } + }, + "ResourceType": { + "target": "com.amazonaws.ec2#IpamPoolSourceResourceType", + "traits": { + "aws.protocols#ec2QueryName": "ResourceType", + "smithy.api#documentation": "

The source resource type.

", + "smithy.api#xmlName": "resourceType" + } + }, + "ResourceRegion": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "ResourceRegion", + "smithy.api#documentation": "

The source resource Region.

", + "smithy.api#xmlName": "resourceRegion" + } + }, + "ResourceOwner": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "ResourceOwner", + "smithy.api#documentation": "

The source resource owner.

", + "smithy.api#xmlName": "resourceOwner" + } + } + }, + "traits": { + "smithy.api#documentation": "

The resource used to provision CIDRs to a resource planning pool.

" + } + }, + "com.amazonaws.ec2#IpamPoolSourceResourceRequest": { + "type": "structure", + "members": { + "ResourceId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#documentation": "

The source resource ID.

" + } + }, + "ResourceType": { + "target": "com.amazonaws.ec2#IpamPoolSourceResourceType", + "traits": { + "smithy.api#documentation": "

The source resource type.

" + } + }, + "ResourceRegion": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#documentation": "

The source resource Region.

" + } + }, + "ResourceOwner": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#documentation": "

The source resource owner.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

The resource used to provision CIDRs to a resource planning pool.

" + } + }, + "com.amazonaws.ec2#IpamPoolSourceResourceType": { + "type": "enum", + "members": { + "vpc": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "vpc" + } + } + } + }, "com.amazonaws.ec2#IpamPoolState": { "type": "enum", "members": { @@ -65120,6 +67008,199 @@ } } }, + "com.amazonaws.ec2#IpamPublicAddressAssociationStatus": { + "type": "enum", + "members": { + "ASSOCIATED": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "associated" + } + }, + "DISASSOCIATED": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "disassociated" + } + } + } + }, + "com.amazonaws.ec2#IpamPublicAddressAwsService": { + "type": "enum", + "members": { + "NAT_GATEWAY": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "nat-gateway" + } + }, + "DMS": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "database-migration-service" + } + }, + "REDSHIFT": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "redshift" + } + }, + "ECS": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "elastic-container-service" + } + }, + "RDS": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "relational-database-service" + } + }, + "S2S_VPN": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "site-to-site-vpn" + } + }, + "EC2_LB": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "load-balancer" + } + }, + "AGA": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "global-accelerator" + } + }, + "OTHER": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "other" + } + } + } + }, + "com.amazonaws.ec2#IpamPublicAddressSecurityGroup": { + "type": "structure", + "members": { + "GroupName": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "GroupName", + "smithy.api#documentation": "

The security group's name.

", + "smithy.api#xmlName": "groupName" + } + }, + "GroupId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "GroupId", + "smithy.api#documentation": "

The security group's ID.

", + "smithy.api#xmlName": "groupId" + } + } + }, + "traits": { + "smithy.api#documentation": "

The security group that the resource with the public IP address is in.

" + } + }, + "com.amazonaws.ec2#IpamPublicAddressSecurityGroupList": { + "type": "list", + "member": { + "target": "com.amazonaws.ec2#IpamPublicAddressSecurityGroup", + "traits": { + "smithy.api#xmlName": "item" + } + } + }, + "com.amazonaws.ec2#IpamPublicAddressTag": { + "type": "structure", + "members": { + "Key": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "Key", + "smithy.api#documentation": "

The tag's key.

", + "smithy.api#xmlName": "key" + } + }, + "Value": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "Value", + "smithy.api#documentation": "

The tag's value.

", + "smithy.api#xmlName": "value" + } + } + }, + "traits": { + "smithy.api#documentation": "

A tag for a public IP address discovered by IPAM.

" + } + }, + "com.amazonaws.ec2#IpamPublicAddressTagList": { + "type": "list", + "member": { + "target": "com.amazonaws.ec2#IpamPublicAddressTag", + "traits": { + "smithy.api#xmlName": "item" + } + } + }, + "com.amazonaws.ec2#IpamPublicAddressTags": { + "type": "structure", + "members": { + "EipTags": { + "target": "com.amazonaws.ec2#IpamPublicAddressTagList", + "traits": { + "aws.protocols#ec2QueryName": "EipTagSet", + "smithy.api#documentation": "

Tags for an Elastic IP address.

", + "smithy.api#xmlName": "eipTagSet" + } + } + }, + "traits": { + "smithy.api#documentation": "

Tags for a public IP address discovered by IPAM.

" + } + }, + "com.amazonaws.ec2#IpamPublicAddressType": { + "type": "enum", + "members": { + "SERVICE_MANAGED_IP": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "service-managed-ip" + } + }, + "SERVICE_MANAGED_BYOIP": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "service-managed-byoip" + } + }, + "AMAZON_OWNED_EIP": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "amazon-owned-eip" + } + }, + "BYOIP": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "byoip" + } + }, + "EC2_PUBLIC_IP": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "ec2-public-ip" + } + } + } + }, "com.amazonaws.ec2#IpamResourceCidr": { "type": "structure", "members": { @@ -65658,6 +67739,12 @@ "traits": { "smithy.api#enumValue": "ipv6-pool" } + }, + "eni": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "eni" + } } } }, @@ -65846,105 +67933,122 @@ } } }, - "com.amazonaws.ec2#IpamScopeType": { + "com.amazonaws.ec2#IpamScopeType": { + "type": "enum", + "members": { + "public": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "public" + } + }, + "private": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "private" + } + } + } + }, + "com.amazonaws.ec2#IpamSet": { + "type": "list", + "member": { + "target": "com.amazonaws.ec2#Ipam", + "traits": { + "smithy.api#xmlName": "item" + } + } + }, + "com.amazonaws.ec2#IpamState": { + "type": "enum", + "members": { + "create_in_progress": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "create-in-progress" + } + }, + "create_complete": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "create-complete" + } + }, + "create_failed": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "create-failed" + } + }, + "modify_in_progress": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "modify-in-progress" + } + }, + "modify_complete": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "modify-complete" + } + }, + "modify_failed": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "modify-failed" + } + }, + "delete_in_progress": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "delete-in-progress" + } + }, + "delete_complete": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "delete-complete" + } + }, + "delete_failed": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "delete-failed" + } + }, + "isolate_in_progress": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "isolate-in-progress" + } + }, + "isolate_complete": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "isolate-complete" + } + }, + "restore_in_progress": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "restore-in-progress" + } + } + } + }, + "com.amazonaws.ec2#IpamTier": { "type": "enum", "members": { - "public": { + "free": { "target": "smithy.api#Unit", "traits": { - "smithy.api#enumValue": "public" + "smithy.api#enumValue": "free" } }, - "private": { + "advanced": { "target": "smithy.api#Unit", "traits": { - "smithy.api#enumValue": "private" - } - } - } - }, - "com.amazonaws.ec2#IpamSet": { - "type": "list", - "member": { - "target": "com.amazonaws.ec2#Ipam", - "traits": { - "smithy.api#xmlName": "item" - } - } - }, - "com.amazonaws.ec2#IpamState": { - "type": "enum", - "members": { - "create_in_progress": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "create-in-progress" - } - }, - "create_complete": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "create-complete" - } - }, - "create_failed": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "create-failed" - } - }, - "modify_in_progress": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "modify-in-progress" - } - }, - "modify_complete": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "modify-complete" - } - }, - "modify_failed": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "modify-failed" - } - }, - "delete_in_progress": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "delete-in-progress" - } - }, - "delete_complete": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "delete-complete" - } - }, - "delete_failed": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "delete-failed" - } - }, - "isolate_in_progress": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "isolate-in-progress" - } - }, - "isolate_complete": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "isolate-complete" - } - }, - "restore_in_progress": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "restore-in-progress" + "smithy.api#enumValue": "advanced" } } } @@ -67131,7 +69235,7 @@ "Iops": { "target": "com.amazonaws.ec2#Integer", "traits": { - "smithy.api#documentation": "

The number of I/O operations per second (IOPS). For gp3,\n io1, and io2 volumes, this represents the number of IOPS that\n are provisioned for the volume. For gp2 volumes, this represents the\n baseline performance of the volume and the rate at which the volume accumulates I/O\n credits for bursting.

\n

The following are the supported values for each volume type:

\n
    \n
  • \n

    \n gp3: 3,000-16,000 IOPS

    \n
  • \n
  • \n

    \n io1: 100-64,000 IOPS

    \n
  • \n
  • \n

    \n io2: 100-64,000 IOPS

    \n
  • \n
\n

For io1 and io2 volumes, we guarantee\n 64,000 IOPS only for Instances built on the\n Nitro System. Other instance families guarantee performance up to\n 32,000 IOPS.

\n

This parameter is supported for io1, io2, and gp3 volumes only. This parameter\n is not supported for gp2, st1, sc1, or standard volumes.

" + "smithy.api#documentation": "

The number of I/O operations per second (IOPS). For gp3,\n io1, and io2 volumes, this represents the number of IOPS that\n are provisioned for the volume. For gp2 volumes, this represents the\n baseline performance of the volume and the rate at which the volume accumulates I/O\n credits for bursting.

\n

The following are the supported values for each volume type:

\n
    \n
  • \n

    \n gp3: 3,000 - 16,000 IOPS

    \n
  • \n
  • \n

    \n io1: 100 - 64,000 IOPS

    \n
  • \n
  • \n

    \n io2: 100 - 256,000 IOPS

    \n
  • \n
\n

For io2 volumes, you can achieve up to 256,000 IOPS on \ninstances \nbuilt on the Nitro System. On other instances, you can achieve performance up to 32,000 IOPS.

\n

This parameter is supported for io1, io2, and gp3 volumes only.

" } }, "KmsKeyId": { @@ -67149,7 +69253,7 @@ "VolumeSize": { "target": "com.amazonaws.ec2#Integer", "traits": { - "smithy.api#documentation": "

The size of the volume, in GiBs. You must specify either a snapshot ID or a volume\n size. The following are the supported volumes sizes for each volume type:

\n
    \n
  • \n

    \n gp2 and gp3: 1-16,384

    \n
  • \n
  • \n

    \n io1 and io2: 4-16,384

    \n
  • \n
  • \n

    \n st1 and sc1: 125-16,384

    \n
  • \n
  • \n

    \n standard: 1-1,024

    \n
  • \n
" + "smithy.api#documentation": "

The size of the volume, in GiBs. You must specify either a snapshot ID or a volume\n size. The following are the supported volumes sizes for each volume type:

\n
    \n
  • \n

    \n gp2 and gp3: 1 - 16,384 GiB

    \n
  • \n
  • \n

    \n io1: 4 - 16,384 GiB

    \n
  • \n
  • \n

    \n io2: 4 - 65,536 GiB

    \n
  • \n
  • \n

    \n st1 and sc1: 125 - 16,384 GiB

    \n
  • \n
  • \n

    \n standard: 1 - 1024 GiB

    \n
  • \n
" } }, "VolumeType": { @@ -67241,6 +69345,46 @@ } } }, + "com.amazonaws.ec2#LaunchTemplateEnaSrdSpecification": { + "type": "structure", + "members": { + "EnaSrdEnabled": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "aws.protocols#ec2QueryName": "EnaSrdEnabled", + "smithy.api#documentation": "

Indicates whether ENA Express is enabled for the network interface.

", + "smithy.api#xmlName": "enaSrdEnabled" + } + }, + "EnaSrdUdpSpecification": { + "target": "com.amazonaws.ec2#LaunchTemplateEnaSrdUdpSpecification", + "traits": { + "aws.protocols#ec2QueryName": "EnaSrdUdpSpecification", + "smithy.api#documentation": "

Configures ENA Express for UDP network traffic.

", + "smithy.api#xmlName": "enaSrdUdpSpecification" + } + } + }, + "traits": { + "smithy.api#documentation": "

ENA Express uses Amazon Web Services Scalable Reliable Datagram (SRD) technology to increase the \n\t\t\tmaximum bandwidth used per stream and minimize tail latency of network traffic between EC2 instances. \n\t\t\tWith ENA Express, you can communicate between two EC2 instances in the same subnet within the same \n\t\t\taccount, or in different accounts. Both sending and receiving instances must have ENA Express enabled.

\n

To improve the reliability of network packet delivery, ENA Express reorders network packets on the \n\t\t\treceiving end by default. However, some UDP-based applications are designed to handle network packets \n\t\t\tthat are out of order to reduce the overhead for packet delivery at the network layer. When ENA Express \n\t\t\tis enabled, you can specify whether UDP network traffic uses it.

" + } + }, + "com.amazonaws.ec2#LaunchTemplateEnaSrdUdpSpecification": { + "type": "structure", + "members": { + "EnaSrdUdpEnabled": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "aws.protocols#ec2QueryName": "EnaSrdUdpEnabled", + "smithy.api#documentation": "

Indicates whether UDP traffic to and from the instance uses ENA Express. To specify this setting, \n\t\t\tyou must first enable ENA Express.

", + "smithy.api#xmlName": "enaSrdUdpEnabled" + } + } + }, + "traits": { + "smithy.api#documentation": "

ENA Express is compatible with both TCP and UDP transport protocols. When it's enabled, TCP traffic \n\t\t\tautomatically uses it. However, some UDP-based applications are designed to handle network packets that are \n\t\t\tout of order, without a need for retransmission, such as live video broadcasting or other near-real-time \n\t\t\tapplications. For UDP traffic, you can specify whether to use ENA Express, based on your application \n\t\t\tenvironment needs.

" + } + }, "com.amazonaws.ec2#LaunchTemplateEnclaveOptions": { "type": "structure", "members": { @@ -67813,6 +69957,22 @@ "smithy.api#documentation": "

The primary IPv6 address of the network interface. When you enable an IPv6 GUA address to be a primary IPv6, the first IPv6 GUA will be made the primary IPv6 address until the instance is terminated or the network interface is detached. For more information about primary IPv6 addresses, see RunInstances.

", "smithy.api#xmlName": "primaryIpv6" } + }, + "EnaSrdSpecification": { + "target": "com.amazonaws.ec2#LaunchTemplateEnaSrdSpecification", + "traits": { + "aws.protocols#ec2QueryName": "EnaSrdSpecification", + "smithy.api#documentation": "

Contains the ENA Express settings for instances launched from your launch template.

", + "smithy.api#xmlName": "enaSrdSpecification" + } + }, + "ConnectionTrackingSpecification": { + "target": "com.amazonaws.ec2#ConnectionTrackingSpecification", + "traits": { + "aws.protocols#ec2QueryName": "ConnectionTrackingSpecification", + "smithy.api#documentation": "

A security group connection tracking specification that enables you to set the timeout for connection tracking on an Elastic network interface. For more information, see Connection tracking timeouts in the Amazon Elastic Compute Cloud User Guide.

", + "smithy.api#xmlName": "connectionTrackingSpecification" + } } }, "traits": { @@ -67953,6 +70113,18 @@ "traits": { "smithy.api#documentation": "

The primary IPv6 address of the network interface. When you enable an IPv6 GUA address to be a primary IPv6, the first IPv6 GUA will be made the primary IPv6 address until the instance is terminated or the network interface is detached. For more information about primary IPv6 addresses, see RunInstances.

" } + }, + "EnaSrdSpecification": { + "target": "com.amazonaws.ec2#EnaSrdSpecificationRequest", + "traits": { + "smithy.api#documentation": "

Configure ENA Express settings for your launch template.

" + } + }, + "ConnectionTrackingSpecification": { + "target": "com.amazonaws.ec2#ConnectionTrackingSpecificationRequest", + "traits": { + "smithy.api#documentation": "

A security group connection tracking specification that enables you to set the timeout for connection tracking on an Elastic network interface. For more information, see Connection tracking timeouts in the Amazon Elastic Compute Cloud User Guide.

" + } } }, "traits": { @@ -68468,7 +70640,7 @@ "ResourceType": { "target": "com.amazonaws.ec2#ResourceType", "traits": { - "smithy.api#documentation": "

The type of resource to tag.

\n

Valid Values lists all resource types for Amazon EC2 that can be tagged. When\n you create a launch template, you can specify tags for the following resource types\n only: instance | volume | elastic-gpu |\n network-interface | spot-instances-request.\n If the instance does include the resource type that you specify, the instance \n launch fails. For example, not all instance types include an Elastic GPU.

\n

To tag a resource after it has been created, see CreateTags.

" + "smithy.api#documentation": "

The type of resource to tag.

\n

Valid Values lists all resource types for Amazon EC2 that can be tagged. When\n you create a launch template, you can specify tags for the following resource types\n only: instance | volume | elastic-gpu |\n network-interface | spot-instances-request.\n If the instance does not include the resource type that you specify, the instance \n launch fails. For example, not all instance types include an Elastic GPU.

\n

To tag a resource after it has been created, see CreateTags.

" } }, "Tags": { @@ -69776,6 +71948,273 @@ } } }, + "com.amazonaws.ec2#LockMode": { + "type": "enum", + "members": { + "compliance": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "compliance" + } + }, + "governance": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "governance" + } + } + } + }, + "com.amazonaws.ec2#LockSnapshot": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#LockSnapshotRequest" + }, + "output": { + "target": "com.amazonaws.ec2#LockSnapshotResult" + }, + "traits": { + "smithy.api#documentation": "

Locks an Amazon EBS snapshot in either governance or compliance \n mode to protect it against accidental or malicious deletions for a specific duration. A locked snapshot \n can't be deleted.

\n

You can also use this action to modify the lock settings for a snapshot that is already locked. The \n allowed modifications depend on the lock mode and lock state:

\n
    \n
  • \n

    If the snapshot is locked in governance mode, you can modify the lock mode and the lock duration \n or lock expiration date.

    \n
  • \n
  • \n

    If the snapshot is locked in compliance mode and it is in the cooling-off period, you can modify \n the lock mode and the lock duration or lock expiration date.

    \n
  • \n
  • \n

    If the snapshot is locked in compliance mode and the cooling-off period has lapsed, you can \n only increase the lock duration or extend the lock expiration date.

    \n
  • \n
" + } + }, + "com.amazonaws.ec2#LockSnapshotRequest": { + "type": "structure", + "members": { + "SnapshotId": { + "target": "com.amazonaws.ec2#SnapshotId", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The ID of the snapshot to lock.

", + "smithy.api#required": {} + } + }, + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, \n and provides an error response. If you have the required permissions, the error response is DryRunOperation. \n Otherwise, it is UnauthorizedOperation.

" + } + }, + "LockMode": { + "target": "com.amazonaws.ec2#LockMode", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The mode in which to lock the snapshot. Specify one of the following:

\n
    \n
  • \n

    \n governance - Locks the snapshot in governance mode. Snapshots locked in governance \n mode can't be deleted until one of the following conditions are met:

    \n
      \n
    • \n

      The lock duration expires.

      \n
    • \n
    • \n

      The snapshot is unlocked by a user with the appropriate permissions.

      \n
    • \n
    \n

    Users with the appropriate IAM permissions can unlock the snapshot, increase or decrease the lock \n duration, and change the lock mode to compliance at any time.

    \n

    If you lock a snapshot in governance mode, omit \n CoolOffPeriod.

    \n
  • \n
  • \n

    \n compliance - Locks the snapshot in compliance mode. Snapshots locked in compliance \n mode can't be unlocked by any user. They can be deleted only after the lock duration expires. Users \n can't decrease the lock duration or change the lock mode to governance. However, users \n with appropriate IAM permissions can increase the lock duration at any time.

    \n

    If you lock a snapshot in compliance mode, you can optionally specify \n CoolOffPeriod.

    \n
  • \n
", + "smithy.api#required": {} + } + }, + "CoolOffPeriod": { + "target": "com.amazonaws.ec2#CoolOffPeriodRequestHours", + "traits": { + "smithy.api#documentation": "

The cooling-off period during which you can unlock the snapshot or modify the lock settings after \n locking the snapshot in compliance mode, in hours. After the cooling-off period expires, you can't \n unlock or delete the snapshot, decrease the lock duration, or change the lock mode. You can increase \n the lock duration after the cooling-off period expires.

\n

The cooling-off period is optional when locking a snapshot in compliance mode. If you are locking \n the snapshot in governance mode, omit this parameter.

\n

To lock the snapshot in compliance mode immediately without a cooling-off period, omit this \n parameter.

\n

If you are extending the lock duration for a snapshot that is locked in compliance mode after \n the cooling-off period has expired, omit this parameter. If you specify a cooling-period in a such \n a request, the request fails.

\n

Allowed values: Min 1, max 72.

" + } + }, + "LockDuration": { + "target": "com.amazonaws.ec2#RetentionPeriodRequestDays", + "traits": { + "smithy.api#documentation": "

The period of time for which to lock the snapshot, in days. The snapshot lock will automatically \n expire after this period lapses.

\n

You must specify either this parameter or ExpirationDate, but \n not both.

\n

Allowed values: Min: 1, max 36500

" + } + }, + "ExpirationDate": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "smithy.api#documentation": "

The date and time at which the snapshot lock is to automatically expire, in the UTC time zone \n (YYYY-MM-DDThh:mm:ss.sssZ).

\n

You must specify either this parameter or LockDuration, but \n not both.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#LockSnapshotResult": { + "type": "structure", + "members": { + "SnapshotId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "SnapshotId", + "smithy.api#documentation": "

The ID of the snapshot

", + "smithy.api#xmlName": "snapshotId" + } + }, + "LockState": { + "target": "com.amazonaws.ec2#LockState", + "traits": { + "aws.protocols#ec2QueryName": "LockState", + "smithy.api#documentation": "

The state of the snapshot lock. Valid states include:

\n
    \n
  • \n

    \n compliance-cooloff - The snapshot has been locked in \n compliance mode but it is still within the cooling-off period. The snapshot can't be \n deleted, but it can be unlocked and the lock settings can be modified by users with \n appropriate permissions.

    \n
  • \n
  • \n

    \n governance - The snapshot is locked in governance mode. The \n snapshot can't be deleted, but it can be unlocked and the lock settings can be \n modified by users with appropriate permissions.

    \n
  • \n
  • \n

    \n compliance - The snapshot is locked in compliance mode and the \n cooling-off period has expired. The snapshot can't be unlocked or deleted. The lock \n duration can only be increased by users with appropriate permissions.

    \n
  • \n
  • \n

    \n expired - The snapshot was locked in compliance or governance \n mode but the lock duration has expired. The snapshot is not locked and can be deleted.

    \n
  • \n
", + "smithy.api#xmlName": "lockState" + } + }, + "LockDuration": { + "target": "com.amazonaws.ec2#RetentionPeriodResponseDays", + "traits": { + "aws.protocols#ec2QueryName": "LockDuration", + "smithy.api#documentation": "

The period of time for which the snapshot is locked, in days.

", + "smithy.api#xmlName": "lockDuration" + } + }, + "CoolOffPeriod": { + "target": "com.amazonaws.ec2#CoolOffPeriodResponseHours", + "traits": { + "aws.protocols#ec2QueryName": "CoolOffPeriod", + "smithy.api#documentation": "

The compliance mode cooling-off period, in hours.

", + "smithy.api#xmlName": "coolOffPeriod" + } + }, + "CoolOffPeriodExpiresOn": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "aws.protocols#ec2QueryName": "CoolOffPeriodExpiresOn", + "smithy.api#documentation": "

The date and time at which the compliance mode cooling-off period expires, in the UTC time zone \n (YYYY-MM-DDThh:mm:ss.sssZ).

", + "smithy.api#xmlName": "coolOffPeriodExpiresOn" + } + }, + "LockCreatedOn": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "aws.protocols#ec2QueryName": "LockCreatedOn", + "smithy.api#documentation": "

The date and time at which the snapshot was locked, in the UTC time zone \n (YYYY-MM-DDThh:mm:ss.sssZ).

", + "smithy.api#xmlName": "lockCreatedOn" + } + }, + "LockExpiresOn": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "aws.protocols#ec2QueryName": "LockExpiresOn", + "smithy.api#documentation": "

The date and time at which the lock will expire, in the UTC time zone \n (YYYY-MM-DDThh:mm:ss.sssZ).

", + "smithy.api#xmlName": "lockExpiresOn" + } + }, + "LockDurationStartTime": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "aws.protocols#ec2QueryName": "LockDurationStartTime", + "smithy.api#documentation": "

The date and time at which the lock duration started, in the UTC time zone \n (YYYY-MM-DDThh:mm:ss.sssZ).

", + "smithy.api#xmlName": "lockDurationStartTime" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.ec2#LockState": { + "type": "enum", + "members": { + "compliance": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "compliance" + } + }, + "governance": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "governance" + } + }, + "compliance_cooloff": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "compliance-cooloff" + } + }, + "expired": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "expired" + } + } + } + }, + "com.amazonaws.ec2#LockedSnapshotsInfo": { + "type": "structure", + "members": { + "OwnerId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "OwnerId", + "smithy.api#documentation": "

The account ID of the Amazon Web Services account that owns the snapshot.

", + "smithy.api#xmlName": "ownerId" + } + }, + "SnapshotId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "SnapshotId", + "smithy.api#documentation": "

The ID of the snapshot.

", + "smithy.api#xmlName": "snapshotId" + } + }, + "LockState": { + "target": "com.amazonaws.ec2#LockState", + "traits": { + "aws.protocols#ec2QueryName": "LockState", + "smithy.api#documentation": "

The state of the snapshot lock. Valid states include:

\n
    \n
  • \n

    \n compliance-cooloff - The snapshot has been locked in \n compliance mode but it is still within the cooling-off period. The snapshot can't be \n deleted, but it can be unlocked and the lock settings can be modified by users with \n appropriate permissions.

    \n
  • \n
  • \n

    \n governance - The snapshot is locked in governance mode. The \n snapshot can't be deleted, but it can be unlocked and the lock settings can be \n modified by users with appropriate permissions.

    \n
  • \n
  • \n

    \n compliance - The snapshot is locked in compliance mode and the \n cooling-off period has expired. The snapshot can't be unlocked or deleted. The lock \n duration can only be increased by users with appropriate permissions.

    \n
  • \n
  • \n

    \n expired - The snapshot was locked in compliance or governance \n mode but the lock duration has expired. The snapshot is not locked and can be deleted.

    \n
  • \n
", + "smithy.api#xmlName": "lockState" + } + }, + "LockDuration": { + "target": "com.amazonaws.ec2#RetentionPeriodResponseDays", + "traits": { + "aws.protocols#ec2QueryName": "LockDuration", + "smithy.api#documentation": "

The period of time for which the snapshot is locked, in days.

", + "smithy.api#xmlName": "lockDuration" + } + }, + "CoolOffPeriod": { + "target": "com.amazonaws.ec2#CoolOffPeriodResponseHours", + "traits": { + "aws.protocols#ec2QueryName": "CoolOffPeriod", + "smithy.api#documentation": "

The compliance mode cooling-off period, in hours.

", + "smithy.api#xmlName": "coolOffPeriod" + } + }, + "CoolOffPeriodExpiresOn": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "aws.protocols#ec2QueryName": "CoolOffPeriodExpiresOn", + "smithy.api#documentation": "

The date and time at which the compliance mode cooling-off period expires, in the UTC time zone \n (YYYY-MM-DDThh:mm:ss.sssZ).

", + "smithy.api#xmlName": "coolOffPeriodExpiresOn" + } + }, + "LockCreatedOn": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "aws.protocols#ec2QueryName": "LockCreatedOn", + "smithy.api#documentation": "

The date and time at which the snapshot was locked, in the UTC time zone (YYYY-MM-DDThh:mm:ss.sssZ).

", + "smithy.api#xmlName": "lockCreatedOn" + } + }, + "LockDurationStartTime": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "aws.protocols#ec2QueryName": "LockDurationStartTime", + "smithy.api#documentation": "

The date and time at which the lock duration started, in the UTC time zone (YYYY-MM-DDThh:mm:ss.sssZ).

\n

If you lock a snapshot that is in the pending state, the lock duration \n starts only once the snapshot enters the completed state.

", + "smithy.api#xmlName": "lockDurationStartTime" + } + }, + "LockExpiresOn": { + "target": "com.amazonaws.ec2#MillisecondDateTime", + "traits": { + "aws.protocols#ec2QueryName": "LockExpiresOn", + "smithy.api#documentation": "

The date and time at which the lock will expire, in the UTC time zone (YYYY-MM-DDThh:mm:ss.sssZ).

", + "smithy.api#xmlName": "lockExpiresOn" + } + } + }, + "traits": { + "smithy.api#documentation": "

Information about a locked snapshot.

" + } + }, + "com.amazonaws.ec2#LockedSnapshotsInfoList": { + "type": "list", + "member": { + "target": "com.amazonaws.ec2#LockedSnapshotsInfo", + "traits": { + "smithy.api#xmlName": "item" + } + } + }, "com.amazonaws.ec2#LogDestinationType": { "type": "enum", "members": { @@ -69939,6 +72378,12 @@ "traits": { "smithy.api#enumValue": "spot" } + }, + "capacity_block": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "capacity-block" + } } } }, @@ -71967,6 +74412,12 @@ "smithy.api#documentation": "

The operating Regions to remove.

", "smithy.api#xmlName": "RemoveOperatingRegion" } + }, + "Tier": { + "target": "com.amazonaws.ec2#IpamTier", + "traits": { + "smithy.api#documentation": "

IPAM is offered in a Free Tier and an Advanced Tier. For more information about the features available in each tier and the costs associated with the tiers, see Amazon VPC pricing > IPAM tab.

" + } } }, "traits": { @@ -72534,6 +74985,12 @@ "traits": { "smithy.api#documentation": "

If you’re modifying a network interface in a dual-stack or IPv6-only subnet, you have\n the option to assign a primary IPv6 IP address. A primary IPv6 address is an IPv6 GUA\n address associated with an ENI that you have enabled to use a primary IPv6 address. Use\n this option if the instance that this ENI will be attached to relies on its IPv6 address\n not changing. Amazon Web Services will automatically assign an IPv6 address associated\n with the ENI attached to your instance to be the primary IPv6 address. Once you enable\n an IPv6 GUA address to be a primary IPv6, you cannot disable it. When you enable an IPv6\n GUA address to be a primary IPv6, the first IPv6 GUA will be made the primary IPv6\n address until the instance is terminated or the network interface is detached. If you\n have multiple IPv6 addresses associated with an ENI attached to your instance and you\n enable a primary IPv6 address, the first IPv6 GUA address associated with the ENI\n becomes the primary IPv6 address.

" } + }, + "ConnectionTrackingSpecification": { + "target": "com.amazonaws.ec2#ConnectionTrackingSpecificationRequest", + "traits": { + "smithy.api#documentation": "

A connection tracking specification.

" + } } }, "traits": { @@ -73384,6 +75841,12 @@ "smithy.api#documentation": "

Enable or disable DNS support.

" } }, + "SecurityGroupReferencingSupport": { + "target": "com.amazonaws.ec2#SecurityGroupReferencingSupportValue", + "traits": { + "smithy.api#documentation": "

Enables you to reference a security group across VPCs attached to a transit gateway (TGW). Use this option to simplify security group management and control of instance-to-instance traffic across VPCs that are connected by transit gateway. You can also use this option to migrate from VPC peering (which was the only option that supported security group referencing) to transit gateways (which now also support security group referencing). This option is disabled by default and there are no additional costs to use this feature.

\n

For important information about this feature, see Create a transit gateway in the Amazon Web Services Transit Gateway Guide.

" + } + }, "AutoAcceptSharedAttachments": { "target": "com.amazonaws.ec2#AutoAcceptSharedAttachmentsValue", "traits": { @@ -73606,6 +76069,12 @@ "smithy.api#documentation": "

Enable or disable DNS support. The default is enable.

" } }, + "SecurityGroupReferencingSupport": { + "target": "com.amazonaws.ec2#SecurityGroupReferencingSupportValue", + "traits": { + "smithy.api#documentation": "

Enables you to reference a security group across VPCs attached to a transit gateway (TGW). Use this option to simplify security group management and control of instance-to-instance traffic across VPCs that are connected by transit gateway. You can also use this option to migrate from VPC peering (which was the only option that supported security group referencing) to transit gateways (which now also support security group referencing). This option is disabled by default and there are no additional costs to use this feature.

\n

For important information about this feature, see Create a transit gateway attachment to a VPC in the Amazon Web Services Transit Gateway Guide.

" + } + }, "Ipv6Support": { "target": "com.amazonaws.ec2#Ipv6SupportValue", "traits": { @@ -73749,7 +76218,7 @@ "SseSpecification": { "target": "com.amazonaws.ec2#VerifiedAccessSseSpecificationRequest", "traits": { - "smithy.api#documentation": "

\n Options for server side encryption.\n

" + "smithy.api#documentation": "

The options for server side encryption.

" } } }, @@ -73780,7 +76249,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessSseSpecificationResponse", "traits": { "aws.protocols#ec2QueryName": "SseSpecification", - "smithy.api#documentation": "

\n Describes the options in use for server side encryption.\n

", + "smithy.api#documentation": "

The options in use for server side encryption.

", "smithy.api#xmlName": "sseSpecification" } } @@ -73849,7 +76318,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessEndpoint", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessEndpoint", - "smithy.api#documentation": "

The Verified Access endpoint details.

", + "smithy.api#documentation": "

Details about the Verified Access endpoint.

", "smithy.api#xmlName": "verifiedAccessEndpoint" } } @@ -73930,7 +76399,7 @@ "SseSpecification": { "target": "com.amazonaws.ec2#VerifiedAccessSseSpecificationRequest", "traits": { - "smithy.api#documentation": "

\n Options for server side encryption.\n

" + "smithy.api#documentation": "

The options for server side encryption.

" } } }, @@ -73961,7 +76430,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessSseSpecificationResponse", "traits": { "aws.protocols#ec2QueryName": "SseSpecification", - "smithy.api#documentation": "

\n Describes the options in use for server side encryption.\n

", + "smithy.api#documentation": "

The options in use for server side encryption.

", "smithy.api#xmlName": "sseSpecification" } } @@ -74018,7 +76487,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessGroup", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessGroup", - "smithy.api#documentation": "

Details of Verified Access group.

", + "smithy.api#documentation": "

Details about the Verified Access group.

", "smithy.api#xmlName": "verifiedAccessGroup" } } @@ -74146,7 +76615,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessInstance", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessInstance", - "smithy.api#documentation": "

The ID of the Verified Access instance.

", + "smithy.api#documentation": "

Details about the Verified Access instance.

", "smithy.api#xmlName": "verifiedAccessInstance" } } @@ -74167,6 +76636,20 @@ "smithy.api#documentation": "

Modifies the configuration of the specified Amazon Web Services Verified Access trust provider.

" } }, + "com.amazonaws.ec2#ModifyVerifiedAccessTrustProviderDeviceOptions": { + "type": "structure", + "members": { + "PublicSigningKeyUrl": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#documentation": "

The URL Amazon Web Services Verified Access will use to verify the authenticity of the device tokens.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Modifies the configuration of the specified device-based Amazon Web Services Verified Access trust provider.

" + } + }, "com.amazonaws.ec2#ModifyVerifiedAccessTrustProviderOidcOptions": { "type": "structure", "members": { @@ -74234,6 +76717,12 @@ "smithy.api#documentation": "

The options for an OpenID Connect-compatible user-identity trust provider.

" } }, + "DeviceOptions": { + "target": "com.amazonaws.ec2#ModifyVerifiedAccessTrustProviderDeviceOptions", + "traits": { + "smithy.api#documentation": "

The options for a device-based trust provider. This parameter is required when the\n provider type is device.

" + } + }, "Description": { "target": "com.amazonaws.ec2#String", "traits": { @@ -74256,7 +76745,7 @@ "SseSpecification": { "target": "com.amazonaws.ec2#VerifiedAccessSseSpecificationRequest", "traits": { - "smithy.api#documentation": "

\n Options for server side encryption.\n

" + "smithy.api#documentation": "

The options for server side encryption.

" } } }, @@ -74271,7 +76760,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessTrustProvider", "traits": { "aws.protocols#ec2QueryName": "VerifiedAccessTrustProvider", - "smithy.api#documentation": "

The ID of the Verified Access trust provider.

", + "smithy.api#documentation": "

Details about the Verified Access trust provider.

", "smithy.api#xmlName": "verifiedAccessTrustProvider" } } @@ -74368,7 +76857,7 @@ "Size": { "target": "com.amazonaws.ec2#Integer", "traits": { - "smithy.api#documentation": "

The target size of the volume, in GiB. The target volume size must be greater than or\n equal to the existing size of the volume.

\n

The following are the supported volumes sizes for each volume type:

\n
    \n
  • \n

    \n gp2 and gp3: 1-16,384

    \n
  • \n
  • \n

    \n io1 and io2: 4-16,384

    \n
  • \n
  • \n

    \n st1 and sc1: 125-16,384

    \n
  • \n
  • \n

    \n standard: 1-1,024

    \n
  • \n
\n

Default: The existing size is retained.

" + "smithy.api#documentation": "

The target size of the volume, in GiB. The target volume size must be greater than or\n equal to the existing size of the volume.

\n

The following are the supported volumes sizes for each volume type:

\n
    \n
  • \n

    \n gp2 and gp3: 1 - 16,384 GiB

    \n
  • \n
  • \n

    \n io1: 4 - 16,384 GiB

    \n
  • \n
  • \n

    \n io2: 4 - 65,536 GiB

    \n
  • \n
  • \n

    \n st1 and sc1: 125 - 16,384 GiB

    \n
  • \n
  • \n

    \n standard: 1 - 1024 GiB

    \n
  • \n
\n

Default: The existing size is retained.

" } }, "VolumeType": { @@ -74380,7 +76869,7 @@ "Iops": { "target": "com.amazonaws.ec2#Integer", "traits": { - "smithy.api#documentation": "

The target IOPS rate of the volume. This parameter is valid only for gp3, io1, and io2 volumes.

\n

The following are the supported values for each volume type:

\n
    \n
  • \n

    \n gp3: 3,000-16,000 IOPS

    \n
  • \n
  • \n

    \n io1: 100-64,000 IOPS

    \n
  • \n
  • \n

    \n io2: 100-64,000 IOPS

    \n
  • \n
\n

Default: The existing value is retained if you keep the same volume type. If you change\n the volume type to io1, io2, or gp3, the default is 3,000.

" + "smithy.api#documentation": "

The target IOPS rate of the volume. This parameter is valid only for gp3, io1, and io2 volumes.

\n

The following are the supported values for each volume type:

\n
    \n
  • \n

    \n gp3: 3,000 - 16,000 IOPS

    \n
  • \n
  • \n

    \n io1: 100 - 64,000 IOPS

    \n
  • \n
  • \n

    \n io2: 100 - 256,000 IOPS

    \n
  • \n
\n

For io2 volumes, you can achieve up to 256,000 IOPS on \ninstances \nbuilt on the Nitro System. On other instances, you can achieve performance up to 32,000 IOPS.

\n

Default: The existing value is retained if you keep the same volume type. If you change\n the volume type to io1, io2, or gp3, the default is 3,000.

" } }, "Throughput": { @@ -75281,7 +77770,7 @@ "SkipTunnelReplacement": { "target": "com.amazonaws.ec2#Boolean", "traits": { - "smithy.api#documentation": "

Choose whether or not to trigger immediate tunnel replacement.

\n

Valid values: True | False\n

" + "smithy.api#documentation": "

Choose whether or not to trigger immediate tunnel replacement. This is only applicable when turning on or off EnableTunnelLifecycleControl.

\n

Valid values: True | False\n

" } } }, @@ -75359,7 +77848,7 @@ "DPDTimeoutSeconds": { "target": "com.amazonaws.ec2#Integer", "traits": { - "smithy.api#documentation": "

The number of seconds after which a DPD timeout occurs.

\n

Constraints: A value greater than or equal to 30.

\n

Default: 30\n

" + "smithy.api#documentation": "

The number of seconds after which a DPD timeout occurs. A DPD timeout of 40 seconds means that the VPN endpoint will consider the peer dead 30 seconds after the first failed keep-alive.

\n

Constraints: A value greater than or equal to 30.

\n

Default: 40\n

" } }, "DPDTimeoutAction": { @@ -77012,6 +79501,14 @@ "smithy.api#xmlName": "availabilityZone" } }, + "ConnectionTrackingConfiguration": { + "target": "com.amazonaws.ec2#ConnectionTrackingConfiguration", + "traits": { + "aws.protocols#ec2QueryName": "ConnectionTrackingConfiguration", + "smithy.api#documentation": "

A security group connection tracking configuration that enables you to set the timeout for connection tracking on an Elastic network interface. For more information, see Connection tracking timeouts in the Amazon Elastic Compute Cloud User Guide.

", + "smithy.api#xmlName": "connectionTrackingConfiguration" + } + }, "Description": { "target": "com.amazonaws.ec2#String", "traits": { @@ -77849,6 +80346,15 @@ } } }, + "com.amazonaws.ec2#NetworkNodesList": { + "type": "list", + "member": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#xmlName": "item" + } + } + }, "com.amazonaws.ec2#NetworkPerformance": { "type": "string" }, @@ -80559,6 +83065,72 @@ "smithy.api#output": {} } }, + "com.amazonaws.ec2#ProvisionIpamByoasn": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#ProvisionIpamByoasnRequest" + }, + "output": { + "target": "com.amazonaws.ec2#ProvisionIpamByoasnResult" + }, + "traits": { + "smithy.api#documentation": "

Provisions your Autonomous System Number (ASN) for use in your Amazon Web Services account. This action requires authorization context for Amazon to bring the ASN to an Amazon Web Services account. For more information, see Tutorial: Bring your ASN to IPAM in the Amazon VPC IPAM guide.

" + } + }, + "com.amazonaws.ec2#ProvisionIpamByoasnRequest": { + "type": "structure", + "members": { + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, \n and provides an error response. If you have the required permissions, the error response is DryRunOperation. \n Otherwise, it is UnauthorizedOperation.

" + } + }, + "IpamId": { + "target": "com.amazonaws.ec2#IpamId", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

An IPAM ID.

", + "smithy.api#required": {} + } + }, + "Asn": { + "target": "com.amazonaws.ec2#String", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

A public 2-byte or 4-byte ASN.

", + "smithy.api#required": {} + } + }, + "AsnAuthorizationContext": { + "target": "com.amazonaws.ec2#AsnAuthorizationContext", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

An ASN authorization context.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#ProvisionIpamByoasnResult": { + "type": "structure", + "members": { + "Byoasn": { + "target": "com.amazonaws.ec2#Byoasn", + "traits": { + "aws.protocols#ec2QueryName": "Byoasn", + "smithy.api#documentation": "

An ASN and BYOIP CIDR association.

", + "smithy.api#xmlName": "byoasn" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#ProvisionIpamPoolCidr": { "type": "operation", "input": { @@ -81003,6 +83575,71 @@ "smithy.api#documentation": "

Describes the result of the purchase.

" } }, + "com.amazonaws.ec2#PurchaseCapacityBlock": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#PurchaseCapacityBlockRequest" + }, + "output": { + "target": "com.amazonaws.ec2#PurchaseCapacityBlockResult" + }, + "traits": { + "smithy.api#documentation": "

Purchase the Capacity Block for use with your account. \n\t\t With Capacity Blocks you ensure GPU capacity is available for machine learning (ML) workloads. You must specify the ID of the Capacity Block offering you are purchasing.

" + } + }, + "com.amazonaws.ec2#PurchaseCapacityBlockRequest": { + "type": "structure", + "members": { + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, and provides an error response. If you have the required permissions, the error response is DryRunOperation. Otherwise, it is UnauthorizedOperation.

" + } + }, + "TagSpecifications": { + "target": "com.amazonaws.ec2#TagSpecificationList", + "traits": { + "smithy.api#documentation": "

The tags to apply to the Capacity Block during launch.

", + "smithy.api#xmlName": "TagSpecification" + } + }, + "CapacityBlockOfferingId": { + "target": "com.amazonaws.ec2#OfferingId", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The ID of the Capacity Block offering.

", + "smithy.api#required": {} + } + }, + "InstancePlatform": { + "target": "com.amazonaws.ec2#CapacityReservationInstancePlatform", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The type of operating system for which to reserve capacity.

", + "smithy.api#required": {} + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#PurchaseCapacityBlockResult": { + "type": "structure", + "members": { + "CapacityReservation": { + "target": "com.amazonaws.ec2#CapacityReservation", + "traits": { + "aws.protocols#ec2QueryName": "CapacityReservation", + "smithy.api#documentation": "

The Capacity Reservation.

", + "smithy.api#xmlName": "capacityReservation" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#PurchaseHostReservation": { "type": "operation", "input": { @@ -81477,7 +84114,7 @@ "target": "com.amazonaws.ec2#String", "traits": { "aws.protocols#ec2QueryName": "VpcPeeringConnectionId", - "smithy.api#documentation": "

The ID of the VPC peering connection.

", + "smithy.api#documentation": "

The ID of the VPC peering connection (if applicable).

", "smithy.api#xmlName": "vpcPeeringConnectionId" } } @@ -83552,14 +86189,14 @@ "SecurityGroupIds": { "target": "com.amazonaws.ec2#SecurityGroupIdStringList", "traits": { - "smithy.api#documentation": "

One or more security group IDs. You can create a security group using CreateSecurityGroup. You cannot specify both a security group ID and\n security name in the same request.

", + "smithy.api#documentation": "

One or more security group IDs. You can create a security group using CreateSecurityGroup.

", "smithy.api#xmlName": "SecurityGroupId" } }, "SecurityGroups": { "target": "com.amazonaws.ec2#SecurityGroupStringList", "traits": { - "smithy.api#documentation": "

One or more security group names. For a nondefault VPC, you must use security group\n IDs instead. You cannot specify both a security group ID and security name in the same\n request.

", + "smithy.api#documentation": "

One or more security group names. For a nondefault VPC, you must use security group\n IDs instead.

", "smithy.api#xmlName": "SecurityGroup" } }, @@ -86654,6 +89291,18 @@ } } }, + "com.amazonaws.ec2#RetentionPeriodRequestDays": { + "type": "integer", + "traits": { + "smithy.api#range": { + "min": 1, + "max": 36500 + } + } + }, + "com.amazonaws.ec2#RetentionPeriodResponseDays": { + "type": "integer" + }, "com.amazonaws.ec2#RevokeClientVpnIngress": { "type": "operation", "input": { @@ -88451,13 +91100,13 @@ "Encrypted": { "target": "com.amazonaws.ec2#Boolean", "traits": { - "smithy.api#documentation": "

Indicates whether the volume is encrypted. You can attached encrypted volumes only to instances that support them.

" + "smithy.api#documentation": "

Indicates whether the volume is encrypted. You can attached encrypted volumes only to instances that \n support them.

" } }, "Iops": { "target": "com.amazonaws.ec2#Integer", "traits": { - "smithy.api#documentation": "

The number of I/O operations per second (IOPS) to provision for an io1 or io2 volume, with a maximum\n \t\tratio of 50 IOPS/GiB for io1, and 500 IOPS/GiB for io2. Range is 100 to 64,000 IOPS for\n \t\tvolumes in most Regions. Maximum IOPS of 64,000 is guaranteed only on\n \t\tinstances built on the Nitro System. Other instance families guarantee performance up to\n \t\t32,000 IOPS. For more information, see Amazon EBS volume types in the\n \t\tAmazon EC2 User Guide.

\n

This parameter is valid only for Provisioned IOPS SSD (io1 and io2) volumes.

" + "smithy.api#documentation": "

The number of I/O operations per second (IOPS) to provision for a gp3, io1, or io2 \n \t volume.

" } }, "SnapshotId": { @@ -88469,13 +91118,13 @@ "VolumeSize": { "target": "com.amazonaws.ec2#Integer", "traits": { - "smithy.api#documentation": "

The size of the volume, in GiB.

\n

Default: If you're creating the volume from a snapshot and don't specify a volume size, the default is the snapshot size.

" + "smithy.api#documentation": "

The size of the volume, in GiB.

\n

Default: If you're creating the volume from a snapshot and don't specify a volume size, the default \n is the snapshot size.

" } }, "VolumeType": { "target": "com.amazonaws.ec2#String", "traits": { - "smithy.api#documentation": "

The volume type. gp2 for General Purpose SSD, io1 or io2 for Provisioned IOPS SSD, Throughput Optimized HDD\n for st1, Cold HDD for sc1, or standard for\n Magnetic.

\n

Default: gp2\n

" + "smithy.api#documentation": "

The volume type.

\n

Default: gp2\n

" } } }, @@ -89259,9 +91908,17 @@ "target": "com.amazonaws.ec2#String", "traits": { "aws.protocols#ec2QueryName": "VpcPeeringConnectionId", - "smithy.api#documentation": "

The ID of the VPC peering connection.

", + "smithy.api#documentation": "

The ID of the VPC peering connection (if applicable). For more information about security group referencing for peering connections, see Update your security groups to reference peer security groups in the VPC Peering Guide.

", "smithy.api#xmlName": "vpcPeeringConnectionId" } + }, + "TransitGatewayId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "TransitGatewayId", + "smithy.api#documentation": "

The ID of the transit gateway (if applicable). For more information about security group referencing for transit gateways, see Create a transit gateway attachment to a VPC in the Amazon Web Services Transit Gateway Guide.

", + "smithy.api#xmlName": "transitGatewayId" + } } }, "traits": { @@ -89277,6 +91934,23 @@ } } }, + "com.amazonaws.ec2#SecurityGroupReferencingSupportValue": { + "type": "enum", + "members": { + "enable": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "enable" + } + }, + "disable": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "disable" + } + } + } + }, "com.amazonaws.ec2#SecurityGroupRule": { "type": "structure", "members": { @@ -90202,6 +92876,29 @@ } } }, + "com.amazonaws.ec2#SnapshotBlockPublicAccessState": { + "type": "enum", + "members": { + "block_all_sharing": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "block-all-sharing" + } + }, + "block_new_sharing": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "block-new-sharing" + } + }, + "unblocked": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "unblocked" + } + } + } + }, "com.amazonaws.ec2#SnapshotDetail": { "type": "structure", "members": { @@ -96393,6 +99090,14 @@ "smithy.api#xmlName": "dnsSupport" } }, + "SecurityGroupReferencingSupport": { + "target": "com.amazonaws.ec2#SecurityGroupReferencingSupportValue", + "traits": { + "aws.protocols#ec2QueryName": "SecurityGroupReferencingSupport", + "smithy.api#documentation": "

Enables you to reference a security group across VPCs attached to a transit gateway (TGW). Use this option to simplify security group management and control of instance-to-instance traffic across VPCs that are connected by transit gateway. You can also use this option to migrate from VPC peering (which was the only option that supported security group referencing) to transit gateways (which now also support security group referencing). This option is disabled by default and there are no additional costs to use this feature.

\n

For important information about this feature, see Create a transit gateway in the Amazon Web Services Transit Gateway Guide.

", + "smithy.api#xmlName": "securityGroupReferencingSupport" + } + }, "MulticastSupport": { "target": "com.amazonaws.ec2#MulticastSupportValue", "traits": { @@ -97037,6 +99742,12 @@ "smithy.api#documentation": "

Enable or disable DNS support. Enabled by default.

" } }, + "SecurityGroupReferencingSupport": { + "target": "com.amazonaws.ec2#SecurityGroupReferencingSupportValue", + "traits": { + "smithy.api#documentation": "

Enables you to reference a security group across VPCs attached to a transit gateway (TGW). Use this option to simplify security group management and control of instance-to-instance traffic across VPCs that are connected by transit gateway. You can also use this option to migrate from VPC peering (which was the only option that supported security group referencing) to transit gateways (which now also support security group referencing). This option is disabled by default and there are no additional costs to use this feature.

\n

For important information about this feature, see Create a transit gateway in the Amazon Web Services Transit Gateway Guide.

" + } + }, "MulticastSupport": { "target": "com.amazonaws.ec2#MulticastSupportValue", "traits": { @@ -97815,6 +100526,14 @@ "smithy.api#xmlName": "dnsSupport" } }, + "SecurityGroupReferencingSupport": { + "target": "com.amazonaws.ec2#SecurityGroupReferencingSupportValue", + "traits": { + "aws.protocols#ec2QueryName": "SecurityGroupReferencingSupport", + "smithy.api#documentation": "

For important information about this feature, see Create a transit gateway attachment to a VPC in the Amazon Web Services Transit Gateway Guide.

", + "smithy.api#xmlName": "securityGroupReferencingSupport" + } + }, "Ipv6Support": { "target": "com.amazonaws.ec2#Ipv6SupportValue", "traits": { @@ -97914,7 +100633,7 @@ } }, "traits": { - "smithy.api#documentation": "\n

Currently available in limited preview only. \n If you are interested in using this feature, contact your account manager.

\n
\n

Information about an association between a branch network interface with a trunk network interface.

" + "smithy.api#documentation": "

Information about an association between a branch network interface with a trunk network interface.

" } }, "com.amazonaws.ec2#TrunkInterfaceAssociationId": { @@ -98394,6 +101113,56 @@ } } }, + "com.amazonaws.ec2#UnlockSnapshot": { + "type": "operation", + "input": { + "target": "com.amazonaws.ec2#UnlockSnapshotRequest" + }, + "output": { + "target": "com.amazonaws.ec2#UnlockSnapshotResult" + }, + "traits": { + "smithy.api#documentation": "

Unlocks a snapshot that is locked in governance mode or that is locked in compliance mode \n but still in the cooling-off period. You can't unlock a snapshot that is locked in compliance \n mode after the cooling-off period has expired.

" + } + }, + "com.amazonaws.ec2#UnlockSnapshotRequest": { + "type": "structure", + "members": { + "SnapshotId": { + "target": "com.amazonaws.ec2#SnapshotId", + "traits": { + "smithy.api#clientOptional": {}, + "smithy.api#documentation": "

The ID of the snapshot to unlock.

", + "smithy.api#required": {} + } + }, + "DryRun": { + "target": "com.amazonaws.ec2#Boolean", + "traits": { + "smithy.api#documentation": "

Checks whether you have the required permissions for the action, without actually making the request, \n and provides an error response. If you have the required permissions, the error response is DryRunOperation. \n Otherwise, it is UnauthorizedOperation.

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ec2#UnlockSnapshotResult": { + "type": "structure", + "members": { + "SnapshotId": { + "target": "com.amazonaws.ec2#String", + "traits": { + "aws.protocols#ec2QueryName": "SnapshotId", + "smithy.api#documentation": "

The ID of the snapshot.

", + "smithy.api#xmlName": "snapshotId" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.ec2#UnmonitorInstances": { "type": "operation", "input": { @@ -98793,6 +101562,12 @@ "traits": { "smithy.api#enumValue": "on-demand" } + }, + "capacity_block": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "capacity-block" + } } } }, @@ -99280,7 +102055,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessSseSpecificationResponse", "traits": { "aws.protocols#ec2QueryName": "SseSpecification", - "smithy.api#documentation": "

\n Describes the options in use for server side encryption.\n

", + "smithy.api#documentation": "

The options in use for server side encryption.

", "smithy.api#xmlName": "sseSpecification" } } @@ -99583,7 +102358,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessSseSpecificationResponse", "traits": { "aws.protocols#ec2QueryName": "SseSpecification", - "smithy.api#documentation": "

\n Describes the options in use for server side encryption.\n

", + "smithy.api#documentation": "

The options in use for server side encryption.

", "smithy.api#xmlName": "sseSpecification" } } @@ -99668,7 +102443,7 @@ "target": "com.amazonaws.ec2#Boolean", "traits": { "aws.protocols#ec2QueryName": "FipsEnabled", - "smithy.api#documentation": "

Describes whether support for Federal Information Processing Standards (FIPS) is enabled on the instance.

", + "smithy.api#documentation": "

Indicates whether support for Federal Information Processing Standards (FIPS) is enabled on the instance.

", "smithy.api#xmlName": "fipsEnabled" } } @@ -99904,13 +102679,13 @@ "LogVersion": { "target": "com.amazonaws.ec2#String", "traits": { - "smithy.api#documentation": "

\n\t\t The logging version to use.\n\t

\n

Valid values: ocsf-0.1 | ocsf-1.0.0-rc.2\n

" + "smithy.api#documentation": "

The logging version.

\n

Valid values: ocsf-0.1 | ocsf-1.0.0-rc.2\n

" } }, "IncludeTrustContext": { "target": "com.amazonaws.ec2#Boolean", "traits": { - "smithy.api#documentation": "

\n\t\t Include trust data sent by trust providers into the logs. \n\t

" + "smithy.api#documentation": "

Indicates whether to include trust data sent by trust providers in the logs.

" } } }, @@ -100031,7 +102806,7 @@ "target": "com.amazonaws.ec2#String", "traits": { "aws.protocols#ec2QueryName": "LogVersion", - "smithy.api#documentation": "

\n Describes current setting for the logging version.\n

", + "smithy.api#documentation": "

The log version.

", "smithy.api#xmlName": "logVersion" } }, @@ -100039,7 +102814,7 @@ "target": "com.amazonaws.ec2#Boolean", "traits": { "aws.protocols#ec2QueryName": "IncludeTrustContext", - "smithy.api#documentation": "

\n\t\t Describes current setting for including trust data into the logs.\n\t

", + "smithy.api#documentation": "

Indicates whether trust data is included in the logs.

", "smithy.api#xmlName": "includeTrustContext" } } @@ -100075,7 +102850,7 @@ "target": "com.amazonaws.ec2#Boolean", "traits": { "aws.protocols#ec2QueryName": "CustomerManagedKeyEnabled", - "smithy.api#documentation": "

\n Describes the use of customer managed KMS keys for server side encryption.\n

\n

Valid values: True | False\n

", + "smithy.api#documentation": "

Indicates whether customer managed KMS keys are in use for server side encryption.

\n

Valid values: True | False\n

", "smithy.api#xmlName": "customerManagedKeyEnabled" } }, @@ -100083,13 +102858,13 @@ "target": "com.amazonaws.ec2#KmsKeyArn", "traits": { "aws.protocols#ec2QueryName": "KmsKeyArn", - "smithy.api#documentation": "

\n Describes the ARN of the KMS key.\n

", + "smithy.api#documentation": "

The ARN of the KMS key.

", "smithy.api#xmlName": "kmsKeyArn" } } }, "traits": { - "smithy.api#documentation": "

\n Describes the options in use for server side encryption.\n

" + "smithy.api#documentation": "

The options in use for server side encryption.

" } }, "com.amazonaws.ec2#VerifiedAccessTrustProvider": { @@ -100187,7 +102962,7 @@ "target": "com.amazonaws.ec2#VerifiedAccessSseSpecificationResponse", "traits": { "aws.protocols#ec2QueryName": "SseSpecification", - "smithy.api#documentation": "

\n Describes the options in use for server side encryption.\n

", + "smithy.api#documentation": "

The options in use for server side encryption.

", "smithy.api#xmlName": "sseSpecification" } } @@ -100307,7 +103082,7 @@ "target": "com.amazonaws.ec2#DateTime", "traits": { "aws.protocols#ec2QueryName": "LastStatusChange", - "smithy.api#documentation": "

The date and time of the last change in status.

", + "smithy.api#documentation": "

The date and time of the last change in status. This field is updated when changes in IKE (Phase 1), IPSec (Phase 2), or BGP status are detected.

", "smithy.api#xmlName": "lastStatusChange" } }, diff --git a/aws/sdk/aws-models/ecs.json b/aws/sdk/aws-models/ecs.json index 37cb034e6c8..9bdd42c52f1 100644 --- a/aws/sdk/aws-models/ecs.json +++ b/aws/sdk/aws-models/ecs.json @@ -267,7 +267,7 @@ "name": "ecs" }, "aws.protocols#awsJson1_1": {}, - "smithy.api#documentation": "Amazon Elastic Container Service\n

Amazon Elastic Container Service (Amazon ECS) is a highly scalable, fast, container management service. It makes\n\t\t\tit easy to run, stop, and manage Docker containers. You can host your cluster on a\n\t\t\tserverless infrastructure that's managed by Amazon ECS by launching your services or tasks on\n\t\t\tFargate. For more control, you can host your tasks on a cluster of Amazon Elastic Compute Cloud (Amazon EC2)\n\t\t\tor External (on-premises) instances that you manage.

\n

Amazon ECS makes it easy to launch and stop container-based applications with simple API\n\t\t\tcalls. This makes it easy to get the state of your cluster from a centralized service,\n\t\t\tand gives you access to many familiar Amazon EC2 features.

\n

You can use Amazon ECS to schedule the placement of containers across your cluster based on\n\t\t\tyour resource needs, isolation policies, and availability requirements. With Amazon ECS, you\n\t\t\tdon't need to operate your own cluster management and configuration management systems.\n\t\t\tYou also don't need to worry about scaling your management infrastructure.

", + "smithy.api#documentation": "Amazon Elastic Container Service\n

Amazon Elastic Container Service (Amazon ECS) is a highly scalable, fast, container management service. It makes\n\t\t\tit easy to run, stop, and manage Docker containers. You can host your cluster on a\n\t\t\tserverless infrastructure that's managed by Amazon ECS by launching your services or tasks on\n\t\t\tFargate. For more control, you can host your tasks on a cluster of Amazon Elastic Compute Cloud (Amazon EC2)\n\t\t\tor External (on-premises) instances that you manage.

\n

Amazon ECS makes it easy to launch and stop container-based applications with simple API\n\t\t\tcalls. This makes it easy to get the state of your cluster from a centralized service,\n\t\t\tand gives you access to many familiar Amazon EC2 features.

\n

You can use Amazon ECS to schedule the placement of containers across your cluster based on\n\t\t\tyour resource needs, isolation policies, and availability requirements. With Amazon ECS, you\n\t\t\tdon't need to operate your own cluster management and configuration management systems.\n\t\t\tYou also don't need to worry about scaling your management infrastructure.

", "smithy.api#title": "Amazon EC2 Container Service", "smithy.api#xmlNamespace": { "uri": "http://ecs.amazonaws.com/doc/2014-11-13/" @@ -1738,7 +1738,7 @@ } }, "traits": { - "smithy.api#documentation": "

These errors are usually caused by a client action. This client action might be using\n\t\t\tan action or resource on behalf of a user that doesn't have permissions to use the\n\t\t\taction or resource,. Or, it might be specifying an identifier that isn't valid.

", + "smithy.api#documentation": "

These errors are usually caused by a client action. This client action might be using\n\t\t\tan action or resource on behalf of a user that doesn't have permissions to use the\n\t\t\taction or resource. Or, it might be specifying an identifier that isn't valid.

", "smithy.api#error": "client" } }, @@ -2054,6 +2054,24 @@ "target": "com.amazonaws.ecs#Compatibility" } }, + "com.amazonaws.ecs#ConflictException": { + "type": "structure", + "members": { + "resourceIds": { + "target": "com.amazonaws.ecs#ResourceIds", + "traits": { + "smithy.api#documentation": "

The existing task ARNs which are already associated with the clientToken.

" + } + }, + "message": { + "target": "com.amazonaws.ecs#String" + } + }, + "traits": { + "smithy.api#documentation": "

The RunTask request could not be processed due to conflicts. The provided\n\t\t\t\tclientToken is already in use with a different RunTask\n\t\t\trequest. The resourceIds are the existing task ARNs which are already\n\t\t\tassociated with the clientToken.

\n

To fix this issue:

\n
    \n
  • \n

    Run RunTask with a unique\n\t\t\t\tclientToken.

    \n
  • \n
  • \n

    Run RunTask with the clientToken and the original set of\n\t\t\t\t\tparameters

    \n
  • \n
", + "smithy.api#error": "client" + } + }, "com.amazonaws.ecs#Connectivity": { "type": "enum", "members": { @@ -3138,7 +3156,7 @@ "clientToken": { "target": "com.amazonaws.ecs#String", "traits": { - "smithy.api#documentation": "

An identifier that you provide to ensure the idempotency of the request. It must be\n\t\t\tunique and is case sensitive. Up to 32 ASCII characters are allowed.

" + "smithy.api#documentation": "

An identifier that you provide to ensure the idempotency of the request. It must be\n\t\t\tunique and is case sensitive. Up to 36 ASCII characters in the range of 33-126 (inclusive) are allowed.

" } }, "launchType": { @@ -3380,7 +3398,7 @@ "clientToken": { "target": "com.amazonaws.ecs#String", "traits": { - "smithy.api#documentation": "

The identifier that you provide to ensure the idempotency of the request. It's case\n\t\t\tsensitive and must be unique. It can be up to 32 ASCII characters are allowed.

" + "smithy.api#documentation": "

An identifier that you provide to ensure the idempotency of the request. It must be\n\t\t\tunique and is case sensitive. Up to 36 ASCII characters in the range of 33-126 (inclusive) are allowed.

" } }, "tags": { @@ -8157,7 +8175,7 @@ "protocol": { "target": "com.amazonaws.ecs#TransportProtocol", "traits": { - "smithy.api#documentation": "

The protocol used for the port mapping. Valid values are tcp and\n\t\t\t\tudp. The default is tcp.

" + "smithy.api#documentation": "

The protocol used for the port mapping. Valid values are tcp and\n\t\t\tudp. The default is tcp. protocol is immutable in a \n\t\t\tService Connect service. Updating this field requires a service deletion and \n\t\t\tredeployment.\n\t\t

" } }, "name": { @@ -8169,7 +8187,7 @@ "appProtocol": { "target": "com.amazonaws.ecs#ApplicationProtocol", "traits": { - "smithy.api#documentation": "

The application protocol that's used for the port mapping. This parameter only applies\n\t\t\tto Service Connect. We recommend that you set this parameter to be consistent with the\n\t\t\tprotocol that your application uses. If you set this parameter, Amazon ECS adds\n\t\t\tprotocol-specific connection handling to the Service Connect proxy. If you set this\n\t\t\tparameter, Amazon ECS adds protocol-specific telemetry in the Amazon ECS console and CloudWatch.

\n

If you don't set a value for this parameter, then TCP is used. However, Amazon ECS doesn't\n\t\t\tadd protocol-specific telemetry for TCP.

\n

Tasks that run in a namespace can use short names to connect\n\tto services in the namespace. Tasks can connect to services across all of the clusters in the namespace.\n\tTasks connect through a managed proxy container\n\tthat collects logs and metrics for increased visibility.\n\tOnly the tasks that Amazon ECS services create are supported with Service Connect.\n\tFor more information, see Service Connect in the Amazon Elastic Container Service Developer Guide.

" + "smithy.api#documentation": "

The application protocol that's used for the port mapping. This parameter only applies\n\t\t\tto Service Connect. We recommend that you set this parameter to be consistent with the\n\t\t\tprotocol that your application uses. If you set this parameter, Amazon ECS adds\n\t\t\tprotocol-specific connection handling to the Service Connect proxy. If you set this\n\t\t\tparameter, Amazon ECS adds protocol-specific telemetry in the Amazon ECS console and CloudWatch.

\n

If you don't set a value for this parameter, then TCP is used. However, Amazon ECS doesn't\n\t\t\tadd protocol-specific telemetry for TCP.

\n

\n appProtocol is immutable in a Service Connect service. Updating this field \n\t\t\trequires a service deletion and redeployment.

\n

Tasks that run in a namespace can use short names to connect\n\tto services in the namespace. Tasks can connect to services across all of the clusters in the namespace.\n\tTasks connect through a managed proxy container\n\tthat collects logs and metrics for increased visibility.\n\tOnly the tasks that Amazon ECS services create are supported with Service Connect.\n\tFor more information, see Service Connect in the Amazon Elastic Container Service Developer Guide.

" } }, "containerPortRange": { @@ -8318,7 +8336,7 @@ } ], "traits": { - "smithy.api#documentation": "

Modifies an account setting. Account settings are set on a per-Region basis.

\n

If you change the root user account setting, the default settings are reset for users\n\t\t\tand roles that do not have specified individual account settings. For more information,\n\t\t\tsee Account\n\t\t\t\tSettings in the Amazon Elastic Container Service Developer Guide.

\n

When you specify serviceLongArnFormat, taskLongArnFormat, or\n\t\t\t\tcontainerInstanceLongArnFormat, the Amazon Resource Name (ARN) and\n\t\t\tresource ID format of the resource type for a specified user, role, or the root user for an\n\t\t\taccount is affected. The opt-in and opt-out account setting must be set for each Amazon ECS\n\t\t\tresource separately. The ARN and resource ID format of a resource is defined by the\n\t\t\topt-in status of the user or role that created the resource. You must turn on this\n\t\t\tsetting to use Amazon ECS features such as resource tagging.

\n

When you specify awsvpcTrunking, the elastic network interface (ENI) limit for\n\t\t\tany new container instances that support the feature is changed. If\n\t\t\t\tawsvpcTrunking is turned on, any new container instances that support\n\t\t\tthe feature are launched have the increased ENI limits available to them. For more\n\t\t\tinformation, see Elastic Network\n\t\t\t\tInterface Trunking in the Amazon Elastic Container Service Developer Guide.

\n

When you specify containerInsights, the default setting indicating whether\n\t\t\tAmazon Web Services CloudWatch Container Insights is turned on for your clusters is changed. If\n\t\t\t\tcontainerInsights is turned on, any new clusters that are created will\n\t\t\thave Container Insights turned on unless you disable it during cluster creation. For\n\t\t\tmore information, see CloudWatch\n\t\t\t\tContainer Insights in the Amazon Elastic Container Service Developer Guide.

\n

Amazon ECS is introducing tagging authorization for resource creation. Users must have\n\t\t\tpermissions for actions that create the resource, such as ecsCreateCluster.\n\t\t\tIf tags are specified when you create a resource, Amazon Web Services performs additional\n\t\t\tauthorization to verify if users or roles have permissions to create tags. Therefore,\n\t\t\tyou must grant explicit permissions to use the ecs:TagResource action. For\n\t\t\tmore information, see Grant\n\t\t\t\tpermission to tag resources on creation in the Amazon ECS Developer\n\t\t\t\t\tGuide.

\n

When Amazon Web Services determines that a security or infrastructure update is needed for an Amazon ECS\n\t\t\ttask hosted on Fargate, the tasks need to be stopped and new tasks launched to replace\n\t\t\tthem. Use fargateTaskRetirementWaitPeriod to configure the wait time to\n\t\t\tretire a Fargate task. For information about the Fargate tasks maintenance, see Amazon Web Services Fargate task maintenance in the Amazon ECS Developer\n\t\t\t\t\tGuide.

", + "smithy.api#documentation": "

Modifies an account setting. Account settings are set on a per-Region basis.

\n

If you change the root user account setting, the default settings are reset for users\n\t\t\tand roles that do not have specified individual account settings. For more information,\n\t\t\tsee Account\n\t\t\t\tSettings in the Amazon Elastic Container Service Developer Guide.

\n

When you specify serviceLongArnFormat, taskLongArnFormat, or\n\t\t\t\tcontainerInstanceLongArnFormat, the Amazon Resource Name (ARN) and\n\t\t\tresource ID format of the resource type for a specified user, role, or the root user for an\n\t\t\taccount is affected. The opt-in and opt-out account setting must be set for each Amazon ECS\n\t\t\tresource separately. The ARN and resource ID format of a resource is defined by the\n\t\t\topt-in status of the user or role that created the resource. You must turn on this\n\t\t\tsetting to use Amazon ECS features such as resource tagging.

\n

When you specify awsvpcTrunking, the elastic network interface (ENI) limit for\n\t\t\tany new container instances that support the feature is changed. If\n\t\t\t\tawsvpcTrunking is turned on, any new container instances that support\n\t\t\tthe feature are launched have the increased ENI limits available to them. For more\n\t\t\tinformation, see Elastic Network\n\t\t\t\tInterface Trunking in the Amazon Elastic Container Service Developer Guide.

\n

When you specify containerInsights, the default setting indicating whether\n\t\t\tAmazon Web Services CloudWatch Container Insights is turned on for your clusters is changed. If\n\t\t\t\tcontainerInsights is turned on, any new clusters that are created will\n\t\t\thave Container Insights turned on unless you disable it during cluster creation. For\n\t\t\tmore information, see CloudWatch\n\t\t\t\tContainer Insights in the Amazon Elastic Container Service Developer Guide.

\n

Amazon ECS is introducing tagging authorization for resource creation. Users must have\n\t\t\tpermissions for actions that create the resource, such as ecsCreateCluster.\n\t\t\tIf tags are specified when you create a resource, Amazon Web Services performs additional\n\t\t\tauthorization to verify if users or roles have permissions to create tags. Therefore,\n\t\t\tyou must grant explicit permissions to use the ecs:TagResource action. For\n\t\t\tmore information, see Grant\n\t\t\t\tpermission to tag resources on creation in the Amazon ECS Developer\n\t\t\t\t\tGuide.

\n

When Amazon Web Services determines that a security or infrastructure update is needed for an Amazon ECS\n\t\t\ttask hosted on Fargate, the tasks need to be stopped and new tasks launched to replace\n\t\t\tthem. Use fargateTaskRetirementWaitPeriod to configure the wait time to\n\t\t\tretire a Fargate task. For information about the Fargate tasks maintenance, see Amazon Web Services Fargate task maintenance in the Amazon ECS Developer\n\t\t\t\t\tGuide.

\n

The guardDutyActivate parameter is read-only in Amazon ECS and indicates whether\n\t\t\tAmazon ECS Runtime Monitoring is enabled or disabled by your security administrator in your\n\t\t\tAmazon ECS account. Amazon GuardDuty controls this account setting on your behalf. For more information, see Protecting Amazon ECS workloads with Amazon ECS Runtime Monitoring.

", "smithy.api#examples": [ { "title": "To modify your account settings", @@ -8384,7 +8402,7 @@ "name": { "target": "com.amazonaws.ecs#SettingName", "traits": { - "smithy.api#documentation": "

The resource name for which to modify the account setting. If you specify\n\t\t\t\tserviceLongArnFormat, the ARN for your Amazon ECS services is affected. If\n\t\t\tyou specify taskLongArnFormat, the ARN and resource ID for your Amazon ECS\n\t\t\ttasks is affected. If you specify containerInstanceLongArnFormat, the ARN\n\t\t\tand resource ID for your Amazon ECS container instances is affected. If you specify\n\t\t\t\tawsvpcTrunking, the ENI limit for your Amazon ECS container instances is\n\t\t\taffected. If you specify containerInsights, the default setting for Amazon Web Services\n\t\t\tCloudWatch Container Insights for your clusters is affected. If you specify\n\t\t\t\ttagResourceAuthorization, the opt-in option for tagging resources on\n\t\t\tcreation is affected. For information about the opt-in timeline, see Tagging authorization timeline in the Amazon ECS Developer\n\t\t\t\tGuide. If you specify fargateTaskRetirementWaitPeriod, the\n\t\t\tdefault wait time to retire a Fargate task due to required maintenance is\n\t\t\taffected.

\n

When you specify fargateFIPSMode for the name and\n\t\t\tenabled for the value, Fargate uses FIPS-140 compliant\n\t\t\tcryptographic algorithms on your tasks. For more information about FIPS-140 compliance\n\t\t\twith Fargate, see Amazon Web Services Fargate Federal Information Processing Standard (FIPS) 140-2\n\t\t\t\tcompliance in the Amazon Elastic Container Service Developer Guide.

\n

When Amazon Web Services determines that a security or infrastructure update is needed for an Amazon ECS task\n\t\t\thosted on Fargate, the tasks need to be stopped and new tasks launched to replace\n\t\t\tthem. Use fargateTaskRetirementWaitPeriod to set the wait time to retire a\n\t\t\tFargate task to the default. For information about the Fargate tasks maintenance,\n\t\t\tsee Amazon Web Services Fargate task\n\t\t\t\tmaintenance in the Amazon ECS Developer Guide.

", + "smithy.api#documentation": "

The resource name for which to modify the account setting. If you specify\n\t\t\t\tserviceLongArnFormat, the ARN for your Amazon ECS services is affected. If\n\t\t\tyou specify taskLongArnFormat, the ARN and resource ID for your Amazon ECS\n\t\t\ttasks is affected. If you specify containerInstanceLongArnFormat, the ARN\n\t\t\tand resource ID for your Amazon ECS container instances is affected. If you specify\n\t\t\t\tawsvpcTrunking, the ENI limit for your Amazon ECS container instances is\n\t\t\taffected. If you specify containerInsights, the default setting for Amazon Web Services\n\t\t\tCloudWatch Container Insights for your clusters is affected. If you specify\n\t\t\t\ttagResourceAuthorization, the opt-in option for tagging resources on\n\t\t\tcreation is affected. For information about the opt-in timeline, see Tagging authorization timeline in the Amazon ECS Developer\n\t\t\t\tGuide. If you specify fargateTaskRetirementWaitPeriod, the\n\t\t\tdefault wait time to retire a Fargate task due to required maintenance is\n\t\t\taffected.

\n

When you specify fargateFIPSMode for the name and\n\t\t\tenabled for the value, Fargate uses FIPS-140 compliant\n\t\t\tcryptographic algorithms on your tasks. For more information about FIPS-140 compliance\n\t\t\twith Fargate, see Amazon Web Services Fargate Federal Information Processing Standard (FIPS) 140-2\n\t\t\t\tcompliance in the Amazon Elastic Container Service Developer Guide.

\n

When Amazon Web Services determines that a security or infrastructure update is needed for an Amazon ECS task\n\t\t\thosted on Fargate, the tasks need to be stopped and new tasks launched to replace\n\t\t\tthem. Use fargateTaskRetirementWaitPeriod to set the wait time to retire a\n\t\t\tFargate task to the default. For information about the Fargate tasks maintenance,\n\t\t\tsee Amazon Web Services Fargate task\n\t\t\t\tmaintenance in the Amazon ECS Developer Guide.

\n

The guardDutyActivate parameter is read-only in Amazon ECS and indicates whether\n\t\t\tAmazon ECS Runtime Monitoring is enabled or disabled by your security administrator in your\n\t\t\tAmazon ECS account. Amazon GuardDuty controls this account setting on your behalf. For more information, see Protecting Amazon ECS workloads with Amazon ECS Runtime Monitoring.

", "smithy.api#required": {} } }, @@ -8420,7 +8438,7 @@ "name": { "target": "com.amazonaws.ecs#SettingName", "traits": { - "smithy.api#documentation": "

The Amazon ECS resource name for which to modify the account setting. If you specify\n\t\t\t\tserviceLongArnFormat, the ARN for your Amazon ECS services is affected. If\n\t\t\tyou specify taskLongArnFormat, the ARN and resource ID for your Amazon ECS\n\t\t\ttasks is affected. If you specify containerInstanceLongArnFormat, the ARN\n\t\t\tand resource ID for your Amazon ECS container instances is affected. If you specify\n\t\t\t\tawsvpcTrunking, the elastic network interface (ENI) limit for your\n\t\t\tAmazon ECS container instances is affected. If you specify containerInsights,\n\t\t\tthe default setting for Amazon Web Services CloudWatch Container Insights for your clusters is affected. If\n\t\t\tyou specify fargateFIPSMode, Fargate FIPS 140 compliance is affected. If\n\t\t\tyou specify tagResourceAuthorization, the opt-in option for tagging\n\t\t\tresources on creation is affected. For information about the opt-in timeline, see Tagging authorization timeline in the Amazon ECS Developer\n\t\t\t\tGuide. If you specify fargateTaskRetirementWaitPeriod, the\n\t\t\twait time to retire a Fargate task is affected.

", + "smithy.api#documentation": "

The Amazon ECS resource name for which to modify the account setting. If you specify\n\t\t\t\tserviceLongArnFormat, the ARN for your Amazon ECS services is affected. If\n\t\t\tyou specify taskLongArnFormat, the ARN and resource ID for your Amazon ECS\n\t\t\ttasks is affected. If you specify containerInstanceLongArnFormat, the ARN\n\t\t\tand resource ID for your Amazon ECS container instances is affected. If you specify\n\t\t\t\tawsvpcTrunking, the elastic network interface (ENI) limit for your\n\t\t\tAmazon ECS container instances is affected. If you specify containerInsights,\n\t\t\tthe default setting for Amazon Web Services CloudWatch Container Insights for your clusters is affected. If\n\t\t\tyou specify fargateFIPSMode, Fargate FIPS 140 compliance is affected. If\n\t\t\tyou specify tagResourceAuthorization, the opt-in option for tagging\n\t\t\tresources on creation is affected. For information about the opt-in timeline, see Tagging authorization timeline in the Amazon ECS Developer\n\t\t\t\tGuide. If you specify fargateTaskRetirementWaitPeriod, the\n\t\t\twait time to retire a Fargate task is affected.

\n

The guardDutyActivate parameter is read-only in Amazon ECS and indicates whether\n\t\t\tAmazon ECS Runtime Monitoring is enabled or disabled by your security administrator in your\n\t\t\tAmazon ECS account. Amazon GuardDuty controls this account setting on your behalf. For more information, see Protecting Amazon ECS workloads with Amazon ECS Runtime Monitoring.

", "smithy.api#required": {} } }, @@ -8963,6 +8981,12 @@ "smithy.api#documentation": "

Describes the resources available for a container instance.

" } }, + "com.amazonaws.ecs#ResourceIds": { + "type": "list", + "member": { + "target": "com.amazonaws.ecs#String" + } + }, "com.amazonaws.ecs#ResourceInUseException": { "type": "structure", "members": { @@ -9059,6 +9083,9 @@ { "target": "com.amazonaws.ecs#ClusterNotFoundException" }, + { + "target": "com.amazonaws.ecs#ConflictException" + }, { "target": "com.amazonaws.ecs#InvalidParameterException" }, @@ -9207,7 +9234,7 @@ "startedBy": { "target": "com.amazonaws.ecs#String", "traits": { - "smithy.api#documentation": "

An optional tag specified when a task is started. For example, if you automatically\n\t\t\ttrigger a task to run a batch process job, you could apply a unique identifier for that\n\t\t\tjob to your task with the startedBy parameter. You can then identify which\n\t\t\ttasks belong to that job by filtering the results of a ListTasks call\n\t\t\twith the startedBy value. Up to 36 letters (uppercase and lowercase),\n\t\t\tnumbers, hyphens (-), and underscores (_) are allowed.

\n

If a task is started by an Amazon ECS service, then the startedBy parameter\n\t\t\tcontains the deployment ID of the service that starts it.

" + "smithy.api#documentation": "

An optional tag specified when a task is started. For example, if you automatically trigger\n\t\t\ta task to run a batch process job, you could apply a unique identifier for that job to\n\t\t\tyour task with the startedBy parameter. You can then identify which tasks\n\t\t\tbelong to that job by filtering the results of a ListTasks call with\n\t\t\tthe startedBy value. Up to 128 letters (uppercase and lowercase), numbers,\n\t\t\thyphens (-), and underscores (_) are allowed.

\n

If a task is started by an Amazon ECS service, then the startedBy parameter\n\t\t\tcontains the deployment ID of the service that starts it.

" } }, "tags": { @@ -9222,6 +9249,13 @@ "smithy.api#documentation": "

The family and revision (family:revision) or\n\t\t\tfull ARN of the task definition to run. If a revision isn't specified,\n\t\t\tthe latest ACTIVE revision is used.

\n

When you create a policy for run-task, you can set the resource to be the latest\n\t\t\ttask definition revision, or a specific revision.

\n

The full ARN value must match the value that you specified as the\n\t\t\t\tResource of the principal's permissions policy.

\n

When you specify the policy resource as the latest task definition version (by setting\n\t\t\tthe Resource in the policy to\n\t\t\t\tarn:aws:ecs:us-east-1:111122223333:task-definition/TaskFamilyName),\n\t\t\tthen set this value to\n\t\t\t\tarn:aws:ecs:us-east-1:111122223333:task-definition/TaskFamilyName.

\n

When you specify the policy resource as a specific task definition version (by setting\n\t\t\tthe Resource in the policy to\n\t\t\t\tarn:aws:ecs:us-east-1:111122223333:task-definition/TaskFamilyName:1 or\n\t\t\t\tarn:aws:ecs:us-east-1:111122223333:task-definition/TaskFamilyName:*),\n\t\t\tthen set this value to\n\t\t\t\tarn:aws:ecs:us-east-1:111122223333:task-definition/TaskFamilyName:1.

\n

For more information, see Policy Resources for Amazon ECS in the Amazon Elastic Container Service developer Guide.

", "smithy.api#required": {} } + }, + "clientToken": { + "target": "com.amazonaws.ecs#String", + "traits": { + "smithy.api#documentation": "

An identifier that you provide to ensure the idempotency of the request. It must be unique\n\t\t\tand is case sensitive. Up to 64 characters are allowed. The valid characters are characters in the range of 33-126, inclusive. For more information, see\n\t\t\t\tEnsuring idempotency.

", + "smithy.api#idempotencyToken": {} + } } }, "traits": { @@ -9234,7 +9268,7 @@ "tasks": { "target": "com.amazonaws.ecs#Tasks", "traits": { - "smithy.api#documentation": "

A full description of the tasks that were run. The tasks that were successfully placed\n\t\t\ton your cluster are described here.

" + "smithy.api#documentation": "

A full description of the tasks that were run. The tasks that were successfully placed\n\t\t\ton your cluster are described here.

\n

" } }, "failures": { @@ -9865,6 +9899,12 @@ "traits": { "smithy.api#documentation": "

The ARN of the principal. It can be a user, role, or the root user. If this\n\t\t\tfield is omitted, the authenticated user is assumed.

" } + }, + "type": { + "target": "com.amazonaws.ecs#SettingType", + "traits": { + "smithy.api#documentation": "

Indicates whether Amazon Web Services manages the account setting, or if the user manages it.

\n

\n aws_managed account settings are read-only, as Amazon Web Services manages such on the\n\t\t\tcustomer's behalf. Currently, the guardDutyActivate account setting is the\n\t\t\tonly one Amazon Web Services manages.

" + } } }, "traits": { @@ -9921,6 +9961,29 @@ "traits": { "smithy.api#enumValue": "fargateTaskRetirementWaitPeriod" } + }, + "GUARD_DUTY_ACTIVATE": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "guardDutyActivate" + } + } + } + }, + "com.amazonaws.ecs#SettingType": { + "type": "enum", + "members": { + "USER": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "user" + } + }, + "AWS_MANAGED": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "aws_managed" + } } } }, diff --git a/aws/sdk/aws-models/iam.json b/aws/sdk/aws-models/iam.json index 21fb32cfd9b..b7b2bb78f84 100644 --- a/aws/sdk/aws-models/iam.json +++ b/aws/sdk/aws-models/iam.json @@ -997,6 +997,57 @@ }, "type": "endpoint" }, + { + "conditions": [ + { + "fn": "stringEquals", + "argv": [ + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "name" + ] + }, + "aws-iso-e" + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + false + ] + } + ], + "endpoint": { + "url": "https://iam.eu-isoe-west-1.cloud.adc-e.uk", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "iam", + "signingRegion": "eu-isoe-west-1" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + }, { "conditions": [ { @@ -1777,6 +1828,17 @@ "expect": { "error": "Invalid Configuration: Missing Region" } + }, + { + "documentation": "Partition doesn't support DualStack", + "expect": { + "error": "DualStack is enabled but this partition does not support DualStack" + }, + "params": { + "Region": "us-isob-east-1", + "UseFIPS": false, + "UseDualStack": true + } } ], "version": "1.0" diff --git a/aws/sdk/aws-models/lambda.json b/aws/sdk/aws-models/lambda.json index 794f4079a77..981d7acab4a 100644 --- a/aws/sdk/aws-models/lambda.json +++ b/aws/sdk/aws-models/lambda.json @@ -1998,6 +1998,47 @@ "smithy.api#documentation": "

Specific configuration settings for an Amazon Managed Streaming for Apache Kafka (Amazon MSK) event source.

" } }, + "com.amazonaws.lambda#ApplicationLogLevel": { + "type": "enum", + "members": { + "Trace": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "TRACE" + } + }, + "Debug": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "DEBUG" + } + }, + "Info": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "INFO" + } + }, + "Warn": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "WARN" + } + }, + "Error": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "ERROR" + } + }, + "Fatal": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "FATAL" + } + } + } + }, "com.amazonaws.lambda#Architecture": { "type": "enum", "members": { @@ -2819,6 +2860,12 @@ "traits": { "smithy.api#documentation": "

The function's SnapStart setting.

" } + }, + "LoggingConfig": { + "target": "com.amazonaws.lambda#LoggingConfig", + "traits": { + "smithy.api#documentation": "

The function's Amazon CloudWatch Logs configuration settings.

" + } } }, "traits": { @@ -4466,6 +4513,12 @@ "traits": { "smithy.api#documentation": "

The ARN of the runtime and any errors that occured.

" } + }, + "LoggingConfig": { + "target": "com.amazonaws.lambda#LoggingConfig", + "traits": { + "smithy.api#documentation": "

The function's Amazon CloudWatch Logs configuration settings.

" + } } }, "traits": { @@ -6455,7 +6508,7 @@ } ], "traits": { - "smithy.api#documentation": "

Invokes a Lambda function. You can invoke a function synchronously (and wait for the response), or\n asynchronously. To invoke a function asynchronously, set InvocationType to Event.

\n

For synchronous invocation,\n details about the function response, including errors, are included in the response body and headers. For either\n invocation type, you can find more information in the execution log and trace.

\n

When an error occurs, your function may be invoked multiple times. Retry behavior varies by error type,\n client, event source, and invocation type. For example, if you invoke a function asynchronously and it returns an\n error, Lambda executes the function up to two more times. For more information, see Error handling and automatic retries in\n Lambda.

\n

For asynchronous invocation,\n Lambda adds events to a queue before sending them to your function. If your function does not have enough capacity\n to keep up with the queue, events may be lost. Occasionally, your function may receive the same event multiple\n times, even if no error occurs. To retain events that were not processed, configure your function with a dead-letter queue.

\n

The status code in the API response doesn't reflect function errors. Error codes are reserved for errors that\n prevent your function from executing, such as permissions errors, quota errors, or issues with your function's code and\n configuration. For example, Lambda returns TooManyRequestsException if running the\n function would cause you to exceed a concurrency limit at either the account level\n (ConcurrentInvocationLimitExceeded) or function level\n (ReservedFunctionConcurrentInvocationLimitExceeded).

\n

For functions with a long timeout, your client might disconnect during synchronous invocation while it waits\n for a response. Configure your HTTP client, SDK, firewall, proxy, or operating system to allow for long\n connections with timeout or keep-alive settings.

\n

This operation requires permission for the lambda:InvokeFunction action. For details on how to set up\n permissions for cross-account invocations, see Granting function\n access to other accounts.

", + "smithy.api#documentation": "

Invokes a Lambda function. You can invoke a function synchronously (and wait for the response), or\n asynchronously. By default, Lambda invokes your function synchronously (i.e. theInvocationType\n is RequestResponse). To invoke a function asynchronously, set InvocationType to\n Event. Lambda passes the ClientContext object to your function for\n synchronous invocations only.

\n

For synchronous invocation,\n details about the function response, including errors, are included in the response body and headers. For either\n invocation type, you can find more information in the execution log and trace.

\n

When an error occurs, your function may be invoked multiple times. Retry behavior varies by error type,\n client, event source, and invocation type. For example, if you invoke a function asynchronously and it returns an\n error, Lambda executes the function up to two more times. For more information, see Error handling and automatic retries in\n Lambda.

\n

For asynchronous invocation,\n Lambda adds events to a queue before sending them to your function. If your function does not have enough capacity\n to keep up with the queue, events may be lost. Occasionally, your function may receive the same event multiple\n times, even if no error occurs. To retain events that were not processed, configure your function with a dead-letter queue.

\n

The status code in the API response doesn't reflect function errors. Error codes are reserved for errors that\n prevent your function from executing, such as permissions errors, quota errors, or issues with your function's code and\n configuration. For example, Lambda returns TooManyRequestsException if running the\n function would cause you to exceed a concurrency limit at either the account level\n (ConcurrentInvocationLimitExceeded) or function level\n (ReservedFunctionConcurrentInvocationLimitExceeded).

\n

For functions with a long timeout, your client might disconnect during synchronous invocation while it waits\n for a response. Configure your HTTP client, SDK, firewall, proxy, or operating system to allow for long\n connections with timeout or keep-alive settings.

\n

This operation requires permission for the lambda:InvokeFunction action. For details on how to set up\n permissions for cross-account invocations, see Granting function\n access to other accounts.

", "smithy.api#http": { "method": "POST", "uri": "/2015-03-31/functions/{FunctionName}/invocations", @@ -8356,6 +8409,33 @@ "smithy.api#pattern": "^/mnt/[a-zA-Z0-9-_.]+$" } }, + "com.amazonaws.lambda#LogFormat": { + "type": "enum", + "members": { + "Json": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "JSON" + } + }, + "Text": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "Text" + } + } + } + }, + "com.amazonaws.lambda#LogGroup": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 1, + "max": 512 + }, + "smithy.api#pattern": "^[\\.\\-_/#A-Za-z0-9]+$" + } + }, "com.amazonaws.lambda#LogType": { "type": "enum", "members": { @@ -8373,6 +8453,38 @@ } } }, + "com.amazonaws.lambda#LoggingConfig": { + "type": "structure", + "members": { + "LogFormat": { + "target": "com.amazonaws.lambda#LogFormat", + "traits": { + "smithy.api#documentation": "

The format in which Lambda sends your function's application and system logs to CloudWatch. Select between \n plain text and structured JSON.

" + } + }, + "ApplicationLogLevel": { + "target": "com.amazonaws.lambda#ApplicationLogLevel", + "traits": { + "smithy.api#documentation": "

Set this property to filter the application logs for your function that Lambda sends to CloudWatch. Lambda only sends application logs at the \n selected level and lower.

" + } + }, + "SystemLogLevel": { + "target": "com.amazonaws.lambda#SystemLogLevel", + "traits": { + "smithy.api#documentation": "

Set this property to filter the system logs for your function that Lambda sends to CloudWatch. Lambda only sends system logs at the \n selected level and lower.

" + } + }, + "LogGroup": { + "target": "com.amazonaws.lambda#LogGroup", + "traits": { + "smithy.api#documentation": "

The name of the Amazon CloudWatch log group the function sends logs to. By default, Lambda functions send logs to a default \n log group named /aws/lambda/. To use a different log group, enter an existing log group or enter a new log group name.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

The function's Amazon CloudWatch Logs configuration settings.

" + } + }, "com.amazonaws.lambda#Long": { "type": "long", "traits": { @@ -9952,6 +10064,30 @@ "traits": { "smithy.api#enumValue": "python3.11" } + }, + "nodejs20x": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "nodejs20.x" + } + }, + "providedal2023": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "provided.al2023" + } + }, + "python312": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "python3.12" + } + }, + "java21": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "java21" + } } } }, @@ -10572,6 +10708,29 @@ } } }, + "com.amazonaws.lambda#SystemLogLevel": { + "type": "enum", + "members": { + "Debug": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "DEBUG" + } + }, + "Info": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "INFO" + } + }, + "Warn": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "WARN" + } + } + } + }, "com.amazonaws.lambda#TagKey": { "type": "string" }, @@ -11480,6 +11639,12 @@ "traits": { "smithy.api#documentation": "

The function's SnapStart setting.

" } + }, + "LoggingConfig": { + "target": "com.amazonaws.lambda#LoggingConfig", + "traits": { + "smithy.api#documentation": "

The function's Amazon CloudWatch Logs configuration settings.

" + } } }, "traits": { diff --git a/aws/sdk/aws-models/polly.json b/aws/sdk/aws-models/polly.json index 0f702c1fdee..def7aa319b5 100644 --- a/aws/sdk/aws-models/polly.json +++ b/aws/sdk/aws-models/polly.json @@ -167,7 +167,7 @@ "Engine": { "target": "com.amazonaws.polly#Engine", "traits": { - "smithy.api#documentation": "

Specifies the engine (standard or neural)\n used by Amazon Polly when processing input text for speech synthesis.

", + "smithy.api#documentation": "

Specifies the engine (standard, neural or\n long-form) used by Amazon Polly when processing input text for\n speech synthesis.

", "smithy.api#httpQuery": "Engine" } }, @@ -232,6 +232,12 @@ "traits": { "smithy.api#enumValue": "neural" } + }, + "LONG_FORM": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "long-form" + } } } }, @@ -2400,7 +2406,7 @@ "Engine": { "target": "com.amazonaws.polly#Engine", "traits": { - "smithy.api#documentation": "

Specifies the engine (standard or neural)\n for Amazon Polly to use when processing input text for speech synthesis. Using a\n voice that is not supported for the engine selected will result in an\n error.

" + "smithy.api#documentation": "

Specifies the engine (standard, neural or\n long-form) for Amazon Polly to use when processing input text for\n speech synthesis. Using a voice that is not supported for the engine\n selected will result in an error.

" } }, "LanguageCode": { @@ -2438,7 +2444,7 @@ "SampleRate": { "target": "com.amazonaws.polly#SampleRate", "traits": { - "smithy.api#documentation": "

The audio frequency specified in Hz.

\n

The valid values for mp3 and ogg_vorbis are \"8000\", \"16000\", \"22050\",\n and \"24000\". The default value for standard voices is \"22050\". The default\n value for neural voices is \"24000\".

\n

Valid values for pcm are \"8000\" and \"16000\" The default value is\n \"16000\".

" + "smithy.api#documentation": "

The audio frequency specified in Hz.

\n

The valid values for mp3 and ogg_vorbis are \"8000\", \"16000\", \"22050\",\n and \"24000\". The default value for standard voices is \"22050\". The default\n value for neural voices is \"24000\". The default value for long-form voices\n is \"24000\".

\n

Valid values for pcm are \"8000\" and \"16000\" The default value is\n \"16000\".

" } }, "SnsTopicArn": { @@ -2498,7 +2504,7 @@ "Engine": { "target": "com.amazonaws.polly#Engine", "traits": { - "smithy.api#documentation": "

Specifies the engine (standard or neural)\n for Amazon Polly to use when processing input text for speech synthesis. Using a\n voice that is not supported for the engine selected will result in an\n error.

" + "smithy.api#documentation": "

Specifies the engine (standard, neural or\n long-form) for Amazon Polly to use when processing input text for\n speech synthesis. Using a voice that is not supported for the engine\n selected will result in an error.

" } }, "TaskId": { @@ -2559,7 +2565,7 @@ "SampleRate": { "target": "com.amazonaws.polly#SampleRate", "traits": { - "smithy.api#documentation": "

The audio frequency specified in Hz.

\n

The valid values for mp3 and ogg_vorbis are \"8000\", \"16000\", \"22050\",\n and \"24000\". The default value for standard voices is \"22050\". The default\n value for neural voices is \"24000\".

\n

Valid values for pcm are \"8000\" and \"16000\" The default value is\n \"16000\".

" + "smithy.api#documentation": "

The audio frequency specified in Hz.

\n

The valid values for mp3 and ogg_vorbis are \"8000\", \"16000\", \"22050\",\n and \"24000\". The default value for standard voices is \"22050\". The default\n value for neural voices is \"24000\". The default value for long-form voices\n is \"24000\".

\n

Valid values for pcm are \"8000\" and \"16000\" The default value is\n \"16000\".

" } }, "SpeechMarkTypes": { @@ -2683,7 +2689,7 @@ "Engine": { "target": "com.amazonaws.polly#Engine", "traits": { - "smithy.api#documentation": "

Specifies the engine (standard or neural)\n for Amazon Polly to use when processing input text for speech synthesis. For\n information on Amazon Polly voices and which voices are available in\n standard-only, NTTS-only, and both standard and NTTS formats, see Available Voices.

\n

\n NTTS-only voices\n

\n

When using NTTS-only voices such as Kevin (en-US), this parameter is\n required and must be set to neural. If the engine is not\n specified, or is set to standard, this will result in an\n error.

\n

Type: String

\n

Valid Values: standard | neural\n

\n

Required: Yes

\n

\n Standard voices\n

\n

For standard voices, this is not required; the engine parameter\n defaults to standard. If the engine is not specified, or is\n set to standard and an NTTS-only voice is selected, this will\n result in an error.

" + "smithy.api#documentation": "

Specifies the engine (standard, neural or\n long-form) for Amazon Polly to use when processing input text for\n speech synthesis. For information on Amazon Polly voices and which voices are\n available for each engine, see Available Voices.

\n

\n NTTS-only voices\n

\n

When using NTTS-only voices such as Kevin (en-US), this parameter is\n required and must be set to neural. If the engine is not\n specified, or is set to standard, this will result in an\n error.

\n

\n long-form-only voices\n

\n

When using long-form-only voices such as Danielle (en-US), this\n parameter is required and must be set to long-form. If the\n engine is not specified, or is set to standard or\n neural, this will result in an error.

\n

Type: String

\n

Valid Values: standard | neural |\n long-form\n

\n

Required: Yes

\n

\n Standard voices\n

\n

For standard voices, this is not required; the engine parameter\n defaults to standard. If the engine is not specified, or is\n set to standard and an NTTS-only voice is selected, this will\n result in an error.

" } }, "LanguageCode": { @@ -2708,7 +2714,7 @@ "SampleRate": { "target": "com.amazonaws.polly#SampleRate", "traits": { - "smithy.api#documentation": "

The audio frequency specified in Hz.

\n

The valid values for mp3 and ogg_vorbis are \"8000\", \"16000\", \"22050\",\n and \"24000\". The default value for standard voices is \"22050\". The default\n value for neural voices is \"24000\".

\n

Valid values for pcm are \"8000\" and \"16000\" The default value is\n \"16000\".

" + "smithy.api#documentation": "

The audio frequency specified in Hz.

\n

The valid values for mp3 and ogg_vorbis are \"8000\", \"16000\", \"22050\",\n and \"24000\". The default value for standard voices is \"22050\". The default\n value for neural voices is \"24000\". The default value for long-form voices\n is \"24000\".

\n

Valid values for pcm are \"8000\" and \"16000\" The default value is\n \"16000\".

" } }, "SpeechMarkTypes": { @@ -2912,7 +2918,7 @@ "SupportedEngines": { "target": "com.amazonaws.polly#EngineList", "traits": { - "smithy.api#documentation": "

Specifies which engines (standard or neural)\n that are supported by a given voice.

" + "smithy.api#documentation": "

Specifies which engines (standard, neural or\n long-form) are supported by a given voice.

" } } }, @@ -3480,6 +3486,18 @@ "traits": { "smithy.api#enumValue": "Zayd" } + }, + "Danielle": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "Danielle" + } + }, + "Gregory": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "Gregory" + } } } }, diff --git a/aws/sdk/aws-models/route53.json b/aws/sdk/aws-models/route53.json index 85d222c1b78..34391261823 100644 --- a/aws/sdk/aws-models/route53.json +++ b/aws/sdk/aws-models/route53.json @@ -744,6 +744,108 @@ }, "type": "endpoint" }, + { + "conditions": [ + { + "fn": "stringEquals", + "argv": [ + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "name" + ] + }, + "aws-iso-e" + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + false + ] + } + ], + "endpoint": { + "url": "https://route53.cloud.adc-e.uk", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "route53", + "signingRegion": "eu-isoe-west-1" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [ + { + "fn": "stringEquals", + "argv": [ + { + "fn": "getAttr", + "argv": [ + { + "ref": "PartitionResult" + }, + "name" + ] + }, + "aws-iso-f" + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + false + ] + } + ], + "endpoint": { + "url": "https://route53.csp.hci.ic.gov", + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "route53", + "signingRegion": "us-isof-south-1" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + }, { "conditions": [ { @@ -1473,6 +1575,17 @@ "expect": { "error": "Invalid Configuration: Missing Region" } + }, + { + "documentation": "Partition doesn't support DualStack", + "expect": { + "error": "DualStack is enabled but this partition does not support DualStack" + }, + "params": { + "Region": "us-isob-east-1", + "UseFIPS": false, + "UseDualStack": true + } } ], "version": "1.0" diff --git a/aws/sdk/aws-models/s3.json b/aws/sdk/aws-models/s3.json index f119125dd9e..38ccaaaeb02 100644 --- a/aws/sdk/aws-models/s3.json +++ b/aws/sdk/aws-models/s3.json @@ -38,7 +38,6 @@ "DaysAfterInitiation": { "target": "com.amazonaws.s3#DaysAfterInitiation", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Specifies the number of days after which Amazon S3 aborts an incomplete multipart\n upload.

" } } @@ -61,7 +60,7 @@ } ], "traits": { - "smithy.api#documentation": "

This action aborts a multipart upload. After a multipart upload is aborted, no\n additional parts can be uploaded using that upload ID. The storage consumed by any\n previously uploaded parts will be freed. However, if any part uploads are currently in\n progress, those part uploads might or might not succeed. As a result, it might be necessary\n to abort a given multipart upload multiple times in order to completely free all storage\n consumed by all parts.

\n

To verify that all parts have been removed, so you don't get charged for the part\n storage, you should call the ListParts action and ensure that\n the parts list is empty.

\n

For information about permissions required to use the multipart upload, see Multipart Upload\n and Permissions.

\n

The following operations are related to AbortMultipartUpload:

\n ", + "smithy.api#documentation": "

This operation aborts a multipart upload. After a multipart upload is aborted, no\n additional parts can be uploaded using that upload ID. The storage consumed by any\n previously uploaded parts will be freed. However, if any part uploads are currently in\n progress, those part uploads might or might not succeed. As a result, it might be necessary\n to abort a given multipart upload multiple times in order to completely free all storage\n consumed by all parts.

\n

To verify that all parts have been removed and prevent getting charged for the part\n storage, you should call the ListParts API operation and ensure that\n the parts list is empty.

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - For information about permissions required to use the multipart upload, see Multipart Upload\n and Permissions in the Amazon S3\n User Guide.

    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation on a directory bucket, we recommend that you use the \n CreateSession\n API operation for session-based authorization. Specifically, you grant the s3express:CreateSession permission to the directory bucket in a bucket policy or an IAM identity-based policy. Then, you make the CreateSession API call on the bucket to obtain a session token. With the session token in your request header, you can make API requests to this operation. After the session token expires, you make another CreateSession API call to generate a new session token for use. \nAmazon Web Services CLI or SDKs create session and refresh the session token automatically to avoid service interruptions when a session expires. For more information about authorization, see \n CreateSession\n .

    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

The following operations are related to AbortMultipartUpload:

\n ", "smithy.api#examples": [ { "title": "To abort a multipart upload", @@ -101,7 +100,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name to which the upload was taking place.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name to which the upload was taking place.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -114,7 +113,10 @@ "traits": { "smithy.api#documentation": "

Key of the object for which the multipart upload was initiated.

", "smithy.api#httpLabel": {}, - "smithy.api#required": {} + "smithy.api#required": {}, + "smithy.rules#contextParam": { + "name": "Key" + } } }, "UploadId": { @@ -134,7 +136,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -199,6 +201,12 @@ "smithy.api#documentation": "

A container for information about access control for replicas.

" } }, + "com.amazonaws.s3#AccessKeyIdValue": { + "type": "string" + }, + "com.amazonaws.s3#AccessPointAlias": { + "type": "boolean" + }, "com.amazonaws.s3#AccessPointArn": { "type": "string" }, @@ -206,10 +214,7 @@ "type": "string" }, "com.amazonaws.s3#AllowQuotedRecordDelimiter": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#AllowedHeader": { "type": "string" @@ -257,6 +262,9 @@ { "target": "com.amazonaws.s3#CreateMultipartUpload" }, + { + "target": "com.amazonaws.s3#CreateSession" + }, { "target": "com.amazonaws.s3#DeleteBucket" }, @@ -416,6 +424,9 @@ { "target": "com.amazonaws.s3#ListBuckets" }, + { + "target": "com.amazonaws.s3#ListDirectoryBuckets" + }, { "target": "com.amazonaws.s3#ListMultipartUploads" }, @@ -537,6 +548,9 @@ "noErrorWrapping": true }, "smithy.api#documentation": "

", + "smithy.api#suppress": [ + "RuleSetAuthSchemes" + ], "smithy.api#title": "Amazon Simple Storage Service", "smithy.api#xmlNamespace": { "uri": "http://s3.amazonaws.com/doc/2006-03-01/" @@ -557,6 +571,10 @@ "Accelerate": { "documentation": "Enables this client to use S3 Transfer Acceleration endpoints.", "type": "boolean" + }, + "DisableS3ExpressSessionAuth": { + "documentation": "Disables this client's usage of Session Auth for S3Express buckets and reverts to using conventional SigV4 for those.", + "type": "boolean" } }, "smithy.rules#endpointRuleSet": { @@ -619,6 +637,16 @@ "documentation": "Internal parameter to use object lambda endpoint for an operation (eg: WriteGetObjectResponse)", "type": "Boolean" }, + "Key": { + "required": false, + "documentation": "The S3 Key used to send the request. This is an optional parameter that will be set automatically for operations that are scoped to an S3 Key.", + "type": "String" + }, + "Prefix": { + "required": false, + "documentation": "The S3 Prefix used to send the request. This is an optional parameter that will be set automatically for operations that are scoped to an S3 Prefix.", + "type": "String" + }, "DisableAccessPoints": { "required": false, "documentation": "Internal parameter to disable Access Point Buckets", @@ -636,6 +664,16 @@ "required": false, "documentation": "When an Access Point ARN is provided and this flag is enabled, the SDK MUST use the ARN's region when constructing the endpoint instead of the client's configured region.", "type": "Boolean" + }, + "UseS3ExpressControlEndpoint": { + "required": false, + "documentation": "Internal parameter to indicate whether S3Express operation should use control plane, (ex. CreateBucket)", + "type": "Boolean" + }, + "DisableS3ExpressSessionAuth": { + "required": false, + "documentation": "Parameter to indicate whether S3Express session auth should be disabled", + "type": "Boolean" } }, "rules": [ @@ -650,7 +688,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -800,158 +837,176 @@ { "ref": "Bucket" }, - 49, - 50, - true - ], - "assign": "hardwareType" - }, - { - "fn": "substring", - "argv": [ - { - "ref": "Bucket" - }, - 8, - 12, + 0, + 6, true ], - "assign": "regionPrefix" + "assign": "bucketSuffix" }, { - "fn": "substring", + "fn": "stringEquals", "argv": [ { - "ref": "Bucket" + "ref": "bucketSuffix" }, - 0, - 7, - true - ], - "assign": "bucketAliasSuffix" - }, + "--x-s3" + ] + } + ], + "rules": [ { - "fn": "substring", - "argv": [ + "conditions": [ { - "ref": "Bucket" - }, - 32, - 49, - true + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + true + ] + } ], - "assign": "outpostId" + "error": "S3Express does not support Dual-stack.", + "type": "error" }, { - "fn": "aws.partition", - "argv": [ + "conditions": [ { - "ref": "Region" + "fn": "booleanEquals", + "argv": [ + { + "ref": "Accelerate" + }, + true + ] } ], - "assign": "regionPartition" + "error": "S3Express does not support S3 Accelerate.", + "type": "error" }, - { - "fn": "stringEquals", - "argv": [ - { - "ref": "bucketAliasSuffix" - }, - "--op-s3" - ] - } - ], - "type": "tree", - "rules": [ { "conditions": [ { - "fn": "isValidHostLabel", + "fn": "isSet", "argv": [ { - "ref": "outpostId" - }, - false + "ref": "Endpoint" + } ] + }, + { + "fn": "parseURL", + "argv": [ + { + "ref": "Endpoint" + } + ], + "assign": "url" } ], - "type": "tree", "rules": [ { "conditions": [ { - "fn": "stringEquals", + "fn": "isSet", "argv": [ { - "ref": "hardwareType" + "ref": "DisableS3ExpressSessionAuth" + } + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "DisableS3ExpressSessionAuth" }, - "e" + true ] } ], - "type": "tree", "rules": [ { "conditions": [ { - "fn": "stringEquals", + "fn": "booleanEquals", "argv": [ { - "ref": "regionPrefix" + "fn": "getAttr", + "argv": [ + { + "ref": "url" + }, + "isIp" + ] }, - "beta" + true ] } ], - "type": "tree", "rules": [ { "conditions": [ { - "fn": "not", + "fn": "uriEncode", "argv": [ { - "fn": "isSet", - "argv": [ + "ref": "Bucket" + } + ], + "assign": "uri_encoded_bucket" + } + ], + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "{url#scheme}://{url#authority}/{uri_encoded_bucket}{url#path}", + "properties": { + "backend": "S3Express", + "authSchemes": [ { - "ref": "Endpoint" + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3express", + "signingRegion": "{Region}" } ] - } - ] + }, + "headers": {} + }, + "type": "endpoint" } ], - "error": "Expected a endpoint to be specified but no endpoint was found", - "type": "error" - }, + "type": "tree" + } + ], + "type": "tree" + }, + { + "conditions": [ { - "conditions": [ + "fn": "aws.isVirtualHostableS3Bucket", + "argv": [ { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] + "ref": "Bucket" }, - { - "fn": "parseURL", - "argv": [ - { - "ref": "Endpoint" - } - ], - "assign": "url" - } - ], + false + ] + } + ], + "rules": [ + { + "conditions": [], "endpoint": { - "url": "https://{Bucket}.ec2.{url#authority}", + "url": "{url#scheme}://{Bucket}.{url#authority}{url#path}", "properties": { + "backend": "S3Express", "authSchemes": [ { "disableDoubleEncoding": true, "name": "sigv4", - "signingName": "s3-outposts", + "signingName": "s3express", "signingRegion": "{Region}" } ] @@ -960,104 +1015,61 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [], - "endpoint": { - "url": "https://{Bucket}.ec2.s3-outposts.{Region}.{regionPartition#dnsSuffix}", - "properties": { - "authSchemes": [ - { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "{Region}" - } - ] - }, - "headers": {} - }, - "type": "endpoint" + "error": "S3Express bucket name is not a valid virtual hostable name.", + "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [ { - "fn": "stringEquals", + "fn": "booleanEquals", "argv": [ { - "ref": "hardwareType" + "fn": "getAttr", + "argv": [ + { + "ref": "url" + }, + "isIp" + ] }, - "o" + true ] } ], - "type": "tree", "rules": [ { "conditions": [ { - "fn": "stringEquals", + "fn": "uriEncode", "argv": [ { - "ref": "regionPrefix" - }, - "beta" - ] + "ref": "Bucket" + } + ], + "assign": "uri_encoded_bucket" } ], - "type": "tree", "rules": [ { - "conditions": [ - { - "fn": "not", - "argv": [ + "conditions": [], + "endpoint": { + "url": "{url#scheme}://{url#authority}/{uri_encoded_bucket}{url#path}", + "properties": { + "backend": "S3Express", + "authSchemes": [ { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] - } - ] - } - ], - "error": "Expected a endpoint to be specified but no endpoint was found", - "type": "error" - }, - { - "conditions": [ - { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] - }, - { - "fn": "parseURL", - "argv": [ - { - "ref": "Endpoint" - } - ], - "assign": "url" - } - ], - "endpoint": { - "url": "https://{Bucket}.op-{outpostId}.{url#authority}", - "properties": { - "authSchemes": [ - { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "{Region}" + "disableDoubleEncoding": true, + "name": "sigv4-s3express", + "signingName": "s3express", + "signingRegion": "{Region}" } ] }, @@ -1065,18 +1077,36 @@ }, "type": "endpoint" } + ], + "type": "tree" + } + ], + "type": "tree" + }, + { + "conditions": [ + { + "fn": "aws.isVirtualHostableS3Bucket", + "argv": [ + { + "ref": "Bucket" + }, + false ] - }, + } + ], + "rules": [ { "conditions": [], "endpoint": { - "url": "https://{Bucket}.op-{outpostId}.s3-outposts.{Region}.{regionPartition#dnsSuffix}", + "url": "{url#scheme}://{Bucket}.{url#authority}{url#path}", "properties": { + "backend": "S3Express", "authSchemes": [ { "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3-outposts", + "name": "sigv4-s3express", + "signingName": "s3express", "signingRegion": "{Region}" } ] @@ -1085,53 +1115,54 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [], - "error": "Unrecognized hardware type: \"Expected hardware type o or e but got {hardwareType}\"", + "error": "S3Express bucket name is not a valid virtual hostable name.", "type": "error" } - ] + ], + "type": "tree" }, - { - "conditions": [], - "error": "Invalid ARN: The outpost Id must only contain a-z, A-Z, 0-9 and `-`.", - "type": "error" - } - ] - }, - { - "conditions": [ - { - "fn": "isSet", - "argv": [ - { - "ref": "Bucket" - } - ] - } - ], - "type": "tree", - "rules": [ { "conditions": [ { "fn": "isSet", "argv": [ { - "ref": "Endpoint" + "ref": "UseS3ExpressControlEndpoint" } ] }, { - "fn": "not", + "fn": "booleanEquals", "argv": [ { - "fn": "isSet", + "ref": "UseS3ExpressControlEndpoint" + }, + true + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "uriEncode", "argv": [ { - "fn": "parseURL", + "ref": "Bucket" + } + ], + "assign": "uri_encoded_bucket" + }, + { + "fn": "not", + "argv": [ + { + "fn": "isSet", "argv": [ { "ref": "Endpoint" @@ -1140,23 +1171,64 @@ } ] } - ] + ], + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + true + ] + } + ], + "endpoint": { + "url": "https://s3express-control-fips.{Region}.amazonaws.com/{uri_encoded_bucket}", + "properties": { + "backend": "S3Express", + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3express", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [], + "endpoint": { + "url": "https://s3express-control.{Region}.amazonaws.com/{uri_encoded_bucket}", + "properties": { + "backend": "S3Express", + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3express", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" } ], - "error": "Custom endpoint `{Endpoint}` was not a valid URI", - "type": "error" + "type": "tree" }, { "conditions": [ - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "ForcePathStyle" - }, - false - ] - }, { "fn": "aws.isVirtualHostableS3Bucket", "argv": [ @@ -1167,77 +1239,67 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ { - "fn": "aws.partition", + "fn": "isSet", "argv": [ { - "ref": "Region" + "ref": "DisableS3ExpressSessionAuth" } - ], - "assign": "partitionResult" + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "DisableS3ExpressSessionAuth" + }, + true + ] } ], - "type": "tree", "rules": [ { "conditions": [ { - "fn": "isValidHostLabel", + "fn": "substring", "argv": [ { - "ref": "Region" + "ref": "Bucket" }, - false - ] - } - ], - "type": "tree", - "rules": [ + 6, + 14, + true + ], + "assign": "s3expressAvailabilityZoneId" + }, { - "conditions": [ + "fn": "substring", + "argv": [ { - "fn": "booleanEquals", - "argv": [ - { - "ref": "Accelerate" - }, - true - ] + "ref": "Bucket" }, - { - "fn": "stringEquals", - "argv": [ - { - "fn": "getAttr", - "argv": [ - { - "ref": "partitionResult" - }, - "name" - ] - }, - "aws-cn" - ] - } + 14, + 16, + true ], - "error": "S3 Accelerate cannot be used in this region", - "type": "error" + "assign": "s3expressAvailabilityZoneDelim" }, { - "conditions": [ + "fn": "stringEquals", + "argv": [ { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseDualStack" - }, - true - ] + "ref": "s3expressAvailabilityZoneDelim" }, + "--" + ] + } + ], + "rules": [ + { + "conditions": [ { "fn": "booleanEquals", "argv": [ @@ -1246,48 +1308,18 @@ }, true ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "Accelerate" - }, - false - ] - }, - { - "fn": "not", - "argv": [ - { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] - } - ] - }, - { - "fn": "stringEquals", - "argv": [ - { - "ref": "Region" - }, - "aws-global" - ] } ], "endpoint": { - "url": "https://{Bucket}.s3-fips.dualstack.us-east-1.{partitionResult#dnsSuffix}", + "url": "https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.amazonaws.com", "properties": { + "backend": "S3Express", "authSchemes": [ { "disableDoubleEncoding": true, "name": "sigv4", - "signingName": "s3", - "signingRegion": "us-east-1" + "signingName": "s3express", + "signingRegion": "{Region}" } ] }, @@ -1296,104 +1328,66 @@ "type": "endpoint" }, { - "conditions": [ - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseDualStack" - }, - true - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseFIPS" - }, - true - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "Accelerate" - }, - false - ] - }, - { - "fn": "not", - "argv": [ + "conditions": [], + "endpoint": { + "url": "https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.amazonaws.com", + "properties": { + "backend": "S3Express", + "authSchemes": [ { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3express", + "signingRegion": "{Region}" } ] }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [ + { + "fn": "substring", + "argv": [ { - "fn": "not", - "argv": [ - { - "fn": "stringEquals", - "argv": [ - { - "ref": "Region" - }, - "aws-global" - ] - } - ] + "ref": "Bucket" }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseGlobalEndpoint" - }, - true - ] - } + 6, + 15, + true ], - "type": "tree", - "rules": [ + "assign": "s3expressAvailabilityZoneId" + }, + { + "fn": "substring", + "argv": [ { - "conditions": [], - "endpoint": { - "url": "https://{Bucket}.s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}", - "properties": { - "authSchemes": [ - { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3", - "signingRegion": "{Region}" - } - ] - }, - "headers": {} - }, - "type": "endpoint" - } - ] + "ref": "Bucket" + }, + 15, + 17, + true + ], + "assign": "s3expressAvailabilityZoneDelim" }, { - "conditions": [ + "fn": "stringEquals", + "argv": [ { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseDualStack" - }, - true - ] + "ref": "s3expressAvailabilityZoneDelim" }, + "--" + ] + } + ], + "rules": [ + { + "conditions": [ { "fn": "booleanEquals", "argv": [ @@ -1402,61 +1396,17 @@ }, true ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "Accelerate" - }, - false - ] - }, - { - "fn": "not", - "argv": [ - { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] - } - ] - }, - { - "fn": "not", - "argv": [ - { - "fn": "stringEquals", - "argv": [ - { - "ref": "Region" - }, - "aws-global" - ] - } - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseGlobalEndpoint" - }, - false - ] } ], "endpoint": { - "url": "https://{Bucket}.s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}", + "url": "https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.amazonaws.com", "properties": { + "backend": "S3Express", "authSchemes": [ { "disableDoubleEncoding": true, "name": "sigv4", - "signingName": "s3", + "signingName": "s3express", "signingRegion": "{Region}" } ] @@ -1466,272 +1416,468 @@ "type": "endpoint" }, { - "conditions": [ - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseDualStack" - }, - false - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseFIPS" - }, - true - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "Accelerate" - }, - false - ] - }, - { - "fn": "not", - "argv": [ - { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] - } - ] - }, - { - "fn": "stringEquals", - "argv": [ - { - "ref": "Region" - }, - "aws-global" - ] - } - ], + "conditions": [], "endpoint": { - "url": "https://{Bucket}.s3-fips.us-east-1.{partitionResult#dnsSuffix}", + "url": "https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.amazonaws.com", "properties": { + "backend": "S3Express", "authSchemes": [ { "disableDoubleEncoding": true, "name": "sigv4", - "signingName": "s3", - "signingRegion": "us-east-1" + "signingName": "s3express", + "signingRegion": "{Region}" } ] }, "headers": {} }, "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [], + "error": "Unrecognized S3Express bucket name format.", + "type": "error" + } + ], + "type": "tree" + }, + { + "conditions": [ + { + "fn": "substring", + "argv": [ + { + "ref": "Bucket" }, + 6, + 14, + true + ], + "assign": "s3expressAvailabilityZoneId" + }, + { + "fn": "substring", + "argv": [ { - "conditions": [ + "ref": "Bucket" + }, + 14, + 16, + true + ], + "assign": "s3expressAvailabilityZoneDelim" + }, + { + "fn": "stringEquals", + "argv": [ + { + "ref": "s3expressAvailabilityZoneDelim" + }, + "--" + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseDualStack" - }, - false - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseFIPS" - }, - true - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "Accelerate" - }, - false - ] - }, - { - "fn": "not", - "argv": [ - { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] - } - ] - }, - { - "fn": "not", - "argv": [ - { - "fn": "stringEquals", - "argv": [ - { - "ref": "Region" - }, - "aws-global" - ] - } - ] + "ref": "UseFIPS" }, + true + ] + } + ], + "endpoint": { + "url": "https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.amazonaws.com", + "properties": { + "backend": "S3Express", + "authSchemes": [ { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseGlobalEndpoint" - }, - true - ] + "disableDoubleEncoding": true, + "name": "sigv4-s3express", + "signingName": "s3express", + "signingRegion": "{Region}" } - ], - "type": "tree", - "rules": [ + ] + }, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [], + "endpoint": { + "url": "https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.amazonaws.com", + "properties": { + "backend": "S3Express", + "authSchemes": [ { - "conditions": [], - "endpoint": { - "url": "https://{Bucket}.s3-fips.{Region}.{partitionResult#dnsSuffix}", - "properties": { - "authSchemes": [ - { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3", - "signingRegion": "{Region}" - } - ] - }, - "headers": {} - }, - "type": "endpoint" + "disableDoubleEncoding": true, + "name": "sigv4-s3express", + "signingName": "s3express", + "signingRegion": "{Region}" } ] }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [ + { + "fn": "substring", + "argv": [ { - "conditions": [ - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseDualStack" - }, - false - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseFIPS" - }, - true - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "Accelerate" - }, - false - ] - }, - { - "fn": "not", - "argv": [ - { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] - } - ] - }, - { - "fn": "not", - "argv": [ - { - "fn": "stringEquals", - "argv": [ - { - "ref": "Region" - }, - "aws-global" - ] - } - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseGlobalEndpoint" - }, - false - ] - } - ], - "endpoint": { - "url": "https://{Bucket}.s3-fips.{Region}.{partitionResult#dnsSuffix}", - "properties": { - "authSchemes": [ - { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3", - "signingRegion": "{Region}" - } - ] - }, - "headers": {} - }, - "type": "endpoint" + "ref": "Bucket" + }, + 6, + 15, + true + ], + "assign": "s3expressAvailabilityZoneId" + }, + { + "fn": "substring", + "argv": [ + { + "ref": "Bucket" }, + 15, + 17, + true + ], + "assign": "s3expressAvailabilityZoneDelim" + }, + { + "fn": "stringEquals", + "argv": [ { - "conditions": [ + "ref": "s3expressAvailabilityZoneDelim" + }, + "--" + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseDualStack" - }, - true - ] + "ref": "UseFIPS" }, + true + ] + } + ], + "endpoint": { + "url": "https://{Bucket}.s3express-fips-{s3expressAvailabilityZoneId}.{Region}.amazonaws.com", + "properties": { + "backend": "S3Express", + "authSchemes": [ { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseFIPS" - }, - false - ] - }, + "disableDoubleEncoding": true, + "name": "sigv4-s3express", + "signingName": "s3express", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [], + "endpoint": { + "url": "https://{Bucket}.s3express-{s3expressAvailabilityZoneId}.{Region}.amazonaws.com", + "properties": { + "backend": "S3Express", + "authSchemes": [ { - "fn": "booleanEquals", - "argv": [ - { - "ref": "Accelerate" - }, - true - ] + "disableDoubleEncoding": true, + "name": "sigv4-s3express", + "signingName": "s3express", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [], + "error": "Unrecognized S3Express bucket name format.", + "type": "error" + } + ], + "type": "tree" + }, + { + "conditions": [], + "error": "S3Express bucket name is not a valid virtual hostable name.", + "type": "error" + } + ], + "type": "tree" + }, + { + "conditions": [ + { + "fn": "not", + "argv": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Bucket" + } + ] + } + ] + }, + { + "fn": "isSet", + "argv": [ + { + "ref": "UseS3ExpressControlEndpoint" + } + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseS3ExpressControlEndpoint" + }, + true + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + }, + { + "fn": "parseURL", + "argv": [ + { + "ref": "Endpoint" + } + ], + "assign": "url" + } + ], + "endpoint": { + "url": "{url#scheme}://{url#authority}{url#path}", + "properties": { + "backend": "S3Express", + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3express", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + true + ] + } + ], + "endpoint": { + "url": "https://s3express-control-fips.{Region}.amazonaws.com", + "properties": { + "backend": "S3Express", + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3express", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [], + "endpoint": { + "url": "https://s3express-control.{Region}.amazonaws.com", + "properties": { + "backend": "S3Express", + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3express", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Bucket" + } + ] + }, + { + "fn": "substring", + "argv": [ + { + "ref": "Bucket" + }, + 49, + 50, + true + ], + "assign": "hardwareType" + }, + { + "fn": "substring", + "argv": [ + { + "ref": "Bucket" + }, + 8, + 12, + true + ], + "assign": "regionPrefix" + }, + { + "fn": "substring", + "argv": [ + { + "ref": "Bucket" + }, + 0, + 7, + true + ], + "assign": "bucketAliasSuffix" + }, + { + "fn": "substring", + "argv": [ + { + "ref": "Bucket" + }, + 32, + 49, + true + ], + "assign": "outpostId" + }, + { + "fn": "aws.partition", + "argv": [ + { + "ref": "Region" + } + ], + "assign": "regionPartition" + }, + { + "fn": "stringEquals", + "argv": [ + { + "ref": "bucketAliasSuffix" + }, + "--op-s3" + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "isValidHostLabel", + "argv": [ + { + "ref": "outpostId" + }, + false + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "stringEquals", + "argv": [ + { + "ref": "hardwareType" + }, + "e" + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "stringEquals", + "argv": [ + { + "ref": "regionPrefix" }, + "beta" + ] + } + ], + "rules": [ + { + "conditions": [ { "fn": "not", "argv": [ @@ -1744,62 +1890,99 @@ ] } ] - }, + } + ], + "error": "Expected a endpoint to be specified but no endpoint was found", + "type": "error" + }, + { + "conditions": [ { - "fn": "stringEquals", + "fn": "isSet", "argv": [ { - "ref": "Region" - }, - "aws-global" + "ref": "Endpoint" + } ] + }, + { + "fn": "parseURL", + "argv": [ + { + "ref": "Endpoint" + } + ], + "assign": "url" } ], "endpoint": { - "url": "https://{Bucket}.s3-accelerate.dualstack.us-east-1.{partitionResult#dnsSuffix}", + "url": "https://{Bucket}.ec2.{url#authority}", "properties": { "authSchemes": [ { "disableDoubleEncoding": true, "name": "sigv4", - "signingName": "s3", - "signingRegion": "us-east-1" + "signingName": "s3-outposts", + "signingRegion": "{Region}" } ] }, "headers": {} }, "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [], + "endpoint": { + "url": "https://{Bucket}.ec2.s3-outposts.{Region}.{regionPartition#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3-outposts", + "signingRegion": "{Region}" + } + ] }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [ + { + "fn": "stringEquals", + "argv": [ { - "conditions": [ - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseDualStack" - }, - true - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseFIPS" - }, - false - ] - }, + "ref": "hardwareType" + }, + "o" + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "stringEquals", + "argv": [ { - "fn": "booleanEquals", - "argv": [ - { - "ref": "Accelerate" - }, - true - ] + "ref": "regionPrefix" }, + "beta" + ] + } + ], + "rules": [ + { + "conditions": [ { "fn": "not", "argv": [ @@ -1812,127 +1995,39 @@ ] } ] - }, - { - "fn": "not", - "argv": [ - { - "fn": "stringEquals", - "argv": [ - { - "ref": "Region" - }, - "aws-global" - ] - } - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseGlobalEndpoint" - }, - true - ] } ], - "type": "tree", - "rules": [ - { - "conditions": [], - "endpoint": { - "url": "https://{Bucket}.s3-accelerate.dualstack.{partitionResult#dnsSuffix}", - "properties": { - "authSchemes": [ - { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3", - "signingRegion": "{Region}" - } - ] - }, - "headers": {} - }, - "type": "endpoint" - } - ] + "error": "Expected a endpoint to be specified but no endpoint was found", + "type": "error" }, { "conditions": [ { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseDualStack" - }, - true - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseFIPS" - }, - false - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "Accelerate" - }, - true - ] - }, - { - "fn": "not", + "fn": "isSet", "argv": [ { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] + "ref": "Endpoint" } ] }, { - "fn": "not", + "fn": "parseURL", "argv": [ { - "fn": "stringEquals", - "argv": [ - { - "ref": "Region" - }, - "aws-global" - ] + "ref": "Endpoint" } - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseGlobalEndpoint" - }, - false - ] + ], + "assign": "url" } ], "endpoint": { - "url": "https://{Bucket}.s3-accelerate.dualstack.{partitionResult#dnsSuffix}", + "url": "https://{Bucket}.op-{outpostId}.{url#authority}", "properties": { "authSchemes": [ { "disableDoubleEncoding": true, "name": "sigv4", - "signingName": "s3", + "signingName": "s3-outposts", "signingRegion": "{Region}" } ] @@ -1940,17 +2035,179 @@ "headers": {} }, "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [], + "endpoint": { + "url": "https://{Bucket}.op-{outpostId}.s3-outposts.{Region}.{regionPartition#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3-outposts", + "signingRegion": "{Region}" + } + ] }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [], + "error": "Unrecognized hardware type: \"Expected hardware type o or e but got {hardwareType}\"", + "type": "error" + } + ], + "type": "tree" + }, + { + "conditions": [], + "error": "Invalid ARN: The outpost Id must only contain a-z, A-Z, 0-9 and `-`.", + "type": "error" + } + ], + "type": "tree" + }, + { + "conditions": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Bucket" + } + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + }, + { + "fn": "not", + "argv": [ + { + "fn": "isSet", + "argv": [ { - "conditions": [ + "fn": "parseURL", + "argv": [ { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseDualStack" - }, - true - ] + "ref": "Endpoint" + } + ] + } + ] + } + ] + } + ], + "error": "Custom endpoint `{Endpoint}` was not a valid URI", + "type": "error" + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "ForcePathStyle" + }, + false + ] + }, + { + "fn": "aws.isVirtualHostableS3Bucket", + "argv": [ + { + "ref": "Bucket" + }, + false + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "aws.partition", + "argv": [ + { + "ref": "Region" + } + ], + "assign": "partitionResult" + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "isValidHostLabel", + "argv": [ + { + "ref": "Region" + }, + false + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "Accelerate" + }, + true + ] + }, + { + "fn": "stringEquals", + "argv": [ + { + "fn": "getAttr", + "argv": [ + { + "ref": "partitionResult" + }, + "name" + ] + }, + "aws-cn" + ] + } + ], + "error": "S3 Accelerate cannot be used in this region", + "type": "error" + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + true + ] }, { "fn": "booleanEquals", @@ -1958,7 +2215,7 @@ { "ref": "UseFIPS" }, - false + true ] }, { @@ -1994,7 +2251,7 @@ } ], "endpoint": { - "url": "https://{Bucket}.s3.dualstack.us-east-1.{partitionResult#dnsSuffix}", + "url": "https://{Bucket}.s3-fips.dualstack.us-east-1.{partitionResult#dnsSuffix}", "properties": { "authSchemes": [ { @@ -2026,7 +2283,7 @@ { "ref": "UseFIPS" }, - false + true ] }, { @@ -2075,12 +2332,11 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [], "endpoint": { - "url": "https://{Bucket}.s3.dualstack.{Region}.{partitionResult#dnsSuffix}", + "url": "https://{Bucket}.s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}", "properties": { "authSchemes": [ { @@ -2095,7 +2351,8 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -2114,7 +2371,7 @@ { "ref": "UseFIPS" }, - false + true ] }, { @@ -2164,7 +2421,7 @@ } ], "endpoint": { - "url": "https://{Bucket}.s3.dualstack.{Region}.{partitionResult#dnsSuffix}", + "url": "https://{Bucket}.s3-fips.dualstack.{Region}.{partitionResult#dnsSuffix}", "properties": { "authSchemes": [ { @@ -2196,7 +2453,7 @@ { "ref": "UseFIPS" }, - false + true ] }, { @@ -2209,35 +2466,16 @@ ] }, { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] - }, - { - "fn": "parseURL", - "argv": [ - { - "ref": "Endpoint" - } - ], - "assign": "url" - }, - { - "fn": "booleanEquals", + "fn": "not", "argv": [ { - "fn": "getAttr", + "fn": "isSet", "argv": [ { - "ref": "url" - }, - "isIp" + "ref": "Endpoint" + } ] - }, - true + } ] }, { @@ -2251,7 +2489,7 @@ } ], "endpoint": { - "url": "{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}", + "url": "https://{Bucket}.s3-fips.us-east-1.{partitionResult#dnsSuffix}", "properties": { "authSchemes": [ { @@ -2283,7 +2521,7 @@ { "ref": "UseFIPS" }, - false + true ] }, { @@ -2296,62 +2534,63 @@ ] }, { - "fn": "isSet", + "fn": "not", "argv": [ { - "ref": "Endpoint" + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] } ] }, { - "fn": "parseURL", - "argv": [ - { - "ref": "Endpoint" - } - ], - "assign": "url" - }, - { - "fn": "booleanEquals", + "fn": "not", "argv": [ { - "fn": "getAttr", + "fn": "stringEquals", "argv": [ { - "ref": "url" + "ref": "Region" }, - "isIp" + "aws-global" ] - }, - false + } ] }, { - "fn": "stringEquals", + "fn": "booleanEquals", "argv": [ { - "ref": "Region" + "ref": "UseGlobalEndpoint" }, - "aws-global" + true ] } ], - "endpoint": { - "url": "{url#scheme}://{Bucket}.{url#authority}{url#path}", - "properties": { - "authSchemes": [ - { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3", - "signingRegion": "us-east-1" - } - ] - }, - "headers": {} - }, - "type": "endpoint" + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "https://{Bucket}.s3-fips.{Region}.{partitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" }, { "conditions": [ @@ -2370,7 +2609,7 @@ { "ref": "UseFIPS" }, - false + true ] }, { @@ -2383,35 +2622,16 @@ ] }, { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] - }, - { - "fn": "parseURL", - "argv": [ - { - "ref": "Endpoint" - } - ], - "assign": "url" - }, - { - "fn": "booleanEquals", + "fn": "not", "argv": [ { - "fn": "getAttr", + "fn": "isSet", "argv": [ { - "ref": "url" - }, - "isIp" + "ref": "Endpoint" + } ] - }, - true + } ] }, { @@ -2434,59 +2654,25 @@ { "ref": "UseGlobalEndpoint" }, - true + false ] } ], - "type": "tree", - "rules": [ - { - "conditions": [ - { - "fn": "stringEquals", - "argv": [ - { - "ref": "Region" - }, - "us-east-1" - ] + "endpoint": { + "url": "https://{Bucket}.s3-fips.{Region}.{partitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" } - ], - "endpoint": { - "url": "{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}", - "properties": { - "authSchemes": [ - { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3", - "signingRegion": "{Region}" - } - ] - }, - "headers": {} - }, - "type": "endpoint" + ] }, - { - "conditions": [], - "endpoint": { - "url": "{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}", - "properties": { - "authSchemes": [ - { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3", - "signingRegion": "{Region}" - } - ] - }, - "headers": {} - }, - "type": "endpoint" - } - ] + "headers": {} + }, + "type": "endpoint" }, { "conditions": [ @@ -2496,7 +2682,7 @@ { "ref": "UseDualStack" }, - false + true ] }, { @@ -2514,39 +2700,88 @@ { "ref": "Accelerate" }, - false + true ] }, { - "fn": "isSet", + "fn": "not", "argv": [ { - "ref": "Endpoint" + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] } ] }, { - "fn": "parseURL", + "fn": "stringEquals", "argv": [ { - "ref": "Endpoint" + "ref": "Region" + }, + "aws-global" + ] + } + ], + "endpoint": { + "url": "https://{Bucket}.s3-accelerate.dualstack.us-east-1.{partitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "us-east-1" } - ], - "assign": "url" + ] }, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [ { "fn": "booleanEquals", "argv": [ { - "fn": "getAttr", + "ref": "UseDualStack" + }, + true + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "Accelerate" + }, + true + ] + }, + { + "fn": "not", + "argv": [ + { + "fn": "isSet", "argv": [ { - "ref": "url" - }, - "isIp" + "ref": "Endpoint" + } ] - }, - false + } ] }, { @@ -2573,40 +2808,11 @@ ] } ], - "type": "tree", "rules": [ - { - "conditions": [ - { - "fn": "stringEquals", - "argv": [ - { - "ref": "Region" - }, - "us-east-1" - ] - } - ], - "endpoint": { - "url": "{url#scheme}://{Bucket}.{url#authority}{url#path}", - "properties": { - "authSchemes": [ - { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3", - "signingRegion": "{Region}" - } - ] - }, - "headers": {} - }, - "type": "endpoint" - }, { "conditions": [], "endpoint": { - "url": "{url#scheme}://{Bucket}.{url#authority}{url#path}", + "url": "https://{Bucket}.s3-accelerate.dualstack.{partitionResult#dnsSuffix}", "properties": { "authSchemes": [ { @@ -2621,7 +2827,8 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -2631,7 +2838,7 @@ { "ref": "UseDualStack" }, - false + true ] }, { @@ -2649,39 +2856,20 @@ { "ref": "Accelerate" }, - false - ] - }, - { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } + true ] }, { - "fn": "parseURL", - "argv": [ - { - "ref": "Endpoint" - } - ], - "assign": "url" - }, - { - "fn": "booleanEquals", + "fn": "not", "argv": [ { - "fn": "getAttr", + "fn": "isSet", "argv": [ { - "ref": "url" - }, - "isIp" + "ref": "Endpoint" + } ] - }, - true + } ] }, { @@ -2709,7 +2897,7 @@ } ], "endpoint": { - "url": "{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}", + "url": "https://{Bucket}.s3-accelerate.dualstack.{partitionResult#dnsSuffix}", "properties": { "authSchemes": [ { @@ -2732,7 +2920,7 @@ { "ref": "UseDualStack" }, - false + true ] }, { @@ -2753,71 +2941,38 @@ false ] }, - { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] - }, - { - "fn": "parseURL", - "argv": [ - { - "ref": "Endpoint" - } - ], - "assign": "url" - }, - { - "fn": "booleanEquals", - "argv": [ - { - "fn": "getAttr", - "argv": [ - { - "ref": "url" - }, - "isIp" - ] - }, - false - ] - }, { "fn": "not", "argv": [ { - "fn": "stringEquals", + "fn": "isSet", "argv": [ { - "ref": "Region" - }, - "aws-global" + "ref": "Endpoint" + } ] } ] }, { - "fn": "booleanEquals", + "fn": "stringEquals", "argv": [ { - "ref": "UseGlobalEndpoint" + "ref": "Region" }, - false + "aws-global" ] } ], "endpoint": { - "url": "{url#scheme}://{Bucket}.{url#authority}{url#path}", + "url": "https://{Bucket}.s3.dualstack.us-east-1.{partitionResult#dnsSuffix}", "properties": { "authSchemes": [ { "disableDoubleEncoding": true, "name": "sigv4", "signingName": "s3", - "signingRegion": "{Region}" + "signingRegion": "us-east-1" } ] }, @@ -2833,7 +2988,7 @@ { "ref": "UseDualStack" }, - false + true ] }, { @@ -2851,7 +3006,7 @@ { "ref": "Accelerate" }, - true + false ] }, { @@ -2868,30 +3023,50 @@ ] }, { - "fn": "stringEquals", + "fn": "not", "argv": [ { - "ref": "Region" + "fn": "stringEquals", + "argv": [ + { + "ref": "Region" + }, + "aws-global" + ] + } + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseGlobalEndpoint" }, - "aws-global" + true ] } ], - "endpoint": { - "url": "https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}", - "properties": { - "authSchemes": [ - { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3", - "signingRegion": "us-east-1" - } - ] - }, - "headers": {} - }, - "type": "endpoint" + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "https://{Bucket}.s3.dualstack.{Region}.{partitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" }, { "conditions": [ @@ -2901,7 +3076,7 @@ { "ref": "UseDualStack" }, - false + true ] }, { @@ -2919,7 +3094,7 @@ { "ref": "Accelerate" }, - true + false ] }, { @@ -2955,59 +3130,25 @@ { "ref": "UseGlobalEndpoint" }, - true + false ] } ], - "type": "tree", - "rules": [ - { - "conditions": [ + "endpoint": { + "url": "https://{Bucket}.s3.dualstack.{Region}.{partitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ { - "fn": "stringEquals", - "argv": [ - { - "ref": "Region" - }, - "us-east-1" - ] + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" } - ], - "endpoint": { - "url": "https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}", - "properties": { - "authSchemes": [ - { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3", - "signingRegion": "{Region}" - } - ] - }, - "headers": {} - }, - "type": "endpoint" + ] }, - { - "conditions": [], - "endpoint": { - "url": "https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}", - "properties": { - "authSchemes": [ - { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3", - "signingRegion": "{Region}" - } - ] - }, - "headers": {} - }, - "type": "endpoint" - } - ] + "headers": {} + }, + "type": "endpoint" }, { "conditions": [ @@ -3035,55 +3176,60 @@ { "ref": "Accelerate" }, - true + false ] }, { - "fn": "not", + "fn": "isSet", "argv": [ { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] + "ref": "Endpoint" } ] }, { - "fn": "not", + "fn": "parseURL", "argv": [ { - "fn": "stringEquals", + "ref": "Endpoint" + } + ], + "assign": "url" + }, + { + "fn": "booleanEquals", + "argv": [ + { + "fn": "getAttr", "argv": [ { - "ref": "Region" + "ref": "url" }, - "aws-global" + "isIp" ] - } + }, + true ] }, { - "fn": "booleanEquals", + "fn": "stringEquals", "argv": [ { - "ref": "UseGlobalEndpoint" + "ref": "Region" }, - false + "aws-global" ] } ], "endpoint": { - "url": "https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}", + "url": "{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}", "properties": { "authSchemes": [ { "disableDoubleEncoding": true, "name": "sigv4", "signingName": "s3", - "signingRegion": "{Region}" + "signingRegion": "us-east-1" } ] }, @@ -3121,16 +3267,35 @@ ] }, { - "fn": "not", + "fn": "isSet", "argv": [ { - "fn": "isSet", + "ref": "Endpoint" + } + ] + }, + { + "fn": "parseURL", + "argv": [ + { + "ref": "Endpoint" + } + ], + "assign": "url" + }, + { + "fn": "booleanEquals", + "argv": [ + { + "fn": "getAttr", "argv": [ { - "ref": "Endpoint" - } + "ref": "url" + }, + "isIp" ] - } + }, + false ] }, { @@ -3144,7 +3309,7 @@ } ], "endpoint": { - "url": "https://{Bucket}.s3.{partitionResult#dnsSuffix}", + "url": "{url#scheme}://{Bucket}.{url#authority}{url#path}", "properties": { "authSchemes": [ { @@ -3189,16 +3354,35 @@ ] }, { - "fn": "not", + "fn": "isSet", "argv": [ { - "fn": "isSet", + "ref": "Endpoint" + } + ] + }, + { + "fn": "parseURL", + "argv": [ + { + "ref": "Endpoint" + } + ], + "assign": "url" + }, + { + "fn": "booleanEquals", + "argv": [ + { + "fn": "getAttr", "argv": [ { - "ref": "Endpoint" - } + "ref": "url" + }, + "isIp" ] - } + }, + true ] }, { @@ -3225,7 +3409,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -3240,7 +3423,7 @@ } ], "endpoint": { - "url": "https://{Bucket}.s3.{partitionResult#dnsSuffix}", + "url": "{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}", "properties": { "authSchemes": [ { @@ -3258,7 +3441,7 @@ { "conditions": [], "endpoint": { - "url": "https://{Bucket}.s3.{Region}.{partitionResult#dnsSuffix}", + "url": "{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}", "properties": { "authSchemes": [ { @@ -3273,7 +3456,8 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -3305,16 +3489,35 @@ ] }, { - "fn": "not", + "fn": "isSet", "argv": [ { - "fn": "isSet", + "ref": "Endpoint" + } + ] + }, + { + "fn": "parseURL", + "argv": [ + { + "ref": "Endpoint" + } + ], + "assign": "url" + }, + { + "fn": "booleanEquals", + "argv": [ + { + "fn": "getAttr", "argv": [ { - "ref": "Endpoint" - } + "ref": "url" + }, + "isIp" ] - } + }, + false ] }, { @@ -3337,151 +3540,147 @@ { "ref": "UseGlobalEndpoint" }, - false + true ] } ], - "endpoint": { - "url": "https://{Bucket}.s3.{Region}.{partitionResult#dnsSuffix}", - "properties": { - "authSchemes": [ + "rules": [ + { + "conditions": [ { - "disableDoubleEncoding": true, - "name": "sigv4", - "signingName": "s3", - "signingRegion": "{Region}" + "fn": "stringEquals", + "argv": [ + { + "ref": "Region" + }, + "us-east-1" + ] } - ] + ], + "endpoint": { + "url": "{url#scheme}://{Bucket}.{url#authority}{url#path}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" }, - "headers": {} - }, - "type": "endpoint" - } - ] - }, - { - "conditions": [], - "error": "Invalid region: region was not a valid DNS name.", - "type": "error" - } - ] - } - ] - }, - { - "conditions": [ - { - "fn": "isSet", - "argv": [ - { - "ref": "Endpoint" - } - ] - }, - { - "fn": "parseURL", - "argv": [ - { - "ref": "Endpoint" - } - ], - "assign": "url" - }, - { - "fn": "stringEquals", - "argv": [ - { - "fn": "getAttr", - "argv": [ - { - "ref": "url" + { + "conditions": [], + "endpoint": { + "url": "{url#scheme}://{Bucket}.{url#authority}{url#path}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" }, - "scheme" - ] - }, - "http" - ] - }, - { - "fn": "aws.isVirtualHostableS3Bucket", - "argv": [ - { - "ref": "Bucket" - }, - true - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "ForcePathStyle" - }, - false - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseFIPS" - }, - false - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseDualStack" - }, - false - ] - }, - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "Accelerate" - }, - false - ] - } - ], - "type": "tree", - "rules": [ - { - "conditions": [ - { - "fn": "aws.partition", - "argv": [ - { - "ref": "Region" - } - ], - "assign": "partitionResult" - } - ], - "type": "tree", - "rules": [ - { - "conditions": [ { - "fn": "isValidHostLabel", - "argv": [ + "conditions": [ { - "ref": "Region" + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + false + ] }, - false - ] - } - ], - "type": "tree", - "rules": [ - { - "conditions": [], + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "Accelerate" + }, + false + ] + }, + { + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + }, + { + "fn": "parseURL", + "argv": [ + { + "ref": "Endpoint" + } + ], + "assign": "url" + }, + { + "fn": "booleanEquals", + "argv": [ + { + "fn": "getAttr", + "argv": [ + { + "ref": "url" + }, + "isIp" + ] + }, + true + ] + }, + { + "fn": "not", + "argv": [ + { + "fn": "stringEquals", + "argv": [ + { + "ref": "Region" + }, + "aws-global" + ] + } + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseGlobalEndpoint" + }, + false + ] + } + ], "endpoint": { - "url": "{url#scheme}://{Bucket}.{url#authority}{url#path}", + "url": "{url#scheme}://{url#authority}{url#normalizedPath}{Bucket}", "properties": { "authSchemes": [ { @@ -3495,196 +3694,965 @@ "headers": {} }, "type": "endpoint" - } - ] - }, - { - "conditions": [], - "error": "Invalid region: region was not a valid DNS name.", - "type": "error" - } - ] - } - ] - }, - { - "conditions": [ - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "ForcePathStyle" - }, - false - ] - }, - { - "fn": "aws.parseArn", - "argv": [ - { - "ref": "Bucket" - } - ], - "assign": "bucketArn" - } - ], - "type": "tree", - "rules": [ - { - "conditions": [ - { - "fn": "getAttr", - "argv": [ - { - "ref": "bucketArn" }, - "resourceId[0]" - ], - "assign": "arnType" - }, - { - "fn": "not", - "argv": [ { - "fn": "stringEquals", - "argv": [ + "conditions": [ { - "ref": "arnType" + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + false + ] }, - "" - ] - } - ] - } - ], - "type": "tree", - "rules": [ - { - "conditions": [ - { - "fn": "stringEquals", - "argv": [ { - "fn": "getAttr", + "fn": "booleanEquals", "argv": [ { - "ref": "bucketArn" + "ref": "UseFIPS" }, - "service" + false ] }, - "s3-object-lambda" - ] - } - ], - "type": "tree", - "rules": [ - { - "conditions": [ { - "fn": "stringEquals", + "fn": "booleanEquals", "argv": [ { - "ref": "arnType" + "ref": "Accelerate" }, - "accesspoint" + false ] - } - ], - "type": "tree", - "rules": [ + }, { - "conditions": [ + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + }, + { + "fn": "parseURL", + "argv": [ + { + "ref": "Endpoint" + } + ], + "assign": "url" + }, + { + "fn": "booleanEquals", + "argv": [ { "fn": "getAttr", "argv": [ { - "ref": "bucketArn" + "ref": "url" }, - "resourceId[1]" - ], - "assign": "accessPointName" + "isIp" + ] }, + false + ] + }, + { + "fn": "not", + "argv": [ { - "fn": "not", + "fn": "stringEquals", "argv": [ { - "fn": "stringEquals", - "argv": [ - { - "ref": "accessPointName" - }, - "" - ] - } + "ref": "Region" + }, + "aws-global" ] } - ], - "type": "tree", - "rules": [ + ] + }, + { + "fn": "booleanEquals", + "argv": [ { - "conditions": [ - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "UseDualStack" - }, - true - ] - } - ], - "error": "S3 Object Lambda does not support Dual-stack", - "type": "error" + "ref": "UseGlobalEndpoint" }, + false + ] + } + ], + "endpoint": { + "url": "{url#scheme}://{Bucket}.{url#authority}{url#path}", + "properties": { + "authSchemes": [ { - "conditions": [ - { - "fn": "booleanEquals", - "argv": [ - { - "ref": "Accelerate" - }, - true - ] - } - ], - "error": "S3 Object Lambda does not support S3 Accelerate", - "type": "error" + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ { - "conditions": [ + "ref": "UseFIPS" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "Accelerate" + }, + true + ] + }, + { + "fn": "not", + "argv": [ + { + "fn": "isSet", + "argv": [ { - "fn": "not", - "argv": [ - { - "fn": "stringEquals", - "argv": [ - { - "fn": "getAttr", - "argv": [ - { - "ref": "bucketArn" - }, - "region" - ] - }, - "" - ] - } - ] + "ref": "Endpoint" } - ], - "type": "tree", - "rules": [ - { - "conditions": [ - { - "fn": "isSet", - "argv": [ - { - "ref": "DisableAccessPoints" - } + ] + } + ] + }, + { + "fn": "stringEquals", + "argv": [ + { + "ref": "Region" + }, + "aws-global" + ] + } + ], + "endpoint": { + "url": "https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "us-east-1" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "Accelerate" + }, + true + ] + }, + { + "fn": "not", + "argv": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + } + ] + }, + { + "fn": "not", + "argv": [ + { + "fn": "stringEquals", + "argv": [ + { + "ref": "Region" + }, + "aws-global" + ] + } + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseGlobalEndpoint" + }, + true + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "stringEquals", + "argv": [ + { + "ref": "Region" + }, + "us-east-1" + ] + } + ], + "endpoint": { + "url": "https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [], + "endpoint": { + "url": "https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "Accelerate" + }, + true + ] + }, + { + "fn": "not", + "argv": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + } + ] + }, + { + "fn": "not", + "argv": [ + { + "fn": "stringEquals", + "argv": [ + { + "ref": "Region" + }, + "aws-global" + ] + } + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseGlobalEndpoint" + }, + false + ] + } + ], + "endpoint": { + "url": "https://{Bucket}.s3-accelerate.{partitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "Accelerate" + }, + false + ] + }, + { + "fn": "not", + "argv": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + } + ] + }, + { + "fn": "stringEquals", + "argv": [ + { + "ref": "Region" + }, + "aws-global" + ] + } + ], + "endpoint": { + "url": "https://{Bucket}.s3.{partitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "us-east-1" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "Accelerate" + }, + false + ] + }, + { + "fn": "not", + "argv": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + } + ] + }, + { + "fn": "not", + "argv": [ + { + "fn": "stringEquals", + "argv": [ + { + "ref": "Region" + }, + "aws-global" + ] + } + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseGlobalEndpoint" + }, + true + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "stringEquals", + "argv": [ + { + "ref": "Region" + }, + "us-east-1" + ] + } + ], + "endpoint": { + "url": "https://{Bucket}.s3.{partitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + }, + { + "conditions": [], + "endpoint": { + "url": "https://{Bucket}.s3.{Region}.{partitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "Accelerate" + }, + false + ] + }, + { + "fn": "not", + "argv": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + } + ] + }, + { + "fn": "not", + "argv": [ + { + "fn": "stringEquals", + "argv": [ + { + "ref": "Region" + }, + "aws-global" + ] + } + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseGlobalEndpoint" + }, + false + ] + } + ], + "endpoint": { + "url": "https://{Bucket}.s3.{Region}.{partitionResult#dnsSuffix}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [], + "error": "Invalid region: region was not a valid DNS name.", + "type": "error" + } + ], + "type": "tree" + } + ], + "type": "tree" + }, + { + "conditions": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "Endpoint" + } + ] + }, + { + "fn": "parseURL", + "argv": [ + { + "ref": "Endpoint" + } + ], + "assign": "url" + }, + { + "fn": "stringEquals", + "argv": [ + { + "fn": "getAttr", + "argv": [ + { + "ref": "url" + }, + "scheme" + ] + }, + "http" + ] + }, + { + "fn": "aws.isVirtualHostableS3Bucket", + "argv": [ + { + "ref": "Bucket" + }, + true + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "ForcePathStyle" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseFIPS" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + false + ] + }, + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "Accelerate" + }, + false + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "aws.partition", + "argv": [ + { + "ref": "Region" + } + ], + "assign": "partitionResult" + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "isValidHostLabel", + "argv": [ + { + "ref": "Region" + }, + false + ] + } + ], + "rules": [ + { + "conditions": [], + "endpoint": { + "url": "{url#scheme}://{Bucket}.{url#authority}{url#path}", + "properties": { + "authSchemes": [ + { + "disableDoubleEncoding": true, + "name": "sigv4", + "signingName": "s3", + "signingRegion": "{Region}" + } + ] + }, + "headers": {} + }, + "type": "endpoint" + } + ], + "type": "tree" + }, + { + "conditions": [], + "error": "Invalid region: region was not a valid DNS name.", + "type": "error" + } + ], + "type": "tree" + } + ], + "type": "tree" + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "ForcePathStyle" + }, + false + ] + }, + { + "fn": "aws.parseArn", + "argv": [ + { + "ref": "Bucket" + } + ], + "assign": "bucketArn" + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "getAttr", + "argv": [ + { + "ref": "bucketArn" + }, + "resourceId[0]" + ], + "assign": "arnType" + }, + { + "fn": "not", + "argv": [ + { + "fn": "stringEquals", + "argv": [ + { + "ref": "arnType" + }, + "" + ] + } + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "stringEquals", + "argv": [ + { + "fn": "getAttr", + "argv": [ + { + "ref": "bucketArn" + }, + "service" + ] + }, + "s3-object-lambda" + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "stringEquals", + "argv": [ + { + "ref": "arnType" + }, + "accesspoint" + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "getAttr", + "argv": [ + { + "ref": "bucketArn" + }, + "resourceId[1]" + ], + "assign": "accessPointName" + }, + { + "fn": "not", + "argv": [ + { + "fn": "stringEquals", + "argv": [ + { + "ref": "accessPointName" + }, + "" + ] + } + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "UseDualStack" + }, + true + ] + } + ], + "error": "S3 Object Lambda does not support Dual-stack", + "type": "error" + }, + { + "conditions": [ + { + "fn": "booleanEquals", + "argv": [ + { + "ref": "Accelerate" + }, + true + ] + } + ], + "error": "S3 Object Lambda does not support S3 Accelerate", + "type": "error" + }, + { + "conditions": [ + { + "fn": "not", + "argv": [ + { + "fn": "stringEquals", + "argv": [ + { + "fn": "getAttr", + "argv": [ + { + "ref": "bucketArn" + }, + "region" + ] + }, + "" + ] + } + ] + } + ], + "rules": [ + { + "conditions": [ + { + "fn": "isSet", + "argv": [ + { + "ref": "DisableAccessPoints" + } ] }, { @@ -3722,7 +4690,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -3785,7 +4752,6 @@ "assign": "bucketPartition" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -3799,7 +4765,6 @@ "assign": "partitionResult" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -3827,7 +4792,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -3847,7 +4811,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -3888,7 +4851,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -3902,7 +4864,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -3986,67 +4947,78 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: The access point name may only contain a-z, A-Z, 0-9 and `-`. Found: `{accessPointName}`", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `{bucketArn#accountId}`", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid region in ARN: `{bucketArn#region}` (invalid DNS name)", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Client was configured for partition `{partitionResult#name}` but ARN (`{Bucket}`) has `{bucketPartition#name}`", "type": "error" } - ] + ], + "type": "tree" } - ] + ], + "type": "tree" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: The ARN may only contain a single resource component after `accesspoint`.", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: bucket ARN is missing a region", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: Expected a resource of the format `accesspoint:` but no name was provided", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: Object Lambda ARNs only support `accesspoint` arn types, but found: `{arnType}`", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -4060,7 +5032,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4089,7 +5060,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4114,7 +5084,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4128,7 +5097,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4153,7 +5121,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4200,7 +5167,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4263,7 +5229,6 @@ "assign": "bucketPartition" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4277,7 +5242,6 @@ "assign": "partitionResult" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4297,7 +5261,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4317,7 +5280,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4337,7 +5299,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4357,7 +5318,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4371,7 +5331,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4590,57 +5549,68 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: The access point name may only contain a-z, A-Z, 0-9 and `-`. Found: `{accessPointName}`", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `{bucketArn#accountId}`", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: The ARN was not for the S3 service, found: {bucketArn#service}", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid region in ARN: `{bucketArn#region}` (invalid DNS name)", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Client was configured for partition `{partitionResult#name}` but ARN (`{Bucket}`) has `{bucketPartition#name}`", "type": "error" } - ] + ], + "type": "tree" } - ] + ], + "type": "tree" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: The ARN may only contain a single resource component after `accesspoint`.", "type": "error" } - ] + ], + "type": "tree" } - ] + ], + "type": "tree" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -4654,7 +5624,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4728,7 +5697,6 @@ "assign": "mrapPartition" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4756,7 +5724,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [], @@ -4778,30 +5745,35 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Client was configured for partition `{mrapPartition#name}` but bucket referred to partition `{bucketArn#partition}`", "type": "error" } - ] + ], + "type": "tree" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid Access Point Name", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: Expected a resource of the format `accesspoint:` but no name was provided", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -4821,7 +5793,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4901,7 +5872,6 @@ "assign": "outpostId" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4915,7 +5885,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4978,7 +5947,6 @@ "assign": "bucketPartition" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -4992,7 +5960,6 @@ "assign": "partitionResult" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -5020,7 +5987,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -5040,7 +6006,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -5060,7 +6025,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -5075,7 +6039,6 @@ "assign": "outpostType" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -5090,7 +6053,6 @@ "assign": "accessPointName" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -5104,7 +6066,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -5160,81 +6121,94 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Expected an outpost type `accesspoint`, found {outpostType}", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: expected an access point name", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: Expected a 4-component resource", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `{bucketArn#accountId}`", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid region in ARN: `{bucketArn#region}` (invalid DNS name)", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Client was configured for partition `{partitionResult#name}` but ARN (`{Bucket}`) has `{bucketPartition#name}`", "type": "error" } - ] + ], + "type": "tree" } - ] + ], + "type": "tree" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: The outpost Id may only contain a-z, A-Z, 0-9 and `-`. Found: `{outpostId}`", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: The Outpost Id was not set", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: Unrecognized format: {Bucket} (type: {arnType})", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid ARN: No ARN type specified", "type": "error" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -5316,7 +6290,6 @@ "assign": "uri_encoded_bucket" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -5330,7 +6303,6 @@ "assign": "partitionResult" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -5344,7 +6316,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -5462,7 +6433,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [], @@ -5482,7 +6452,8 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -5673,7 +6644,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [], @@ -5693,7 +6663,8 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -5884,7 +6855,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [], @@ -5904,7 +6874,8 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -6103,7 +7074,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -6151,7 +7121,8 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -6346,7 +7317,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -6394,7 +7364,8 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -6469,18 +7440,22 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Path-style addressing cannot be used with S3 Accelerate", "type": "error" } - ] + ], + "type": "tree" } - ] + ], + "type": "tree" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -6502,7 +7477,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -6516,7 +7490,6 @@ "assign": "partitionResult" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -6530,7 +7503,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -6644,16 +7616,19 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid region: region was not a valid DNS name.", "type": "error" } - ] + ], + "type": "tree" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -6671,7 +7646,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -6685,7 +7659,6 @@ "assign": "partitionResult" } ], - "type": "tree", "rules": [ { "conditions": [ @@ -6699,7 +7672,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -6817,7 +7789,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [], @@ -6837,7 +7808,8 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -7028,7 +8000,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [], @@ -7048,7 +8019,8 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -7239,7 +8211,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [], @@ -7259,7 +8230,8 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -7458,7 +8430,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -7506,7 +8477,8 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -7701,7 +8673,6 @@ ] } ], - "type": "tree", "rules": [ { "conditions": [ @@ -7749,7 +8720,8 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [ @@ -7824,167 +8796,731 @@ }, "type": "endpoint" } - ] + ], + "type": "tree" }, { "conditions": [], "error": "Invalid region: region was not a valid DNS name.", "type": "error" } - ] + ], + "type": "tree" } - ] + ], + "type": "tree" + } + ], + "type": "tree" + }, + { + "conditions": [], + "error": "A region must be set when sending requests to S3.", + "type": "error" + } + ] + }, + "smithy.rules#endpointTests": { + "testCases": [ + { + "documentation": "region is not a valid DNS-suffix", + "expect": { + "error": "Invalid region: region was not a valid DNS name." + }, + "params": { + "Region": "a b", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false + } + }, + { + "documentation": "Invalid access point ARN: Not S3", + "expect": { + "error": "Invalid ARN: The ARN was not for the S3 service, found: not-s3" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:not-s3:us-west-2:123456789012:accesspoint:myendpoint", + "Key": "key" + } + } + ], + "params": { + "Region": "us-east-1", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false, + "Bucket": "arn:aws:not-s3:us-west-2:123456789012:accesspoint:myendpoint" + } + }, + { + "documentation": "Invalid access point ARN: invalid resource", + "expect": { + "error": "Invalid ARN: The ARN may only contain a single resource component after `accesspoint`." + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint:more-data", + "Key": "key" + } + } + ], + "params": { + "Region": "us-east-1", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false, + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint:more-data" + } + }, + { + "documentation": "Invalid access point ARN: invalid no ap name", + "expect": { + "error": "Invalid ARN: Expected a resource of the format `accesspoint:` but no name was provided" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:", + "Key": "key" + } + } + ], + "params": { + "Region": "us-east-1", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false, + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:" + } + }, + { + "documentation": "Invalid access point ARN: AccountId is invalid", + "expect": { + "error": "Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `123456_789012`" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3:us-west-2:123456_789012:accesspoint:apname", + "Key": "key" + } + } + ], + "params": { + "Region": "us-east-1", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false, + "Bucket": "arn:aws:s3:us-west-2:123456_789012:accesspoint:apname" + } + }, + { + "documentation": "Invalid access point ARN: access point name is invalid", + "expect": { + "error": "Invalid ARN: The access point name may only contain a-z, A-Z, 0-9 and `-`. Found: `ap_name`" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:ap_name", + "Key": "key" + } + } + ], + "params": { + "Region": "us-east-1", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false, + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:ap_name" + } + }, + { + "documentation": "Access points (disable access points explicitly false)", + "expect": { + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "us-west-2", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://myendpoint-123456789012.s3-accesspoint.us-west-2.amazonaws.com" + } + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "Key": "key" + } + } + ], + "params": { + "Region": "us-east-1", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false, + "DisableAccessPoints": false, + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint" + } + }, + { + "documentation": "Access points: partition does not support FIPS", + "expect": { + "error": "Partition does not support FIPS" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "cn-north-1", + "AWS::UseFIPS": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "Key": "key" + } + } + ], + "params": { + "Region": "cn-north-1", + "UseFIPS": true, + "UseDualStack": false, + "Accelerate": false, + "Bucket": "arn:aws:s3:cn-north-1:123456789012:accesspoint:myendpoint" + } + }, + { + "documentation": "Bucket region is invalid", + "expect": { + "error": "Invalid region in ARN: `us-west -2` (invalid DNS name)" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3:us-west -2:123456789012:accesspoint:myendpoint", + "Key": "key" + } + } + ], + "params": { + "Region": "us-east-1", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false, + "DisableAccessPoints": false, + "Bucket": "arn:aws:s3:us-west -2:123456789012:accesspoint:myendpoint" + } + }, + { + "documentation": "Access points when Access points explicitly disabled (used for CreateBucket)", + "expect": { + "error": "Access points are not supported for this operation" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1" + }, + "operationName": "CreateBucket", + "operationParams": { + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint" + } } - ] + ], + "params": { + "Region": "us-east-1", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false, + "DisableAccessPoints": true, + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint" + } }, { - "conditions": [], - "error": "A region must be set when sending requests to S3.", - "type": "error" - } - ] - }, - "smithy.rules#endpointTests": { - "testCases": [ + "documentation": "missing arn type", + "expect": { + "error": "Invalid ARN: `arn:aws:s3:us-west-2:123456789012:` was not a valid ARN" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3:us-west-2:123456789012:", + "Key": "key" + } + } + ], + "params": { + "Region": "us-east-1", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false, + "DisableAccessPoints": true, + "Bucket": "arn:aws:s3:us-west-2:123456789012:" + } + }, + { + "documentation": "SDK::Host + access point + Dualstack is an error", + "expect": { + "error": "Cannot set dual-stack in combination with a custom endpoint." + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "cn-north-1", + "AWS::UseDualStack": true, + "SDK::Endpoint": "https://beta.example.com" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "Key": "key" + } + } + ], + "params": { + "Accelerate": false, + "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "Endpoint": "https://beta.example.com", + "Region": "cn-north-1", + "UseDualStack": true, + "UseFIPS": false + } + }, + { + "documentation": "Access point ARN with FIPS & Dualstack", + "expect": { + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "us-west-2", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://myendpoint-123456789012.s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com" + } + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1", + "AWS::UseFIPS": true, + "AWS::UseDualStack": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "Key": "key" + } + } + ], + "params": { + "Region": "us-east-1", + "UseFIPS": true, + "UseDualStack": true, + "Accelerate": false, + "DisableAccessPoints": false, + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint" + } + }, + { + "documentation": "Access point ARN with Dualstack", + "expect": { + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "us-west-2", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://myendpoint-123456789012.s3-accesspoint.dualstack.us-west-2.amazonaws.com" + } + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1", + "AWS::UseDualStack": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "Key": "key" + } + } + ], + "params": { + "Region": "us-east-1", + "UseFIPS": false, + "UseDualStack": true, + "Accelerate": false, + "DisableAccessPoints": false, + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint" + } + }, + { + "documentation": "vanilla MRAP", + "expect": { + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4a", + "signingRegionSet": [ + "*" + ], + "signingName": "s3", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://mfzwi23gnjvgw.mrap.accesspoint.s3-global.amazonaws.com" + } + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Key": "key" + } + } + ], + "params": { + "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Region": "us-east-1", + "DisableMultiRegionAccessPoints": false, + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false + } + }, + { + "documentation": "MRAP does not support FIPS", + "expect": { + "error": "S3 MRAP does not support FIPS" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1", + "AWS::UseFIPS": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Key": "key" + } + } + ], + "params": { + "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Region": "us-east-1", + "DisableMultiRegionAccessPoints": false, + "UseFIPS": true, + "UseDualStack": false, + "Accelerate": false + } + }, + { + "documentation": "MRAP does not support DualStack", + "expect": { + "error": "S3 MRAP does not support dual-stack" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1", + "AWS::UseDualStack": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Key": "key" + } + } + ], + "params": { + "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Region": "us-east-1", + "DisableMultiRegionAccessPoints": false, + "UseFIPS": false, + "UseDualStack": true, + "Accelerate": false + } + }, { - "documentation": "region is not a valid DNS-suffix", + "documentation": "MRAP does not support S3 Accelerate", "expect": { - "error": "Invalid region: region was not a valid DNS name." + "error": "S3 MRAP does not support S3 Accelerate" }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1", + "AWS::S3::Accelerate": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Key": "key" + } + } + ], "params": { - "Region": "a b", + "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Region": "us-east-1", + "DisableMultiRegionAccessPoints": false, "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": true } }, { - "documentation": "Invalid access point ARN: Not S3", + "documentation": "MRAP explicitly disabled", "expect": { - "error": "Invalid ARN: The ARN was not for the S3 service, found: not-s3" + "error": "Invalid configuration: Multi-Region Access Point ARNs are disabled." }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1" + "AWS::Region": "us-east-1", + "AWS::S3::DisableMultiRegionAccessPoints": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:not-s3:us-west-2:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", "Key": "key" } } ], "params": { + "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", "Region": "us-east-1", + "DisableMultiRegionAccessPoints": true, "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "Bucket": "arn:aws:not-s3:us-west-2:123456789012:accesspoint:myendpoint" + "Accelerate": false } }, { - "documentation": "Invalid access point ARN: invalid resource", + "documentation": "Dual-stack endpoint with path-style forced", "expect": { - "error": "Invalid ARN: The ARN may only contain a single resource component after `accesspoint`." + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "us-west-2", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://s3.dualstack.us-west-2.amazonaws.com/bucketname" + } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1" + "AWS::Region": "us-west-2", + "AWS::UseDualStack": true, + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint:more-data", + "Bucket": "bucketname", "Key": "key" } } ], "params": { - "Region": "us-east-1", + "Bucket": "bucketname", + "Region": "us-west-2", + "ForcePathStyle": true, "UseFIPS": false, - "UseDualStack": false, "Accelerate": false, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint:more-data" + "UseDualStack": true } }, { - "documentation": "Invalid access point ARN: invalid no ap name", + "documentation": "Dual-stack endpoint + SDK::Host is error", "expect": { - "error": "Invalid ARN: Expected a resource of the format `accesspoint:` but no name was provided" + "error": "Cannot set dual-stack in combination with a custom endpoint." }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1" + "AWS::Region": "us-west-2", + "AWS::UseDualStack": true, + "SDK::Endpoint": "https://abc.com", + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:", + "Bucket": "bucketname", "Key": "key" } } ], "params": { - "Region": "us-east-1", + "Bucket": "bucketname", + "Region": "us-west-2", + "ForcePathStyle": true, "UseFIPS": false, - "UseDualStack": false, "Accelerate": false, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:" + "UseDualStack": true, + "Endpoint": "https://abc.com" } }, { - "documentation": "Invalid access point ARN: AccountId is invalid", + "documentation": "path style + ARN bucket", "expect": { - "error": "Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `123456_789012`" + "error": "Path-style addressing cannot be used with ARN buckets" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1" + "AWS::Region": "us-west-2", + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456_789012:accesspoint:apname", + "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", "Key": "key" } } ], "params": { - "Region": "us-east-1", - "UseFIPS": false, + "Accelerate": false, + "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "ForcePathStyle": true, + "Region": "us-west-2", "UseDualStack": false, + "UseFIPS": false + } + }, + { + "documentation": "implicit path style bucket + dualstack", + "expect": { + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "us-west-2", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://s3.dualstack.us-west-2.amazonaws.com/99_ab" + } + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "AWS::UseDualStack": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "99_ab", + "Key": "key" + } + } + ], + "params": { "Accelerate": false, - "Bucket": "arn:aws:s3:us-west-2:123456_789012:accesspoint:apname" + "Bucket": "99_ab", + "Region": "us-west-2", + "UseDualStack": true, + "UseFIPS": false } }, { - "documentation": "Invalid access point ARN: access point name is invalid", + "documentation": "implicit path style bucket + dualstack", "expect": { - "error": "Invalid ARN: The access point name may only contain a-z, A-Z, 0-9 and `-`. Found: `ap_name`" + "error": "Cannot set dual-stack in combination with a custom endpoint." }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1" + "AWS::Region": "us-west-2", + "AWS::UseDualStack": true, + "SDK::Endpoint": "http://abc.com" }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:ap_name", + "Bucket": "99_ab", "Key": "key" } } ], "params": { - "Region": "us-east-1", - "UseFIPS": false, - "UseDualStack": false, "Accelerate": false, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:ap_name" + "Bucket": "99_ab", + "Region": "us-west-2", + "UseDualStack": true, + "UseFIPS": false, + "Endpoint": "http://abc.com" } }, { - "documentation": "Access points (disable access points explicitly false)", + "documentation": "don't allow URL injections in the bucket", "expect": { "endpoint": { "properties": { @@ -7997,164 +9533,240 @@ } ] }, - "url": "https://myendpoint-123456789012.s3-accesspoint.us-west-2.amazonaws.com" + "url": "https://s3.us-west-2.amazonaws.com/example.com%23" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1" + "AWS::Region": "us-west-2" }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "Bucket": "example.com#", "Key": "key" } } ], "params": { - "Region": "us-east-1", - "UseFIPS": false, + "Bucket": "example.com#", + "Region": "us-west-2", "UseDualStack": false, - "Accelerate": false, - "DisableAccessPoints": false, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint" + "UseFIPS": false, + "Accelerate": false } }, { - "documentation": "Access points: partition does not support FIPS", + "documentation": "URI encode bucket names in the path", "expect": { - "error": "Partition does not support FIPS" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "us-west-2", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://s3.us-west-2.amazonaws.com/bucket%20name" + } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1", - "AWS::UseFIPS": true + "AWS::Region": "us-west-2" }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "Bucket": "bucket name", "Key": "key" } } ], "params": { - "Region": "cn-north-1", - "UseFIPS": true, + "Bucket": "bucket name", + "Region": "us-west-2", + "UseDualStack": false, + "UseFIPS": false, + "Accelerate": false + } + }, + { + "documentation": "scheme is respected", + "expect": { + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "af-south-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/99_ab" + } + }, + "params": { + "Accelerate": false, + "Bucket": "99_ab", + "Endpoint": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", + "Region": "af-south-1", "UseDualStack": false, + "UseFIPS": false + } + }, + { + "documentation": "scheme is respected (virtual addressing)", + "expect": { + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "af-south-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "http://bucketname.control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/foo" + } + }, + "params": { "Accelerate": false, - "Bucket": "arn:aws:s3:cn-north-1:123456789012:accesspoint:myendpoint" + "Bucket": "bucketname", + "Endpoint": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/foo", + "Region": "af-south-1", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "Bucket region is invalid", + "documentation": "path style + implicit private link", "expect": { - "error": "Invalid region in ARN: `us-west -2` (invalid DNS name)" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "af-south-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/99_ab" + } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1" + "AWS::Region": "af-south-1", + "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:us-west -2:123456789012:accesspoint:myendpoint", + "Bucket": "99_ab", "Key": "key" } } ], "params": { - "Region": "us-east-1", - "UseFIPS": false, - "UseDualStack": false, "Accelerate": false, - "DisableAccessPoints": false, - "Bucket": "arn:aws:s3:us-west -2:123456789012:accesspoint:myendpoint" + "Bucket": "99_ab", + "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", + "Region": "af-south-1", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "Access points when Access points explicitly disabled (used for CreateBucket)", + "documentation": "invalid Endpoint override", "expect": { - "error": "Access points are not supported for this operation" + "error": "Custom endpoint `abcde://nota#url` was not a valid URI" }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-east-1" - }, - "operationName": "CreateBucket", - "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint" - } - } - ], "params": { - "Region": "us-east-1", - "UseFIPS": false, - "UseDualStack": false, "Accelerate": false, - "DisableAccessPoints": true, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint" + "Bucket": "bucketname", + "Endpoint": "abcde://nota#url", + "Region": "af-south-1", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "missing arn type", + "documentation": "using an IPv4 address forces path style", "expect": { - "error": "Invalid ARN: `arn:aws:s3:us-west-2:123456789012:` was not a valid ARN" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "af-south-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://123.123.0.1/bucketname" + } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1" + "AWS::Region": "af-south-1", + "SDK::Endpoint": "https://123.123.0.1" }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:", + "Bucket": "bucketname", "Key": "key" } } ], "params": { - "Region": "us-east-1", - "UseFIPS": false, - "UseDualStack": false, "Accelerate": false, - "DisableAccessPoints": true, - "Bucket": "arn:aws:s3:us-west-2:123456789012:" + "Bucket": "bucketname", + "Endpoint": "https://123.123.0.1", + "Region": "af-south-1", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "SDK::Host + access point + Dualstack is an error", + "documentation": "vanilla access point arn with region mismatch and UseArnRegion=false", "expect": { - "error": "Cannot set dual-stack in combination with a custom endpoint." + "error": "Invalid configuration: region from ARN `us-east-1` does not match client region `us-west-2` and UseArnRegion is `false`" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1", - "AWS::UseDualStack": true, - "SDK::Endpoint": "https://beta.example.com" + "AWS::Region": "us-west-2", + "AWS::S3::UseArnRegion": false }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3:us-east-1:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3:us-east-1:123456789012:accesspoint:myendpoint", "ForcePathStyle": false, - "Endpoint": "https://beta.example.com", - "Region": "cn-north-1", - "UseDualStack": true, + "UseArnRegion": false, + "Region": "us-west-2", + "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "Access point ARN with FIPS & Dualstack", + "documentation": "vanilla access point arn with region mismatch and UseArnRegion unset", "expect": { "endpoint": { "properties": { @@ -8167,15 +9779,13 @@ } ] }, - "url": "https://myendpoint-123456789012.s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com" + "url": "https://myendpoint-123456789012.s3-accesspoint.us-west-2.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::UseFIPS": true, - "AWS::UseDualStack": true + "AWS::Region": "us-east-1" }, "operationName": "GetObject", "operationParams": { @@ -8185,16 +9795,16 @@ } ], "params": { - "Region": "us-east-1", - "UseFIPS": true, - "UseDualStack": true, "Accelerate": false, - "DisableAccessPoints": false, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint" + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "Region": "us-east-1", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "Access point ARN with Dualstack", + "documentation": "vanilla access point arn with region mismatch and UseArnRegion=true", "expect": { "endpoint": { "properties": { @@ -8207,14 +9817,14 @@ } ] }, - "url": "https://myendpoint-123456789012.s3-accesspoint.dualstack.us-west-2.amazonaws.com" + "url": "https://myendpoint-123456789012.s3-accesspoint.us-west-2.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-east-1", - "AWS::UseDualStack": true + "AWS::S3::UseArnRegion": true }, "operationName": "GetObject", "operationParams": { @@ -8224,31 +9834,30 @@ } ], "params": { - "Region": "us-east-1", - "UseFIPS": false, - "UseDualStack": true, "Accelerate": false, - "DisableAccessPoints": false, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint" + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "UseArnRegion": true, + "Region": "us-east-1", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "vanilla MRAP", + "documentation": "subdomains are not allowed in virtual buckets", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "name": "sigv4a", - "signingRegionSet": [ - "*" - ], + "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" } ] }, - "url": "https://mfzwi23gnjvgw.mrap.accesspoint.s3-global.amazonaws.com" + "url": "https://s3.us-east-1.amazonaws.com/bucket.name" } }, "operationInputs": [ @@ -8258,130 +9867,120 @@ }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Bucket": "bucket.name", "Key": "key" } } ], "params": { - "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", - "Region": "us-east-1", - "DisableMultiRegionAccessPoints": false, - "UseFIPS": false, - "UseDualStack": false, - "Accelerate": false + "Bucket": "bucket.name", + "Region": "us-east-1" } }, { - "documentation": "MRAP does not support FIPS", + "documentation": "bucket names with 3 characters are allowed in virtual buckets", "expect": { - "error": "S3 MRAP does not support FIPS" - }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::UseFIPS": true + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" + } + ] }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", - "Key": "key" - } + "url": "https://aaa.s3.us-east-1.amazonaws.com" } - ], - "params": { - "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", - "Region": "us-east-1", - "DisableMultiRegionAccessPoints": false, - "UseFIPS": true, - "UseDualStack": false, - "Accelerate": false - } - }, - { - "documentation": "MRAP does not support DualStack", - "expect": { - "error": "S3 MRAP does not support dual-stack" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::UseDualStack": true + "AWS::Region": "us-east-1" }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Bucket": "aaa", "Key": "key" } } ], "params": { - "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", - "Region": "us-east-1", - "DisableMultiRegionAccessPoints": false, - "UseFIPS": false, - "UseDualStack": true, - "Accelerate": false + "Bucket": "aaa", + "Region": "us-east-1" } }, { - "documentation": "MRAP does not support S3 Accelerate", + "documentation": "bucket names with fewer than 3 characters are not allowed in virtual host", "expect": { - "error": "S3 MRAP does not support S3 Accelerate" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" + } + ] + }, + "url": "https://s3.us-east-1.amazonaws.com/aa" + } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::S3::Accelerate": true + "AWS::Region": "us-east-1" }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Bucket": "aa", "Key": "key" } } ], "params": { - "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", - "Region": "us-east-1", - "DisableMultiRegionAccessPoints": false, - "UseFIPS": false, - "UseDualStack": false, - "Accelerate": true + "Bucket": "aa", + "Region": "us-east-1" } }, { - "documentation": "MRAP explicitly disabled", + "documentation": "bucket names with uppercase characters are not allowed in virtual host", "expect": { - "error": "Invalid configuration: Multi-Region Access Point ARNs are disabled." + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" + } + ] + }, + "url": "https://s3.us-east-1.amazonaws.com/BucketName" + } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::S3::DisableMultiRegionAccessPoints": true + "AWS::Region": "us-east-1" }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Bucket": "BucketName", "Key": "key" } } ], "params": { - "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", - "Region": "us-east-1", - "DisableMultiRegionAccessPoints": true, - "UseFIPS": false, - "UseDualStack": false, - "Accelerate": false + "Bucket": "BucketName", + "Region": "us-east-1" } }, { - "documentation": "Dual-stack endpoint with path-style forced", + "documentation": "subdomains are allowed in virtual buckets on http endpoints", "expect": { "endpoint": { "properties": { @@ -8389,96 +9988,112 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" } ] }, - "url": "https://s3.dualstack.us-west-2.amazonaws.com/bucketname" + "url": "http://bucket.name.example.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::UseDualStack": true, - "AWS::S3::ForcePathStyle": true + "AWS::Region": "us-east-1", + "SDK::Endpoint": "http://example.com" }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucketname", + "Bucket": "bucket.name", "Key": "key" } } ], "params": { - "Bucket": "bucketname", - "Region": "us-west-2", - "ForcePathStyle": true, - "UseFIPS": false, - "Accelerate": false, - "UseDualStack": true + "Bucket": "bucket.name", + "Region": "us-east-1", + "Endpoint": "http://example.com" } }, { - "documentation": "Dual-stack endpoint + SDK::Host is error", + "documentation": "no region set", "expect": { - "error": "Cannot set dual-stack in combination with a custom endpoint." + "error": "A region must be set when sending requests to S3." + }, + "params": { + "Bucket": "bucket-name" + } + }, + { + "documentation": "UseGlobalEndpoints=true, region=us-east-1 uses the global endpoint", + "expect": { + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "us-east-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://s3.amazonaws.com" + } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::UseDualStack": true, - "SDK::Endpoint": "https://abc.com", - "AWS::S3::ForcePathStyle": true + "AWS::Region": "us-east-1", + "AWS::S3::UseGlobalEndpoint": true }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucketname", - "Key": "key" - } + "operationName": "ListBuckets" } ], "params": { - "Bucket": "bucketname", - "Region": "us-west-2", - "ForcePathStyle": true, + "Region": "us-east-1", + "UseGlobalEndpoint": true, "UseFIPS": false, - "Accelerate": false, - "UseDualStack": true, - "Endpoint": "https://abc.com" + "UseDualStack": false, + "Accelerate": false } }, { - "documentation": "path style + ARN bucket", + "documentation": "UseGlobalEndpoints=true, region=us-west-2 uses the regional endpoint", "expect": { - "error": "Path-style addressing cannot be used with ARN buckets" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "us-west-2", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://s3.us-west-2.amazonaws.com" + } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-west-2", - "AWS::S3::ForcePathStyle": true + "AWS::S3::UseGlobalEndpoint": true }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", - "Key": "key" - } + "operationName": "ListBuckets" } ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", - "ForcePathStyle": true, "Region": "us-west-2", + "UseGlobalEndpoint": true, + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false } }, { - "documentation": "implicit path style bucket + dualstack", + "documentation": "UseGlobalEndpoints=true, region=cn-north-1 uses the regional endpoint", "expect": { "endpoint": { "properties": { @@ -8486,65 +10101,68 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", + "signingRegion": "cn-north-1", "disableDoubleEncoding": true } ] }, - "url": "https://s3.dualstack.us-west-2.amazonaws.com/99_ab" + "url": "https://s3.cn-north-1.amazonaws.com.cn" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::UseDualStack": true + "AWS::Region": "cn-north-1", + "AWS::S3::UseGlobalEndpoint": true }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "99_ab", - "Key": "key" - } + "operationName": "ListBuckets" } ], "params": { - "Accelerate": false, - "Bucket": "99_ab", - "Region": "us-west-2", - "UseDualStack": true, - "UseFIPS": false + "Region": "cn-north-1", + "UseGlobalEndpoint": true, + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false } }, { - "documentation": "implicit path style bucket + dualstack", + "documentation": "UseGlobalEndpoints=true, region=us-east-1, fips=true uses the regional endpoint with fips", "expect": { - "error": "Cannot set dual-stack in combination with a custom endpoint." + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "us-east-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://s3-fips.us-east-1.amazonaws.com" + } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::UseDualStack": true, - "SDK::Endpoint": "http://abc.com" + "AWS::Region": "us-east-1", + "AWS::UseFIPS": true, + "AWS::S3::UseGlobalEndpoint": true }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "99_ab", - "Key": "key" - } + "operationName": "ListBuckets" } ], "params": { - "Accelerate": false, - "Bucket": "99_ab", - "Region": "us-west-2", - "UseDualStack": true, - "UseFIPS": false, - "Endpoint": "http://abc.com" + "Region": "us-east-1", + "UseGlobalEndpoint": true, + "UseFIPS": true, + "UseDualStack": false, + "Accelerate": false } }, { - "documentation": "don't allow URL injections in the bucket", + "documentation": "UseGlobalEndpoints=true, region=us-east-1, dualstack=true uses the regional endpoint with dualstack", "expect": { "endpoint": { "properties": { @@ -8552,36 +10170,34 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://s3.us-west-2.amazonaws.com/example.com%23" + "url": "https://s3.dualstack.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2" + "AWS::Region": "us-east-1", + "AWS::UseDualStack": true, + "AWS::S3::UseGlobalEndpoint": true }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "example.com#", - "Key": "key" - } + "operationName": "ListBuckets" } ], "params": { - "Bucket": "example.com#", - "Region": "us-west-2", - "UseDualStack": false, + "Region": "us-east-1", + "UseGlobalEndpoint": true, "UseFIPS": false, + "UseDualStack": true, "Accelerate": false } }, { - "documentation": "URI encode bucket names in the path", + "documentation": "UseGlobalEndpoints=true, region=us-east-1, dualstack and fips uses the regional endpoint with fips/dualstack", "expect": { "endpoint": { "properties": { @@ -8589,36 +10205,35 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://s3.us-west-2.amazonaws.com/bucket%20name" + "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2" + "AWS::Region": "us-east-1", + "AWS::UseFIPS": true, + "AWS::UseDualStack": true, + "AWS::S3::UseGlobalEndpoint": true }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket name", - "Key": "key" - } + "operationName": "ListBuckets" } ], "params": { - "Bucket": "bucket name", - "Region": "us-west-2", - "UseDualStack": false, - "UseFIPS": false, + "Region": "us-east-1", + "UseGlobalEndpoint": true, + "UseFIPS": true, + "UseDualStack": true, "Accelerate": false } }, { - "documentation": "scheme is respected", + "documentation": "UseGlobalEndpoints=true, region=us-east-1 with custom endpoint, uses custom", "expect": { "endpoint": { "properties": { @@ -8626,25 +10241,35 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "af-south-1", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/99_ab" + "url": "https://example.com" } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1", + "SDK::Endpoint": "https://example.com", + "AWS::S3::UseGlobalEndpoint": true + }, + "operationName": "ListBuckets" + } + ], "params": { - "Accelerate": false, - "Bucket": "99_ab", - "Endpoint": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "af-south-1", + "Region": "us-east-1", + "Endpoint": "https://example.com", + "UseGlobalEndpoint": true, + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false } }, { - "documentation": "scheme is respected (virtual addressing)", + "documentation": "UseGlobalEndpoints=true, region=us-west-2 with custom endpoint, uses custom", "expect": { "endpoint": { "properties": { @@ -8652,25 +10277,35 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "af-south-1", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "http://bucketname.control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/foo" + "url": "https://example.com" } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "SDK::Endpoint": "https://example.com", + "AWS::S3::UseGlobalEndpoint": true + }, + "operationName": "ListBuckets" + } + ], "params": { - "Accelerate": false, - "Bucket": "bucketname", - "Endpoint": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/foo", - "Region": "af-south-1", + "Region": "us-west-2", + "Endpoint": "https://example.com", + "UseGlobalEndpoint": true, + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false } }, { - "documentation": "path style + implicit private link", + "documentation": "UseGlobalEndpoints=true, region=us-east-1 with accelerate on non bucket case uses the global endpoint and ignores accelerate", "expect": { "endpoint": { "properties": { @@ -8678,52 +10313,34 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "af-south-1", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/99_ab" + "url": "https://s3.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" + "AWS::Region": "us-east-1", + "AWS::S3::Accelerate": true, + "AWS::S3::UseGlobalEndpoint": true }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "99_ab", - "Key": "key" - } + "operationName": "ListBuckets" } ], "params": { - "Accelerate": false, - "Bucket": "99_ab", - "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "af-south-1", - "UseDualStack": false, - "UseFIPS": false - } - }, - { - "documentation": "invalid Endpoint override", - "expect": { - "error": "Custom endpoint `abcde://nota#url` was not a valid URI" - }, - "params": { - "Accelerate": false, - "Bucket": "bucketname", - "Endpoint": "abcde://nota#url", - "Region": "af-south-1", + "Region": "us-east-1", + "UseGlobalEndpoint": true, + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": true } }, { - "documentation": "using an IPv4 address forces path style", + "documentation": "aws-global region uses the global endpoint", "expect": { "endpoint": { "properties": { @@ -8731,66 +10348,31 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "af-south-1", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://123.123.0.1/bucketname" - } - }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "af-south-1", - "SDK::Endpoint": "https://123.123.0.1" - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucketname", - "Key": "key" - } + "url": "https://s3.amazonaws.com" } - ], - "params": { - "Accelerate": false, - "Bucket": "bucketname", - "Endpoint": "https://123.123.0.1", - "Region": "af-south-1", - "UseDualStack": false, - "UseFIPS": false - } - }, - { - "documentation": "vanilla access point arn with region mismatch and UseArnRegion=false", - "expect": { - "error": "Invalid configuration: region from ARN `us-east-1` does not match client region `us-west-2` and UseArnRegion is `false`" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::S3::UseArnRegion": false + "AWS::Region": "aws-global" }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3:us-east-1:123456789012:accesspoint:myendpoint", - "Key": "key" - } + "operationName": "ListBuckets" } ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3:us-east-1:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, - "UseArnRegion": false, - "Region": "us-west-2", + "Region": "aws-global", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false } }, { - "documentation": "vanilla access point arn with region mismatch and UseArnRegion unset", + "documentation": "aws-global region with fips uses the regional endpoint", "expect": { "endpoint": { "properties": { @@ -8798,37 +10380,32 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://myendpoint-123456789012.s3-accesspoint.us-west-2.amazonaws.com" + "url": "https://s3-fips.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1" + "AWS::Region": "aws-global", + "AWS::UseFIPS": true }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", - "Key": "key" - } + "operationName": "ListBuckets" } ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, - "Region": "us-east-1", + "Region": "aws-global", + "UseFIPS": true, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false } }, { - "documentation": "vanilla access point arn with region mismatch and UseArnRegion=true", + "documentation": "aws-global region with dualstack uses the regional endpoint", "expect": { "endpoint": { "properties": { @@ -8836,39 +10413,32 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://myendpoint-123456789012.s3-accesspoint.us-west-2.amazonaws.com" + "url": "https://s3.dualstack.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::S3::UseArnRegion": true + "AWS::Region": "aws-global", + "AWS::UseDualStack": true }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", - "Key": "key" - } + "operationName": "ListBuckets" } ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, - "UseArnRegion": true, - "Region": "us-east-1", - "UseDualStack": false, - "UseFIPS": false + "Region": "aws-global", + "UseFIPS": false, + "UseDualStack": true, + "Accelerate": false } }, { - "documentation": "subdomains are not allowed in virtual buckets", + "documentation": "aws-global region with fips and dualstack uses the regional endpoint", "expect": { "endpoint": { "properties": { @@ -8876,33 +10446,33 @@ { "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "signingRegion": "us-east-1", + "disableDoubleEncoding": true } ] }, - "url": "https://s3.us-east-1.amazonaws.com/bucket.name" + "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1" + "AWS::Region": "aws-global", + "AWS::UseFIPS": true, + "AWS::UseDualStack": true }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket.name", - "Key": "key" - } + "operationName": "ListBuckets" } ], "params": { - "Bucket": "bucket.name", - "Region": "us-east-1" + "Region": "aws-global", + "UseFIPS": true, + "UseDualStack": true, + "Accelerate": false } }, { - "documentation": "bucket names with 3 characters are allowed in virtual buckets", + "documentation": "aws-global region with accelerate on non-bucket case, uses global endpoint and ignores accelerate", "expect": { "endpoint": { "properties": { @@ -8910,33 +10480,32 @@ { "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "signingRegion": "us-east-1", + "disableDoubleEncoding": true } ] }, - "url": "https://aaa.s3.us-east-1.amazonaws.com" + "url": "https://s3.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1" + "AWS::Region": "aws-global", + "AWS::S3::Accelerate": true }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "aaa", - "Key": "key" - } + "operationName": "ListBuckets" } ], "params": { - "Bucket": "aaa", - "Region": "us-east-1" + "Region": "aws-global", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": true } }, { - "documentation": "bucket names with fewer than 3 characters are not allowed in virtual host", + "documentation": "aws-global region with custom endpoint, uses custom", "expect": { "endpoint": { "properties": { @@ -8944,33 +10513,34 @@ { "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "signingRegion": "us-east-1", + "disableDoubleEncoding": true } ] }, - "url": "https://s3.us-east-1.amazonaws.com/aa" + "url": "https://example.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1" + "AWS::Region": "aws-global", + "SDK::Endpoint": "https://example.com" }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "aa", - "Key": "key" - } + "operationName": "ListBuckets" } ], "params": { - "Bucket": "aa", - "Region": "us-east-1" + "Region": "aws-global", + "Endpoint": "https://example.com", + "UseGlobalEndpoint": false, + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false } }, { - "documentation": "bucket names with uppercase characters are not allowed in virtual host", + "documentation": "virtual addressing, aws-global region uses the global endpoint", "expect": { "endpoint": { "properties": { @@ -8978,33 +10548,36 @@ { "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "signingRegion": "us-east-1", + "disableDoubleEncoding": true } ] }, - "url": "https://s3.us-east-1.amazonaws.com/BucketName" + "url": "https://bucket-name.s3.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1" + "AWS::Region": "aws-global" }, "operationName": "GetObject", "operationParams": { - "Bucket": "BucketName", + "Bucket": "bucket-name", "Key": "key" } } ], "params": { - "Bucket": "BucketName", - "Region": "us-east-1" + "Region": "aws-global", + "Bucket": "bucket-name", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false } }, { - "documentation": "subdomains are allowed in virtual buckets on http endpoints", + "documentation": "virtual addressing, aws-global region with Prefix, and Key uses the global endpoint. Prefix and Key parameters should not be used in endpoint evaluation.", "expect": { "endpoint": { "properties": { @@ -9012,44 +10585,38 @@ { "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "signingRegion": "us-east-1", + "disableDoubleEncoding": true } ] }, - "url": "http://bucket.name.example.com" + "url": "https://bucket-name.s3.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1", - "SDK::Endpoint": "http://example.com" + "AWS::Region": "aws-global" }, - "operationName": "GetObject", + "operationName": "ListObjects", "operationParams": { - "Bucket": "bucket.name", - "Key": "key" + "Bucket": "bucket-name", + "Prefix": "prefix" } } ], "params": { - "Bucket": "bucket.name", - "Region": "us-east-1", - "Endpoint": "http://example.com" - } - }, - { - "documentation": "no region set", - "expect": { - "error": "A region must be set when sending requests to S3." - }, - "params": { - "Bucket": "bucket-name" + "Region": "aws-global", + "Bucket": "bucket-name", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false, + "Prefix": "prefix", + "Key": "key" } }, { - "documentation": "UseGlobalEndpoints=true, region=us-east-1 uses the global endpoint", + "documentation": "virtual addressing, aws-global region with fips uses the regional fips endpoint", "expect": { "endpoint": { "properties": { @@ -9062,28 +10629,32 @@ } ] }, - "url": "https://s3.amazonaws.com" + "url": "https://bucket-name.s3-fips.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::S3::UseGlobalEndpoint": true + "AWS::Region": "aws-global", + "AWS::UseFIPS": true }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { - "Region": "us-east-1", - "UseGlobalEndpoint": true, - "UseFIPS": false, + "Region": "aws-global", + "Bucket": "bucket-name", + "UseFIPS": true, "UseDualStack": false, "Accelerate": false } }, { - "documentation": "UseGlobalEndpoints=true, region=us-west-2 uses the regional endpoint", + "documentation": "virtual addressing, aws-global region with dualstack uses the regional dualstack endpoint", "expect": { "endpoint": { "properties": { @@ -9091,33 +10662,37 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://s3.us-west-2.amazonaws.com" + "url": "https://bucket-name.s3.dualstack.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::S3::UseGlobalEndpoint": true + "AWS::Region": "aws-global", + "AWS::UseDualStack": true }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { - "Region": "us-west-2", - "UseGlobalEndpoint": true, + "Region": "aws-global", + "Bucket": "bucket-name", "UseFIPS": false, - "UseDualStack": false, + "UseDualStack": true, "Accelerate": false } }, { - "documentation": "UseGlobalEndpoints=true, region=cn-north-1 uses the regional endpoint", + "documentation": "virtual addressing, aws-global region with fips/dualstack uses the regional fips/dualstack endpoint", "expect": { "endpoint": { "properties": { @@ -9125,33 +10700,38 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "cn-north-1", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://s3.cn-north-1.amazonaws.com.cn" + "url": "https://bucket-name.s3-fips.dualstack.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1", - "AWS::S3::UseGlobalEndpoint": true + "AWS::Region": "aws-global", + "AWS::UseFIPS": true, + "AWS::UseDualStack": true }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { - "Region": "cn-north-1", - "UseGlobalEndpoint": true, - "UseFIPS": false, - "UseDualStack": false, + "Region": "aws-global", + "Bucket": "bucket-name", + "UseFIPS": true, + "UseDualStack": true, "Accelerate": false } }, { - "documentation": "UseGlobalEndpoints=true, region=us-east-1, fips=true uses the regional endpoint with fips", + "documentation": "virtual addressing, aws-global region with accelerate uses the global accelerate endpoint", "expect": { "endpoint": { "properties": { @@ -9164,29 +10744,32 @@ } ] }, - "url": "https://s3-fips.us-east-1.amazonaws.com" + "url": "https://bucket-name.s3-accelerate.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::UseFIPS": true, - "AWS::S3::UseGlobalEndpoint": true + "AWS::Region": "aws-global", + "AWS::S3::Accelerate": true }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { - "Region": "us-east-1", - "UseGlobalEndpoint": true, - "UseFIPS": true, + "Region": "aws-global", + "Bucket": "bucket-name", + "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": true } }, { - "documentation": "UseGlobalEndpoints=true, region=us-east-1, dualstack=true uses the regional endpoint with dualstack", + "documentation": "virtual addressing, aws-global region with custom endpoint", "expect": { "endpoint": { "properties": { @@ -9199,29 +10782,33 @@ } ] }, - "url": "https://s3.dualstack.us-east-1.amazonaws.com" + "url": "https://bucket-name.example.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::UseDualStack": true, - "AWS::S3::UseGlobalEndpoint": true + "AWS::Region": "aws-global", + "SDK::Endpoint": "https://example.com" }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { - "Region": "us-east-1", - "UseGlobalEndpoint": true, + "Region": "aws-global", + "Endpoint": "https://example.com", + "Bucket": "bucket-name", "UseFIPS": false, - "UseDualStack": true, + "UseDualStack": false, "Accelerate": false } }, { - "documentation": "UseGlobalEndpoints=true, region=us-east-1, dualstack and fips uses the regional endpoint with fips/dualstack", + "documentation": "virtual addressing, UseGlobalEndpoint and us-east-1 region uses the global endpoint", "expect": { "endpoint": { "properties": { @@ -9234,30 +10821,33 @@ } ] }, - "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com" + "url": "https://bucket-name.s3.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-east-1", - "AWS::UseFIPS": true, - "AWS::UseDualStack": true, "AWS::S3::UseGlobalEndpoint": true }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { "Region": "us-east-1", "UseGlobalEndpoint": true, - "UseFIPS": true, - "UseDualStack": true, + "Bucket": "bucket-name", + "UseFIPS": false, + "UseDualStack": false, "Accelerate": false } }, { - "documentation": "UseGlobalEndpoints=true, region=us-east-1 with custom endpoint, uses custom", + "documentation": "virtual addressing, UseGlobalEndpoint and us-west-2 region uses the regional endpoint", "expect": { "endpoint": { "properties": { @@ -9265,35 +10855,38 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://example.com" + "url": "https://bucket-name.s3.us-west-2.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1", - "SDK::Endpoint": "https://example.com", + "AWS::Region": "us-west-2", "AWS::S3::UseGlobalEndpoint": true }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { - "Region": "us-east-1", - "Endpoint": "https://example.com", + "Region": "us-west-2", "UseGlobalEndpoint": true, + "Bucket": "bucket-name", "UseFIPS": false, "UseDualStack": false, "Accelerate": false } }, { - "documentation": "UseGlobalEndpoints=true, region=us-west-2 with custom endpoint, uses custom", + "documentation": "virtual addressing, UseGlobalEndpoint and us-east-1 region and fips uses the regional fips endpoint", "expect": { "endpoint": { "properties": { @@ -9301,35 +10894,39 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://example.com" + "url": "https://bucket-name.s3-fips.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "SDK::Endpoint": "https://example.com", + "AWS::Region": "us-east-1", + "AWS::UseFIPS": true, "AWS::S3::UseGlobalEndpoint": true }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { - "Region": "us-west-2", - "Endpoint": "https://example.com", + "Region": "us-east-1", "UseGlobalEndpoint": true, - "UseFIPS": false, + "Bucket": "bucket-name", + "UseFIPS": true, "UseDualStack": false, "Accelerate": false } }, { - "documentation": "UseGlobalEndpoints=true, region=us-east-1 with accelerate on non bucket case uses the global endpoint and ignores accelerate", + "documentation": "virtual addressing, UseGlobalEndpoint and us-east-1 region and dualstack uses the regional dualstack endpoint", "expect": { "endpoint": { "properties": { @@ -9342,29 +10939,34 @@ } ] }, - "url": "https://s3.amazonaws.com" + "url": "https://bucket-name.s3.dualstack.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-east-1", - "AWS::S3::Accelerate": true, + "AWS::UseDualStack": true, "AWS::S3::UseGlobalEndpoint": true }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { "Region": "us-east-1", "UseGlobalEndpoint": true, + "Bucket": "bucket-name", "UseFIPS": false, - "UseDualStack": false, - "Accelerate": true + "UseDualStack": true, + "Accelerate": false } }, { - "documentation": "aws-global region uses the global endpoint", + "documentation": "virtual addressing, UseGlobalEndpoint and us-east-1 region and accelerate uses the global accelerate endpoint", "expect": { "endpoint": { "properties": { @@ -9377,26 +10979,34 @@ } ] }, - "url": "https://s3.amazonaws.com" + "url": "https://bucket-name.s3-accelerate.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "aws-global" + "AWS::Region": "us-east-1", + "AWS::S3::Accelerate": true, + "AWS::S3::UseGlobalEndpoint": true }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { - "Region": "aws-global", + "Region": "us-east-1", + "UseGlobalEndpoint": true, + "Bucket": "bucket-name", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": true } }, { - "documentation": "aws-global region with fips uses the regional endpoint", + "documentation": "virtual addressing, UseGlobalEndpoint and us-east-1 region with custom endpoint", "expect": { "endpoint": { "properties": { @@ -9409,27 +11019,35 @@ } ] }, - "url": "https://s3-fips.us-east-1.amazonaws.com" + "url": "https://bucket-name.example.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "aws-global", - "AWS::UseFIPS": true + "AWS::Region": "us-east-1", + "SDK::Endpoint": "https://example.com", + "AWS::S3::UseGlobalEndpoint": true }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { - "Region": "aws-global", - "UseFIPS": true, + "Region": "us-east-1", + "Endpoint": "https://example.com", + "UseGlobalEndpoint": true, + "Bucket": "bucket-name", + "UseFIPS": false, "UseDualStack": false, "Accelerate": false } }, { - "documentation": "aws-global region with dualstack uses the regional endpoint", + "documentation": "ForcePathStyle, aws-global region uses the global endpoint", "expect": { "endpoint": { "properties": { @@ -9442,61 +11060,59 @@ } ] }, - "url": "https://s3.dualstack.us-east-1.amazonaws.com" + "url": "https://s3.amazonaws.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "aws-global", - "AWS::UseDualStack": true + "AWS::S3::ForcePathStyle": true }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { "Region": "aws-global", + "Bucket": "bucket-name", + "ForcePathStyle": true, "UseFIPS": false, - "UseDualStack": true, + "UseDualStack": false, "Accelerate": false } }, { - "documentation": "aws-global region with fips and dualstack uses the regional endpoint", + "documentation": "ForcePathStyle, aws-global region with fips is invalid", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "name": "sigv4", "signingName": "s3", "signingRegion": "us-east-1", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "name": "sigv4" } ] }, - "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com" + "url": "https://s3-fips.us-east-1.amazonaws.com/bucket-name" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "aws-global", - "AWS::UseFIPS": true, - "AWS::UseDualStack": true - }, - "operationName": "ListBuckets" - } - ], "params": { "Region": "aws-global", + "Bucket": "bucket-name", + "ForcePathStyle": true, "UseFIPS": true, - "UseDualStack": true, + "UseDualStack": false, "Accelerate": false } }, { - "documentation": "aws-global region with accelerate on non-bucket case, uses global endpoint and ignores accelerate", + "documentation": "ForcePathStyle, aws-global region with dualstack uses regional dualstack endpoint", "expect": { "endpoint": { "properties": { @@ -9509,27 +11125,34 @@ } ] }, - "url": "https://s3.amazonaws.com" + "url": "https://s3.dualstack.us-east-1.amazonaws.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "aws-global", - "AWS::S3::Accelerate": true + "AWS::UseDualStack": true, + "AWS::S3::ForcePathStyle": true }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { "Region": "aws-global", + "Bucket": "bucket-name", + "ForcePathStyle": true, "UseFIPS": false, - "UseDualStack": false, - "Accelerate": true + "UseDualStack": true, + "Accelerate": false } }, { - "documentation": "aws-global region with custom endpoint, uses custom", + "documentation": "ForcePathStyle, aws-global region custom endpoint uses the custom endpoint", "expect": { "endpoint": { "properties": { @@ -9542,29 +11165,35 @@ } ] }, - "url": "https://example.com" + "url": "https://example.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "aws-global", - "SDK::Endpoint": "https://example.com" + "SDK::Endpoint": "https://example.com", + "AWS::S3::ForcePathStyle": true }, - "operationName": "ListBuckets" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } ], "params": { "Region": "aws-global", "Endpoint": "https://example.com", - "UseGlobalEndpoint": false, + "Bucket": "bucket-name", + "ForcePathStyle": true, "UseFIPS": false, "UseDualStack": false, "Accelerate": false } }, { - "documentation": "virtual addressing, aws-global region uses the global endpoint", + "documentation": "ForcePathStyle, UseGlobalEndpoint us-east-1 region uses the global endpoint", "expect": { "endpoint": { "properties": { @@ -9577,13 +11206,15 @@ } ] }, - "url": "https://bucket-name.s3.amazonaws.com" + "url": "https://s3.amazonaws.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "aws-global" + "AWS::Region": "us-east-1", + "AWS::S3::ForcePathStyle": true, + "AWS::S3::UseGlobalEndpoint": true }, "operationName": "GetObject", "operationParams": { @@ -9593,15 +11224,17 @@ } ], "params": { - "Region": "aws-global", + "Region": "us-east-1", "Bucket": "bucket-name", + "UseGlobalEndpoint": true, + "ForcePathStyle": true, "UseFIPS": false, "UseDualStack": false, "Accelerate": false } }, { - "documentation": "virtual addressing, aws-global region with fips uses the regional fips endpoint", + "documentation": "ForcePathStyle, UseGlobalEndpoint us-west-2 region uses the regional endpoint", "expect": { "endpoint": { "properties": { @@ -9609,19 +11242,20 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://bucket-name.s3-fips.us-east-1.amazonaws.com" + "url": "https://s3.us-west-2.amazonaws.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "aws-global", - "AWS::UseFIPS": true + "AWS::Region": "us-west-2", + "AWS::S3::ForcePathStyle": true, + "AWS::S3::UseGlobalEndpoint": true }, "operationName": "GetObject", "operationParams": { @@ -9631,15 +11265,17 @@ } ], "params": { - "Region": "aws-global", + "Region": "us-west-2", "Bucket": "bucket-name", - "UseFIPS": true, + "UseGlobalEndpoint": true, + "ForcePathStyle": true, + "UseFIPS": false, "UseDualStack": false, "Accelerate": false } }, { - "documentation": "virtual addressing, aws-global region with dualstack uses the regional dualstack endpoint", + "documentation": "ForcePathStyle, UseGlobalEndpoint us-east-1 region, dualstack uses the regional dualstack endpoint", "expect": { "endpoint": { "properties": { @@ -9652,14 +11288,16 @@ } ] }, - "url": "https://bucket-name.s3.dualstack.us-east-1.amazonaws.com" + "url": "https://s3.dualstack.us-east-1.amazonaws.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "aws-global", - "AWS::UseDualStack": true + "AWS::Region": "us-east-1", + "AWS::UseDualStack": true, + "AWS::S3::ForcePathStyle": true, + "AWS::S3::UseGlobalEndpoint": true }, "operationName": "GetObject", "operationParams": { @@ -9669,15 +11307,17 @@ } ], "params": { - "Region": "aws-global", + "Region": "us-east-1", "Bucket": "bucket-name", + "UseGlobalEndpoint": true, + "ForcePathStyle": true, "UseFIPS": false, "UseDualStack": true, "Accelerate": false } }, { - "documentation": "virtual addressing, aws-global region with fips/dualstack uses the regional fips/dualstack endpoint", + "documentation": "ForcePathStyle, UseGlobalEndpoint us-east-1 region custom endpoint uses the custom endpoint", "expect": { "endpoint": { "properties": { @@ -9690,15 +11330,16 @@ } ] }, - "url": "https://bucket-name.s3-fips.dualstack.us-east-1.amazonaws.com" + "url": "https://example.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "aws-global", - "AWS::UseFIPS": true, - "AWS::UseDualStack": true + "AWS::Region": "us-east-1", + "SDK::Endpoint": "https://example.com", + "AWS::S3::ForcePathStyle": true, + "AWS::S3::UseGlobalEndpoint": true }, "operationName": "GetObject", "operationParams": { @@ -9708,53 +11349,79 @@ } ], "params": { - "Region": "aws-global", + "Region": "us-east-1", "Bucket": "bucket-name", - "UseFIPS": true, - "UseDualStack": true, + "Endpoint": "https://example.com", + "UseGlobalEndpoint": true, + "ForcePathStyle": true, + "UseFIPS": false, + "UseDualStack": false, "Accelerate": false } }, { - "documentation": "virtual addressing, aws-global region with accelerate uses the global accelerate endpoint", + "documentation": "ARN with aws-global region and UseArnRegion uses the regional endpoint", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3", + "signingName": "s3-outposts", "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://bucket-name.s3-accelerate.amazonaws.com" + "url": "https://reports-123456789012.op-01234567890123456.s3-outposts.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "aws-global", - "AWS::S3::Accelerate": true + "AWS::S3::UseArnRegion": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456/accesspoint/reports", "Key": "key" } } ], "params": { "Region": "aws-global", - "Bucket": "bucket-name", + "UseArnRegion": true, "UseFIPS": false, "UseDualStack": false, - "Accelerate": true + "Accelerate": false, + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456/accesspoint/reports" } }, { - "documentation": "virtual addressing, aws-global region with custom endpoint", + "documentation": "cross partition MRAP ARN is an error", + "expect": { + "error": "Client was configured for partition `aws` but bucket referred to partition `aws-cn`" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws-cn:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Key": "key" + } + } + ], + "params": { + "Bucket": "arn:aws-cn:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", + "Region": "us-west-1" + } + }, + { + "documentation": "Endpoint override, accesspoint with HTTP, port", "expect": { "endpoint": { "properties": { @@ -9762,38 +11429,97 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://bucket-name.example.com" + "url": "http://myendpoint-123456789012.beta.example.com:1234" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "aws-global", - "SDK::Endpoint": "https://example.com" + "AWS::Region": "us-west-2", + "SDK::Endpoint": "http://beta.example.com:1234" }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { - "Region": "aws-global", - "Endpoint": "https://example.com", - "Bucket": "bucket-name", + "Endpoint": "http://beta.example.com:1234", + "Region": "us-west-2", + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint" + } + }, + { + "documentation": "Endpoint override, accesspoint with http, path, query, and port", + "expect": { + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "us-west-2", + "disableDoubleEncoding": true + } + ] + }, + "url": "http://myendpoint-123456789012.beta.example.com:1234/path" + } + }, + "params": { + "Region": "us-west-2", + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "Endpoint": "http://beta.example.com:1234/path", + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false + } + }, + { + "documentation": "non-bucket endpoint override with FIPS = error", + "expect": { + "error": "A custom endpoint cannot be combined with FIPS" + }, + "params": { + "Region": "us-west-2", + "Endpoint": "http://beta.example.com:1234/path", + "UseFIPS": true, + "UseDualStack": false + } + }, + { + "documentation": "FIPS + dualstack + custom endpoint", + "expect": { + "error": "Cannot set dual-stack in combination with a custom endpoint." + }, + "params": { + "Region": "us-west-2", + "Endpoint": "http://beta.example.com:1234/path", + "UseFIPS": true, + "UseDualStack": true + } + }, + { + "documentation": "dualstack + custom endpoint", + "expect": { + "error": "Cannot set dual-stack in combination with a custom endpoint." + }, + "params": { + "Region": "us-west-2", + "Endpoint": "http://beta.example.com:1234/path", "UseFIPS": false, - "UseDualStack": false, - "Accelerate": false + "UseDualStack": true } }, { - "documentation": "virtual addressing, UseGlobalEndpoint and us-east-1 region uses the global endpoint", + "documentation": "custom endpoint without FIPS/dualstack", "expect": { "endpoint": { "properties": { @@ -9801,38 +11527,34 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://bucket-name.s3.amazonaws.com" + "url": "http://beta.example.com:1234/path" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::S3::UseGlobalEndpoint": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], "params": { - "Region": "us-east-1", - "UseGlobalEndpoint": true, - "Bucket": "bucket-name", + "Region": "us-west-2", + "Endpoint": "http://beta.example.com:1234/path", "UseFIPS": false, - "UseDualStack": false, - "Accelerate": false + "UseDualStack": false } }, { - "documentation": "virtual addressing, UseGlobalEndpoint and us-west-2 region uses the regional endpoint", + "documentation": "s3 object lambda with access points disabled", + "expect": { + "error": "Access points are not supported for this operation" + }, + "params": { + "Region": "us-west-2", + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:myendpoint", + "DisableAccessPoints": true + } + }, + { + "documentation": "non bucket + FIPS", "expect": { "endpoint": { "properties": { @@ -9845,33 +11567,17 @@ } ] }, - "url": "https://bucket-name.s3.us-west-2.amazonaws.com" + "url": "https://s3-fips.us-west-2.amazonaws.com" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::S3::UseGlobalEndpoint": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], "params": { "Region": "us-west-2", - "UseGlobalEndpoint": true, - "Bucket": "bucket-name", - "UseFIPS": false, - "UseDualStack": false, - "Accelerate": false + "UseFIPS": true, + "UseDualStack": false } }, { - "documentation": "virtual addressing, UseGlobalEndpoint and us-east-1 region and fips uses the regional fips endpoint", + "documentation": "standard non bucket endpoint", "expect": { "endpoint": { "properties": { @@ -9879,39 +11585,22 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://bucket-name.s3-fips.us-east-1.amazonaws.com" + "url": "https://s3.us-west-2.amazonaws.com" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::UseFIPS": true, - "AWS::S3::UseGlobalEndpoint": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], "params": { - "Region": "us-east-1", - "UseGlobalEndpoint": true, - "Bucket": "bucket-name", - "UseFIPS": true, - "UseDualStack": false, - "Accelerate": false + "Region": "us-west-2", + "UseFIPS": false, + "UseDualStack": false } }, { - "documentation": "virtual addressing, UseGlobalEndpoint and us-east-1 region and dualstack uses the regional dualstack endpoint", + "documentation": "non bucket endpoint with FIPS + Dualstack", "expect": { "endpoint": { "properties": { @@ -9919,39 +11608,22 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://bucket-name.s3.dualstack.us-east-1.amazonaws.com" + "url": "https://s3-fips.dualstack.us-west-2.amazonaws.com" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::UseDualStack": true, - "AWS::S3::UseGlobalEndpoint": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], "params": { - "Region": "us-east-1", - "UseGlobalEndpoint": true, - "Bucket": "bucket-name", - "UseFIPS": false, - "UseDualStack": true, - "Accelerate": false + "Region": "us-west-2", + "UseFIPS": true, + "UseDualStack": true } }, { - "documentation": "virtual addressing, UseGlobalEndpoint and us-east-1 region and accelerate uses the global accelerate endpoint", + "documentation": "non bucket endpoint with dualstack", "expect": { "endpoint": { "properties": { @@ -9959,39 +11631,22 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://bucket-name.s3-accelerate.amazonaws.com" + "url": "https://s3.dualstack.us-west-2.amazonaws.com" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::S3::Accelerate": true, - "AWS::S3::UseGlobalEndpoint": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], "params": { - "Region": "us-east-1", - "UseGlobalEndpoint": true, - "Bucket": "bucket-name", + "Region": "us-west-2", "UseFIPS": false, - "UseDualStack": false, - "Accelerate": true + "UseDualStack": true } }, { - "documentation": "virtual addressing, UseGlobalEndpoint and us-east-1 region with custom endpoint", + "documentation": "use global endpoint + IP address endpoint override", "expect": { "endpoint": { "properties": { @@ -9999,40 +11654,25 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" } ] }, - "url": "https://bucket-name.example.com" + "url": "http://127.0.0.1/bucket" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-east-1", - "SDK::Endpoint": "https://example.com", - "AWS::S3::UseGlobalEndpoint": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], "params": { "Region": "us-east-1", - "Endpoint": "https://example.com", - "UseGlobalEndpoint": true, - "Bucket": "bucket-name", + "Bucket": "bucket", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Endpoint": "http://127.0.0.1", + "UseGlobalEndpoint": true } }, { - "documentation": "ForcePathStyle, aws-global region uses the global endpoint", + "documentation": "non-dns endpoint + global endpoint", "expect": { "endpoint": { "properties": { @@ -10040,64 +11680,50 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" } ] }, - "url": "https://s3.amazonaws.com/bucket-name" + "url": "https://s3.amazonaws.com/bucket%21" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "aws-global", - "AWS::S3::ForcePathStyle": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], "params": { - "Region": "aws-global", - "Bucket": "bucket-name", - "ForcePathStyle": true, + "Region": "us-east-1", + "Bucket": "bucket!", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "UseGlobalEndpoint": true } }, { - "documentation": "ForcePathStyle, aws-global region with fips is invalid", + "documentation": "endpoint override + use global endpoint", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", "disableDoubleEncoding": true, - "name": "sigv4" + "signingRegion": "us-east-1" } ] }, - "url": "https://s3-fips.us-east-1.amazonaws.com/bucket-name" + "url": "http://foo.com/bucket%21" } }, "params": { - "Region": "aws-global", - "Bucket": "bucket-name", - "ForcePathStyle": true, - "UseFIPS": true, + "Region": "us-east-1", + "Bucket": "bucket!", + "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "UseGlobalEndpoint": true, + "Endpoint": "http://foo.com" } }, { - "documentation": "ForcePathStyle, aws-global region with dualstack uses regional dualstack endpoint", + "documentation": "FIPS + dualstack + non-bucket endpoint", "expect": { "endpoint": { "properties": { @@ -10105,39 +11731,23 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" } ] }, - "url": "https://s3.dualstack.us-east-1.amazonaws.com/bucket-name" + "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com/bucket%21" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "aws-global", - "AWS::UseDualStack": true, - "AWS::S3::ForcePathStyle": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], - "params": { - "Region": "aws-global", - "Bucket": "bucket-name", - "ForcePathStyle": true, - "UseFIPS": false, - "UseDualStack": true, - "Accelerate": false + "params": { + "Region": "us-east-1", + "Bucket": "bucket!", + "UseFIPS": true, + "UseDualStack": true } }, { - "documentation": "ForcePathStyle, aws-global region custom endpoint uses the custom endpoint", + "documentation": "FIPS + dualstack + non-DNS endpoint", "expect": { "endpoint": { "properties": { @@ -10145,40 +11755,51 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" } ] }, - "url": "https://example.com/bucket-name" + "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com/bucket%21" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "aws-global", - "SDK::Endpoint": "https://example.com", - "AWS::S3::ForcePathStyle": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], "params": { - "Region": "aws-global", - "Endpoint": "https://example.com", - "Bucket": "bucket-name", + "Region": "us-east-1", + "Bucket": "bucket!", "ForcePathStyle": true, - "UseFIPS": false, + "UseFIPS": true, + "UseDualStack": true + } + }, + { + "documentation": "endpoint override + FIPS + dualstack (BUG)", + "expect": { + "error": "A custom endpoint cannot be combined with FIPS" + }, + "params": { + "Region": "us-east-1", + "Bucket": "bucket!", + "ForcePathStyle": true, + "UseFIPS": true, "UseDualStack": false, - "Accelerate": false + "Endpoint": "http://foo.com" } }, { - "documentation": "ForcePathStyle, UseGlobalEndpoint us-east-1 region uses the global endpoint", + "documentation": "endpoint override + non-dns bucket + FIPS (BUG)", + "expect": { + "error": "A custom endpoint cannot be combined with FIPS" + }, + "params": { + "Region": "us-east-1", + "Bucket": "bucket!", + "UseFIPS": true, + "UseDualStack": false, + "Endpoint": "http://foo.com" + } + }, + { + "documentation": "FIPS + bucket endpoint + force path style", "expect": { "endpoint": { "properties": { @@ -10186,40 +11807,25 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" } ] }, - "url": "https://s3.amazonaws.com/bucket-name" + "url": "https://s3-fips.us-east-1.amazonaws.com/bucket%21" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::S3::ForcePathStyle": true, - "AWS::S3::UseGlobalEndpoint": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], "params": { "Region": "us-east-1", - "Bucket": "bucket-name", - "UseGlobalEndpoint": true, + "Bucket": "bucket!", "ForcePathStyle": true, - "UseFIPS": false, + "UseFIPS": true, "UseDualStack": false, - "Accelerate": false + "UseGlobalEndpoint": true } }, { - "documentation": "ForcePathStyle, UseGlobalEndpoint us-west-2 region uses the regional endpoint", + "documentation": "bucket + FIPS + force path style", "expect": { "endpoint": { "properties": { @@ -10227,40 +11833,25 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" } ] }, - "url": "https://s3.us-west-2.amazonaws.com/bucket-name" + "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com/bucket" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::S3::ForcePathStyle": true, - "AWS::S3::UseGlobalEndpoint": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], "params": { - "Region": "us-west-2", - "Bucket": "bucket-name", - "UseGlobalEndpoint": true, + "Region": "us-east-1", + "Bucket": "bucket", "ForcePathStyle": true, - "UseFIPS": false, - "UseDualStack": false, - "Accelerate": false + "UseFIPS": true, + "UseDualStack": true, + "UseGlobalEndpoint": true } }, { - "documentation": "ForcePathStyle, UseGlobalEndpoint us-east-1 region, dualstack uses the regional dualstack endpoint", + "documentation": "FIPS + dualstack + use global endpoint", "expect": { "endpoint": { "properties": { @@ -10268,41 +11859,38 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" } ] }, - "url": "https://s3.dualstack.us-east-1.amazonaws.com/bucket-name" + "url": "https://bucket.s3-fips.dualstack.us-east-1.amazonaws.com" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::UseDualStack": true, - "AWS::S3::ForcePathStyle": true, - "AWS::S3::UseGlobalEndpoint": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], "params": { "Region": "us-east-1", - "Bucket": "bucket-name", - "UseGlobalEndpoint": true, - "ForcePathStyle": true, - "UseFIPS": false, + "Bucket": "bucket", + "UseFIPS": true, "UseDualStack": true, - "Accelerate": false + "UseGlobalEndpoint": true } }, { - "documentation": "ForcePathStyle, UseGlobalEndpoint us-east-1 region custom endpoint uses the custom endpoint", + "documentation": "URI encoded bucket + use global endpoint", + "expect": { + "error": "A custom endpoint cannot be combined with FIPS" + }, + "params": { + "Region": "us-east-1", + "Bucket": "bucket!", + "UseFIPS": true, + "UseDualStack": false, + "UseGlobalEndpoint": true, + "Endpoint": "https://foo.com" + } + }, + { + "documentation": "FIPS + path based endpoint", "expect": { "endpoint": { "properties": { @@ -10310,103 +11898,51 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-east-1", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" } ] }, - "url": "https://example.com/bucket-name" + "url": "https://s3-fips.us-east-1.amazonaws.com/bucket%21" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-east-1", - "SDK::Endpoint": "https://example.com", - "AWS::S3::ForcePathStyle": true, - "AWS::S3::UseGlobalEndpoint": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], "params": { "Region": "us-east-1", - "Bucket": "bucket-name", - "Endpoint": "https://example.com", - "UseGlobalEndpoint": true, - "ForcePathStyle": true, - "UseFIPS": false, + "Bucket": "bucket!", + "UseFIPS": true, "UseDualStack": false, - "Accelerate": false + "Accelerate": false, + "UseGlobalEndpoint": true } }, { - "documentation": "ARN with aws-global region and UseArnRegion uses the regional endpoint", + "documentation": "accelerate + dualstack + global endpoint", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "us-east-1", - "disableDoubleEncoding": true + "signingName": "s3", + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" } ] }, - "url": "https://reports-123456789012.op-01234567890123456.s3-outposts.us-east-1.amazonaws.com" + "url": "https://bucket.s3-accelerate.dualstack.amazonaws.com" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "aws-global", - "AWS::S3::UseArnRegion": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456/accesspoint/reports", - "Key": "key" - } - } - ], "params": { - "Region": "aws-global", - "UseArnRegion": true, + "Region": "us-east-1", + "Bucket": "bucket", "UseFIPS": false, - "UseDualStack": false, - "Accelerate": false, - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456/accesspoint/reports" - } - }, - { - "documentation": "cross partition MRAP ARN is an error", - "expect": { - "error": "Client was configured for partition `aws` but bucket referred to partition `aws-cn`" - }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-1" - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws-cn:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", - "Key": "key" - } - } - ], - "params": { - "Bucket": "arn:aws-cn:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap", - "Region": "us-west-1" + "UseDualStack": true, + "Accelerate": true, + "UseGlobalEndpoint": true } }, { - "documentation": "Endpoint override, accesspoint with HTTP, port", + "documentation": "dualstack + global endpoint + non URI safe bucket", "expect": { "endpoint": { "properties": { @@ -10414,35 +11950,25 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" } ] }, - "url": "http://myendpoint-123456789012.beta.example.com:1234" + "url": "https://s3.dualstack.us-east-1.amazonaws.com/bucket%21" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2", - "SDK::Endpoint": "http://beta.example.com:1234" - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", - "Key": "key" - } - } - ], "params": { - "Endpoint": "http://beta.example.com:1234", - "Region": "us-west-2", - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint" + "Region": "us-east-1", + "Bucket": "bucket!", + "Accelerate": false, + "UseDualStack": true, + "UseFIPS": false, + "UseGlobalEndpoint": true } }, { - "documentation": "Endpoint override, accesspoint with http, path, query, and port", + "documentation": "FIPS + uri encoded bucket", "expect": { "endpoint": { "properties": { @@ -10450,298 +11976,304 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" } ] }, - "url": "http://myendpoint-123456789012.beta.example.com:1234/path" + "url": "https://s3-fips.us-east-1.amazonaws.com/bucket%21" } }, "params": { - "Region": "us-west-2", - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", - "Endpoint": "http://beta.example.com:1234/path", - "UseFIPS": false, + "Region": "us-east-1", + "Bucket": "bucket!", + "ForcePathStyle": true, + "Accelerate": false, "UseDualStack": false, - "Accelerate": false + "UseFIPS": true, + "UseGlobalEndpoint": true } }, { - "documentation": "non-bucket endpoint override with FIPS = error", + "documentation": "endpoint override + non-uri safe endpoint + force path style", "expect": { "error": "A custom endpoint cannot be combined with FIPS" }, "params": { - "Region": "us-west-2", - "Endpoint": "http://beta.example.com:1234/path", + "Region": "us-east-1", + "Bucket": "bucket!", + "ForcePathStyle": true, + "Accelerate": false, + "UseDualStack": false, "UseFIPS": true, - "UseDualStack": false + "Endpoint": "http://foo.com", + "UseGlobalEndpoint": true } }, { - "documentation": "FIPS + dualstack + custom endpoint", + "documentation": "FIPS + Dualstack + global endpoint + non-dns bucket", + "expect": { + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "disableDoubleEncoding": true, + "signingRegion": "us-east-1" + } + ] + }, + "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com/bucket%21" + } + }, + "params": { + "Region": "us-east-1", + "Bucket": "bucket!", + "Accelerate": false, + "UseDualStack": true, + "UseFIPS": true, + "UseGlobalEndpoint": true + } + }, + { + "documentation": "endpoint override + FIPS + dualstack", "expect": { "error": "Cannot set dual-stack in combination with a custom endpoint." }, "params": { - "Region": "us-west-2", - "Endpoint": "http://beta.example.com:1234/path", + "Region": "us-east-1", + "UseDualStack": true, "UseFIPS": true, - "UseDualStack": true + "UseGlobalEndpoint": true, + "Endpoint": "http://foo.com" } }, { - "documentation": "dualstack + custom endpoint", + "documentation": "non-bucket endpoint override + dualstack + global endpoint", "expect": { "error": "Cannot set dual-stack in combination with a custom endpoint." }, "params": { - "Region": "us-west-2", - "Endpoint": "http://beta.example.com:1234/path", + "Region": "us-east-1", "UseFIPS": false, - "UseDualStack": true + "UseDualStack": true, + "UseGlobalEndpoint": true, + "Endpoint": "http://foo.com" } }, { - "documentation": "custom endpoint without FIPS/dualstack", + "documentation": "Endpoint override + UseGlobalEndpoint + us-east-1", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "signingRegion": "us-west-2", - "disableDoubleEncoding": true - } - ] - }, - "url": "http://beta.example.com:1234/path" - } + "error": "A custom endpoint cannot be combined with FIPS" }, "params": { - "Region": "us-west-2", - "Endpoint": "http://beta.example.com:1234/path", - "UseFIPS": false, - "UseDualStack": false + "Region": "us-east-1", + "UseFIPS": true, + "UseDualStack": false, + "UseGlobalEndpoint": true, + "Endpoint": "http://foo.com" } }, { - "documentation": "s3 object lambda with access points disabled", + "documentation": "non-FIPS partition with FIPS set + custom endpoint", "expect": { - "error": "Access points are not supported for this operation" + "error": "Partition does not support FIPS" }, "params": { - "Region": "us-west-2", - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:myendpoint", - "DisableAccessPoints": true + "Region": "cn-north-1", + "UseFIPS": true, + "UseDualStack": false, + "UseGlobalEndpoint": true } }, { - "documentation": "non bucket + FIPS", + "documentation": "aws-global signs as us-east-1", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://s3-fips.us-west-2.amazonaws.com" + "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com/bucket%21" } }, "params": { - "Region": "us-west-2", + "Region": "aws-global", + "Bucket": "bucket!", "UseFIPS": true, - "UseDualStack": false + "Accelerate": false, + "UseDualStack": true } }, { - "documentation": "standard non bucket endpoint", + "documentation": "aws-global signs as us-east-1", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://s3.us-west-2.amazonaws.com" + "url": "https://bucket.foo.com" } }, "params": { - "Region": "us-west-2", + "Region": "aws-global", + "Bucket": "bucket", + "UseDualStack": false, "UseFIPS": false, - "UseDualStack": false + "Accelerate": false, + "Endpoint": "https://foo.com" } }, { - "documentation": "non bucket endpoint with FIPS + Dualstack", + "documentation": "aws-global + dualstack + path-only bucket", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://s3-fips.dualstack.us-west-2.amazonaws.com" + "url": "https://s3.dualstack.us-east-1.amazonaws.com/bucket%21" } }, "params": { - "Region": "us-west-2", - "UseFIPS": true, - "UseDualStack": true + "Region": "aws-global", + "Bucket": "bucket!", + "UseDualStack": true, + "UseFIPS": false, + "Accelerate": false } }, { - "documentation": "non bucket endpoint with dualstack", + "documentation": "aws-global + path-only bucket", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://s3.dualstack.us-west-2.amazonaws.com" + "url": "https://s3.amazonaws.com/bucket%21" } }, "params": { - "Region": "us-west-2", - "UseFIPS": false, - "UseDualStack": true + "Region": "aws-global", + "Bucket": "bucket!" } }, { - "documentation": "use global endpoint + IP address endpoint override", + "documentation": "aws-global + fips + custom endpoint", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" - } - ] - }, - "url": "http://127.0.0.1/bucket" - } + "error": "A custom endpoint cannot be combined with FIPS" }, "params": { - "Region": "us-east-1", - "Bucket": "bucket", - "UseFIPS": false, + "Region": "aws-global", + "Bucket": "bucket!", "UseDualStack": false, - "Endpoint": "http://127.0.0.1", - "UseGlobalEndpoint": true + "UseFIPS": true, + "Accelerate": false, + "Endpoint": "http://foo.com" } }, { - "documentation": "non-dns endpoint + global endpoint", + "documentation": "aws-global, endpoint override & path only-bucket", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "disableDoubleEncoding": true } ] }, - "url": "https://s3.amazonaws.com/bucket%21" + "url": "http://foo.com/bucket%21" } }, "params": { - "Region": "us-east-1", + "Region": "aws-global", "Bucket": "bucket!", - "UseFIPS": false, "UseDualStack": false, - "UseGlobalEndpoint": true + "UseFIPS": false, + "Accelerate": false, + "Endpoint": "http://foo.com" } }, { - "documentation": "endpoint override + use global endpoint", + "documentation": "aws-global + dualstack + custom endpoint", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" - } - ] - }, - "url": "http://foo.com/bucket%21" - } + "error": "Cannot set dual-stack in combination with a custom endpoint." }, "params": { - "Region": "us-east-1", - "Bucket": "bucket!", + "Region": "aws-global", + "UseDualStack": true, "UseFIPS": false, - "UseDualStack": false, - "UseGlobalEndpoint": true, + "Accelerate": false, "Endpoint": "http://foo.com" } }, { - "documentation": "FIPS + dualstack + non-bucket endpoint", + "documentation": "accelerate, dualstack + aws-global", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "disableDoubleEncoding": true } ] }, - "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com/bucket%21" + "url": "https://bucket.s3-accelerate.dualstack.us-east-1.amazonaws.com" } }, "params": { - "Region": "us-east-1", - "Bucket": "bucket!", - "UseFIPS": true, - "UseDualStack": true + "Region": "aws-global", + "Bucket": "bucket", + "UseDualStack": true, + "UseFIPS": false, + "Accelerate": true } }, { - "documentation": "FIPS + dualstack + non-DNS endpoint", + "documentation": "FIPS + aws-global + path only bucket. This is not supported by S3 but we allow garbage in garbage out", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "disableDoubleEncoding": true } ] }, @@ -10749,943 +12281,1125 @@ } }, "params": { - "Region": "us-east-1", + "Region": "aws-global", "Bucket": "bucket!", "ForcePathStyle": true, + "UseDualStack": true, "UseFIPS": true, - "UseDualStack": true + "Accelerate": false } }, { - "documentation": "endpoint override + FIPS + dualstack (BUG)", + "documentation": "aws-global + FIPS + endpoint override.", "expect": { "error": "A custom endpoint cannot be combined with FIPS" }, "params": { - "Region": "us-east-1", - "Bucket": "bucket!", - "ForcePathStyle": true, + "Region": "aws-global", "UseFIPS": true, - "UseDualStack": false, "Endpoint": "http://foo.com" } }, { - "documentation": "endpoint override + non-dns bucket + FIPS (BUG)", + "documentation": "force path style, FIPS, aws-global & endpoint override", "expect": { "error": "A custom endpoint cannot be combined with FIPS" }, "params": { - "Region": "us-east-1", + "Region": "aws-global", "Bucket": "bucket!", + "ForcePathStyle": true, "UseFIPS": true, - "UseDualStack": false, "Endpoint": "http://foo.com" } }, { - "documentation": "FIPS + bucket endpoint + force path style", + "documentation": "ip address causes path style to be forced", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "disableDoubleEncoding": true } ] }, - "url": "https://s3-fips.us-east-1.amazonaws.com/bucket%21" + "url": "http://192.168.1.1/bucket" } }, "params": { - "Region": "us-east-1", - "Bucket": "bucket!", - "ForcePathStyle": true, - "UseFIPS": true, - "UseDualStack": false, - "UseGlobalEndpoint": true + "Region": "aws-global", + "Bucket": "bucket", + "Endpoint": "http://192.168.1.1" } }, { - "documentation": "bucket + FIPS + force path style", + "documentation": "endpoint override with aws-global region", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" - } - ] - }, - "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com/bucket" - } + "error": "Cannot set dual-stack in combination with a custom endpoint." }, "params": { - "Region": "us-east-1", - "Bucket": "bucket", - "ForcePathStyle": true, + "Region": "aws-global", "UseFIPS": true, "UseDualStack": true, - "UseGlobalEndpoint": true + "Endpoint": "http://foo.com" } }, { - "documentation": "FIPS + dualstack + use global endpoint", + "documentation": "FIPS + path-only (TODO: consider making this an error)", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "disableDoubleEncoding": true } ] }, - "url": "https://bucket.s3-fips.dualstack.us-east-1.amazonaws.com" + "url": "https://s3-fips.us-east-1.amazonaws.com/bucket%21" } }, "params": { - "Region": "us-east-1", - "Bucket": "bucket", - "UseFIPS": true, - "UseDualStack": true, - "UseGlobalEndpoint": true + "Region": "aws-global", + "Bucket": "bucket!", + "UseFIPS": true } }, { - "documentation": "URI encoded bucket + use global endpoint", + "documentation": "empty arn type", "expect": { - "error": "A custom endpoint cannot be combined with FIPS" + "error": "Invalid ARN: No ARN type specified" }, "params": { - "Region": "us-east-1", - "Bucket": "bucket!", - "UseFIPS": true, - "UseDualStack": false, - "UseGlobalEndpoint": true, - "Endpoint": "https://foo.com" + "Region": "us-east-2", + "Bucket": "arn:aws:not-s3:us-west-2:123456789012::myendpoint" } }, { - "documentation": "FIPS + path based endpoint", + "documentation": "path style can't be used with accelerate", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" - } - ] - }, - "url": "https://s3-fips.us-east-1.amazonaws.com/bucket%21" - } + "error": "Path-style addressing cannot be used with S3 Accelerate" }, "params": { - "Region": "us-east-1", + "Region": "us-east-2", "Bucket": "bucket!", - "UseFIPS": true, - "UseDualStack": false, - "Accelerate": false, - "UseGlobalEndpoint": true + "Accelerate": true + } + }, + { + "documentation": "invalid region", + "expect": { + "error": "Invalid region: region was not a valid DNS name." + }, + "params": { + "Region": "us-east-2!", + "Bucket": "bucket.subdomain", + "Endpoint": "http://foo.com" + } + }, + { + "documentation": "invalid region", + "expect": { + "error": "Invalid region: region was not a valid DNS name." + }, + "params": { + "Region": "us-east-2!", + "Bucket": "bucket", + "Endpoint": "http://foo.com" + } + }, + { + "documentation": "empty arn type", + "expect": { + "error": "Invalid Access Point Name" + }, + "params": { + "Region": "us-east-2", + "Bucket": "arn:aws:s3::123456789012:accesspoint:my_endpoint" + } + }, + { + "documentation": "empty arn type", + "expect": { + "error": "Client was configured for partition `aws` but ARN (`arn:aws:s3:cn-north-1:123456789012:accesspoint:my-endpoint`) has `aws-cn`" + }, + "params": { + "Region": "us-east-2", + "Bucket": "arn:aws:s3:cn-north-1:123456789012:accesspoint:my-endpoint", + "UseArnRegion": true + } + }, + { + "documentation": "invalid arn region", + "expect": { + "error": "Invalid region in ARN: `us-east_2` (invalid DNS name)" + }, + "params": { + "Region": "us-east-2", + "Bucket": "arn:aws:s3-object-lambda:us-east_2:123456789012:accesspoint:my-endpoint", + "UseArnRegion": true + } + }, + { + "documentation": "invalid ARN outpost", + "expect": { + "error": "Invalid ARN: The outpost Id may only contain a-z, A-Z, 0-9 and `-`. Found: `op_01234567890123456`" + }, + "params": { + "Region": "us-east-2", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op_01234567890123456/accesspoint/reports", + "UseArnRegion": true + } + }, + { + "documentation": "invalid ARN", + "expect": { + "error": "Invalid ARN: expected an access point name" + }, + "params": { + "Region": "us-east-2", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456/reports" + } + }, + { + "documentation": "invalid ARN", + "expect": { + "error": "Invalid ARN: Expected a 4-component resource" + }, + "params": { + "Region": "us-east-2", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456" + } + }, + { + "documentation": "invalid outpost type", + "expect": { + "error": "Expected an outpost type `accesspoint`, found not-accesspoint" + }, + "params": { + "Region": "us-east-2", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456/not-accesspoint/reports" + } + }, + { + "documentation": "invalid outpost type", + "expect": { + "error": "Invalid region in ARN: `us-east_1` (invalid DNS name)" + }, + "params": { + "Region": "us-east-2", + "Bucket": "arn:aws:s3-outposts:us-east_1:123456789012:outpost/op-01234567890123456/not-accesspoint/reports" + } + }, + { + "documentation": "invalid outpost type", + "expect": { + "error": "Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `12345_789012`" + }, + "params": { + "Region": "us-east-2", + "Bucket": "arn:aws:s3-outposts:us-east-1:12345_789012:outpost/op-01234567890123456/not-accesspoint/reports" + } + }, + { + "documentation": "invalid outpost type", + "expect": { + "error": "Invalid ARN: The Outpost Id was not set" + }, + "params": { + "Region": "us-east-2", + "Bucket": "arn:aws:s3-outposts:us-east-1:12345789012:outpost" } }, { - "documentation": "accelerate + dualstack + global endpoint", + "documentation": "use global endpoint virtual addressing", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "signingRegion": "us-east-2", "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "disableDoubleEncoding": true } ] }, - "url": "https://bucket.s3-accelerate.dualstack.amazonaws.com" + "url": "http://bucket.example.com" } }, "params": { - "Region": "us-east-1", + "Region": "us-east-2", "Bucket": "bucket", - "UseFIPS": false, - "UseDualStack": true, - "Accelerate": true, + "Endpoint": "http://example.com", "UseGlobalEndpoint": true } }, { - "documentation": "dualstack + global endpoint + non URI safe bucket", + "documentation": "global endpoint + ip address", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "signingRegion": "us-east-2", "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "disableDoubleEncoding": true } ] }, - "url": "https://s3.dualstack.us-east-1.amazonaws.com/bucket%21" + "url": "http://192.168.0.1/bucket" } }, "params": { - "Region": "us-east-1", - "Bucket": "bucket!", - "Accelerate": false, - "UseDualStack": true, - "UseFIPS": false, + "Region": "us-east-2", + "Bucket": "bucket", + "Endpoint": "http://192.168.0.1", "UseGlobalEndpoint": true } }, { - "documentation": "FIPS + uri encoded bucket", + "documentation": "invalid outpost type", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "signingRegion": "us-east-2", "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "disableDoubleEncoding": true } ] }, - "url": "https://s3-fips.us-east-1.amazonaws.com/bucket%21" + "url": "https://s3.us-east-2.amazonaws.com/bucket%21" } }, "params": { - "Region": "us-east-1", - "Bucket": "bucket!", - "ForcePathStyle": true, - "Accelerate": false, - "UseDualStack": false, - "UseFIPS": true, - "UseGlobalEndpoint": true - } - }, - { - "documentation": "endpoint override + non-uri safe endpoint + force path style", - "expect": { - "error": "A custom endpoint cannot be combined with FIPS" - }, - "params": { - "Region": "us-east-1", + "Region": "us-east-2", "Bucket": "bucket!", - "ForcePathStyle": true, - "Accelerate": false, - "UseDualStack": false, - "UseFIPS": true, - "Endpoint": "http://foo.com", "UseGlobalEndpoint": true } }, { - "documentation": "FIPS + Dualstack + global endpoint + non-dns bucket", + "documentation": "invalid outpost type", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "signingRegion": "us-east-2", "name": "sigv4", "signingName": "s3", - "disableDoubleEncoding": true, - "signingRegion": "us-east-1" + "disableDoubleEncoding": true } ] }, - "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com/bucket%21" + "url": "https://bucket.s3-accelerate.amazonaws.com" } }, "params": { - "Region": "us-east-1", - "Bucket": "bucket!", - "Accelerate": false, - "UseDualStack": true, - "UseFIPS": true, - "UseGlobalEndpoint": true - } - }, - { - "documentation": "endpoint override + FIPS + dualstack", - "expect": { - "error": "Cannot set dual-stack in combination with a custom endpoint." - }, - "params": { - "Region": "us-east-1", - "UseDualStack": true, - "UseFIPS": true, - "UseGlobalEndpoint": true, - "Endpoint": "http://foo.com" - } - }, - { - "documentation": "non-bucket endpoint override + dualstack + global endpoint", - "expect": { - "error": "Cannot set dual-stack in combination with a custom endpoint." - }, - "params": { - "Region": "us-east-1", - "UseFIPS": false, - "UseDualStack": true, - "UseGlobalEndpoint": true, - "Endpoint": "http://foo.com" - } - }, - { - "documentation": "Endpoint override + UseGlobalEndpoint + us-east-1", - "expect": { - "error": "A custom endpoint cannot be combined with FIPS" - }, - "params": { - "Region": "us-east-1", - "UseFIPS": true, - "UseDualStack": false, - "UseGlobalEndpoint": true, - "Endpoint": "http://foo.com" - } - }, - { - "documentation": "non-FIPS partition with FIPS set + custom endpoint", - "expect": { - "error": "Partition does not support FIPS" - }, - "params": { - "Region": "cn-north-1", - "UseFIPS": true, - "UseDualStack": false, + "Region": "us-east-2", + "Bucket": "bucket", + "Accelerate": true, "UseGlobalEndpoint": true } }, { - "documentation": "aws-global signs as us-east-1", + "documentation": "use global endpoint + custom endpoint", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "signingRegion": "us-east-1", + "signingRegion": "us-east-2", "name": "sigv4", "signingName": "s3", "disableDoubleEncoding": true } ] }, - "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com/bucket%21" + "url": "http://foo.com/bucket%21" } }, "params": { - "Region": "aws-global", + "Region": "us-east-2", "Bucket": "bucket!", - "UseFIPS": true, - "Accelerate": false, - "UseDualStack": true + "UseGlobalEndpoint": true, + "Endpoint": "http://foo.com" } }, { - "documentation": "aws-global signs as us-east-1", + "documentation": "use global endpoint, not us-east-1, force path style", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "signingRegion": "us-east-1", + "signingRegion": "us-east-2", "name": "sigv4", "signingName": "s3", "disableDoubleEncoding": true } ] }, - "url": "https://bucket.foo.com" + "url": "http://foo.com/bucket%21" } }, "params": { - "Region": "aws-global", - "Bucket": "bucket", - "UseDualStack": false, - "UseFIPS": false, - "Accelerate": false, - "Endpoint": "https://foo.com" + "Region": "us-east-2", + "Bucket": "bucket!", + "UseGlobalEndpoint": true, + "ForcePathStyle": true, + "Endpoint": "http://foo.com" } }, { - "documentation": "aws-global + dualstack + path-only bucket", + "documentation": "vanilla virtual addressing@us-west-2", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://s3.dualstack.us-east-1.amazonaws.com/bucket%21" + "url": "https://bucket-name.s3.us-west-2.amazonaws.com" } }, - "params": { - "Region": "aws-global", - "Bucket": "bucket!", - "UseDualStack": true, - "UseFIPS": false, - "Accelerate": false - } - }, - { - "documentation": "aws-global + path-only bucket", - "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "signingRegion": "us-east-1", - "name": "sigv4", - "signingName": "s3", - "disableDoubleEncoding": true - } - ] + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2" }, - "url": "https://s3.amazonaws.com/bucket%21" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } - }, - "params": { - "Region": "aws-global", - "Bucket": "bucket!" - } - }, - { - "documentation": "aws-global + fips + custom endpoint", - "expect": { - "error": "A custom endpoint cannot be combined with FIPS" - }, + ], "params": { - "Region": "aws-global", - "Bucket": "bucket!", - "UseDualStack": false, - "UseFIPS": true, "Accelerate": false, - "Endpoint": "http://foo.com" + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "us-west-2", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "aws-global, endpoint override & path only-bucket", + "documentation": "virtual addressing + dualstack@us-west-2", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "http://foo.com/bucket%21" + "url": "https://bucket-name.s3.dualstack.us-west-2.amazonaws.com" } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "AWS::UseDualStack": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "aws-global", - "Bucket": "bucket!", - "UseDualStack": false, - "UseFIPS": false, "Accelerate": false, - "Endpoint": "http://foo.com" - } - }, - { - "documentation": "aws-global + dualstack + custom endpoint", - "expect": { - "error": "Cannot set dual-stack in combination with a custom endpoint." - }, - "params": { - "Region": "aws-global", + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "us-west-2", "UseDualStack": true, - "UseFIPS": false, - "Accelerate": false, - "Endpoint": "http://foo.com" + "UseFIPS": false } }, { - "documentation": "accelerate, dualstack + aws-global", + "documentation": "accelerate + dualstack@us-west-2", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://bucket.s3-accelerate.dualstack.us-east-1.amazonaws.com" + "url": "https://bucket-name.s3-accelerate.dualstack.amazonaws.com" } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "AWS::UseDualStack": true, + "AWS::S3::Accelerate": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "aws-global", - "Bucket": "bucket", + "Accelerate": true, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "us-west-2", "UseDualStack": true, - "UseFIPS": false, - "Accelerate": true + "UseFIPS": false } }, { - "documentation": "FIPS + aws-global + path only bucket. This is not supported by S3 but we allow garbage in garbage out", + "documentation": "accelerate (dualstack=false)@us-west-2", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://s3-fips.dualstack.us-east-1.amazonaws.com/bucket%21" + "url": "https://bucket-name.s3-accelerate.amazonaws.com" } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "AWS::S3::Accelerate": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "aws-global", - "Bucket": "bucket!", - "ForcePathStyle": true, - "UseDualStack": true, - "UseFIPS": true, - "Accelerate": false - } - }, - { - "documentation": "aws-global + FIPS + endpoint override.", - "expect": { - "error": "A custom endpoint cannot be combined with FIPS" - }, - "params": { - "Region": "aws-global", - "UseFIPS": true, - "Endpoint": "http://foo.com" - } - }, - { - "documentation": "force path style, FIPS, aws-global & endpoint override", - "expect": { - "error": "A custom endpoint cannot be combined with FIPS" - }, - "params": { - "Region": "aws-global", - "Bucket": "bucket!", - "ForcePathStyle": true, - "UseFIPS": true, - "Endpoint": "http://foo.com" + "Accelerate": true, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "us-west-2", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "ip address causes path style to be forced", + "documentation": "virtual addressing + fips@us-west-2", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "http://192.168.1.1/bucket" + "url": "https://bucket-name.s3-fips.us-west-2.amazonaws.com" } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "AWS::UseFIPS": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "aws-global", - "Bucket": "bucket", - "Endpoint": "http://192.168.1.1" - } - }, - { - "documentation": "endpoint override with aws-global region", - "expect": { - "error": "Cannot set dual-stack in combination with a custom endpoint." - }, - "params": { - "Region": "aws-global", - "UseFIPS": true, - "UseDualStack": true, - "Endpoint": "http://foo.com" + "Accelerate": false, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "us-west-2", + "UseDualStack": false, + "UseFIPS": true } }, { - "documentation": "FIPS + path-only (TODO: consider making this an error)", + "documentation": "virtual addressing + dualstack + fips@us-west-2", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "signingRegion": "us-east-1", "name": "sigv4", "signingName": "s3", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://s3-fips.us-east-1.amazonaws.com/bucket%21" + "url": "https://bucket-name.s3-fips.dualstack.us-west-2.amazonaws.com" } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "AWS::UseFIPS": true, + "AWS::UseDualStack": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "aws-global", - "Bucket": "bucket!", + "Accelerate": false, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "us-west-2", + "UseDualStack": true, "UseFIPS": true } }, { - "documentation": "empty arn type", - "expect": { - "error": "Invalid ARN: No ARN type specified" - }, - "params": { - "Region": "us-east-2", - "Bucket": "arn:aws:not-s3:us-west-2:123456789012::myendpoint" - } - }, - { - "documentation": "path style can't be used with accelerate", - "expect": { - "error": "Path-style addressing cannot be used with S3 Accelerate" - }, - "params": { - "Region": "us-east-2", - "Bucket": "bucket!", - "Accelerate": true - } - }, - { - "documentation": "invalid region", - "expect": { - "error": "Invalid region: region was not a valid DNS name." - }, - "params": { - "Region": "us-east-2!", - "Bucket": "bucket.subdomain", - "Endpoint": "http://foo.com" - } - }, - { - "documentation": "invalid region", - "expect": { - "error": "Invalid region: region was not a valid DNS name." - }, - "params": { - "Region": "us-east-2!", - "Bucket": "bucket", - "Endpoint": "http://foo.com" - } - }, - { - "documentation": "empty arn type", - "expect": { - "error": "Invalid Access Point Name" - }, - "params": { - "Region": "us-east-2", - "Bucket": "arn:aws:s3::123456789012:accesspoint:my_endpoint" - } - }, - { - "documentation": "empty arn type", - "expect": { - "error": "Client was configured for partition `aws` but ARN (`arn:aws:s3:cn-north-1:123456789012:accesspoint:my-endpoint`) has `aws-cn`" - }, - "params": { - "Region": "us-east-2", - "Bucket": "arn:aws:s3:cn-north-1:123456789012:accesspoint:my-endpoint", - "UseArnRegion": true - } - }, - { - "documentation": "invalid arn region", - "expect": { - "error": "Invalid region in ARN: `us-east_2` (invalid DNS name)" - }, - "params": { - "Region": "us-east-2", - "Bucket": "arn:aws:s3-object-lambda:us-east_2:123456789012:accesspoint:my-endpoint", - "UseArnRegion": true - } - }, - { - "documentation": "invalid ARN outpost", + "documentation": "accelerate + fips = error@us-west-2", "expect": { - "error": "Invalid ARN: The outpost Id may only contain a-z, A-Z, 0-9 and `-`. Found: `op_01234567890123456`" + "error": "Accelerate cannot be used with FIPS" }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "AWS::UseFIPS": true, + "AWS::S3::Accelerate": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "us-east-2", - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op_01234567890123456/accesspoint/reports", - "UseArnRegion": true + "Accelerate": true, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "us-west-2", + "UseDualStack": false, + "UseFIPS": true } }, { - "documentation": "invalid ARN", + "documentation": "vanilla virtual addressing@cn-north-1", "expect": { - "error": "Invalid ARN: expected an access point name" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "cn-north-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://bucket-name.s3.cn-north-1.amazonaws.com.cn" + } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "cn-north-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "us-east-2", - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456/reports" + "Accelerate": false, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "cn-north-1", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "invalid ARN", + "documentation": "virtual addressing + dualstack@cn-north-1", "expect": { - "error": "Invalid ARN: Expected a 4-component resource" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "cn-north-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://bucket-name.s3.dualstack.cn-north-1.amazonaws.com.cn" + } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "cn-north-1", + "AWS::UseDualStack": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "us-east-2", - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456" + "Accelerate": false, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "cn-north-1", + "UseDualStack": true, + "UseFIPS": false } }, { - "documentation": "invalid outpost type", + "documentation": "accelerate (dualstack=false)@cn-north-1", "expect": { - "error": "Expected an outpost type `accesspoint`, found not-accesspoint" + "error": "S3 Accelerate cannot be used in this region" }, "params": { - "Region": "us-east-2", - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456/not-accesspoint/reports" + "Accelerate": true, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "cn-north-1", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "invalid outpost type", + "documentation": "virtual addressing + fips@cn-north-1", "expect": { - "error": "Invalid region in ARN: `us-east_1` (invalid DNS name)" + "error": "Partition does not support FIPS" }, "params": { - "Region": "us-east-2", - "Bucket": "arn:aws:s3-outposts:us-east_1:123456789012:outpost/op-01234567890123456/not-accesspoint/reports" + "Accelerate": false, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "cn-north-1", + "UseDualStack": false, + "UseFIPS": true } }, { - "documentation": "invalid outpost type", + "documentation": "vanilla virtual addressing@af-south-1", "expect": { - "error": "Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `12345_789012`" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "af-south-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://bucket-name.s3.af-south-1.amazonaws.com" + } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "af-south-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "us-east-2", - "Bucket": "arn:aws:s3-outposts:us-east-1:12345_789012:outpost/op-01234567890123456/not-accesspoint/reports" + "Accelerate": false, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "af-south-1", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "invalid outpost type", + "documentation": "virtual addressing + dualstack@af-south-1", "expect": { - "error": "Invalid ARN: The Outpost Id was not set" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "af-south-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://bucket-name.s3.dualstack.af-south-1.amazonaws.com" + } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "af-south-1", + "AWS::UseDualStack": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "us-east-2", - "Bucket": "arn:aws:s3-outposts:us-east-1:12345789012:outpost" + "Accelerate": false, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "af-south-1", + "UseDualStack": true, + "UseFIPS": false } }, { - "documentation": "use global endpoint virtual addressing", + "documentation": "accelerate + dualstack@af-south-1", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "signingRegion": "us-east-2", "name": "sigv4", "signingName": "s3", + "signingRegion": "af-south-1", "disableDoubleEncoding": true } ] }, - "url": "http://bucket.example.com" + "url": "https://bucket-name.s3-accelerate.dualstack.amazonaws.com" } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "af-south-1", + "AWS::UseDualStack": true, + "AWS::S3::Accelerate": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "us-east-2", - "Bucket": "bucket", - "Endpoint": "http://example.com", - "UseGlobalEndpoint": true + "Accelerate": true, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "af-south-1", + "UseDualStack": true, + "UseFIPS": false } }, { - "documentation": "global endpoint + ip address", + "documentation": "accelerate (dualstack=false)@af-south-1", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "signingRegion": "us-east-2", "name": "sigv4", "signingName": "s3", + "signingRegion": "af-south-1", "disableDoubleEncoding": true } ] }, - "url": "http://192.168.0.1/bucket" + "url": "https://bucket-name.s3-accelerate.amazonaws.com" } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "af-south-1", + "AWS::S3::Accelerate": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "us-east-2", - "Bucket": "bucket", - "Endpoint": "http://192.168.0.1", - "UseGlobalEndpoint": true + "Accelerate": true, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "af-south-1", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "invalid outpost type", + "documentation": "virtual addressing + fips@af-south-1", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "signingRegion": "us-east-2", "name": "sigv4", "signingName": "s3", + "signingRegion": "af-south-1", "disableDoubleEncoding": true } ] }, - "url": "https://s3.us-east-2.amazonaws.com/bucket%21" + "url": "https://bucket-name.s3-fips.af-south-1.amazonaws.com" } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "af-south-1", + "AWS::UseFIPS": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "us-east-2", - "Bucket": "bucket!", - "UseGlobalEndpoint": true + "Accelerate": false, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "af-south-1", + "UseDualStack": false, + "UseFIPS": true } }, { - "documentation": "invalid outpost type", + "documentation": "virtual addressing + dualstack + fips@af-south-1", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "signingRegion": "us-east-2", "name": "sigv4", "signingName": "s3", + "signingRegion": "af-south-1", "disableDoubleEncoding": true } ] }, - "url": "https://bucket.s3-accelerate.amazonaws.com" + "url": "https://bucket-name.s3-fips.dualstack.af-south-1.amazonaws.com" } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "af-south-1", + "AWS::UseFIPS": true, + "AWS::UseDualStack": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "us-east-2", - "Bucket": "bucket", - "Accelerate": true, - "UseGlobalEndpoint": true + "Accelerate": false, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "af-south-1", + "UseDualStack": true, + "UseFIPS": true } }, { - "documentation": "use global endpoint + custom endpoint", + "documentation": "accelerate + fips = error@af-south-1", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "signingRegion": "us-east-2", - "name": "sigv4", - "signingName": "s3", - "disableDoubleEncoding": true - } - ] + "error": "Accelerate cannot be used with FIPS" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "af-south-1", + "AWS::UseFIPS": true, + "AWS::S3::Accelerate": true }, - "url": "http://foo.com/bucket%21" + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } - }, + ], "params": { - "Region": "us-east-2", - "Bucket": "bucket!", - "UseGlobalEndpoint": true, - "Endpoint": "http://foo.com" + "Accelerate": true, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "af-south-1", + "UseDualStack": false, + "UseFIPS": true } }, { - "documentation": "use global endpoint, not us-east-1, force path style", + "documentation": "vanilla path style@us-west-2", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "signingRegion": "us-east-2", "name": "sigv4", "signingName": "s3", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "http://foo.com/bucket%21" + "url": "https://s3.us-west-2.amazonaws.com/bucket-name" } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "AWS::S3::ForcePathStyle": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], "params": { - "Region": "us-east-2", - "Bucket": "bucket!", - "UseGlobalEndpoint": true, + "Accelerate": false, + "Bucket": "bucket-name", "ForcePathStyle": true, - "Endpoint": "http://foo.com" + "Region": "us-west-2", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "vanilla virtual addressing@us-west-2", + "documentation": "fips@us-gov-west-2, bucket is not S3-dns-compatible (subdomains)", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", - "disableDoubleEncoding": true + "signingRegion": "us-gov-west-1", + "disableDoubleEncoding": true, + "name": "sigv4" } ] }, - "url": "https://bucket-name.s3.us-west-2.amazonaws.com" + "url": "https://s3-fips.us-gov-west-1.amazonaws.com/bucket.with.dots" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2" + "AWS::Region": "us-gov-west-1", + "AWS::UseFIPS": true, + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "bucket.with.dots", "Key": "key" } } ], "params": { "Accelerate": false, + "Bucket": "bucket.with.dots", + "Region": "us-gov-west-1", + "UseDualStack": false, + "UseFIPS": true + } + }, + { + "documentation": "path style + accelerate = error@us-west-2", + "expect": { + "error": "Path-style addressing cannot be used with S3 Accelerate" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "AWS::S3::ForcePathStyle": true, + "AWS::S3::Accelerate": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], + "params": { + "Accelerate": true, "Bucket": "bucket-name", - "ForcePathStyle": false, + "ForcePathStyle": true, "Region": "us-west-2", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "virtual addressing + dualstack@us-west-2", + "documentation": "path style + dualstack@us-west-2", "expect": { "endpoint": { "properties": { @@ -11698,14 +13412,15 @@ } ] }, - "url": "https://bucket-name.s3.dualstack.us-west-2.amazonaws.com" + "url": "https://s3.dualstack.us-west-2.amazonaws.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-west-2", - "AWS::UseDualStack": true + "AWS::UseDualStack": true, + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { @@ -11717,14 +13432,41 @@ "params": { "Accelerate": false, "Bucket": "bucket-name", - "ForcePathStyle": false, + "ForcePathStyle": true, "Region": "us-west-2", "UseDualStack": true, "UseFIPS": false } }, { - "documentation": "accelerate + dualstack@us-west-2", + "documentation": "path style + arn is error@us-west-2", + "expect": { + "error": "Path-style addressing cannot be used with ARN buckets" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "AWS::S3::ForcePathStyle": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:PARTITION:s3-outposts:REGION:123456789012:outpost:op-01234567890123456:bucket:mybucket", + "Key": "key" + } + } + ], + "params": { + "Accelerate": false, + "Bucket": "arn:PARTITION:s3-outposts:REGION:123456789012:outpost:op-01234567890123456:bucket:mybucket", + "ForcePathStyle": true, + "Region": "us-west-2", + "UseDualStack": false, + "UseFIPS": false + } + }, + { + "documentation": "path style + invalid DNS name@us-west-2", "expect": { "endpoint": { "properties": { @@ -11737,34 +13479,33 @@ } ] }, - "url": "https://bucket-name.s3-accelerate.dualstack.amazonaws.com" + "url": "https://s3.us-west-2.amazonaws.com/99a_b" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-west-2", - "AWS::UseDualStack": true, - "AWS::S3::Accelerate": true + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "99a_b", "Key": "key" } } ], "params": { - "Accelerate": true, - "Bucket": "bucket-name", - "ForcePathStyle": false, + "Accelerate": false, + "Bucket": "99a_b", + "ForcePathStyle": true, "Region": "us-west-2", - "UseDualStack": true, + "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "accelerate (dualstack=false)@us-west-2", + "documentation": "no path style + invalid DNS name@us-west-2", "expect": { "endpoint": { "properties": { @@ -11777,33 +13518,31 @@ } ] }, - "url": "https://bucket-name.s3-accelerate.amazonaws.com" + "url": "https://s3.us-west-2.amazonaws.com/99a_b" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::S3::Accelerate": true + "AWS::Region": "us-west-2" }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "99a_b", "Key": "key" } } ], "params": { - "Accelerate": true, - "Bucket": "bucket-name", - "ForcePathStyle": false, + "Accelerate": false, + "Bucket": "99a_b", "Region": "us-west-2", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "virtual addressing + fips@us-west-2", + "documentation": "vanilla path style@cn-north-1", "expect": { "endpoint": { "properties": { @@ -11811,19 +13550,75 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", + "signingRegion": "cn-north-1", "disableDoubleEncoding": true } ] }, - "url": "https://bucket-name.s3-fips.us-west-2.amazonaws.com" + "url": "https://s3.cn-north-1.amazonaws.com.cn/bucket-name" + } + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "cn-north-1", + "AWS::S3::ForcePathStyle": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], + "params": { + "Accelerate": false, + "Bucket": "bucket-name", + "ForcePathStyle": true, + "Region": "cn-north-1", + "UseDualStack": false, + "UseFIPS": false + } + }, + { + "documentation": "path style + fips@cn-north-1", + "expect": { + "error": "Partition does not support FIPS" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "cn-north-1", + "AWS::UseFIPS": true, + "AWS::S3::ForcePathStyle": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } } + ], + "params": { + "Accelerate": false, + "Bucket": "bucket-name", + "ForcePathStyle": true, + "Region": "cn-north-1", + "UseDualStack": false, + "UseFIPS": true + } + }, + { + "documentation": "path style + accelerate = error@cn-north-1", + "expect": { + "error": "Path-style addressing cannot be used with S3 Accelerate" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::UseFIPS": true + "AWS::Region": "cn-north-1", + "AWS::S3::ForcePathStyle": true, + "AWS::S3::Accelerate": true }, "operationName": "GetObject", "operationParams": { @@ -11833,16 +13628,16 @@ } ], "params": { - "Accelerate": false, + "Accelerate": true, "Bucket": "bucket-name", - "ForcePathStyle": false, - "Region": "us-west-2", + "ForcePathStyle": true, + "Region": "cn-north-1", "UseDualStack": false, - "UseFIPS": true + "UseFIPS": false } }, { - "documentation": "virtual addressing + dualstack + fips@us-west-2", + "documentation": "path style + dualstack@cn-north-1", "expect": { "endpoint": { "properties": { @@ -11850,20 +13645,20 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", + "signingRegion": "cn-north-1", "disableDoubleEncoding": true } ] }, - "url": "https://bucket-name.s3-fips.dualstack.us-west-2.amazonaws.com" + "url": "https://s3.dualstack.cn-north-1.amazonaws.com.cn/bucket-name" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::UseFIPS": true, - "AWS::UseDualStack": true + "AWS::Region": "cn-north-1", + "AWS::UseDualStack": true, + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { @@ -11875,42 +13670,41 @@ "params": { "Accelerate": false, "Bucket": "bucket-name", - "ForcePathStyle": false, - "Region": "us-west-2", + "ForcePathStyle": true, + "Region": "cn-north-1", "UseDualStack": true, - "UseFIPS": true + "UseFIPS": false } }, { - "documentation": "accelerate + fips = error@us-west-2", + "documentation": "path style + arn is error@cn-north-1", "expect": { - "error": "Accelerate cannot be used with FIPS" + "error": "Path-style addressing cannot be used with ARN buckets" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::UseFIPS": true, - "AWS::S3::Accelerate": true + "AWS::Region": "cn-north-1", + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:PARTITION:s3-outposts:REGION:123456789012:outpost:op-01234567890123456:bucket:mybucket", "Key": "key" } } ], "params": { - "Accelerate": true, - "Bucket": "bucket-name", - "ForcePathStyle": false, - "Region": "us-west-2", + "Accelerate": false, + "Bucket": "arn:PARTITION:s3-outposts:REGION:123456789012:outpost:op-01234567890123456:bucket:mybucket", + "ForcePathStyle": true, + "Region": "cn-north-1", "UseDualStack": false, - "UseFIPS": true + "UseFIPS": false } }, { - "documentation": "vanilla virtual addressing@cn-north-1", + "documentation": "path style + invalid DNS name@cn-north-1", "expect": { "endpoint": { "properties": { @@ -11923,32 +13717,33 @@ } ] }, - "url": "https://bucket-name.s3.cn-north-1.amazonaws.com.cn" + "url": "https://s3.cn-north-1.amazonaws.com.cn/99a_b" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1" + "AWS::Region": "cn-north-1", + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "99a_b", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": false, + "Bucket": "99a_b", + "ForcePathStyle": true, "Region": "cn-north-1", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "virtual addressing + dualstack@cn-north-1", + "documentation": "no path style + invalid DNS name@cn-north-1", "expect": { "endpoint": { "properties": { @@ -11961,61 +13756,31 @@ } ] }, - "url": "https://bucket-name.s3.dualstack.cn-north-1.amazonaws.com.cn" + "url": "https://s3.cn-north-1.amazonaws.com.cn/99a_b" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1", - "AWS::UseDualStack": true + "AWS::Region": "cn-north-1" }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "99a_b", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": false, - "Region": "cn-north-1", - "UseDualStack": true, - "UseFIPS": false - } - }, - { - "documentation": "accelerate (dualstack=false)@cn-north-1", - "expect": { - "error": "S3 Accelerate cannot be used in this region" - }, - "params": { - "Accelerate": true, - "Bucket": "bucket-name", - "ForcePathStyle": false, + "Bucket": "99a_b", "Region": "cn-north-1", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "virtual addressing + fips@cn-north-1", - "expect": { - "error": "Partition does not support FIPS" - }, - "params": { - "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": false, - "Region": "cn-north-1", - "UseDualStack": false, - "UseFIPS": true - } - }, - { - "documentation": "vanilla virtual addressing@af-south-1", + "documentation": "vanilla path style@af-south-1", "expect": { "endpoint": { "properties": { @@ -12028,13 +13793,14 @@ } ] }, - "url": "https://bucket-name.s3.af-south-1.amazonaws.com" + "url": "https://s3.af-south-1.amazonaws.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1" + "AWS::Region": "af-south-1", + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { @@ -12046,34 +13812,35 @@ "params": { "Accelerate": false, "Bucket": "bucket-name", - "ForcePathStyle": false, + "ForcePathStyle": true, "Region": "af-south-1", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "virtual addressing + dualstack@af-south-1", + "documentation": "path style + fips@af-south-1", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "name": "sigv4", "signingName": "s3", "signingRegion": "af-south-1", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "name": "sigv4" } ] }, - "url": "https://bucket-name.s3.dualstack.af-south-1.amazonaws.com" + "url": "https://s3-fips.af-south-1.amazonaws.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "af-south-1", - "AWS::UseDualStack": true + "AWS::UseFIPS": true, + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { @@ -12085,34 +13852,22 @@ "params": { "Accelerate": false, "Bucket": "bucket-name", - "ForcePathStyle": false, + "ForcePathStyle": true, "Region": "af-south-1", - "UseDualStack": true, - "UseFIPS": false + "UseDualStack": false, + "UseFIPS": true } }, { - "documentation": "accelerate + dualstack@af-south-1", + "documentation": "path style + accelerate = error@af-south-1", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "signingRegion": "af-south-1", - "disableDoubleEncoding": true - } - ] - }, - "url": "https://bucket-name.s3-accelerate.dualstack.amazonaws.com" - } + "error": "Path-style addressing cannot be used with S3 Accelerate" }, "operationInputs": [ { "builtInParams": { "AWS::Region": "af-south-1", - "AWS::UseDualStack": true, + "AWS::S3::ForcePathStyle": true, "AWS::S3::Accelerate": true }, "operationName": "GetObject", @@ -12125,14 +13880,14 @@ "params": { "Accelerate": true, "Bucket": "bucket-name", - "ForcePathStyle": false, + "ForcePathStyle": true, "Region": "af-south-1", - "UseDualStack": true, + "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "accelerate (dualstack=false)@af-south-1", + "documentation": "path style + dualstack@af-south-1", "expect": { "endpoint": { "properties": { @@ -12145,14 +13900,15 @@ } ] }, - "url": "https://bucket-name.s3-accelerate.amazonaws.com" + "url": "https://s3.dualstack.af-south-1.amazonaws.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "af-south-1", - "AWS::S3::Accelerate": true + "AWS::UseDualStack": true, + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { @@ -12162,55 +13918,43 @@ } ], "params": { - "Accelerate": true, + "Accelerate": false, "Bucket": "bucket-name", - "ForcePathStyle": false, + "ForcePathStyle": true, "Region": "af-south-1", - "UseDualStack": false, + "UseDualStack": true, "UseFIPS": false } }, { - "documentation": "virtual addressing + fips@af-south-1", + "documentation": "path style + arn is error@af-south-1", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "signingRegion": "af-south-1", - "disableDoubleEncoding": true - } - ] - }, - "url": "https://bucket-name.s3-fips.af-south-1.amazonaws.com" - } + "error": "Path-style addressing cannot be used with ARN buckets" }, "operationInputs": [ { "builtInParams": { "AWS::Region": "af-south-1", - "AWS::UseFIPS": true + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:PARTITION:s3-outposts:REGION:123456789012:outpost:op-01234567890123456:bucket:mybucket", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": false, + "Bucket": "arn:PARTITION:s3-outposts:REGION:123456789012:outpost:op-01234567890123456:bucket:mybucket", + "ForcePathStyle": true, "Region": "af-south-1", "UseDualStack": false, - "UseFIPS": true + "UseFIPS": false } }, { - "documentation": "virtual addressing + dualstack + fips@af-south-1", + "documentation": "path style + invalid DNS name@af-south-1", "expect": { "endpoint": { "properties": { @@ -12223,62 +13967,70 @@ } ] }, - "url": "https://bucket-name.s3-fips.dualstack.af-south-1.amazonaws.com" + "url": "https://s3.af-south-1.amazonaws.com/99a_b" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "af-south-1", - "AWS::UseFIPS": true, - "AWS::UseDualStack": true + "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "99a_b", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": false, + "Bucket": "99a_b", + "ForcePathStyle": true, "Region": "af-south-1", - "UseDualStack": true, - "UseFIPS": true + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "accelerate + fips = error@af-south-1", + "documentation": "no path style + invalid DNS name@af-south-1", "expect": { - "error": "Accelerate cannot be used with FIPS" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "af-south-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://s3.af-south-1.amazonaws.com/99a_b" + } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "AWS::UseFIPS": true, - "AWS::S3::Accelerate": true + "AWS::Region": "af-south-1" }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "99a_b", "Key": "key" } } ], "params": { - "Accelerate": true, - "Bucket": "bucket-name", - "ForcePathStyle": false, + "Accelerate": false, + "Bucket": "99a_b", "Region": "af-south-1", "UseDualStack": false, - "UseFIPS": true + "UseFIPS": false } }, { - "documentation": "vanilla path style@us-west-2", + "documentation": "virtual addressing + private link@us-west-2", "expect": { "endpoint": { "properties": { @@ -12291,14 +14043,14 @@ } ] }, - "url": "https://s3.us-west-2.amazonaws.com/bucket-name" + "url": "http://bucket-name.control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-west-2", - "AWS::S3::ForcePathStyle": true + "SDK::Endpoint": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" }, "operationName": "GetObject", "operationParams": { @@ -12310,62 +14062,65 @@ "params": { "Accelerate": false, "Bucket": "bucket-name", - "ForcePathStyle": true, + "ForcePathStyle": false, + "Endpoint": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", "Region": "us-west-2", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "fips@us-gov-west-2, bucket is not S3-dns-compatible (subdomains)", + "documentation": "path style + private link@us-west-2", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "name": "sigv4", "signingName": "s3", - "signingRegion": "us-gov-west-1", - "disableDoubleEncoding": true, - "name": "sigv4" + "signingRegion": "us-west-2", + "disableDoubleEncoding": true } ] }, - "url": "https://s3-fips.us-gov-west-1.amazonaws.com/bucket.with.dots" + "url": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-gov-west-1", - "AWS::UseFIPS": true, + "AWS::Region": "us-west-2", + "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket.with.dots", + "Bucket": "bucket-name", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket.with.dots", - "Region": "us-gov-west-1", + "Bucket": "bucket-name", + "ForcePathStyle": true, + "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", + "Region": "us-west-2", "UseDualStack": false, - "UseFIPS": true + "UseFIPS": false } }, { - "documentation": "path style + accelerate = error@us-west-2", + "documentation": "SDK::Host + FIPS@us-west-2", "expect": { - "error": "Path-style addressing cannot be used with S3 Accelerate" + "error": "A custom endpoint cannot be combined with FIPS" }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-west-2", - "AWS::S3::ForcePathStyle": true, - "AWS::S3::Accelerate": true + "AWS::UseFIPS": true, + "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" }, "operationName": "GetObject", "operationParams": { @@ -12375,37 +14130,26 @@ } ], "params": { - "Accelerate": true, + "Accelerate": false, "Bucket": "bucket-name", - "ForcePathStyle": true, + "ForcePathStyle": false, + "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", "Region": "us-west-2", "UseDualStack": false, - "UseFIPS": false + "UseFIPS": true } }, { - "documentation": "path style + dualstack@us-west-2", + "documentation": "SDK::Host + DualStack@us-west-2", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "signingRegion": "us-west-2", - "disableDoubleEncoding": true - } - ] - }, - "url": "https://s3.dualstack.us-west-2.amazonaws.com/bucket-name" - } + "error": "Cannot set dual-stack in combination with a custom endpoint." }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-west-2", "AWS::UseDualStack": true, - "AWS::S3::ForcePathStyle": true + "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" }, "operationName": "GetObject", "operationParams": { @@ -12417,41 +14161,44 @@ "params": { "Accelerate": false, "Bucket": "bucket-name", - "ForcePathStyle": true, + "ForcePathStyle": false, + "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", "Region": "us-west-2", "UseDualStack": true, "UseFIPS": false } }, { - "documentation": "path style + arn is error@us-west-2", + "documentation": "SDK::HOST + accelerate@us-west-2", "expect": { - "error": "Path-style addressing cannot be used with ARN buckets" + "error": "A custom endpoint cannot be combined with S3 Accelerate" }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-west-2", - "AWS::S3::ForcePathStyle": true + "SDK::Endpoint": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", + "AWS::S3::Accelerate": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:PARTITION:s3-outposts:REGION:123456789012:outpost:op-01234567890123456:bucket:mybucket", + "Bucket": "bucket-name", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "arn:PARTITION:s3-outposts:REGION:123456789012:outpost:op-01234567890123456:bucket:mybucket", - "ForcePathStyle": true, + "Accelerate": true, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Endpoint": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", "Region": "us-west-2", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "path style + invalid DNS name@us-west-2", + "documentation": "SDK::Host + access point ARN@us-west-2", "expect": { "endpoint": { "properties": { @@ -12464,33 +14211,34 @@ } ] }, - "url": "https://s3.us-west-2.amazonaws.com/99a_b" + "url": "https://myendpoint-123456789012.beta.example.com" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-west-2", - "AWS::S3::ForcePathStyle": true + "SDK::Endpoint": "https://beta.example.com" }, "operationName": "GetObject", "operationParams": { - "Bucket": "99a_b", + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "99a_b", - "ForcePathStyle": true, + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "Endpoint": "https://beta.example.com", "Region": "us-west-2", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "no path style + invalid DNS name@us-west-2", + "documentation": "virtual addressing + private link@cn-north-1", "expect": { "endpoint": { "properties": { @@ -12498,36 +14246,39 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", + "signingRegion": "cn-north-1", "disableDoubleEncoding": true } ] }, - "url": "https://s3.us-west-2.amazonaws.com/99a_b" + "url": "https://bucket-name.control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2" + "AWS::Region": "cn-north-1", + "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" }, "operationName": "GetObject", "operationParams": { - "Bucket": "99a_b", + "Bucket": "bucket-name", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "99a_b", - "Region": "us-west-2", + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", + "Region": "cn-north-1", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "vanilla path style@cn-north-1", + "documentation": "path style + private link@cn-north-1", "expect": { "endpoint": { "properties": { @@ -12540,13 +14291,14 @@ } ] }, - "url": "https://s3.cn-north-1.amazonaws.com.cn/bucket-name" + "url": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "cn-north-1", + "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", @@ -12560,22 +14312,37 @@ "Accelerate": false, "Bucket": "bucket-name", "ForcePathStyle": true, + "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", "Region": "cn-north-1", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "path style + fips@cn-north-1", + "documentation": "FIPS@cn-north-1", "expect": { "error": "Partition does not support FIPS" }, + "params": { + "Accelerate": false, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Region": "cn-north-1", + "UseDualStack": false, + "UseFIPS": true + } + }, + { + "documentation": "SDK::Host + DualStack@cn-north-1", + "expect": { + "error": "Cannot set dual-stack in combination with a custom endpoint." + }, "operationInputs": [ { "builtInParams": { "AWS::Region": "cn-north-1", - "AWS::UseFIPS": true, - "AWS::S3::ForcePathStyle": true + "AWS::UseDualStack": true, + "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" }, "operationName": "GetObject", "operationParams": { @@ -12587,23 +14354,90 @@ "params": { "Accelerate": false, "Bucket": "bucket-name", - "ForcePathStyle": true, + "ForcePathStyle": false, + "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", + "Region": "cn-north-1", + "UseDualStack": true, + "UseFIPS": false + } + }, + { + "documentation": "SDK::HOST + accelerate@cn-north-1", + "expect": { + "error": "A custom endpoint cannot be combined with S3 Accelerate" + }, + "params": { + "Accelerate": true, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", "Region": "cn-north-1", "UseDualStack": false, - "UseFIPS": true + "UseFIPS": false } }, { - "documentation": "path style + accelerate = error@cn-north-1", + "documentation": "SDK::Host + access point ARN@cn-north-1", "expect": { - "error": "Path-style addressing cannot be used with S3 Accelerate" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "cn-north-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://myendpoint-123456789012.beta.example.com" + } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "cn-north-1", - "AWS::S3::ForcePathStyle": true, - "AWS::S3::Accelerate": true + "SDK::Endpoint": "https://beta.example.com" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "Key": "key" + } + } + ], + "params": { + "Accelerate": false, + "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "Endpoint": "https://beta.example.com", + "Region": "cn-north-1", + "UseDualStack": false, + "UseFIPS": false + } + }, + { + "documentation": "virtual addressing + private link@af-south-1", + "expect": { + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "af-south-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://bucket-name.control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" + } + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "af-south-1", + "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" }, "operationName": "GetObject", "operationParams": { @@ -12613,16 +14447,17 @@ } ], "params": { - "Accelerate": true, + "Accelerate": false, "Bucket": "bucket-name", - "ForcePathStyle": true, - "Region": "cn-north-1", + "ForcePathStyle": false, + "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", + "Region": "af-south-1", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "path style + dualstack@cn-north-1", + "documentation": "path style + private link@af-south-1", "expect": { "endpoint": { "properties": { @@ -12630,19 +14465,19 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "cn-north-1", + "signingRegion": "af-south-1", "disableDoubleEncoding": true } ] }, - "url": "https://s3.dualstack.cn-north-1.amazonaws.com.cn/bucket-name" + "url": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/bucket-name" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1", - "AWS::UseDualStack": true, + "AWS::Region": "af-south-1", + "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", "AWS::S3::ForcePathStyle": true }, "operationName": "GetObject", @@ -12656,79 +14491,101 @@ "Accelerate": false, "Bucket": "bucket-name", "ForcePathStyle": true, - "Region": "cn-north-1", - "UseDualStack": true, + "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", + "Region": "af-south-1", + "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "path style + arn is error@cn-north-1", + "documentation": "SDK::Host + FIPS@af-south-1", + "expect": { + "error": "A custom endpoint cannot be combined with FIPS" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "af-south-1", + "AWS::UseFIPS": true, + "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "bucket-name", + "Key": "key" + } + } + ], + "params": { + "Accelerate": false, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", + "Region": "af-south-1", + "UseDualStack": false, + "UseFIPS": true + } + }, + { + "documentation": "SDK::Host + DualStack@af-south-1", "expect": { - "error": "Path-style addressing cannot be used with ARN buckets" + "error": "Cannot set dual-stack in combination with a custom endpoint." }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1", - "AWS::S3::ForcePathStyle": true + "AWS::Region": "af-south-1", + "AWS::UseDualStack": true, + "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:PARTITION:s3-outposts:REGION:123456789012:outpost:op-01234567890123456:bucket:mybucket", + "Bucket": "bucket-name", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "arn:PARTITION:s3-outposts:REGION:123456789012:outpost:op-01234567890123456:bucket:mybucket", - "ForcePathStyle": true, - "Region": "cn-north-1", - "UseDualStack": false, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", + "Region": "af-south-1", + "UseDualStack": true, "UseFIPS": false } }, { - "documentation": "path style + invalid DNS name@cn-north-1", + "documentation": "SDK::HOST + accelerate@af-south-1", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "signingRegion": "cn-north-1", - "disableDoubleEncoding": true - } - ] - }, - "url": "https://s3.cn-north-1.amazonaws.com.cn/99a_b" - } + "error": "A custom endpoint cannot be combined with S3 Accelerate" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1", - "AWS::S3::ForcePathStyle": true + "AWS::Region": "af-south-1", + "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", + "AWS::S3::Accelerate": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "99a_b", + "Bucket": "bucket-name", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "99a_b", - "ForcePathStyle": true, - "Region": "cn-north-1", + "Accelerate": true, + "Bucket": "bucket-name", + "ForcePathStyle": false, + "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", + "Region": "af-south-1", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "no path style + invalid DNS name@cn-north-1", + "documentation": "SDK::Host + access point ARN@af-south-1", "expect": { "endpoint": { "properties": { @@ -12736,36 +14593,39 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "cn-north-1", + "signingRegion": "af-south-1", "disableDoubleEncoding": true } ] }, - "url": "https://s3.cn-north-1.amazonaws.com.cn/99a_b" + "url": "https://myendpoint-123456789012.beta.example.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1" + "AWS::Region": "af-south-1", + "SDK::Endpoint": "https://beta.example.com" }, "operationName": "GetObject", "operationParams": { - "Bucket": "99a_b", + "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "99a_b", - "Region": "cn-north-1", + "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "Endpoint": "https://beta.example.com", + "Region": "af-south-1", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "vanilla path style@af-south-1", + "documentation": "vanilla access point arn@us-west-2", "expect": { "endpoint": { "properties": { @@ -12773,106 +14633,103 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "af-south-1", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://s3.af-south-1.amazonaws.com/bucket-name" + "url": "https://myendpoint-123456789012.s3-accesspoint.us-west-2.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "AWS::S3::ForcePathStyle": true + "AWS::Region": "us-west-2" }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": true, - "Region": "af-south-1", + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "Region": "us-west-2", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "path style + fips@af-south-1", + "documentation": "access point arn + FIPS@us-west-2", "expect": { "endpoint": { "properties": { "authSchemes": [ { + "name": "sigv4", "signingName": "s3", - "signingRegion": "af-south-1", - "disableDoubleEncoding": true, - "name": "sigv4" + "signingRegion": "us-west-2", + "disableDoubleEncoding": true } ] }, - "url": "https://s3-fips.af-south-1.amazonaws.com/bucket-name" + "url": "https://myendpoint-123456789012.s3-accesspoint-fips.us-west-2.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "AWS::UseFIPS": true, - "AWS::S3::ForcePathStyle": true + "AWS::Region": "us-west-2", + "AWS::UseFIPS": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": true, - "Region": "af-south-1", + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "Region": "us-west-2", "UseDualStack": false, "UseFIPS": true } }, { - "documentation": "path style + accelerate = error@af-south-1", + "documentation": "access point arn + accelerate = error@us-west-2", "expect": { - "error": "Path-style addressing cannot be used with S3 Accelerate" + "error": "Access Points do not support S3 Accelerate" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "AWS::S3::ForcePathStyle": true, + "AWS::Region": "us-west-2", "AWS::S3::Accelerate": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { "Accelerate": true, - "Bucket": "bucket-name", - "ForcePathStyle": true, - "Region": "af-south-1", + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "Region": "us-west-2", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "path style + dualstack@af-south-1", + "documentation": "access point arn + FIPS + DualStack@us-west-2", "expect": { "endpoint": { "properties": { @@ -12880,66 +14737,39 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "af-south-1", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://s3.dualstack.af-south-1.amazonaws.com/bucket-name" + "url": "https://myendpoint-123456789012.s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "AWS::UseDualStack": true, - "AWS::S3::ForcePathStyle": true + "AWS::Region": "us-west-2", + "AWS::UseFIPS": true, + "AWS::UseDualStack": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": true, - "Region": "af-south-1", + "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "Region": "us-west-2", "UseDualStack": true, - "UseFIPS": false - } - }, - { - "documentation": "path style + arn is error@af-south-1", - "expect": { - "error": "Path-style addressing cannot be used with ARN buckets" - }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "af-south-1", - "AWS::S3::ForcePathStyle": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:PARTITION:s3-outposts:REGION:123456789012:outpost:op-01234567890123456:bucket:mybucket", - "Key": "key" - } - } - ], - "params": { - "Accelerate": false, - "Bucket": "arn:PARTITION:s3-outposts:REGION:123456789012:outpost:op-01234567890123456:bucket:mybucket", - "ForcePathStyle": true, - "Region": "af-south-1", - "UseDualStack": false, - "UseFIPS": false + "UseFIPS": true } }, { - "documentation": "path style + invalid DNS name@af-south-1", + "documentation": "vanilla access point arn@cn-north-1", "expect": { "endpoint": { "properties": { @@ -12947,75 +14777,92 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "af-south-1", + "signingRegion": "cn-north-1", "disableDoubleEncoding": true } ] }, - "url": "https://s3.af-south-1.amazonaws.com/99a_b" + "url": "https://myendpoint-123456789012.s3-accesspoint.cn-north-1.amazonaws.com.cn" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "AWS::S3::ForcePathStyle": true + "AWS::Region": "cn-north-1" }, "operationName": "GetObject", "operationParams": { - "Bucket": "99a_b", + "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "99a_b", - "ForcePathStyle": true, - "Region": "af-south-1", + "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "Region": "cn-north-1", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "no path style + invalid DNS name@af-south-1", + "documentation": "access point arn + FIPS@cn-north-1", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "signingRegion": "af-south-1", - "disableDoubleEncoding": true - } - ] - }, - "url": "https://s3.af-south-1.amazonaws.com/99a_b" - } + "error": "Partition does not support FIPS" + }, + "params": { + "Accelerate": false, + "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "Region": "cn-north-1", + "UseDualStack": false, + "UseFIPS": true + } + }, + { + "documentation": "access point arn + accelerate = error@cn-north-1", + "expect": { + "error": "Access Points do not support S3 Accelerate" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1" + "AWS::Region": "cn-north-1", + "AWS::S3::Accelerate": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "99a_b", + "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "99a_b", - "Region": "af-south-1", + "Accelerate": true, + "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "Region": "cn-north-1", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "virtual addressing + private link@us-west-2", + "documentation": "access point arn + FIPS + DualStack@cn-north-1", + "expect": { + "error": "Partition does not support FIPS" + }, + "params": { + "Accelerate": false, + "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "ForcePathStyle": false, + "Region": "cn-north-1", + "UseDualStack": true, + "UseFIPS": true + } + }, + { + "documentation": "vanilla access point arn@af-south-1", "expect": { "endpoint": { "properties": { @@ -13023,39 +14870,37 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", + "signingRegion": "af-south-1", "disableDoubleEncoding": true } ] }, - "url": "http://bucket-name.control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" + "url": "https://myendpoint-123456789012.s3-accesspoint.af-south-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "SDK::Endpoint": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" + "AWS::Region": "af-south-1" }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", "ForcePathStyle": false, - "Endpoint": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "us-west-2", + "Region": "af-south-1", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "path style + private link@us-west-2", + "documentation": "access point arn + FIPS@af-south-1", "expect": { "endpoint": { "properties": { @@ -13063,127 +14908,65 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", + "signingRegion": "af-south-1", "disableDoubleEncoding": true } ] }, - "url": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/bucket-name" - } - }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2", - "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "AWS::S3::ForcePathStyle": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } + "url": "https://myendpoint-123456789012.s3-accesspoint-fips.af-south-1.amazonaws.com" } - ], - "params": { - "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": true, - "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "us-west-2", - "UseDualStack": false, - "UseFIPS": false - } - }, - { - "documentation": "SDK::Host + FIPS@us-west-2", - "expect": { - "error": "A custom endpoint cannot be combined with FIPS" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::UseFIPS": true, - "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" + "AWS::Region": "af-south-1", + "AWS::UseFIPS": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", "ForcePathStyle": false, - "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "us-west-2", + "Region": "af-south-1", "UseDualStack": false, "UseFIPS": true } }, { - "documentation": "SDK::Host + DualStack@us-west-2", - "expect": { - "error": "Cannot set dual-stack in combination with a custom endpoint." - }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::UseDualStack": true, - "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], - "params": { - "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": false, - "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "us-west-2", - "UseDualStack": true, - "UseFIPS": false - } - }, - { - "documentation": "SDK::HOST + accelerate@us-west-2", + "documentation": "access point arn + accelerate = error@af-south-1", "expect": { - "error": "A custom endpoint cannot be combined with S3 Accelerate" + "error": "Access Points do not support S3 Accelerate" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "SDK::Endpoint": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", + "AWS::Region": "af-south-1", "AWS::S3::Accelerate": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { "Accelerate": true, - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", "ForcePathStyle": false, - "Endpoint": "http://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "us-west-2", + "Region": "af-south-1", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "SDK::Host + access point ARN@us-west-2", + "documentation": "access point arn + FIPS + DualStack@af-south-1", "expect": { "endpoint": { "properties": { @@ -13191,1138 +14974,959 @@ { "name": "sigv4", "signingName": "s3", - "signingRegion": "us-west-2", + "signingRegion": "af-south-1", "disableDoubleEncoding": true } ] }, - "url": "https://myendpoint-123456789012.beta.example.com" + "url": "https://myendpoint-123456789012.s3-accesspoint-fips.dualstack.af-south-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "SDK::Endpoint": "https://beta.example.com" + "AWS::Region": "af-south-1", + "AWS::UseFIPS": true, + "AWS::UseDualStack": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", "ForcePathStyle": false, - "Endpoint": "https://beta.example.com", - "Region": "us-west-2", - "UseDualStack": false, - "UseFIPS": false + "Region": "af-south-1", + "UseDualStack": true, + "UseFIPS": true } }, { - "documentation": "virtual addressing + private link@cn-north-1", + "documentation": "S3 outposts vanilla test", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3", - "signingRegion": "cn-north-1", + "signingName": "s3-outposts", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://bucket-name.control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" + "url": "https://reports-123456789012.op-01234567890123456.s3-outposts.us-west-2.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1", - "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" + "AWS::Region": "us-west-2" }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": false, - "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "cn-north-1", + "Region": "us-west-2", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports" } }, { - "documentation": "path style + private link@cn-north-1", + "documentation": "S3 outposts custom endpoint", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3", - "signingRegion": "cn-north-1", + "signingName": "s3-outposts", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/bucket-name" + "url": "https://reports-123456789012.op-01234567890123456.example.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1", - "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "AWS::S3::ForcePathStyle": true + "AWS::Region": "us-west-2", + "SDK::Endpoint": "https://example.amazonaws.com" }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": true, - "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "cn-north-1", + "Region": "us-west-2", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false - } - }, - { - "documentation": "FIPS@cn-north-1", - "expect": { - "error": "Partition does not support FIPS" - }, - "params": { "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": false, - "Region": "cn-north-1", - "UseDualStack": false, - "UseFIPS": true + "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports", + "Endpoint": "https://example.amazonaws.com" } }, { - "documentation": "SDK::Host + DualStack@cn-north-1", + "documentation": "outposts arn with region mismatch and UseArnRegion=false", "expect": { - "error": "Cannot set dual-stack in combination with a custom endpoint." + "error": "Invalid configuration: region from ARN `us-east-1` does not match client region `us-west-2` and UseArnRegion is `false`" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1", - "AWS::UseDualStack": true, - "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" + "AWS::Region": "us-west-2", + "AWS::S3::UseArnRegion": false }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": false, - "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "cn-north-1", - "UseDualStack": true, - "UseFIPS": false - } - }, - { - "documentation": "SDK::HOST + accelerate@cn-north-1", - "expect": { - "error": "A custom endpoint cannot be combined with S3 Accelerate" - }, - "params": { - "Accelerate": true, - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", "ForcePathStyle": false, - "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "cn-north-1", + "UseArnRegion": false, + "Region": "us-west-2", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "SDK::Host + access point ARN@cn-north-1", + "documentation": "outposts arn with region mismatch, custom region and UseArnRegion=false", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "signingRegion": "cn-north-1", - "disableDoubleEncoding": true - } - ] - }, - "url": "https://myendpoint-123456789012.beta.example.com" - } + "error": "Invalid configuration: region from ARN `us-east-1` does not match client region `us-west-2` and UseArnRegion is `false`" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1", - "SDK::Endpoint": "https://beta.example.com" + "AWS::Region": "us-west-2", + "SDK::Endpoint": "https://example.com", + "AWS::S3::UseArnRegion": false }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", + "Endpoint": "https://example.com", "ForcePathStyle": false, - "Endpoint": "https://beta.example.com", - "Region": "cn-north-1", + "UseArnRegion": false, + "Region": "us-west-2", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "virtual addressing + private link@af-south-1", + "documentation": "outposts arn with region mismatch and UseArnRegion=true", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3", - "signingRegion": "af-south-1", + "signingName": "s3-outposts", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://bucket-name.control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" + "url": "https://myaccesspoint-123456789012.op-01234567890123456.s3-outposts.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" + "AWS::Region": "us-west-2", + "AWS::S3::UseArnRegion": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", "ForcePathStyle": false, - "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "af-south-1", + "UseArnRegion": true, + "Region": "us-west-2", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "path style + private link@af-south-1", + "documentation": "outposts arn with region mismatch and UseArnRegion unset", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3", - "signingRegion": "af-south-1", + "signingName": "s3-outposts", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com/bucket-name" + "url": "https://myaccesspoint-123456789012.op-01234567890123456.s3-outposts.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "AWS::S3::ForcePathStyle": true + "AWS::Region": "us-west-2" }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": true, - "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "af-south-1", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", + "ForcePathStyle": false, + "Region": "us-west-2", "UseDualStack": false, "UseFIPS": false } }, { - "documentation": "SDK::Host + FIPS@af-south-1", + "documentation": "outposts arn with partition mismatch and UseArnRegion=true", "expect": { - "error": "A custom endpoint cannot be combined with FIPS" + "error": "Client was configured for partition `aws` but ARN (`arn:aws:s3-outposts:cn-north-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint`) has `aws-cn`" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "AWS::UseFIPS": true, - "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" + "AWS::Region": "us-west-2", + "AWS::S3::UseArnRegion": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3-outposts:cn-north-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", "Key": "key" } } ], "params": { "Accelerate": false, - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3-outposts:cn-north-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", "ForcePathStyle": false, - "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "af-south-1", + "UseArnRegion": true, + "Region": "us-west-2", "UseDualStack": false, - "UseFIPS": true + "UseFIPS": false } }, { - "documentation": "SDK::Host + DualStack@af-south-1", + "documentation": "ARN with UseGlobalEndpoint and use-east-1 region uses the regional endpoint", "expect": { - "error": "Cannot set dual-stack in combination with a custom endpoint." + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3-outposts", + "signingRegion": "us-east-1", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://reports-123456789012.op-01234567890123456.s3-outposts.us-east-1.amazonaws.com" + } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "AWS::UseDualStack": true, - "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com" + "AWS::Region": "us-east-1", + "AWS::S3::UseGlobalEndpoint": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "bucket-name", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456/accesspoint/reports", "Key": "key" } } ], "params": { + "Region": "us-east-1", + "UseGlobalEndpoint": true, + "UseFIPS": false, + "UseDualStack": false, "Accelerate": false, - "Bucket": "bucket-name", - "ForcePathStyle": false, - "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "af-south-1", + "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456/accesspoint/reports" + } + }, + { + "documentation": "S3 outposts does not support dualstack", + "expect": { + "error": "S3 Outposts does not support Dual-stack" + }, + "params": { + "Region": "us-east-1", + "UseFIPS": false, "UseDualStack": true, - "UseFIPS": false + "Accelerate": false, + "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports" } }, { - "documentation": "SDK::HOST + accelerate@af-south-1", + "documentation": "S3 outposts does not support fips", "expect": { - "error": "A custom endpoint cannot be combined with S3 Accelerate" + "error": "S3 Outposts does not support FIPS" + }, + "params": { + "Region": "us-east-1", + "UseFIPS": true, + "UseDualStack": false, + "Accelerate": false, + "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports" + } + }, + { + "documentation": "S3 outposts does not support accelerate", + "expect": { + "error": "S3 Outposts does not support S3 Accelerate" }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "af-south-1", - "SDK::Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "AWS::S3::Accelerate": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "bucket-name", - "Key": "key" - } - } - ], "params": { + "Region": "us-east-1", + "UseFIPS": false, + "UseDualStack": false, "Accelerate": true, - "Bucket": "bucket-name", - "ForcePathStyle": false, - "Endpoint": "https://control.vpce-1a2b3c4d-5e6f.s3.us-west-2.vpce.amazonaws.com", - "Region": "af-south-1", + "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports" + } + }, + { + "documentation": "validates against subresource", + "expect": { + "error": "Invalid Arn: Outpost Access Point ARN contains sub resources" + }, + "params": { + "Region": "us-west-2", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost:op-01234567890123456:accesspoint:mybucket:object:foo" } }, { - "documentation": "SDK::Host + access point ARN@af-south-1", + "documentation": "object lambda @us-east-1", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3", - "signingRegion": "af-south-1", + "signingName": "s3-object-lambda", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://myendpoint-123456789012.beta.example.com" + "url": "https://mybanner-123456789012.s3-object-lambda.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "SDK::Endpoint": "https://beta.example.com" + "AWS::Region": "us-east-1", + "AWS::S3::UseArnRegion": false }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, - "Endpoint": "https://beta.example.com", - "Region": "af-south-1", + "Region": "us-east-1", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "UseArnRegion": false, + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner" } }, { - "documentation": "vanilla access point arn@us-west-2", + "documentation": "object lambda @us-west-2", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3", + "signingName": "s3-object-lambda", "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://myendpoint-123456789012.s3-accesspoint.us-west-2.amazonaws.com" + "url": "https://mybanner-123456789012.s3-object-lambda.us-west-2.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2" + "AWS::Region": "us-west-2", + "AWS::S3::UseArnRegion": false }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, "Region": "us-west-2", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "UseArnRegion": false, + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner" } }, { - "documentation": "access point arn + FIPS@us-west-2", + "documentation": "object lambda, colon resource deliminator @us-west-2", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3", + "signingName": "s3-object-lambda", "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://myendpoint-123456789012.s3-accesspoint-fips.us-west-2.amazonaws.com" - } - }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::UseFIPS": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", - "Key": "key" - } + "url": "https://mybanner-123456789012.s3-object-lambda.us-west-2.amazonaws.com" } - ], - "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, - "Region": "us-west-2", - "UseDualStack": false, - "UseFIPS": true - } - }, - { - "documentation": "access point arn + accelerate = error@us-west-2", - "expect": { - "error": "Access Points do not support S3 Accelerate" }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-west-2", - "AWS::S3::Accelerate": true + "AWS::S3::UseArnRegion": false }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:mybanner", "Key": "key" } } ], "params": { - "Accelerate": true, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, "Region": "us-west-2", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "UseArnRegion": false, + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:mybanner" } }, { - "documentation": "access point arn + FIPS + DualStack@us-west-2", + "documentation": "object lambda @us-east-1, client region us-west-2, useArnRegion=true", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3", - "signingRegion": "us-west-2", + "signingName": "s3-object-lambda", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://myendpoint-123456789012.s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com" + "url": "https://mybanner-123456789012.s3-object-lambda.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-west-2", - "AWS::UseFIPS": true, - "AWS::UseDualStack": true + "AWS::S3::UseArnRegion": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", "Key": "key" } } ], - "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3:us-west-2:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, + "params": { "Region": "us-west-2", - "UseDualStack": true, - "UseFIPS": true + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false, + "UseArnRegion": true, + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner" } }, { - "documentation": "vanilla access point arn@cn-north-1", + "documentation": "object lambda @us-east-1, client region s3-external-1, useArnRegion=true", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3", - "signingRegion": "cn-north-1", + "signingName": "s3-object-lambda", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://myendpoint-123456789012.s3-accesspoint.cn-north-1.amazonaws.com.cn" + "url": "https://mybanner-123456789012.s3-object-lambda.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1" + "AWS::Region": "s3-external-1", + "AWS::S3::UseArnRegion": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, - "Region": "cn-north-1", + "Region": "s3-external-1", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false - } - }, - { - "documentation": "access point arn + FIPS@cn-north-1", - "expect": { - "error": "Partition does not support FIPS" - }, - "params": { "Accelerate": false, - "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, - "Region": "cn-north-1", - "UseDualStack": false, - "UseFIPS": true + "UseArnRegion": true, + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner" } }, { - "documentation": "access point arn + accelerate = error@cn-north-1", + "documentation": "object lambda @us-east-1, client region s3-external-1, useArnRegion=false", "expect": { - "error": "Access Points do not support S3 Accelerate" + "error": "Invalid configuration: region from ARN `us-east-1` does not match client region `s3-external-1` and UseArnRegion is `false`" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "cn-north-1", - "AWS::S3::Accelerate": true + "AWS::Region": "s3-external-1", + "AWS::S3::UseArnRegion": false }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", "Key": "key" } } ], "params": { - "Accelerate": true, - "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, - "Region": "cn-north-1", + "Region": "s3-external-1", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false - } - }, - { - "documentation": "access point arn + FIPS + DualStack@cn-north-1", - "expect": { - "error": "Partition does not support FIPS" - }, - "params": { "Accelerate": false, - "Bucket": "arn:aws-cn:s3:cn-north-1:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, - "Region": "cn-north-1", - "UseDualStack": true, - "UseFIPS": true + "UseArnRegion": false, + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner" } }, { - "documentation": "vanilla access point arn@af-south-1", + "documentation": "object lambda @us-east-1, client region aws-global, useArnRegion=true", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3", - "signingRegion": "af-south-1", + "signingName": "s3-object-lambda", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://myendpoint-123456789012.s3-accesspoint.af-south-1.amazonaws.com" + "url": "https://mybanner-123456789012.s3-object-lambda.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1" + "AWS::Region": "aws-global", + "AWS::S3::UseArnRegion": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, - "Region": "af-south-1", + "Region": "aws-global", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "UseArnRegion": true, + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner" } }, { - "documentation": "access point arn + FIPS@af-south-1", + "documentation": "object lambda @us-east-1, client region aws-global, useArnRegion=false", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "signingRegion": "af-south-1", - "disableDoubleEncoding": true - } - ] - }, - "url": "https://myendpoint-123456789012.s3-accesspoint-fips.af-south-1.amazonaws.com" - } + "error": "Invalid configuration: region from ARN `us-east-1` does not match client region `aws-global` and UseArnRegion is `false`" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "AWS::UseFIPS": true + "AWS::Region": "aws-global", + "AWS::S3::UseArnRegion": false }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, - "Region": "af-south-1", + "Region": "aws-global", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": true + "Accelerate": false, + "UseArnRegion": false, + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner" } }, { - "documentation": "access point arn + accelerate = error@af-south-1", + "documentation": "object lambda @cn-north-1, client region us-west-2 (cross partition), useArnRegion=true", "expect": { - "error": "Access Points do not support S3 Accelerate" + "error": "Client was configured for partition `aws` but ARN (`arn:aws-cn:s3-object-lambda:cn-north-1:123456789012:accesspoint/mybanner`) has `aws-cn`" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "AWS::S3::Accelerate": true + "AWS::Region": "aws-global", + "AWS::S3::UseArnRegion": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws-cn:s3-object-lambda:cn-north-1:123456789012:accesspoint/mybanner", "Key": "key" } } ], "params": { - "Accelerate": true, - "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, - "Region": "af-south-1", + "Region": "aws-global", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "UseArnRegion": true, + "Bucket": "arn:aws-cn:s3-object-lambda:cn-north-1:123456789012:accesspoint/mybanner" } }, { - "documentation": "access point arn + FIPS + DualStack@af-south-1", + "documentation": "object lambda with dualstack", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "signingRegion": "af-south-1", - "disableDoubleEncoding": true - } - ] - }, - "url": "https://myendpoint-123456789012.s3-accesspoint-fips.dualstack.af-south-1.amazonaws.com" - } + "error": "S3 Object Lambda does not support Dual-stack" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "af-south-1", - "AWS::UseFIPS": true, - "AWS::UseDualStack": true + "AWS::Region": "us-west-2", + "AWS::UseDualStack": true, + "AWS::S3::UseArnRegion": false }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3:af-south-1:123456789012:accesspoint:myendpoint", - "ForcePathStyle": false, - "Region": "af-south-1", + "Region": "us-west-2", + "UseFIPS": false, "UseDualStack": true, - "UseFIPS": true + "Accelerate": false, + "UseArnRegion": false, + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner" } }, { - "documentation": "S3 outposts vanilla test", + "documentation": "object lambda @us-gov-east-1", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "us-west-2", + "signingName": "s3-object-lambda", + "signingRegion": "us-gov-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://reports-123456789012.op-01234567890123456.s3-outposts.us-west-2.amazonaws.com" + "url": "https://mybanner-123456789012.s3-object-lambda.us-gov-east-1.amazonaws.com" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2" - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports", - "Key": "key" - } - } - ], "params": { - "Region": "us-west-2", + "Region": "us-gov-east-1", "UseFIPS": false, "UseDualStack": false, "Accelerate": false, - "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports" + "UseArnRegion": false, + "Bucket": "arn:aws-us-gov:s3-object-lambda:us-gov-east-1:123456789012:accesspoint/mybanner" } }, { - "documentation": "S3 outposts custom endpoint", + "documentation": "object lambda @us-gov-east-1, with fips", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "us-west-2", + "signingName": "s3-object-lambda", + "signingRegion": "us-gov-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://reports-123456789012.op-01234567890123456.example.amazonaws.com" + "url": "https://mybanner-123456789012.s3-object-lambda-fips.us-gov-east-1.amazonaws.com" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2", - "SDK::Endpoint": "https://example.amazonaws.com" - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports", - "Key": "key" - } - } - ], "params": { - "Region": "us-west-2", - "UseFIPS": false, + "Region": "us-gov-east-1", + "UseFIPS": true, "UseDualStack": false, "Accelerate": false, - "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports", - "Endpoint": "https://example.amazonaws.com" + "UseArnRegion": false, + "Bucket": "arn:aws-us-gov:s3-object-lambda:us-gov-east-1:123456789012:accesspoint/mybanner" } }, { - "documentation": "outposts arn with region mismatch and UseArnRegion=false", + "documentation": "object lambda @cn-north-1, with fips", "expect": { - "error": "Invalid configuration: region from ARN `us-east-1` does not match client region `us-west-2` and UseArnRegion is `false`" + "error": "Partition does not support FIPS" + }, + "params": { + "Region": "cn-north-1", + "UseFIPS": true, + "UseDualStack": false, + "Accelerate": false, + "UseArnRegion": false, + "Bucket": "arn:aws-cn:s3-object-lambda:cn-north-1:123456789012:accesspoint/mybanner" + } + }, + { + "documentation": "object lambda with accelerate", + "expect": { + "error": "S3 Object Lambda does not support S3 Accelerate" }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-west-2", + "AWS::S3::Accelerate": true, "AWS::S3::UseArnRegion": false }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", - "ForcePathStyle": false, - "UseArnRegion": false, "Region": "us-west-2", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": true, + "UseArnRegion": false, + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner" } }, { - "documentation": "outposts arn with region mismatch, custom region and UseArnRegion=false", + "documentation": "object lambda with invalid arn - bad service and someresource", "expect": { - "error": "Invalid configuration: region from ARN `us-east-1` does not match client region `us-west-2` and UseArnRegion is `false`" + "error": "Invalid ARN: Unrecognized format: arn:aws:sqs:us-west-2:123456789012:someresource (type: someresource)" }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-west-2", - "SDK::Endpoint": "https://example.com", "AWS::S3::UseArnRegion": false }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", + "Bucket": "arn:aws:sqs:us-west-2:123456789012:someresource", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", - "Endpoint": "https://example.com", - "ForcePathStyle": false, - "UseArnRegion": false, "Region": "us-west-2", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "UseArnRegion": false, + "Bucket": "arn:aws:sqs:us-west-2:123456789012:someresource" } }, { - "documentation": "outposts arn with region mismatch and UseArnRegion=true", + "documentation": "object lambda with invalid arn - invalid resource", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "us-east-1", - "disableDoubleEncoding": true - } - ] - }, - "url": "https://myaccesspoint-123456789012.op-01234567890123456.s3-outposts.us-east-1.amazonaws.com" - } + "error": "Invalid ARN: Object Lambda ARNs only support `accesspoint` arn types, but found: `bucket_name`" }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::S3::UseArnRegion": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", - "Key": "key" - } - } - ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", - "ForcePathStyle": false, - "UseArnRegion": true, "Region": "us-west-2", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "UseArnRegion": false, + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:bucket_name:mybucket" } }, { - "documentation": "outposts arn with region mismatch and UseArnRegion unset", + "documentation": "object lambda with invalid arn - missing region", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "us-east-1", - "disableDoubleEncoding": true - } - ] - }, - "url": "https://myaccesspoint-123456789012.op-01234567890123456.s3-outposts.us-east-1.amazonaws.com" - } + "error": "Invalid ARN: bucket ARN is missing a region" }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2" - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", - "Key": "key" - } - } - ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", - "ForcePathStyle": false, "Region": "us-west-2", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "UseArnRegion": false, + "Bucket": "arn:aws:s3-object-lambda::123456789012:accesspoint/mybanner" } }, { - "documentation": "outposts arn with partition mismatch and UseArnRegion=true", + "documentation": "object lambda with invalid arn - missing account-id", "expect": { - "error": "Client was configured for partition `aws` but ARN (`arn:aws:s3-outposts:cn-north-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint`) has `aws-cn`" + "error": "Invalid ARN: Missing account id" }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::S3::UseArnRegion": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3-outposts:cn-north-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", - "Key": "key" - } - } - ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3-outposts:cn-north-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint", - "ForcePathStyle": false, - "UseArnRegion": true, "Region": "us-west-2", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "UseArnRegion": true, + "Bucket": "arn:aws:s3-object-lambda:us-west-2::accesspoint/mybanner" } }, { - "documentation": "ARN with UseGlobalEndpoint and use-east-1 region uses the regional endpoint", + "documentation": "object lambda with invalid arn - account id contains invalid characters", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "us-east-1", - "disableDoubleEncoding": true - } - ] - }, - "url": "https://reports-123456789012.op-01234567890123456.s3-outposts.us-east-1.amazonaws.com" - } + "error": "Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `123.45678.9012`" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::S3::UseGlobalEndpoint": true + "AWS::Region": "us-west-2", + "AWS::S3::UseArnRegion": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456/accesspoint/reports", + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123.45678.9012:accesspoint:mybucket", "Key": "key" } } ], "params": { - "Region": "us-east-1", - "UseGlobalEndpoint": true, + "Region": "us-west-2", "UseFIPS": false, "UseDualStack": false, "Accelerate": false, - "Bucket": "arn:aws:s3-outposts:us-east-1:123456789012:outpost/op-01234567890123456/accesspoint/reports" + "UseArnRegion": true, + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123.45678.9012:accesspoint:mybucket" } }, { - "documentation": "S3 outposts does not support dualstack", + "documentation": "object lambda with invalid arn - missing access point name", "expect": { - "error": "S3 Outposts does not support Dual-stack" + "error": "Invalid ARN: Expected a resource of the format `accesspoint:` but no name was provided" }, "params": { - "Region": "us-east-1", + "Region": "us-west-2", "UseFIPS": false, - "UseDualStack": true, + "UseDualStack": false, "Accelerate": false, - "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports" + "UseArnRegion": true, + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint" } }, { - "documentation": "S3 outposts does not support fips", + "documentation": "object lambda with invalid arn - access point name contains invalid character: *", "expect": { - "error": "S3 Outposts does not support FIPS" + "error": "Invalid ARN: The access point name may only contain a-z, A-Z, 0-9 and `-`. Found: `*`" }, "params": { - "Region": "us-east-1", - "UseFIPS": true, + "Region": "us-west-2", + "UseFIPS": false, "UseDualStack": false, "Accelerate": false, - "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports" + "UseArnRegion": true, + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:*" } }, { - "documentation": "S3 outposts does not support accelerate", + "documentation": "object lambda with invalid arn - access point name contains invalid character: .", "expect": { - "error": "S3 Outposts does not support S3 Accelerate" + "error": "Invalid ARN: The access point name may only contain a-z, A-Z, 0-9 and `-`. Found: `my.bucket`" }, "params": { - "Region": "us-east-1", + "Region": "us-west-2", "UseFIPS": false, "UseDualStack": false, - "Accelerate": true, - "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost/op-01234567890123456/accesspoint/reports" + "Accelerate": false, + "UseArnRegion": true, + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:my.bucket" } }, { - "documentation": "validates against subresource", + "documentation": "object lambda with invalid arn - access point name contains sub resources", "expect": { - "error": "Invalid Arn: Outpost Access Point ARN contains sub resources" + "error": "Invalid ARN: The ARN may only contain a single resource component after `accesspoint`." }, "params": { "Region": "us-west-2", "UseFIPS": false, "UseDualStack": false, "Accelerate": false, - "Bucket": "arn:aws:s3-outposts:us-west-2:123456789012:outpost:op-01234567890123456:accesspoint:mybucket:object:foo" + "UseArnRegion": true, + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:mybucket:object:foo" } }, { - "documentation": "object lambda @us-east-1", + "documentation": "object lambda with custom endpoint", "expect": { "endpoint": { "properties": { @@ -14330,38 +15934,68 @@ { "name": "sigv4", "signingName": "s3-object-lambda", - "signingRegion": "us-east-1", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } ] }, - "url": "https://mybanner-123456789012.s3-object-lambda.us-east-1.amazonaws.com" + "url": "https://mybanner-123456789012.my-endpoint.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1", + "AWS::Region": "us-west-2", + "SDK::Endpoint": "https://my-endpoint.com", "AWS::S3::UseArnRegion": false }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner", "Key": "key" } } ], "params": { - "Region": "us-east-1", + "Region": "us-west-2", "UseFIPS": false, "UseDualStack": false, "Accelerate": false, "UseArnRegion": false, - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner" + "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner", + "Endpoint": "https://my-endpoint.com" } }, { - "documentation": "object lambda @us-west-2", + "documentation": "object lambda arn with region mismatch and UseArnRegion=false", + "expect": { + "error": "Invalid configuration: region from ARN `us-east-1` does not match client region `us-west-2` and UseArnRegion is `false`" + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "AWS::S3::UseArnRegion": false + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", + "Key": "key" + } + } + ], + "params": { + "Accelerate": false, + "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", + "ForcePathStyle": false, + "UseArnRegion": false, + "Region": "us-west-2", + "UseDualStack": false, + "UseFIPS": false + } + }, + { + "documentation": "WriteGetObjectResponse @ us-west-2", "expect": { "endpoint": { "properties": { @@ -14374,33 +16008,31 @@ } ] }, - "url": "https://mybanner-123456789012.s3-object-lambda.us-west-2.amazonaws.com" + "url": "https://s3-object-lambda.us-west-2.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::S3::UseArnRegion": false + "AWS::Region": "us-west-2" }, - "operationName": "GetObject", + "operationName": "WriteGetObjectResponse", "operationParams": { - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner", - "Key": "key" + "RequestRoute": "RequestRoute", + "RequestToken": "RequestToken" } } ], "params": { + "Accelerate": false, + "UseObjectLambdaEndpoint": true, "Region": "us-west-2", - "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": false, - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner" + "UseFIPS": false } }, { - "documentation": "object lambda, colon resource deliminator @us-west-2", + "documentation": "WriteGetObjectResponse with custom endpoint", "expect": { "endpoint": { "properties": { @@ -14413,33 +16045,33 @@ } ] }, - "url": "https://mybanner-123456789012.s3-object-lambda.us-west-2.amazonaws.com" + "url": "https://my-endpoint.com" } }, "operationInputs": [ { "builtInParams": { "AWS::Region": "us-west-2", - "AWS::S3::UseArnRegion": false + "SDK::Endpoint": "https://my-endpoint.com" }, - "operationName": "GetObject", + "operationName": "WriteGetObjectResponse", "operationParams": { - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:mybanner", - "Key": "key" + "RequestRoute": "RequestRoute", + "RequestToken": "RequestToken" } } ], "params": { + "Accelerate": false, + "UseObjectLambdaEndpoint": true, + "Endpoint": "https://my-endpoint.com", "Region": "us-west-2", - "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": false, - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:mybanner" + "UseFIPS": false } }, { - "documentation": "object lambda @us-east-1, client region us-west-2, useArnRegion=true", + "documentation": "WriteGetObjectResponse @ us-east-1", "expect": { "endpoint": { "properties": { @@ -14452,33 +16084,31 @@ } ] }, - "url": "https://mybanner-123456789012.s3-object-lambda.us-east-1.amazonaws.com" + "url": "https://s3-object-lambda.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::S3::UseArnRegion": true + "AWS::Region": "us-east-1" }, - "operationName": "GetObject", + "operationName": "WriteGetObjectResponse", "operationParams": { - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", - "Key": "key" + "RequestRoute": "RequestRoute", + "RequestToken": "RequestToken" } } ], "params": { - "Region": "us-west-2", - "UseFIPS": false, - "UseDualStack": false, "Accelerate": false, - "UseArnRegion": true, - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner" + "UseObjectLambdaEndpoint": true, + "Region": "us-east-1", + "UseDualStack": false, + "UseFIPS": false } }, { - "documentation": "object lambda @us-east-1, client region s3-external-1, useArnRegion=true", + "documentation": "WriteGetObjectResponse with fips", "expect": { "endpoint": { "properties": { @@ -14491,60 +16121,97 @@ } ] }, - "url": "https://mybanner-123456789012.s3-object-lambda.us-east-1.amazonaws.com" + "url": "https://s3-object-lambda-fips.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "s3-external-1", - "AWS::S3::UseArnRegion": true + "AWS::Region": "us-east-1", + "AWS::UseFIPS": true }, - "operationName": "GetObject", + "operationName": "WriteGetObjectResponse", "operationParams": { - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", - "Key": "key" + "RequestRoute": "RequestRoute", + "RequestToken": "RequestToken" } } ], "params": { - "Region": "s3-external-1", - "UseFIPS": false, - "UseDualStack": false, "Accelerate": false, - "UseArnRegion": true, - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner" + "UseObjectLambdaEndpoint": true, + "Region": "us-east-1", + "UseDualStack": false, + "UseFIPS": true } }, { - "documentation": "object lambda @us-east-1, client region s3-external-1, useArnRegion=false", + "documentation": "WriteGetObjectResponse with dualstack", "expect": { - "error": "Invalid configuration: region from ARN `us-east-1` does not match client region `s3-external-1` and UseArnRegion is `false`" + "error": "S3 Object Lambda does not support Dual-stack" }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "s3-external-1", - "AWS::S3::UseArnRegion": false + "AWS::Region": "us-east-1", + "AWS::UseDualStack": true }, - "operationName": "GetObject", + "operationName": "WriteGetObjectResponse", "operationParams": { - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", - "Key": "key" + "RequestRoute": "RequestRoute", + "RequestToken": "RequestToken" } } ], "params": { - "Region": "s3-external-1", - "UseFIPS": false, + "Accelerate": false, + "UseObjectLambdaEndpoint": true, + "Region": "us-east-1", + "UseDualStack": true, + "UseFIPS": false + } + }, + { + "documentation": "WriteGetObjectResponse with accelerate", + "expect": { + "error": "S3 Object Lambda does not support S3 Accelerate" + }, + "params": { + "Accelerate": true, + "UseObjectLambdaEndpoint": true, + "Region": "us-east-1", "UseDualStack": false, + "UseFIPS": false + } + }, + { + "documentation": "WriteGetObjectResponse with fips in CN", + "expect": { + "error": "Partition does not support FIPS" + }, + "params": { "Accelerate": false, - "UseArnRegion": false, - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner" + "Region": "cn-north-1", + "UseObjectLambdaEndpoint": true, + "UseDualStack": false, + "UseFIPS": true } }, { - "documentation": "object lambda @us-east-1, client region aws-global, useArnRegion=true", + "documentation": "WriteGetObjectResponse with invalid partition", + "expect": { + "error": "Invalid region: region was not a valid DNS name." + }, + "params": { + "Accelerate": false, + "UseObjectLambdaEndpoint": true, + "Region": "not a valid DNS name", + "UseDualStack": false, + "UseFIPS": false + } + }, + { + "documentation": "WriteGetObjectResponse with an unknown partition", "expect": { "endpoint": { "properties": { @@ -14552,524 +16219,503 @@ { "name": "sigv4", "signingName": "s3-object-lambda", - "signingRegion": "us-east-1", - "disableDoubleEncoding": true + "disableDoubleEncoding": true, + "signingRegion": "us-east.special" } ] }, - "url": "https://mybanner-123456789012.s3-object-lambda.us-east-1.amazonaws.com" + "url": "https://s3-object-lambda.us-east.special.amazonaws.com" } }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "aws-global", - "AWS::S3::UseArnRegion": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", - "Key": "key" - } - } - ], "params": { - "Region": "aws-global", - "UseFIPS": false, - "UseDualStack": false, "Accelerate": false, - "UseArnRegion": true, - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner" - } - }, - { - "documentation": "object lambda @us-east-1, client region aws-global, useArnRegion=false", - "expect": { - "error": "Invalid configuration: region from ARN `us-east-1` does not match client region `aws-global` and UseArnRegion is `false`" - }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "aws-global", - "AWS::S3::UseArnRegion": false - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", - "Key": "key" - } - } - ], - "params": { - "Region": "aws-global", - "UseFIPS": false, + "UseObjectLambdaEndpoint": true, + "Region": "us-east.special", "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": false, - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner" + "UseFIPS": false } }, { - "documentation": "object lambda @cn-north-1, client region us-west-2 (cross partition), useArnRegion=true", + "documentation": "S3 Outposts bucketAlias Real Outpost Prod us-west-1", "expect": { - "error": "Client was configured for partition `aws` but ARN (`arn:aws-cn:s3-object-lambda:cn-north-1:123456789012:accesspoint/mybanner`) has `aws-cn`" - }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "aws-global", - "AWS::S3::UseArnRegion": true + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3-outposts", + "signingRegion": "us-west-1", + "disableDoubleEncoding": true + } + ] }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws-cn:s3-object-lambda:cn-north-1:123456789012:accesspoint/mybanner", - "Key": "key" - } + "url": "https://test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3.op-0b1d075431d83bebd.s3-outposts.us-west-1.amazonaws.com" } - ], + }, "params": { - "Region": "aws-global", + "Region": "us-west-1", + "Bucket": "test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": true, - "Bucket": "arn:aws-cn:s3-object-lambda:cn-north-1:123456789012:accesspoint/mybanner" + "Accelerate": false } }, { - "documentation": "object lambda with dualstack", + "documentation": "S3 Outposts bucketAlias Real Outpost Prod ap-east-1", "expect": { - "error": "S3 Object Lambda does not support Dual-stack" - }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::UseDualStack": true, - "AWS::S3::UseArnRegion": false + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3-outposts", + "signingRegion": "ap-east-1", + "disableDoubleEncoding": true + } + ] }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner", - "Key": "key" - } + "url": "https://test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3.op-0b1d075431d83bebd.s3-outposts.ap-east-1.amazonaws.com" } - ], + }, "params": { - "Region": "us-west-2", + "Region": "ap-east-1", + "Bucket": "test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3", "UseFIPS": false, - "UseDualStack": true, - "Accelerate": false, - "UseArnRegion": false, - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner" + "UseDualStack": false, + "Accelerate": false } }, { - "documentation": "object lambda @us-gov-east-1", + "documentation": "S3 Outposts bucketAlias Ec2 Outpost Prod us-east-1", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3-object-lambda", - "signingRegion": "us-gov-east-1", + "signingName": "s3-outposts", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } ] }, - "url": "https://mybanner-123456789012.s3-object-lambda.us-gov-east-1.amazonaws.com" + "url": "https://test-accessp-e0000075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3.ec2.s3-outposts.us-east-1.amazonaws.com" } }, "params": { - "Region": "us-gov-east-1", + "Region": "us-east-1", + "Bucket": "test-accessp-e0000075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": false, - "Bucket": "arn:aws-us-gov:s3-object-lambda:us-gov-east-1:123456789012:accesspoint/mybanner" + "Accelerate": false } }, { - "documentation": "object lambda @us-gov-east-1, with fips", + "documentation": "S3 Outposts bucketAlias Ec2 Outpost Prod me-south-1", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3-object-lambda", - "signingRegion": "us-gov-east-1", + "signingName": "s3-outposts", + "signingRegion": "me-south-1", "disableDoubleEncoding": true } ] }, - "url": "https://mybanner-123456789012.s3-object-lambda-fips.us-gov-east-1.amazonaws.com" + "url": "https://test-accessp-e0000075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3.ec2.s3-outposts.me-south-1.amazonaws.com" } }, "params": { - "Region": "us-gov-east-1", - "UseFIPS": true, - "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": false, - "Bucket": "arn:aws-us-gov:s3-object-lambda:us-gov-east-1:123456789012:accesspoint/mybanner" - } - }, - { - "documentation": "object lambda @cn-north-1, with fips", - "expect": { - "error": "Partition does not support FIPS" - }, - "params": { - "Region": "cn-north-1", - "UseFIPS": true, + "Region": "me-south-1", + "Bucket": "test-accessp-e0000075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3", + "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": false, - "Bucket": "arn:aws-cn:s3-object-lambda:cn-north-1:123456789012:accesspoint/mybanner" + "Accelerate": false } }, { - "documentation": "object lambda with accelerate", + "documentation": "S3 Outposts bucketAlias Real Outpost Beta", "expect": { - "error": "S3 Object Lambda does not support S3 Accelerate" - }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::S3::Accelerate": true, - "AWS::S3::UseArnRegion": false + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3-outposts", + "signingRegion": "us-east-1", + "disableDoubleEncoding": true + } + ] }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner", - "Key": "key" - } + "url": "https://test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kbeta0--op-s3.op-0b1d075431d83bebd.example.amazonaws.com" } - ], + }, "params": { - "Region": "us-west-2", + "Region": "us-east-1", + "Bucket": "test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kbeta0--op-s3", + "Endpoint": "https://example.amazonaws.com", "UseFIPS": false, "UseDualStack": false, - "Accelerate": true, - "UseArnRegion": false, - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner" + "Accelerate": false } }, { - "documentation": "object lambda with invalid arn - bad service and someresource", + "documentation": "S3 Outposts bucketAlias Ec2 Outpost Beta", "expect": { - "error": "Invalid ARN: Unrecognized format: arn:aws:sqs:us-west-2:123456789012:someresource (type: someresource)" - }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::S3::UseArnRegion": false + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3-outposts", + "signingRegion": "us-east-1", + "disableDoubleEncoding": true + } + ] }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:sqs:us-west-2:123456789012:someresource", - "Key": "key" - } + "url": "https://161743052723-e00000136899934034jeahy1t8gpzpbwjj8kb7beta0--op-s3.ec2.example.amazonaws.com" } - ], + }, "params": { - "Region": "us-west-2", + "Region": "us-east-1", + "Bucket": "161743052723-e00000136899934034jeahy1t8gpzpbwjj8kb7beta0--op-s3", + "Endpoint": "https://example.amazonaws.com", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": false, - "Bucket": "arn:aws:sqs:us-west-2:123456789012:someresource" + "Accelerate": false } }, { - "documentation": "object lambda with invalid arn - invalid resource", + "documentation": "S3 Outposts bucketAlias - No endpoint set for beta", "expect": { - "error": "Invalid ARN: Object Lambda ARNs only support `accesspoint` arn types, but found: `bucket_name`" + "error": "Expected a endpoint to be specified but no endpoint was found" }, "params": { - "Region": "us-west-2", + "Region": "us-east-1", + "Bucket": "test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kbeta0--op-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": false, - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:bucket_name:mybucket" + "Accelerate": false } }, { - "documentation": "object lambda with invalid arn - missing region", + "documentation": "S3 Outposts bucketAlias Invalid hardware type", "expect": { - "error": "Invalid ARN: bucket ARN is missing a region" + "error": "Unrecognized hardware type: \"Expected hardware type o or e but got h\"" }, "params": { - "Region": "us-west-2", + "Region": "us-east-1", + "Bucket": "test-accessp-h0000075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": false, - "Bucket": "arn:aws:s3-object-lambda::123456789012:accesspoint/mybanner" + "Accelerate": false } }, { - "documentation": "object lambda with invalid arn - missing account-id", + "documentation": "S3 Outposts bucketAlias Special character in Outpost Arn", "expect": { - "error": "Invalid ARN: Missing account id" + "error": "Invalid ARN: The outpost Id must only contain a-z, A-Z, 0-9 and `-`." }, "params": { - "Region": "us-west-2", + "Region": "us-east-1", + "Bucket": "test-accessp-o00000754%1d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": true, - "Bucket": "arn:aws:s3-object-lambda:us-west-2::accesspoint/mybanner" + "Accelerate": false } }, { - "documentation": "object lambda with invalid arn - account id contains invalid characters", + "documentation": "S3 Outposts bucketAlias - No endpoint set for beta", "expect": { - "error": "Invalid ARN: The account id may only contain a-z, A-Z, 0-9 and `-`. Found: `123.45678.9012`" + "error": "Expected a endpoint to be specified but no endpoint was found" }, - "operationInputs": [ - { - "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::S3::UseArnRegion": true - }, - "operationName": "GetObject", - "operationParams": { - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123.45678.9012:accesspoint:mybucket", - "Key": "key" - } - } - ], "params": { - "Region": "us-west-2", + "Region": "us-east-1", + "Bucket": "test-accessp-e0b1d075431d83bebde8xz5w8ijx1qzlbp3i3ebeta0--op-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": true, - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123.45678.9012:accesspoint:mybucket" + "Accelerate": false } }, { - "documentation": "object lambda with invalid arn - missing access point name", + "documentation": "S3 Snow with bucket", "expect": { - "error": "Invalid ARN: Expected a resource of the format `accesspoint:` but no name was provided" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "snow", + "disableDoubleEncoding": true + } + ] + }, + "url": "http://10.0.1.12:433/bucketName" + } }, "params": { - "Region": "us-west-2", + "Region": "snow", + "Bucket": "bucketName", + "Endpoint": "http://10.0.1.12:433", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": true, - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint" + "Accelerate": false } }, { - "documentation": "object lambda with invalid arn - access point name contains invalid character: *", + "documentation": "S3 Snow without bucket", "expect": { - "error": "Invalid ARN: The access point name may only contain a-z, A-Z, 0-9 and `-`. Found: `*`" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "snow", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://10.0.1.12:433" + } }, "params": { - "Region": "us-west-2", + "Region": "snow", + "Endpoint": "https://10.0.1.12:433", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": true, - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:*" + "Accelerate": false } }, { - "documentation": "object lambda with invalid arn - access point name contains invalid character: .", + "documentation": "S3 Snow no port", "expect": { - "error": "Invalid ARN: The access point name may only contain a-z, A-Z, 0-9 and `-`. Found: `my.bucket`" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "snow", + "disableDoubleEncoding": true + } + ] + }, + "url": "http://10.0.1.12/bucketName" + } }, "params": { - "Region": "us-west-2", + "Region": "snow", + "Bucket": "bucketName", + "Endpoint": "http://10.0.1.12", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": true, - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:my.bucket" + "Accelerate": false } }, { - "documentation": "object lambda with invalid arn - access point name contains sub resources", + "documentation": "S3 Snow dns endpoint", "expect": { - "error": "Invalid ARN: The ARN may only contain a single resource component after `accesspoint`." + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3", + "signingRegion": "snow", + "disableDoubleEncoding": true + } + ] + }, + "url": "https://amazonaws.com/bucketName" + } }, "params": { - "Region": "us-west-2", + "Region": "snow", + "Bucket": "bucketName", + "Endpoint": "https://amazonaws.com", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false, - "UseArnRegion": true, - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint:mybucket:object:foo" + "Accelerate": false } }, { - "documentation": "object lambda with custom endpoint", + "documentation": "Data Plane with short AZ", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "name": "sigv4", - "signingName": "s3-object-lambda", - "signingRegion": "us-west-2", + "name": "sigv4-s3express", + "signingName": "s3express", + "signingRegion": "us-east-1", "disableDoubleEncoding": true } - ] + ], + "backend": "S3Express" }, - "url": "https://mybanner-123456789012.my-endpoint.com" + "url": "https://mybucket--use1-az1--x-s3.s3express-use1-az1.us-east-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "SDK::Endpoint": "https://my-endpoint.com", - "AWS::S3::UseArnRegion": false + "AWS::Region": "us-east-1" }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner", + "Bucket": "mybucket--use1-az1--x-s3", "Key": "key" } } ], "params": { - "Region": "us-west-2", + "Region": "us-east-1", + "Bucket": "mybucket--use1-az1--x-s3", "UseFIPS": false, "UseDualStack": false, "Accelerate": false, - "UseArnRegion": false, - "Bucket": "arn:aws:s3-object-lambda:us-west-2:123456789012:accesspoint/mybanner", - "Endpoint": "https://my-endpoint.com" + "UseS3ExpressControlEndpoint": false } }, { - "documentation": "object lambda arn with region mismatch and UseArnRegion=false", + "documentation": "Data Plane with short AZ fips", "expect": { - "error": "Invalid configuration: region from ARN `us-east-1` does not match client region `us-west-2` and UseArnRegion is `false`" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4-s3express", + "signingName": "s3express", + "signingRegion": "us-east-1", + "disableDoubleEncoding": true + } + ], + "backend": "S3Express" + }, + "url": "https://mybucket--use1-az1--x-s3.s3express-fips-use1-az1.us-east-1.amazonaws.com" + } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "AWS::S3::UseArnRegion": false + "AWS::Region": "us-east-1", + "AWS::UseFIPS": true }, "operationName": "GetObject", "operationParams": { - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", + "Bucket": "mybucket--use1-az1--x-s3", "Key": "key" } } ], "params": { - "Accelerate": false, - "Bucket": "arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner", - "ForcePathStyle": false, - "UseArnRegion": false, - "Region": "us-west-2", + "Region": "us-east-1", + "Bucket": "mybucket--use1-az1--x-s3", + "UseFIPS": true, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "UseS3ExpressControlEndpoint": false } }, { - "documentation": "WriteGetObjectResponse @ us-west-2", + "documentation": "Data Plane with long AZ", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "name": "sigv4", - "signingName": "s3-object-lambda", - "signingRegion": "us-west-2", + "name": "sigv4-s3express", + "signingName": "s3express", + "signingRegion": "ap-northeast-1", "disableDoubleEncoding": true } - ] + ], + "backend": "S3Express" }, - "url": "https://s3-object-lambda.us-west-2.amazonaws.com" + "url": "https://mybucket--apne1-az1--x-s3.s3express-apne1-az1.ap-northeast-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2" + "AWS::Region": "ap-northeast-1" }, - "operationName": "WriteGetObjectResponse", + "operationName": "GetObject", "operationParams": { - "RequestRoute": "RequestRoute", - "RequestToken": "RequestToken" + "Bucket": "mybucket--apne1-az1--x-s3", + "Key": "key" } } ], "params": { - "Accelerate": false, - "UseObjectLambdaEndpoint": true, - "Region": "us-west-2", + "Region": "ap-northeast-1", + "Bucket": "mybucket--apne1-az1--x-s3", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "UseS3ExpressControlEndpoint": false } }, { - "documentation": "WriteGetObjectResponse with custom endpoint", + "documentation": "Data Plane with long AZ fips", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "name": "sigv4", - "signingName": "s3-object-lambda", - "signingRegion": "us-west-2", + "name": "sigv4-s3express", + "signingName": "s3express", + "signingRegion": "ap-northeast-1", "disableDoubleEncoding": true } - ] + ], + "backend": "S3Express" }, - "url": "https://my-endpoint.com" + "url": "https://mybucket--apne1-az1--x-s3.s3express-fips-apne1-az1.ap-northeast-1.amazonaws.com" } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-west-2", - "SDK::Endpoint": "https://my-endpoint.com" + "AWS::Region": "ap-northeast-1", + "AWS::UseFIPS": true }, - "operationName": "WriteGetObjectResponse", + "operationName": "GetObject", "operationParams": { - "RequestRoute": "RequestRoute", - "RequestToken": "RequestToken" + "Bucket": "mybucket--apne1-az1--x-s3", + "Key": "key" } } ], "params": { - "Accelerate": false, - "UseObjectLambdaEndpoint": true, - "Endpoint": "https://my-endpoint.com", - "Region": "us-west-2", + "Region": "ap-northeast-1", + "Bucket": "mybucket--apne1-az1--x-s3", + "UseFIPS": true, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "UseS3ExpressControlEndpoint": false } }, { - "documentation": "WriteGetObjectResponse @ us-east-1", + "documentation": "Control plane with short AZ bucket", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3-object-lambda", + "signingName": "s3express", "signingRegion": "us-east-1", "disableDoubleEncoding": true } - ] + ], + "backend": "S3Express" }, - "url": "https://s3-object-lambda.us-east-1.amazonaws.com" + "url": "https://s3express-control.us-east-1.amazonaws.com/mybucket--use1-az1--x-s3" } }, "operationInputs": [ @@ -15077,36 +16723,38 @@ "builtInParams": { "AWS::Region": "us-east-1" }, - "operationName": "WriteGetObjectResponse", + "operationName": "CreateBucket", "operationParams": { - "RequestRoute": "RequestRoute", - "RequestToken": "RequestToken" + "Bucket": "mybucket--use1-az1--x-s3" } } ], "params": { - "Accelerate": false, - "UseObjectLambdaEndpoint": true, "Region": "us-east-1", + "Bucket": "mybucket--use1-az1--x-s3", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "UseS3ExpressControlEndpoint": true, + "DisableS3ExpressSessionAuth": false } }, { - "documentation": "WriteGetObjectResponse with fips", + "documentation": "Control plane with short AZ bucket and fips", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3-object-lambda", + "signingName": "s3express", "signingRegion": "us-east-1", "disableDoubleEncoding": true } - ] + ], + "backend": "S3Express" }, - "url": "https://s3-object-lambda-fips.us-east-1.amazonaws.com" + "url": "https://s3express-control-fips.us-east-1.amazonaws.com/mybucket--use1-az1--x-s3" } }, "operationInputs": [ @@ -15115,416 +16763,542 @@ "AWS::Region": "us-east-1", "AWS::UseFIPS": true }, - "operationName": "WriteGetObjectResponse", + "operationName": "CreateBucket", "operationParams": { - "RequestRoute": "RequestRoute", - "RequestToken": "RequestToken" + "Bucket": "mybucket--use1-az1--x-s3" } } ], "params": { - "Accelerate": false, - "UseObjectLambdaEndpoint": true, "Region": "us-east-1", + "Bucket": "mybucket--use1-az1--x-s3", + "UseFIPS": true, "UseDualStack": false, - "UseFIPS": true + "Accelerate": false, + "UseS3ExpressControlEndpoint": true, + "DisableS3ExpressSessionAuth": false } }, { - "documentation": "WriteGetObjectResponse with dualstack", + "documentation": "Control plane without bucket", "expect": { - "error": "S3 Object Lambda does not support Dual-stack" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3express", + "signingRegion": "us-east-1", + "disableDoubleEncoding": true + } + ], + "backend": "S3Express" + }, + "url": "https://s3express-control.us-east-1.amazonaws.com" + } }, "operationInputs": [ { "builtInParams": { - "AWS::Region": "us-east-1", - "AWS::UseDualStack": true + "AWS::Region": "us-east-1" }, - "operationName": "WriteGetObjectResponse", - "operationParams": { - "RequestRoute": "RequestRoute", - "RequestToken": "RequestToken" - } + "operationName": "ListDirectoryBuckets" } ], "params": { - "Accelerate": false, - "UseObjectLambdaEndpoint": true, "Region": "us-east-1", - "UseDualStack": true, - "UseFIPS": false + "UseFIPS": false, + "UseDualStack": false, + "Accelerate": false, + "UseS3ExpressControlEndpoint": true, + "DisableS3ExpressSessionAuth": false } }, { - "documentation": "WriteGetObjectResponse with accelerate", + "documentation": "Control plane without bucket and fips", "expect": { - "error": "S3 Object Lambda does not support S3 Accelerate" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3express", + "signingRegion": "us-east-1", + "disableDoubleEncoding": true + } + ], + "backend": "S3Express" + }, + "url": "https://s3express-control-fips.us-east-1.amazonaws.com" + } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1", + "AWS::UseFIPS": true + }, + "operationName": "ListDirectoryBuckets" + } + ], "params": { - "Accelerate": true, - "UseObjectLambdaEndpoint": true, "Region": "us-east-1", + "UseFIPS": true, "UseDualStack": false, - "UseFIPS": false - } - }, - { - "documentation": "WriteGetObjectResponse with fips in CN", - "expect": { - "error": "Partition does not support FIPS" - }, - "params": { "Accelerate": false, - "Region": "cn-north-1", - "UseObjectLambdaEndpoint": true, - "UseDualStack": false, - "UseFIPS": true + "UseS3ExpressControlEndpoint": true, + "DisableS3ExpressSessionAuth": false } }, { - "documentation": "WriteGetObjectResponse with invalid partition", + "documentation": "Data Plane sigv4 auth with short AZ", "expect": { - "error": "Invalid region: region was not a valid DNS name." + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4", + "signingName": "s3express", + "signingRegion": "us-west-2", + "disableDoubleEncoding": true + } + ], + "backend": "S3Express" + }, + "url": "https://mybucket--usw2-az1--x-s3.s3express-usw2-az1.us-west-2.amazonaws.com" + } }, "params": { - "Accelerate": false, - "UseObjectLambdaEndpoint": true, - "Region": "not a valid DNS name", + "Region": "us-west-2", + "Bucket": "mybucket--usw2-az1--x-s3", + "UseFIPS": false, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "DisableS3ExpressSessionAuth": true } }, { - "documentation": "WriteGetObjectResponse with an unknown partition", + "documentation": "Data Plane sigv4 auth with short AZ fips", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3-object-lambda", - "disableDoubleEncoding": true, - "signingRegion": "us-east.special" + "signingName": "s3express", + "signingRegion": "us-west-2", + "disableDoubleEncoding": true } - ] + ], + "backend": "S3Express" }, - "url": "https://s3-object-lambda.us-east.special.amazonaws.com" + "url": "https://mybucket--usw2-az1--x-s3.s3express-fips-usw2-az1.us-west-2.amazonaws.com" } }, "params": { - "Accelerate": false, - "UseObjectLambdaEndpoint": true, - "Region": "us-east.special", + "Region": "us-west-2", + "Bucket": "mybucket--usw2-az1--x-s3", + "UseFIPS": true, "UseDualStack": false, - "UseFIPS": false + "Accelerate": false, + "DisableS3ExpressSessionAuth": true } }, { - "documentation": "S3 Outposts bucketAlias Real Outpost Prod us-west-1", + "documentation": "Data Plane sigv4 auth with long AZ", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "us-west-1", + "signingName": "s3express", + "signingRegion": "ap-northeast-1", "disableDoubleEncoding": true } - ] + ], + "backend": "S3Express" }, - "url": "https://test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3.op-0b1d075431d83bebd.s3-outposts.us-west-1.amazonaws.com" + "url": "https://mybucket--apne1-az1--x-s3.s3express-apne1-az1.ap-northeast-1.amazonaws.com" } }, "params": { - "Region": "us-west-1", - "Bucket": "test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3", + "Region": "ap-northeast-1", + "Bucket": "mybucket--apne1-az1--x-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": false, + "UseS3ExpressControlEndpoint": false, + "DisableS3ExpressSessionAuth": true } }, { - "documentation": "S3 Outposts bucketAlias Real Outpost Prod ap-east-1", + "documentation": "Data Plane sigv4 auth with long AZ fips", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "ap-east-1", + "signingName": "s3express", + "signingRegion": "ap-northeast-1", "disableDoubleEncoding": true } - ] + ], + "backend": "S3Express" }, - "url": "https://test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3.op-0b1d075431d83bebd.s3-outposts.ap-east-1.amazonaws.com" + "url": "https://mybucket--apne1-az1--x-s3.s3express-fips-apne1-az1.ap-northeast-1.amazonaws.com" } }, "params": { - "Region": "ap-east-1", - "Bucket": "test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3", - "UseFIPS": false, + "Region": "ap-northeast-1", + "Bucket": "mybucket--apne1-az1--x-s3", + "UseFIPS": true, "UseDualStack": false, - "Accelerate": false + "Accelerate": false, + "UseS3ExpressControlEndpoint": false, + "DisableS3ExpressSessionAuth": true } }, { - "documentation": "S3 Outposts bucketAlias Ec2 Outpost Prod us-east-1", + "documentation": "Control Plane host override", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "us-east-1", + "signingName": "s3express", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } - ] + ], + "backend": "S3Express" }, - "url": "https://test-accessp-e0000075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3.ec2.s3-outposts.us-east-1.amazonaws.com" + "url": "https://mybucket--usw2-az1--x-s3.custom.com" } }, "params": { - "Region": "us-east-1", - "Bucket": "test-accessp-e0000075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3", + "Region": "us-west-2", + "Bucket": "mybucket--usw2-az1--x-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": false, + "UseS3ExpressControlEndpoint": true, + "DisableS3ExpressSessionAuth": true, + "Endpoint": "https://custom.com" } }, { - "documentation": "S3 Outposts bucketAlias Ec2 Outpost Prod me-south-1", + "documentation": "Control Plane host override no bucket", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "me-south-1", + "signingName": "s3express", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } - ] + ], + "backend": "S3Express" }, - "url": "https://test-accessp-e0000075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3.ec2.s3-outposts.me-south-1.amazonaws.com" + "url": "https://custom.com" } }, "params": { - "Region": "me-south-1", - "Bucket": "test-accessp-e0000075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3", + "Region": "us-west-2", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": false, + "UseS3ExpressControlEndpoint": true, + "DisableS3ExpressSessionAuth": true, + "Endpoint": "https://custom.com" } }, { - "documentation": "S3 Outposts bucketAlias Real Outpost Beta", + "documentation": "Data plane host override non virtual session auth", "expect": { "endpoint": { "properties": { "authSchemes": [ { - "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "us-east-1", + "name": "sigv4-s3express", + "signingName": "s3express", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } - ] + ], + "backend": "S3Express" }, - "url": "https://test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kbeta0--op-s3.op-0b1d075431d83bebd.example.amazonaws.com" + "url": "https://10.0.0.1/mybucket--usw2-az1--x-s3" } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "SDK::Endpoint": "https://10.0.0.1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "mybucket--usw2-az1--x-s3", + "Key": "key" + } + } + ], "params": { - "Region": "us-east-1", - "Bucket": "test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kbeta0--op-s3", - "Endpoint": "https://example.amazonaws.com", + "Region": "us-west-2", + "Bucket": "mybucket--usw2-az1--x-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": false, + "Endpoint": "https://10.0.0.1" } }, { - "documentation": "S3 Outposts bucketAlias Ec2 Outpost Beta", + "documentation": "Control Plane host override ip", "expect": { "endpoint": { "properties": { "authSchemes": [ { "name": "sigv4", - "signingName": "s3-outposts", - "signingRegion": "us-east-1", + "signingName": "s3express", + "signingRegion": "us-west-2", "disableDoubleEncoding": true } - ] + ], + "backend": "S3Express" }, - "url": "https://161743052723-e00000136899934034jeahy1t8gpzpbwjj8kb7beta0--op-s3.ec2.example.amazonaws.com" + "url": "https://10.0.0.1/mybucket--usw2-az1--x-s3" } }, "params": { - "Region": "us-east-1", - "Bucket": "161743052723-e00000136899934034jeahy1t8gpzpbwjj8kb7beta0--op-s3", - "Endpoint": "https://example.amazonaws.com", + "Region": "us-west-2", + "Bucket": "mybucket--usw2-az1--x-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": false, + "UseS3ExpressControlEndpoint": true, + "DisableS3ExpressSessionAuth": true, + "Endpoint": "https://10.0.0.1" } }, { - "documentation": "S3 Outposts bucketAlias - No endpoint set for beta", + "documentation": "Data plane host override", "expect": { - "error": "Expected a endpoint to be specified but no endpoint was found" + "endpoint": { + "properties": { + "authSchemes": [ + { + "name": "sigv4-s3express", + "signingName": "s3express", + "signingRegion": "us-west-2", + "disableDoubleEncoding": true + } + ], + "backend": "S3Express" + }, + "url": "https://mybucket--usw2-az1--x-s3.custom.com" + } }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "SDK::Endpoint": "https://custom.com" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "mybucket--usw2-az1--x-s3", + "Key": "key" + } + } + ], "params": { - "Region": "us-east-1", - "Bucket": "test-accessp-o0b1d075431d83bebde8xz5w8ijx1qzlbp3i3kbeta0--op-s3", + "Region": "us-west-2", + "Bucket": "mybucket--usw2-az1--x-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": false, + "Endpoint": "https://custom.com" } }, { - "documentation": "S3 Outposts bucketAlias Invalid hardware type", + "documentation": "bad format error", "expect": { - "error": "Unrecognized hardware type: \"Expected hardware type o or e but got h\"" + "error": "Unrecognized S3Express bucket name format." }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "mybucket--usaz1--x-s3", + "Key": "key" + } + } + ], "params": { "Region": "us-east-1", - "Bucket": "test-accessp-h0000075431d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3", + "Bucket": "mybucket--usaz1--x-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": false, + "UseS3ExpressControlEndpoint": false } }, { - "documentation": "S3 Outposts bucketAlias Special character in Outpost Arn", + "documentation": "bad format error no session auth", "expect": { - "error": "Invalid ARN: The outpost Id must only contain a-z, A-Z, 0-9 and `-`." + "error": "Unrecognized S3Express bucket name format." }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1" + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "mybucket--usaz1--x-s3", + "Key": "key" + } + } + ], "params": { "Region": "us-east-1", - "Bucket": "test-accessp-o00000754%1d83bebde8xz5w8ijx1qzlbp3i3kuse10--op-s3", + "Bucket": "mybucket--usaz1--x-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": false, + "UseS3ExpressControlEndpoint": false, + "DisableS3ExpressSessionAuth": true } }, { - "documentation": "S3 Outposts bucketAlias - No endpoint set for beta", + "documentation": "dual-stack error", "expect": { - "error": "Expected a endpoint to be specified but no endpoint was found" + "error": "S3Express does not support Dual-stack." }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1", + "AWS::UseDualStack": true + }, + "operationName": "GetObject", + "operationParams": { + "Bucket": "mybucket--use1-az1--x-s3", + "Key": "key" + } + } + ], "params": { "Region": "us-east-1", - "Bucket": "test-accessp-e0b1d075431d83bebde8xz5w8ijx1qzlbp3i3ebeta0--op-s3", + "Bucket": "mybucket--use1-az1--x-s3", "UseFIPS": false, - "UseDualStack": false, - "Accelerate": false + "UseDualStack": true, + "Accelerate": false, + "UseS3ExpressControlEndpoint": false } }, { - "documentation": "S3 Snow with bucket", + "documentation": "accelerate error", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "signingRegion": "snow", - "disableDoubleEncoding": true - } - ] + "error": "S3Express does not support S3 Accelerate." + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1", + "AWS::S3::Accelerate": true }, - "url": "http://10.0.1.12:433/bucketName" + "operationName": "GetObject", + "operationParams": { + "Bucket": "mybucket--use1-az1--x-s3", + "Key": "key" + } } - }, + ], "params": { - "Region": "snow", - "Bucket": "bucketName", - "Endpoint": "http://10.0.1.12:433", + "Region": "us-east-1", + "Bucket": "mybucket--use1-az1--x-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": true, + "UseS3ExpressControlEndpoint": false } }, { - "documentation": "S3 Snow without bucket", + "documentation": "Data plane bucket format error", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "signingRegion": "snow", - "disableDoubleEncoding": true - } - ] + "error": "S3Express bucket name is not a valid virtual hostable name." + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-east-1" }, - "url": "https://10.0.1.12:433" + "operationName": "GetObject", + "operationParams": { + "Bucket": "my.bucket--use1-az1--x-s3", + "Key": "key" + } } - }, + ], "params": { - "Region": "snow", - "Endpoint": "https://10.0.1.12:433", + "Region": "us-east-1", + "Bucket": "my.bucket--use1-az1--x-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": false, + "UseS3ExpressControlEndpoint": false } }, { - "documentation": "S3 Snow no port", + "documentation": "host override data plane bucket error session auth", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "signingRegion": "snow", - "disableDoubleEncoding": true - } - ] + "error": "S3Express bucket name is not a valid virtual hostable name." + }, + "operationInputs": [ + { + "builtInParams": { + "AWS::Region": "us-west-2", + "SDK::Endpoint": "https://custom.com" }, - "url": "http://10.0.1.12/bucketName" + "operationName": "GetObject", + "operationParams": { + "Bucket": "my.bucket--usw2-az1--x-s3", + "Key": "key" + } } - }, + ], "params": { - "Region": "snow", - "Bucket": "bucketName", - "Endpoint": "http://10.0.1.12", + "Region": "us-west-2", + "Bucket": "my.bucket--usw2-az1--x-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": false, + "Endpoint": "https://custom.com" } }, { - "documentation": "S3 Snow dns endpoint", + "documentation": "host override data plane bucket error", "expect": { - "endpoint": { - "properties": { - "authSchemes": [ - { - "name": "sigv4", - "signingName": "s3", - "signingRegion": "snow", - "disableDoubleEncoding": true - } - ] - }, - "url": "https://amazonaws.com/bucketName" - } + "error": "S3Express bucket name is not a valid virtual hostable name." }, "params": { - "Region": "snow", - "Bucket": "bucketName", - "Endpoint": "https://amazonaws.com", + "Region": "us-west-2", + "Bucket": "my.bucket--usw2-az1--x-s3", "UseFIPS": false, "UseDualStack": false, - "Accelerate": false + "Accelerate": false, + "Endpoint": "https://custom.com", + "DisableS3ExpressSessionAuth": true } } ], @@ -15714,7 +17488,7 @@ } }, "traits": { - "smithy.api#documentation": "

In terms of implementation, a Bucket is a resource. An Amazon S3 bucket name is globally\n unique, and the namespace is shared by all Amazon Web Services accounts.

" + "smithy.api#documentation": "

In terms of implementation, a Bucket is a resource.

" } }, "com.amazonaws.s3#BucketAccelerateStatus": { @@ -15739,7 +17513,8 @@ "members": {}, "traits": { "smithy.api#documentation": "

The requested bucket name is not available. The bucket namespace is shared by all users\n of the system. Select a different name and try again.

", - "smithy.api#error": "client" + "smithy.api#error": "client", + "smithy.api#httpError": 409 } }, "com.amazonaws.s3#BucketAlreadyOwnedByYou": { @@ -15747,7 +17522,8 @@ "members": {}, "traits": { "smithy.api#documentation": "

The bucket you tried to create already exists, and you own it. Amazon S3 returns this error\n in all Amazon Web Services Regions except in the North Virginia Region. For legacy compatibility, if you\n re-create an existing bucket that you already own in the North Virginia Region, Amazon S3\n returns 200 OK and resets the bucket access control lists (ACLs).

", - "smithy.api#error": "client" + "smithy.api#error": "client", + "smithy.api#httpError": 409 } }, "com.amazonaws.s3#BucketCannedACL": { @@ -15768,22 +17544,39 @@ "public_read_write": { "target": "smithy.api#Unit", "traits": { - "smithy.api#enumValue": "public-read-write" + "smithy.api#enumValue": "public-read-write" + } + }, + "authenticated_read": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "authenticated-read" + } + } + } + }, + "com.amazonaws.s3#BucketInfo": { + "type": "structure", + "members": { + "DataRedundancy": { + "target": "com.amazonaws.s3#DataRedundancy", + "traits": { + "smithy.api#documentation": "

The number of Availability Zone that's used for redundancy for the bucket.

" } }, - "authenticated_read": { - "target": "smithy.api#Unit", + "Type": { + "target": "com.amazonaws.s3#BucketType", "traits": { - "smithy.api#enumValue": "authenticated-read" + "smithy.api#documentation": "

The type of bucket.

" } } + }, + "traits": { + "smithy.api#documentation": "

Specifies the information about the bucket that will be created. For more information about directory buckets, see \n Directory buckets in the Amazon S3 User Guide.

\n \n

This functionality is only supported by directory buckets.

\n
" } }, "com.amazonaws.s3#BucketKeyEnabled": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#BucketLifecycleConfiguration": { "type": "structure", @@ -15841,6 +17634,12 @@ "smithy.api#enumValue": "ap-south-1" } }, + "ap_south_2": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "ap-south-2" + } + }, "ap_southeast_1": { "target": "smithy.api#Unit", "traits": { @@ -15901,6 +17700,12 @@ "smithy.api#enumValue": "eu-south-1" } }, + "eu_south_2": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "eu-south-2" + } + }, "eu_west_1": { "target": "smithy.api#Unit", "traits": { @@ -15960,21 +17765,12 @@ "traits": { "smithy.api#enumValue": "us-west-2" } - }, - "ap_south_2": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "ap-south-2" - } - }, - "eu_south_2": { - "target": "smithy.api#Unit", - "traits": { - "smithy.api#enumValue": "eu-south-2" - } } } }, + "com.amazonaws.s3#BucketLocationName": { + "type": "string" + }, "com.amazonaws.s3#BucketLoggingStatus": { "type": "structure", "members": { @@ -16012,6 +17808,17 @@ "com.amazonaws.s3#BucketName": { "type": "string" }, + "com.amazonaws.s3#BucketType": { + "type": "enum", + "members": { + "Directory": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "Directory" + } + } + } + }, "com.amazonaws.s3#BucketVersioningStatus": { "type": "enum", "members": { @@ -16039,28 +17846,16 @@ } }, "com.amazonaws.s3#BypassGovernanceRetention": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#BytesProcessed": { - "type": "long", - "traits": { - "smithy.api#default": 0 - } + "type": "long" }, "com.amazonaws.s3#BytesReturned": { - "type": "long", - "traits": { - "smithy.api#default": 0 - } + "type": "long" }, "com.amazonaws.s3#BytesScanned": { - "type": "long", - "traits": { - "smithy.api#default": 0 - } + "type": "long" }, "com.amazonaws.s3#CORSConfiguration": { "type": "structure", @@ -16125,7 +17920,6 @@ "MaxAgeSeconds": { "target": "com.amazonaws.s3#MaxAgeSeconds", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The time in seconds that your browser is to cache the preflight response for the\n specified resource.

" } } @@ -16182,7 +17976,6 @@ "AllowQuotedRecordDelimiter": { "target": "com.amazonaws.s3#AllowQuotedRecordDelimiter", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Specifies that CSV field values may contain quoted record delimiters and such records\n should be allowed. Default value is FALSE. Setting this value to TRUE may lower\n performance.

" } } @@ -16238,25 +18031,25 @@ "ChecksumCRC32": { "target": "com.amazonaws.s3#ChecksumCRC32", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumCRC32C": { "target": "com.amazonaws.s3#ChecksumCRC32C", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA1": { "target": "com.amazonaws.s3#ChecksumSHA1", "traits": { - "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. When you use the API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA256": { "target": "com.amazonaws.s3#ChecksumSHA256", "traits": { - "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } } }, @@ -16357,7 +18150,7 @@ "target": "com.amazonaws.s3#CompleteMultipartUploadOutput" }, "traits": { - "smithy.api#documentation": "

Completes a multipart upload by assembling previously uploaded parts.

\n

You first initiate the multipart upload and then upload all parts using the UploadPart\n operation. After successfully uploading all relevant parts of an upload, you call this\n action to complete the upload. Upon receiving this request, Amazon S3 concatenates all the parts\n in ascending order by part number to create a new object. In the Complete Multipart Upload\n request, you must provide the parts list. You must ensure that the parts list is complete.\n This action concatenates the parts that you provide in the list. For each part in the list,\n you must provide the part number and the ETag value, returned after that part\n was uploaded.

\n

Processing of a Complete Multipart Upload request could take several minutes to\n complete. After Amazon S3 begins processing the request, it sends an HTTP response header that\n specifies a 200 OK response. While processing is in progress, Amazon S3 periodically sends white\n space characters to keep the connection from timing out. A request could fail after the\n initial 200 OK response has been sent. This means that a 200 OK response can\n contain either a success or an error. If you call the S3 API directly, make sure to design\n your application to parse the contents of the response and handle it appropriately. If you\n use Amazon Web Services SDKs, SDKs handle this condition. The SDKs detect the embedded error and apply\n error handling per your configuration settings (including automatically retrying the\n request as appropriate). If the condition persists, the SDKs throws an exception (or, for\n the SDKs that don't use exceptions, they return the error).

\n

Note that if CompleteMultipartUpload fails, applications should be prepared\n to retry the failed requests. For more information, see Amazon S3 Error Best\n Practices.

\n \n

You cannot use Content-Type: application/x-www-form-urlencoded with\n Complete Multipart Upload requests. Also, if you do not provide a\n Content-Type header, CompleteMultipartUpload returns a 200\n OK response.

\n
\n

For more information about multipart uploads, see Uploading Objects Using Multipart\n Upload.

\n

For information about permissions required to use the multipart upload API, see Multipart Upload\n and Permissions.

\n

\n CompleteMultipartUpload has the following special errors:

\n
    \n
  • \n

    Error code: EntityTooSmall\n

    \n
      \n
    • \n

      Description: Your proposed upload is smaller than the minimum allowed object\n size. Each part must be at least 5 MB in size, except the last part.

      \n
    • \n
    • \n

      400 Bad Request

      \n
    • \n
    \n
  • \n
  • \n

    Error code: InvalidPart\n

    \n
      \n
    • \n

      Description: One or more of the specified parts could not be found. The part\n might not have been uploaded, or the specified entity tag might not have\n matched the part's entity tag.

      \n
    • \n
    • \n

      400 Bad Request

      \n
    • \n
    \n
  • \n
  • \n

    Error code: InvalidPartOrder\n

    \n
      \n
    • \n

      Description: The list of parts was not in ascending order. The parts list\n must be specified in order by part number.

      \n
    • \n
    • \n

      400 Bad Request

      \n
    • \n
    \n
  • \n
  • \n

    Error code: NoSuchUpload\n

    \n
      \n
    • \n

      Description: The specified multipart upload does not exist. The upload ID\n might be invalid, or the multipart upload might have been aborted or\n completed.

      \n
    • \n
    • \n

      404 Not Found

      \n
    • \n
    \n
  • \n
\n

The following operations are related to CompleteMultipartUpload:

\n ", + "smithy.api#documentation": "

Completes a multipart upload by assembling previously uploaded parts.

\n

You first initiate the multipart upload and then upload all parts using the UploadPart\n operation or the UploadPartCopy\n operation. After successfully uploading all relevant parts of an upload, you call this\n CompleteMultipartUpload operation to complete the upload. Upon receiving this request, Amazon S3 concatenates all the parts\n in ascending order by part number to create a new object. In the CompleteMultipartUpload \n request, you must provide the parts list and ensure that the parts list is complete.\n The CompleteMultipartUpload API operation concatenates the parts that you provide in the list. For each part in the list,\n you must provide the PartNumber value and the ETag value that are returned after that part\n was uploaded.

\n

The processing of a CompleteMultipartUpload request could take several minutes to\n finalize. After Amazon S3 begins processing the request, it sends an HTTP response header that\n specifies a 200 OK response. While processing is in progress, Amazon S3 periodically sends white\n space characters to keep the connection from timing out. A request could fail after the\n initial 200 OK response has been sent. This means that a 200 OK response can\n contain either a success or an error. The error response might be embedded in the 200 OK response. \n If you call this API operation directly, make sure to design\n your application to parse the contents of the response and handle it appropriately. If you\n use Amazon Web Services SDKs, SDKs handle this condition. The SDKs detect the embedded error and apply\n error handling per your configuration settings (including automatically retrying the\n request as appropriate). If the condition persists, the SDKs throw an exception (or, for\n the SDKs that don't use exceptions, they return an error).

\n

Note that if CompleteMultipartUpload fails, applications should be prepared\n to retry the failed requests. For more information, see Amazon S3 Error Best\n Practices.

\n \n

You can't use Content-Type: application/x-www-form-urlencoded for the \n CompleteMultipartUpload requests. Also, if you don't provide a\n Content-Type header, CompleteMultipartUpload can still return a 200\n OK response.

\n
\n

For more information about multipart uploads, see Uploading Objects Using Multipart\n Upload in the Amazon S3\n User Guide.

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - For information about permissions required to use the multipart upload API, see Multipart Upload\n and Permissions in the Amazon S3\n User Guide.

    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation on a directory bucket, we recommend that you use the \n CreateSession\n API operation for session-based authorization. Specifically, you grant the s3express:CreateSession permission to the directory bucket in a bucket policy or an IAM identity-based policy. Then, you make the CreateSession API call on the bucket to obtain a session token. With the session token in your request header, you can make API requests to this operation. After the session token expires, you make another CreateSession API call to generate a new session token for use. \nAmazon Web Services CLI or SDKs create session and refresh the session token automatically to avoid service interruptions when a session expires. For more information about authorization, see \n CreateSession\n .

    \n
  • \n
\n
\n
Special errors
\n
\n
    \n
  • \n

    Error Code: EntityTooSmall\n

    \n
      \n
    • \n

      Description: Your proposed upload is smaller than the minimum allowed object\n size. Each part must be at least 5 MB in size, except the last part.

      \n
    • \n
    • \n

      HTTP Status Code: 400 Bad Request

      \n
    • \n
    \n
  • \n
  • \n

    Error Code: InvalidPart\n

    \n
      \n
    • \n

      Description: One or more of the specified parts could not be found. The part\n might not have been uploaded, or the specified ETag might not have\n matched the uploaded part's ETag.

      \n
    • \n
    • \n

      HTTP Status Code: 400 Bad Request

      \n
    • \n
    \n
  • \n
  • \n

    Error Code: InvalidPartOrder\n

    \n
      \n
    • \n

      Description: The list of parts was not in ascending order. The parts list\n must be specified in order by part number.

      \n
    • \n
    • \n

      HTTP Status Code: 400 Bad Request

      \n
    • \n
    \n
  • \n
  • \n

    Error Code: NoSuchUpload\n

    \n
      \n
    • \n

      Description: The specified multipart upload does not exist. The upload ID\n might be invalid, or the multipart upload might have been aborted or\n completed.

      \n
    • \n
    • \n

      HTTP Status Code: 404 Not Found

      \n
    • \n
    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

The following operations are related to CompleteMultipartUpload:

\n ", "smithy.api#http": { "method": "POST", "uri": "/{Bucket}/{Key+}?x-id=CompleteMultipartUpload", @@ -16377,7 +18170,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket that contains the newly created object. Does not return the access point\n ARN or access point alias if used.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The name of the bucket that contains the newly created object. Does not return the access point\n ARN or access point alias if used.

\n \n

Access points are not supported by directory buckets.

\n
" } }, "Key": { @@ -16389,7 +18182,7 @@ "Expiration": { "target": "com.amazonaws.s3#Expiration", "traits": { - "smithy.api#documentation": "

If the object expiration is configured, this will contain the expiration date\n (expiry-date) and rule ID (rule-id). The value of\n rule-id is URL-encoded.

", + "smithy.api#documentation": "

If the object expiration is configured, this will contain the expiration date\n (expiry-date) and rule ID (rule-id). The value of\n rule-id is URL-encoded.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-expiration" } }, @@ -16402,53 +18195,52 @@ "ChecksumCRC32": { "target": "com.amazonaws.s3#ChecksumCRC32", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumCRC32C": { "target": "com.amazonaws.s3#ChecksumCRC32C", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA1": { "target": "com.amazonaws.s3#ChecksumSHA1", "traits": { - "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. When you use the API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA256": { "target": "com.amazonaws.s3#ChecksumSHA256", "traits": { - "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ServerSideEncryption": { "target": "com.amazonaws.s3#ServerSideEncryption", "traits": { - "smithy.api#documentation": "

The server-side encryption algorithm used when storing this object in Amazon S3 (for example,\n AES256, aws:kms).

", + "smithy.api#documentation": "

The server-side encryption algorithm used when storing this object in Amazon S3 (for example,\n AES256, aws:kms).

\n \n

For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption" } }, "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

Version ID of the newly created object, in case the bucket has versioning turned\n on.

", + "smithy.api#documentation": "

Version ID of the newly created object, in case the bucket has versioning turned\n on.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-version-id" } }, "SSEKMSKeyId": { "target": "com.amazonaws.s3#SSEKMSKeyId", "traits": { - "smithy.api#documentation": "

If present, specifies the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n that was used for the object.

", + "smithy.api#documentation": "

If present, indicates the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n that was used for the object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-aws-kms-key-id" } }, "BucketKeyEnabled": { "target": "com.amazonaws.s3#BucketKeyEnabled", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

", + "smithy.api#documentation": "

Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-bucket-key-enabled" } }, @@ -16470,7 +18262,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

Name of the bucket to which the multipart upload was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

Name of the bucket to which the multipart upload was initiated.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -16483,7 +18275,10 @@ "traits": { "smithy.api#documentation": "

Object key for which the multipart upload was initiated.

", "smithy.api#httpLabel": {}, - "smithy.api#required": {} + "smithy.api#required": {}, + "smithy.rules#contextParam": { + "name": "Key" + } } }, "MultipartUpload": { @@ -16539,28 +18334,28 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

The server-side encryption (SSE) algorithm used to encrypt the object. This parameter is needed only when the object was created \n using a checksum algorithm. For more information,\n see Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", + "smithy.api#documentation": "

The server-side encryption (SSE) algorithm used to encrypt the object. This parameter is\n required only when the object was created using a checksum algorithm or if\n your bucket policy requires the use of SSE-C. For more information, see Protecting data\n using SSE-C keys in the Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKey": { "target": "com.amazonaws.s3#SSECustomerKey", "traits": { - "smithy.api#documentation": "

The server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum algorithm. \n For more information, see\n Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", + "smithy.api#documentation": "

The server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum algorithm. \n For more information, see\n Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

The MD5 server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum \n algorithm. For more information,\n see Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", + "smithy.api#documentation": "

The MD5 server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum \n algorithm. For more information,\n see Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } } @@ -16597,32 +18392,31 @@ "ChecksumCRC32": { "target": "com.amazonaws.s3#ChecksumCRC32", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumCRC32C": { "target": "com.amazonaws.s3#ChecksumCRC32C", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA1": { "target": "com.amazonaws.s3#ChecksumSHA1", "traits": { - "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. When you use the API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA256": { "target": "com.amazonaws.s3#ChecksumSHA256", "traits": { - "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "PartNumber": { "target": "com.amazonaws.s3#PartNumber", "traits": { - "smithy.api#default": 0, - "smithy.api#documentation": "

Part number that identifies the part. This is a positive integer between 1 and\n 10,000.

" + "smithy.api#documentation": "

Part number that identifies the part. This is a positive integer between 1 and\n 10,000.

\n \n
    \n
  • \n

    \n General purpose buckets - In CompleteMultipartUpload, when a additional checksum (including x-amz-checksum-crc32, x-amz-checksum-crc32c, x-amz-checksum-sha1, or \n x-amz-checksum-sha256) is applied to each part, the PartNumber must start at 1 and \n the part numbers must be consecutive. Otherwise, Amazon S3 generates an HTTP 400 Bad Request status code and an InvalidPartOrder error code.

    \n
  • \n
  • \n

    \n Directory buckets - In CompleteMultipartUpload, the PartNumber must start at 1 and \n the part numbers must be consecutive.

    \n
  • \n
\n
" } } }, @@ -16680,10 +18474,7 @@ } }, "com.amazonaws.s3#ConfirmRemoveSelfBucketAccess": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#ContentDisposition": { "type": "string" @@ -16695,10 +18486,7 @@ "type": "string" }, "com.amazonaws.s3#ContentLength": { - "type": "long", - "traits": { - "smithy.api#default": 0 - } + "type": "long" }, "com.amazonaws.s3#ContentMD5": { "type": "string" @@ -16730,7 +18518,7 @@ } ], "traits": { - "smithy.api#documentation": "

Creates a copy of an object that is already stored in Amazon S3.

\n \n

You can store individual objects of up to 5 TB in Amazon S3. You create a copy of your\n object up to 5 GB in size in a single atomic action using this API. However, to copy an\n object greater than 5 GB, you must use the multipart upload Upload Part - Copy\n (UploadPartCopy) API. For more information, see Copy Object Using the\n REST Multipart Upload API.

\n
\n

All copy requests must be authenticated. Additionally, you must have\n read access to the source object and write\n access to the destination bucket. For more information, see REST Authentication. Both the\n Region that you want to copy the object from and the Region that you want to copy the\n object to must be enabled for your account.

\n

A copy request might return an error when Amazon S3 receives the copy request or while Amazon S3\n is copying the files. If the error occurs before the copy action starts, you receive a\n standard Amazon S3 error. If the error occurs during the copy operation, the error response is\n embedded in the 200 OK response. This means that a 200 OK\n response can contain either a success or an error. If you call the S3 API directly, make\n sure to design your application to parse the contents of the response and handle it\n appropriately. If you use Amazon Web Services SDKs, SDKs handle this condition. The SDKs detect the\n embedded error and apply error handling per your configuration settings (including\n automatically retrying the request as appropriate). If the condition persists, the SDKs\n throws an exception (or, for the SDKs that don't use exceptions, they return the\n error).

\n

If the copy is successful, you receive a response with information about the copied\n object.

\n \n

If the request is an HTTP 1.1 request, the response is chunk encoded. If it were not,\n it would not contain the content-length, and you would need to read the entire\n body.

\n
\n

The copy request charge is based on the storage class and Region that you specify for\n the destination object. The request can also result in a data retrieval charge for the\n source if the source storage class bills for data retrieval. For pricing information, see\n Amazon S3 pricing.

\n \n

Amazon S3 transfer acceleration does not support cross-Region copies. If you request a\n cross-Region copy using a transfer acceleration endpoint, you get a 400 Bad\n Request error. For more information, see Transfer\n Acceleration.

\n
\n
\n
Metadata
\n
\n

When copying an object, you can preserve all metadata (the default) or specify\n new metadata. However, the access control list (ACL) is not preserved and is set\n to private for the user making the request. To override the default ACL setting,\n specify a new ACL when generating a copy request. For more information, see Using\n ACLs.

\n

To specify whether you want the object metadata copied from the source object\n or replaced with metadata provided in the request, you can optionally add the\n x-amz-metadata-directive header. When you grant permissions, you\n can use the s3:x-amz-metadata-directive condition key to enforce\n certain metadata behavior when objects are uploaded. For more information, see\n Specifying Conditions in a\n Policy in the Amazon S3 User Guide. For a complete list\n of Amazon S3-specific condition keys, see Actions, Resources, and Condition\n Keys for Amazon S3.

\n \n

\n x-amz-website-redirect-location is unique to each object and\n must be specified in the request headers to copy the value.

\n
\n
\n
x-amz-copy-source-if Headers
\n
\n

To only copy an object under certain conditions, such as whether the\n Etag matches or whether the object was modified before or after a\n specified date, use the following request parameters:

\n
    \n
  • \n

    \n x-amz-copy-source-if-match\n

    \n
  • \n
  • \n

    \n x-amz-copy-source-if-none-match\n

    \n
  • \n
  • \n

    \n x-amz-copy-source-if-unmodified-since\n

    \n
  • \n
  • \n

    \n x-amz-copy-source-if-modified-since\n

    \n
  • \n
\n

If both the x-amz-copy-source-if-match and\n x-amz-copy-source-if-unmodified-since headers are present in the\n request and evaluate as follows, Amazon S3 returns 200 OK and copies the\n data:

\n
    \n
  • \n

    \n x-amz-copy-source-if-match condition evaluates to\n true

    \n
  • \n
  • \n

    \n x-amz-copy-source-if-unmodified-since condition evaluates to\n false

    \n
  • \n
\n

If both the x-amz-copy-source-if-none-match and\n x-amz-copy-source-if-modified-since headers are present in the\n request and evaluate as follows, Amazon S3 returns the 412 Precondition\n Failed response code:

\n
    \n
  • \n

    \n x-amz-copy-source-if-none-match condition evaluates to\n false

    \n
  • \n
  • \n

    \n x-amz-copy-source-if-modified-since condition evaluates to\n true

    \n
  • \n
\n \n

All headers with the x-amz- prefix, including\n x-amz-copy-source, must be signed.

\n
\n
\n
Server-side encryption
\n
\n

Amazon S3 automatically encrypts all new objects that are copied to an S3 bucket.\n When copying an object, if you don't specify encryption information in your copy\n request, the encryption setting of the target object is set to the default\n encryption configuration of the destination bucket. By default, all buckets have a\n base level of encryption configuration that uses server-side encryption with Amazon S3\n managed keys (SSE-S3). If the destination bucket has a default encryption\n configuration that uses server-side encryption with Key Management Service (KMS) keys\n (SSE-KMS), dual-layer server-side encryption with Amazon Web Services KMS keys (DSSE-KMS), or\n server-side encryption with customer-provided encryption keys (SSE-C), Amazon S3 uses\n the corresponding KMS key, or a customer-provided key to encrypt the target\n object copy.

\n

When you perform a CopyObject operation, if you want to use a\n different type of encryption setting for the target object, you can use other\n appropriate encryption-related headers to encrypt the target object with a\n KMS key, an Amazon S3 managed key, or a customer-provided key. With server-side\n encryption, Amazon S3 encrypts your data as it writes your data to disks in its data\n centers and decrypts the data when you access it. If the encryption setting in\n your request is different from the default encryption configuration of the\n destination bucket, the encryption setting in your request takes precedence. If\n the source object for the copy is stored in Amazon S3 using SSE-C, you must provide the\n necessary encryption information in your request so that Amazon S3 can decrypt the\n object for copying. For more information about server-side encryption, see Using\n Server-Side Encryption.

\n

If a target object uses SSE-KMS, you can enable an S3 Bucket Key for the\n object. For more information, see Amazon S3 Bucket Keys in the\n Amazon S3 User Guide.

\n
\n
Access Control List (ACL)-Specific Request Headers
\n
\n

When copying an object, you can optionally use headers to grant ACL-based\n permissions. By default, all objects are private. Only the owner has full access\n control. When adding a new object, you can grant permissions to individual\n Amazon Web Services accounts or to predefined groups that are defined by Amazon S3. These permissions\n are then added to the ACL on the object. For more information, see Access Control\n List (ACL) Overview and Managing ACLs Using the REST\n API.

\n

If the bucket that you're copying objects to uses the bucket owner enforced\n setting for S3 Object Ownership, ACLs are disabled and no longer affect\n permissions. Buckets that use this setting only accept PUT requests\n that don't specify an ACL or PUT requests that specify bucket owner\n full control ACLs, such as the bucket-owner-full-control canned ACL\n or an equivalent form of this ACL expressed in the XML format.

\n

For more information, see Controlling\n ownership of objects and disabling ACLs in the\n Amazon S3 User Guide.

\n \n

If your bucket uses the bucket owner enforced setting for Object Ownership,\n all objects written to the bucket by any account will be owned by the bucket\n owner.

\n
\n
\n
Checksums
\n
\n

When copying an object, if it has a checksum, that checksum will be copied to\n the new object by default. When you copy the object over, you can optionally\n specify a different checksum algorithm to use with the\n x-amz-checksum-algorithm header.

\n
\n
Storage Class Options
\n
\n

You can use the CopyObject action to change the storage class of\n an object that is already stored in Amazon S3 by using the StorageClass\n parameter. For more information, see Storage Classes in\n the Amazon S3 User Guide.

\n

If the source object's storage class is GLACIER or\n DEEP_ARCHIVE, or the object's storage class is\n INTELLIGENT_TIERING and it's S3 Intelligent-Tiering access tier is\n Archive Access or Deep Archive Access, you must restore a copy of this object\n before you can use it as a source object for the copy operation. For more\n information, see RestoreObject. For\n more information, see Copying\n Objects.

\n
\n
Versioning
\n
\n

By default, x-amz-copy-source header identifies the current\n version of an object to copy. If the current version is a delete marker, Amazon S3\n behaves as if the object was deleted. To copy a different version, use the\n versionId subresource.

\n

If you enable versioning on the target bucket, Amazon S3 generates a unique version\n ID for the object being copied. This version ID is different from the version ID\n of the source object. Amazon S3 returns the version ID of the copied object in the\n x-amz-version-id response header in the response.

\n

If you do not enable versioning or suspend it on the target bucket, the version\n ID that Amazon S3 generates is always null.

\n
\n
\n

The following operations are related to CopyObject:

\n ", + "smithy.api#documentation": "

Creates a copy of an object that is already stored in Amazon S3.

\n \n

You can store individual objects of up to 5 TB in Amazon S3. You create a copy of your\n object up to 5 GB in size in a single atomic action using this API. However, to copy an\n object greater than 5 GB, you must use the multipart upload Upload Part - Copy\n (UploadPartCopy) API. For more information, see Copy Object Using the\n REST Multipart Upload API.

\n
\n

You can copy individual objects between general purpose buckets, between directory buckets, and \n between general purpose buckets and directory buckets.

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n

Both the\n Region that you want to copy the object from and the Region that you want to copy the\n object to must be enabled for your account.

\n \n

Amazon S3 transfer acceleration does not support cross-Region copies. If you request a\n cross-Region copy using a transfer acceleration endpoint, you get a 400 Bad\n Request error. For more information, see Transfer\n Acceleration.

\n
\n
\n
Authentication and authorization
\n
\n

All CopyObject requests must be authenticated and signed by using IAM credentials (access key ID and secret access key for the IAM identities). All headers with the x-amz- prefix, including\n x-amz-copy-source, must be signed. For more information, see REST Authentication.

\n

\n Directory buckets - You must use the IAM credentials to authenticate and authorize your access to the CopyObject API operation, instead of using the \n temporary security credentials through the CreateSession API operation.

\n

Amazon Web Services CLI or SDKs handles authentication and authorization on your behalf.

\n
\n
Permissions
\n
\n

You must have\n read access to the source object and write\n access to the destination bucket.

\n
    \n
  • \n

    \n General purpose bucket permissions -\n You must have permissions in an IAM policy based on the source and destination\n bucket types in a CopyObject operation.

    \n
      \n
    • \n

      If the source object is in a general purpose bucket, you must have\n \n s3:GetObject\n \n permission to read the source object that is being copied.

      \n
    • \n
    • \n

      If the destination bucket is a general purpose bucket, you must have\n \n s3:PubObject\n \n permission to write the object copy to the destination bucket.

      \n
    • \n
    \n
  • \n
  • \n

    \n Directory bucket permissions -\n You must have permissions in a bucket policy or an IAM identity-based policy based on the source and destination\n bucket types in a CopyObject operation.

    \n
      \n
    • \n

      If the source object that you want to copy is in a\n directory bucket, you must have the \n s3express:CreateSession\n permission in\n the Action element of a policy to read the object. By default, the session is in the ReadWrite mode. If you want to restrict the access, you can explicitly set the s3express:SessionMode condition key to ReadOnly on the copy source bucket.

      \n
    • \n
    • \n

      If the copy destination is a directory bucket, you must have the \n s3express:CreateSession\n permission in the\n Action element of a policy to write the object\n to the destination. The s3express:SessionMode condition\n key can't be set to ReadOnly on the copy destination bucket.

      \n
    • \n
    \n

    For example policies, see Example bucket policies for S3 Express One Zone and Amazon Web Services Identity and Access Management (IAM) identity-based policies for S3 Express One Zone in the\n Amazon S3 User Guide.

    \n
  • \n
\n
\n
Response and special errors
\n
\n

When the request is an HTTP 1.1 request, the response is chunk encoded. \n When the request is not an HTTP 1.1 request, the response would not contain the Content-Length. \n You always need to read the entire response body to check if the copy succeeds. \n to keep the connection alive while we copy the data.

\n
    \n
  • \n

    If the copy is successful, you receive a response with information about the copied\n object.

    \n
  • \n
  • \n

    A copy request might return an error when Amazon S3 receives the copy request or while Amazon S3\n is copying the files. A 200 OK response can contain either a success or an error.

    \n
      \n
    • \n

      If the error occurs before the copy action starts, you receive a\n standard Amazon S3 error.

      \n
    • \n
    • \n

      If the error occurs during the copy operation, the error response is\n embedded in the 200 OK response. For example, in a cross-region copy, you \n may encounter throttling and receive a 200 OK response. \n For more information, see Resolve \n the Error 200 response when copying objects to Amazon S3. \n The 200 OK status code means the copy was accepted, but \n it doesn't mean the copy is complete. Another example is \n when you disconnect from Amazon S3 before the copy is complete, Amazon S3 might cancel the copy and you may receive a 200 OK response. \n You must stay connected to Amazon S3 until the entire response is successfully received and processed.

      \n

      If you call this API operation directly, make\n sure to design your application to parse the content of the response and handle it\n appropriately. If you use Amazon Web Services SDKs, SDKs handle this condition. The SDKs detect the\n embedded error and apply error handling per your configuration settings (including\n automatically retrying the request as appropriate). If the condition persists, the SDKs\n throw an exception (or, for the SDKs that don't use exceptions, they return an \n error).

      \n
    • \n
    \n
  • \n
\n
\n
Charge
\n
\n

The copy request charge is based on the storage class and Region that you specify for\n the destination object. The request can also result in a data retrieval charge for the\n source if the source storage class bills for data retrieval. For pricing information, see\n Amazon S3 pricing.

\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

The following operations are related to CopyObject:

\n ", "smithy.api#examples": [ { "title": "To copy an object", @@ -16752,6 +18540,11 @@ "method": "PUT", "uri": "/{Bucket}/{Key+}?x-id=CopyObject", "code": 200 + }, + "smithy.rules#staticContextParams": { + "DisableS3ExpressSessionAuth": { + "value": true + } } } }, @@ -16768,64 +18561,63 @@ "Expiration": { "target": "com.amazonaws.s3#Expiration", "traits": { - "smithy.api#documentation": "

If the object expiration is configured, the response includes this header.

", + "smithy.api#documentation": "

If the object expiration is configured, the response includes this header.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-expiration" } }, "CopySourceVersionId": { "target": "com.amazonaws.s3#CopySourceVersionId", "traits": { - "smithy.api#documentation": "

Version of the copied object in the destination bucket.

", + "smithy.api#documentation": "

Version ID of the source object that was copied.

\n \n

This functionality is not supported when the source object is in a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-copy-source-version-id" } }, "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

Version ID of the newly created copy.

", + "smithy.api#documentation": "

Version ID of the newly created copy.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-version-id" } }, "ServerSideEncryption": { "target": "com.amazonaws.s3#ServerSideEncryption", "traits": { - "smithy.api#documentation": "

The server-side encryption algorithm used when storing this object in Amazon S3 (for example,\n AES256, aws:kms, aws:kms:dsse).

", + "smithy.api#documentation": "

The server-side encryption algorithm used when you store this object in Amazon S3 (for example,\n AES256, aws:kms, aws:kms:dsse).

\n \n

For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption" } }, "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header confirming the encryption algorithm used.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to confirm the encryption algorithm that's used.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide round-trip message integrity verification of\n the customer-provided encryption key.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide the round-trip message integrity verification of\n the customer-provided encryption key.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, "SSEKMSKeyId": { "target": "com.amazonaws.s3#SSEKMSKeyId", "traits": { - "smithy.api#documentation": "

If present, specifies the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n that was used for the object.

", + "smithy.api#documentation": "

If present, indicates the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n that was used for the object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-aws-kms-key-id" } }, "SSEKMSEncryptionContext": { "target": "com.amazonaws.s3#SSEKMSEncryptionContext", "traits": { - "smithy.api#documentation": "

If present, specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The\n value of this header is a base64-encoded UTF-8 string holding JSON with the encryption\n context key-value pairs.

", + "smithy.api#documentation": "

If present, indicates the Amazon Web Services KMS Encryption Context to use for object encryption. The\n value of this header is a base64-encoded UTF-8 string holding JSON with the encryption\n context key-value pairs.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-context" } }, "BucketKeyEnabled": { "target": "com.amazonaws.s3#BucketKeyEnabled", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Indicates whether the copied object uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

", + "smithy.api#documentation": "

Indicates whether the copied object uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-bucket-key-enabled" } }, @@ -16846,14 +18638,14 @@ "ACL": { "target": "com.amazonaws.s3#ObjectCannedACL", "traits": { - "smithy.api#documentation": "

The canned ACL to apply to the object.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

The canned access control list (ACL) to apply to the object.

\n

When you copy an object, the ACL metadata is not preserved and is set\n to private by default. Only the owner has full access\n control. To override the default ACL setting,\n specify a new ACL when you generate a copy request. For more information, see Using\n ACLs.

\n

If the destination bucket that you're copying objects to uses the bucket owner enforced\n setting for S3 Object Ownership, ACLs are disabled and no longer affect\n permissions. Buckets that use this setting only accept PUT requests\n that don't specify an ACL or PUT requests that specify bucket owner\n full control ACLs, such as the bucket-owner-full-control canned ACL\n or an equivalent form of this ACL expressed in the XML format. For more information, see Controlling\n ownership of objects and disabling ACLs in the\n Amazon S3 User Guide.

\n \n
    \n
  • \n

    If your destination bucket uses the bucket owner enforced setting for Object Ownership,\n all objects written to the bucket by any account will be owned by the bucket\n owner.

    \n
  • \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-acl" } }, "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the destination bucket.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the destination bucket.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -16864,28 +18656,28 @@ "CacheControl": { "target": "com.amazonaws.s3#CacheControl", "traits": { - "smithy.api#documentation": "

Specifies caching behavior along the request/reply chain.

", + "smithy.api#documentation": "

Specifies the caching behavior along the request/reply chain.

", "smithy.api#httpHeader": "Cache-Control" } }, "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm you want Amazon S3 to use to create the checksum for the object. For more information, see\n Checking object integrity in\n the Amazon S3 User Guide.

", + "smithy.api#documentation": "

Indicates the algorithm that you want Amazon S3 to use to create the checksum for the object. For more information, see\n Checking object integrity in\n the Amazon S3 User Guide.

\n

When you copy an object, if the source object has a checksum, that checksum value will be copied to\n the new object by default. If the CopyObject request does not include this x-amz-checksum-algorithm header, the checksum algorithm will be copied from the source object to the destination object (if it's present on the source object). You can optionally\n specify a different checksum algorithm to use with the\n x-amz-checksum-algorithm header. Unrecognized or unsupported values will respond with the HTTP status code 400 Bad Request.

\n \n

For directory buckets, when you use Amazon Web Services SDKs, CRC32 is the default checksum algorithm that's used for performance.

\n
", "smithy.api#httpHeader": "x-amz-checksum-algorithm" } }, "ContentDisposition": { "target": "com.amazonaws.s3#ContentDisposition", "traits": { - "smithy.api#documentation": "

Specifies presentational information for the object.

", + "smithy.api#documentation": "

Specifies presentational information for the object. Indicates whether an object should be displayed in a web browser or downloaded as a file. It allows specifying the desired filename for the downloaded file.

", "smithy.api#httpHeader": "Content-Disposition" } }, "ContentEncoding": { "target": "com.amazonaws.s3#ContentEncoding", "traits": { - "smithy.api#documentation": "

Specifies what content encodings have been applied to the object and thus what decoding\n mechanisms must be applied to obtain the media-type referenced by the Content-Type header\n field.

", + "smithy.api#documentation": "

Specifies what content encodings have been applied to the object and thus what decoding\n mechanisms must be applied to obtain the media-type referenced by the Content-Type header\n field.

\n \n

For directory buckets, only the aws-chunked value is supported in this header field.

\n
", "smithy.api#httpHeader": "Content-Encoding" } }, @@ -16899,14 +18691,14 @@ "ContentType": { "target": "com.amazonaws.s3#ContentType", "traits": { - "smithy.api#documentation": "

A standard MIME type describing the format of the object data.

", + "smithy.api#documentation": "

A standard MIME type that describes the format of the object data.

", "smithy.api#httpHeader": "Content-Type" } }, "CopySource": { "target": "com.amazonaws.s3#CopySource", "traits": { - "smithy.api#documentation": "

Specifies the source object for the copy operation. You specify the value in one of two\n formats, depending on whether you want to access the source object through an access point:

\n
    \n
  • \n

    For objects not accessed through an access point, specify the name of the source bucket\n and the key of the source object, separated by a slash (/). For example, to copy the\n object reports/january.pdf from the bucket\n awsexamplebucket, use awsexamplebucket/reports/january.pdf.\n The value must be URL-encoded.

    \n
  • \n
  • \n

    For objects accessed through access points, specify the Amazon Resource Name (ARN) of the object as accessed through the access point, in the format arn:aws:s3:::accesspoint//object/. For example, to copy the object reports/january.pdf through access point my-access-point owned by account 123456789012 in Region us-west-2, use the URL encoding of arn:aws:s3:us-west-2:123456789012:accesspoint/my-access-point/object/reports/january.pdf. The value must be URL encoded.

    \n \n

    Amazon S3 supports copy operations using access points only when the source and destination buckets are in the same Amazon Web Services Region.

    \n
    \n

    Alternatively, for objects accessed through Amazon S3 on Outposts, specify the ARN of the object as accessed in the format arn:aws:s3-outposts:::outpost//object/. For example, to copy the object reports/january.pdf through outpost my-outpost owned by account 123456789012 in Region us-west-2, use the URL encoding of arn:aws:s3-outposts:us-west-2:123456789012:outpost/my-outpost/object/reports/january.pdf. The value must be URL-encoded.

    \n
  • \n
\n

To copy a specific version of an object, append ?versionId=\n to the value (for example,\n awsexamplebucket/reports/january.pdf?versionId=QUpfdndhfd8438MNFDN93jdnJFkdmqnh893).\n If you don't specify a version ID, Amazon S3 copies the latest version of the source\n object.

", + "smithy.api#documentation": "

Specifies the source object for the copy operation. The source object \n can be up to 5 GB. If the source object is an object that was uploaded by using a multipart upload, the object copy will be a single part object after the source object is copied to the destination bucket.

\n

You specify the value of the copy source in one of two\n formats, depending on whether you want to access the source object through an access point:

\n
    \n
  • \n

    For objects not accessed through an access point, specify the name of the source bucket\n and the key of the source object, separated by a slash (/). For example, to copy the\n object reports/january.pdf from the general purpose bucket \n awsexamplebucket, use awsexamplebucket/reports/january.pdf.\n The value must be URL-encoded. To copy the\n object reports/january.pdf from the directory bucket \n awsexamplebucket--use1-az5--x-s3, use awsexamplebucket--use1-az5--x-s3/reports/january.pdf.\n The value must be URL-encoded.

    \n
  • \n
  • \n

    For objects accessed through access points, specify the Amazon Resource Name (ARN) of the object as accessed through the access point, in the format arn:aws:s3:::accesspoint//object/. For example, to copy the object reports/january.pdf through access point my-access-point owned by account 123456789012 in Region us-west-2, use the URL encoding of arn:aws:s3:us-west-2:123456789012:accesspoint/my-access-point/object/reports/january.pdf. The value must be URL encoded.

    \n \n
      \n
    • \n

      Amazon S3 supports copy operations using Access points only when the source and destination buckets are in the same Amazon Web Services Region.

      \n
    • \n
    • \n

      Access points are not supported by directory buckets.

      \n
    • \n
    \n
    \n

    Alternatively, for objects accessed through Amazon S3 on Outposts, specify the ARN of the object as accessed in the format arn:aws:s3-outposts:::outpost//object/. For example, to copy the object reports/january.pdf through outpost my-outpost owned by account 123456789012 in Region us-west-2, use the URL encoding of arn:aws:s3-outposts:us-west-2:123456789012:outpost/my-outpost/object/reports/january.pdf. The value must be URL-encoded.

    \n
  • \n
\n

If your source bucket versioning is enabled, the x-amz-copy-source header by default identifies the current\n version of an object to copy. If the current version is a delete marker, Amazon S3\n behaves as if the object was deleted. To copy a different version, use the\n versionId query parameter. Specifically, append ?versionId=\n to the value (for example,\n awsexamplebucket/reports/january.pdf?versionId=QUpfdndhfd8438MNFDN93jdnJFkdmqnh893).\n If you don't specify a version ID, Amazon S3 copies the latest version of the source\n object.

\n

If you enable versioning on the destination bucket, Amazon S3 generates a unique version\n ID for the copied object. This version ID is different from the version ID\n of the source object. Amazon S3 returns the version ID of the copied object in the\n x-amz-version-id response header in the response.

\n

If you do not enable versioning or suspend it on the destination bucket, the version\n ID that Amazon S3 generates in the\n x-amz-version-id response header is always null.

\n \n

\n Directory buckets - S3 Versioning isn't enabled and supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-copy-source", "smithy.api#required": {} } @@ -16914,28 +18706,28 @@ "CopySourceIfMatch": { "target": "com.amazonaws.s3#CopySourceIfMatch", "traits": { - "smithy.api#documentation": "

Copies the object if its entity tag (ETag) matches the specified tag.

", + "smithy.api#documentation": "

Copies the object if its entity tag (ETag) matches the specified tag.

\n

If both the x-amz-copy-source-if-match and\n x-amz-copy-source-if-unmodified-since headers are present in the\n request and evaluate as follows, Amazon S3 returns 200 OK and copies the\n data:

\n
    \n
  • \n

    \n x-amz-copy-source-if-match condition evaluates to\n true

    \n
  • \n
  • \n

    \n x-amz-copy-source-if-unmodified-since condition evaluates to\n false

    \n
  • \n
", "smithy.api#httpHeader": "x-amz-copy-source-if-match" } }, "CopySourceIfModifiedSince": { "target": "com.amazonaws.s3#CopySourceIfModifiedSince", "traits": { - "smithy.api#documentation": "

Copies the object if it has been modified since the specified time.

", + "smithy.api#documentation": "

Copies the object if it has been modified since the specified time.

\n

If both the x-amz-copy-source-if-none-match and\n x-amz-copy-source-if-modified-since headers are present in the\n request and evaluate as follows, Amazon S3 returns the 412 Precondition\n Failed response code:

\n
    \n
  • \n

    \n x-amz-copy-source-if-none-match condition evaluates to\n false

    \n
  • \n
  • \n

    \n x-amz-copy-source-if-modified-since condition evaluates to\n true

    \n
  • \n
", "smithy.api#httpHeader": "x-amz-copy-source-if-modified-since" } }, "CopySourceIfNoneMatch": { "target": "com.amazonaws.s3#CopySourceIfNoneMatch", "traits": { - "smithy.api#documentation": "

Copies the object if its entity tag (ETag) is different than the specified ETag.

", + "smithy.api#documentation": "

Copies the object if its entity tag (ETag) is different than the specified ETag.

\n

If both the x-amz-copy-source-if-none-match and\n x-amz-copy-source-if-modified-since headers are present in the\n request and evaluate as follows, Amazon S3 returns the 412 Precondition\n Failed response code:

\n
    \n
  • \n

    \n x-amz-copy-source-if-none-match condition evaluates to\n false

    \n
  • \n
  • \n

    \n x-amz-copy-source-if-modified-since condition evaluates to\n true

    \n
  • \n
", "smithy.api#httpHeader": "x-amz-copy-source-if-none-match" } }, "CopySourceIfUnmodifiedSince": { "target": "com.amazonaws.s3#CopySourceIfUnmodifiedSince", "traits": { - "smithy.api#documentation": "

Copies the object if it hasn't been modified since the specified time.

", + "smithy.api#documentation": "

Copies the object if it hasn't been modified since the specified time.

\n

If both the x-amz-copy-source-if-match and\n x-amz-copy-source-if-unmodified-since headers are present in the\n request and evaluate as follows, Amazon S3 returns 200 OK and copies the\n data:

\n
    \n
  • \n

    \n x-amz-copy-source-if-match condition evaluates to\n true

    \n
  • \n
  • \n

    \n x-amz-copy-source-if-unmodified-since condition evaluates to\n false

    \n
  • \n
", "smithy.api#httpHeader": "x-amz-copy-source-if-unmodified-since" } }, @@ -16949,28 +18741,28 @@ "GrantFullControl": { "target": "com.amazonaws.s3#GrantFullControl", "traits": { - "smithy.api#documentation": "

Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object.

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-grant-full-control" } }, "GrantRead": { "target": "com.amazonaws.s3#GrantRead", "traits": { - "smithy.api#documentation": "

Allows grantee to read the object data and its metadata.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Allows grantee to read the object data and its metadata.

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-grant-read" } }, "GrantReadACP": { "target": "com.amazonaws.s3#GrantReadACP", "traits": { - "smithy.api#documentation": "

Allows grantee to read the object ACL.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Allows grantee to read the object ACL.

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-grant-read-acp" } }, "GrantWriteACP": { "target": "com.amazonaws.s3#GrantWriteACP", "traits": { - "smithy.api#documentation": "

Allows grantee to write the ACL for the applicable object.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Allows grantee to write the ACL for the applicable object.

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-grant-write-acp" } }, @@ -16992,99 +18784,98 @@ "MetadataDirective": { "target": "com.amazonaws.s3#MetadataDirective", "traits": { - "smithy.api#documentation": "

Specifies whether the metadata is copied from the source object or replaced with\n metadata provided in the request.

", + "smithy.api#documentation": "

Specifies whether the metadata is copied from the source object or replaced with\n metadata that's provided in the request. \n When copying an object, you can preserve all metadata (the default) or specify\n new metadata. If this header isn’t specified, COPY is the default behavior. \n

\n

\n General purpose bucket - For general purpose buckets, when you grant permissions, you\n can use the s3:x-amz-metadata-directive condition key to enforce\n certain metadata behavior when objects are uploaded. For more information, see\n Amazon S3 condition key examples in the Amazon S3 User Guide.

\n \n

\n x-amz-website-redirect-location is unique to each object and is not copied when using the\n x-amz-metadata-directive header. To copy the value, you \n must specify x-amz-website-redirect-location in the request header.

\n
", "smithy.api#httpHeader": "x-amz-metadata-directive" } }, "TaggingDirective": { "target": "com.amazonaws.s3#TaggingDirective", "traits": { - "smithy.api#documentation": "

Specifies whether the object tag-set are copied from the source object or replaced with\n tag-set provided in the request.

", + "smithy.api#documentation": "

Specifies whether the object tag-set is copied from the source object or replaced with\n the tag-set that's provided in the request.

\n

The default value is COPY.

\n \n

\n Directory buckets - For directory buckets in a CopyObject operation, only the empty tag-set is supported. Any requests that attempt to write non-empty tags into directory buckets will receive a 501 Not Implemented status code. \nWhen the destination bucket is a directory bucket, you will receive a 501 Not Implemented response in any of the following situations:

\n
    \n
  • \n

    When you attempt to COPY the tag-set from an S3 source object that has non-empty tags.

    \n
  • \n
  • \n

    When you attempt to REPLACE the tag-set of a source object and set a non-empty value to x-amz-tagging.

    \n
  • \n
  • \n

    When you don't set the x-amz-tagging-directive header and the source object has non-empty tags. This is because the default value of x-amz-tagging-directive is COPY.

    \n
  • \n
\n

Because only the empty tag-set is supported for directory buckets in a CopyObject operation, the following situations are allowed:

\n
    \n
  • \n

    When you attempt to COPY the tag-set from a directory bucket source object that has no tags to a general purpose bucket. It copies an empty tag-set to the destination object.

    \n
  • \n
  • \n

    When you attempt to REPLACE the tag-set of a directory bucket source object and set the x-amz-tagging value of the directory bucket destination object to empty.

    \n
  • \n
  • \n

    When you attempt to REPLACE the tag-set of a general purpose bucket source object that has non-empty tags and set the x-amz-tagging value of the directory bucket destination object to empty.

    \n
  • \n
  • \n

    When you attempt to REPLACE the tag-set of a directory bucket source object and don't set the x-amz-tagging value of the directory bucket destination object. This is because the default value of x-amz-tagging is the empty value.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-tagging-directive" } }, "ServerSideEncryption": { "target": "com.amazonaws.s3#ServerSideEncryption", "traits": { - "smithy.api#documentation": "

The server-side encryption algorithm used when storing this object in Amazon S3 (for example,\n AES256, aws:kms, aws:kms:dsse).

", + "smithy.api#documentation": "

The server-side encryption algorithm used when storing this object in Amazon S3 (for example,\n AES256, aws:kms, aws:kms:dsse). Unrecognized or unsupported values won’t write a destination object and will receive a 400 Bad Request response.

\n

Amazon S3 automatically encrypts all new objects that are copied to an S3 bucket.\n When copying an object, if you don't specify encryption information in your copy\n request, the encryption setting of the target object is set to the default\n encryption configuration of the destination bucket. By default, all buckets have a\n base level of encryption configuration that uses server-side encryption with Amazon S3\n managed keys (SSE-S3). If the destination bucket has a default encryption\n configuration that uses server-side encryption with Key Management Service (KMS) keys\n (SSE-KMS), dual-layer server-side encryption with Amazon Web Services KMS keys (DSSE-KMS), or\n server-side encryption with customer-provided encryption keys (SSE-C), Amazon S3 uses\n the corresponding KMS key, or a customer-provided key to encrypt the target\n object copy.

\n

When you perform a CopyObject operation, if you want to use a\n different type of encryption setting for the target object, you can specify \n appropriate encryption-related headers to encrypt the target object with an Amazon S3 managed key, a\n KMS key, or a customer-provided key. If the encryption setting in\n your request is different from the default encryption configuration of the\n destination bucket, the encryption setting in your request takes precedence.

\n

With server-side\n encryption, Amazon S3 encrypts your data as it writes your data to disks in its data\n centers and decrypts the data when you access it. For more information about server-side encryption, see Using\n Server-Side Encryption in the\n Amazon S3 User Guide.

\n \n

For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption" } }, "StorageClass": { "target": "com.amazonaws.s3#StorageClass", "traits": { - "smithy.api#documentation": "

If the x-amz-storage-class header is not used, the copied object will be stored in the\n STANDARD Storage Class by default. The STANDARD storage class provides high durability and\n high availability. Depending on performance needs, you can specify a different Storage\n Class. Amazon S3 on Outposts only uses the OUTPOSTS Storage Class. For more information, see\n Storage\n Classes in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

If the x-amz-storage-class header is not used, the copied object will be stored in the\n STANDARD Storage Class by default. The STANDARD storage class provides high durability and\n high availability. Depending on performance needs, you can specify a different Storage\n Class.\n

\n \n
    \n
  • \n

    \n Directory buckets - For directory buckets, only the S3 Express One Zone storage class is supported to store newly created objects. \nUnsupported storage class values won't write a destination object and will respond with the HTTP status code 400 Bad Request.

    \n
  • \n
  • \n

    \n Amazon S3 on Outposts - S3 on Outposts only uses the OUTPOSTS Storage Class.

    \n
  • \n
\n
\n

You can use the CopyObject action to change the storage class of\n an object that is already stored in Amazon S3 by using the x-amz-storage-class \n header. For more information, see Storage Classes in\n the Amazon S3 User Guide.

\n

Before using an object as a source object for the copy operation, you must restore a copy of it if it meets any of the following conditions:

\n
    \n
  • \n

    The storage class of the source object is GLACIER or\n DEEP_ARCHIVE.

    \n
  • \n
  • \n

    The storage class of the source object is\n INTELLIGENT_TIERING and it's S3 Intelligent-Tiering access tier is\n Archive Access or Deep Archive Access.

    \n
  • \n
\n

For more\n information, see RestoreObject and Copying\n Objects in\n the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-storage-class" } }, "WebsiteRedirectLocation": { "target": "com.amazonaws.s3#WebsiteRedirectLocation", "traits": { - "smithy.api#documentation": "

If the bucket is configured as a website, redirects requests for this object to another\n object in the same bucket or to an external URL. Amazon S3 stores the value of this header in\n the object metadata. This value is unique to each object and is not copied when using the\n x-amz-metadata-directive header. Instead, you may opt to provide this\n header in combination with the directive.

", + "smithy.api#documentation": "

If the destination bucket is configured as a website, redirects requests for this object copy to another\n object in the same bucket or to an external URL. Amazon S3 stores the value of this header in\n the object metadata. This value is unique to each object and is not copied when using the\n x-amz-metadata-directive header. Instead, you may opt to provide this\n header in combination with the x-amz-metadata-directive header.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-website-redirect-location" } }, "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

Specifies the algorithm to use to when encrypting the object (for example,\n AES256).

", + "smithy.api#documentation": "

Specifies the algorithm to use when encrypting the object (for example,\n AES256).

\n

When you perform a CopyObject operation, if you want to use a\n different type of encryption setting for the target object, you can specify \n appropriate encryption-related headers to encrypt the target object with an Amazon S3 managed key, a\n KMS key, or a customer-provided key. If the encryption setting in\n your request is different from the default encryption configuration of the\n destination bucket, the encryption setting in your request takes precedence.

\n \n

This functionality is not supported when the destination bucket is a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKey": { "target": "com.amazonaws.s3#SSECustomerKey", "traits": { - "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header.

", + "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded. Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header.

\n \n

This functionality is not supported when the destination bucket is a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

", + "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

\n \n

This functionality is not supported when the destination bucket is a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, "SSEKMSKeyId": { "target": "com.amazonaws.s3#SSEKMSKeyId", "traits": { - "smithy.api#documentation": "

Specifies the KMS ID (Key ID, Key ARN, or Key Alias) to use for object encryption. All GET and PUT requests for an\n object protected by KMS will fail if they're not made via SSL or using SigV4. For\n information about configuring any of the officially supported Amazon Web Services SDKs and Amazon Web Services CLI, see\n Specifying the\n Signature Version in Request Authentication in the\n Amazon S3 User Guide.

", + "smithy.api#documentation": "

Specifies the KMS ID (Key ID, Key ARN, or Key Alias) to use for object encryption. All GET and PUT requests for an\n object protected by KMS will fail if they're not made via SSL or using SigV4. For\n information about configuring any of the officially supported Amazon Web Services SDKs and Amazon Web Services CLI, see\n Specifying the\n Signature Version in Request Authentication in the\n Amazon S3 User Guide.

\n \n

This functionality is not supported when the destination bucket is a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-aws-kms-key-id" } }, "SSEKMSEncryptionContext": { "target": "com.amazonaws.s3#SSEKMSEncryptionContext", "traits": { - "smithy.api#documentation": "

Specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The value of\n this header is a base64-encoded UTF-8 string holding JSON with the encryption context\n key-value pairs.

", + "smithy.api#documentation": "

Specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The value of\n this header is a base64-encoded UTF-8 string holding JSON with the encryption context\n key-value pairs. This value must be explicitly added to specify encryption context for \n CopyObject requests.

\n \n

This functionality is not supported when the destination bucket is a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-context" } }, "BucketKeyEnabled": { "target": "com.amazonaws.s3#BucketKeyEnabled", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Specifies whether Amazon S3 should use an S3 Bucket Key for object encryption with\n server-side encryption using Key Management Service (KMS) keys (SSE-KMS). Setting this header to\n true causes Amazon S3 to use an S3 Bucket Key for object encryption with\n SSE-KMS.

\n

Specifying this header with a COPY action doesn’t affect bucket-level settings for S3\n Bucket Key.

", + "smithy.api#documentation": "

Specifies whether Amazon S3 should use an S3 Bucket Key for object encryption with\n server-side encryption using Key Management Service (KMS) keys (SSE-KMS). If a target object uses SSE-KMS, you can enable an S3 Bucket Key for the\n object.

\n

Setting this header to\n true causes Amazon S3 to use an S3 Bucket Key for object encryption with\n SSE-KMS. Specifying this header with a COPY action doesn’t affect bucket-level settings for S3\n Bucket Key.

\n

For more information, see Amazon S3 Bucket Keys in the\n Amazon S3 User Guide.

\n \n

This functionality is not supported when the destination bucket is a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-bucket-key-enabled" } }, "CopySourceSSECustomerAlgorithm": { "target": "com.amazonaws.s3#CopySourceSSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

Specifies the algorithm to use when decrypting the source object (for example,\n AES256).

", + "smithy.api#documentation": "

Specifies the algorithm to use when decrypting the source object (for example,\n AES256).

\n

If\n the source object for the copy is stored in Amazon S3 using SSE-C, you must provide the\n necessary encryption information in your request so that Amazon S3 can decrypt the\n object for copying.

\n \n

This functionality is not supported when the source object is in a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-copy-source-server-side-encryption-customer-algorithm" } }, "CopySourceSSECustomerKey": { "target": "com.amazonaws.s3#CopySourceSSECustomerKey", "traits": { - "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use to decrypt the source\n object. The encryption key provided in this header must be one that was used when the\n source object was created.

", + "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use to decrypt the source\n object. The encryption key provided in this header must be the same one that was used when the\n source object was created.

\n

If\n the source object for the copy is stored in Amazon S3 using SSE-C, you must provide the\n necessary encryption information in your request so that Amazon S3 can decrypt the\n object for copying.

\n \n

This functionality is not supported when the source object is in a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-copy-source-server-side-encryption-customer-key" } }, "CopySourceSSECustomerKeyMD5": { "target": "com.amazonaws.s3#CopySourceSSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

", + "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

\n

If\n the source object for the copy is stored in Amazon S3 using SSE-C, you must provide the\n necessary encryption information in your request so that Amazon S3 can decrypt the\n object for copying.

\n \n

This functionality is not supported when the source object is in a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-copy-source-server-side-encryption-customer-key-MD5" } }, @@ -17097,42 +18888,42 @@ "Tagging": { "target": "com.amazonaws.s3#TaggingHeader", "traits": { - "smithy.api#documentation": "

The tag-set for the object destination object this value must be used in conjunction\n with the TaggingDirective. The tag-set must be encoded as URL Query\n parameters.

", + "smithy.api#documentation": "

The tag-set for the object copy in the destination bucket. This value must be used in conjunction\n with the x-amz-tagging-directive if you choose REPLACE for the x-amz-tagging-directive. If you choose COPY for the x-amz-tagging-directive, you don't need to set \n the x-amz-tagging header, because the tag-set will be copied from the source object directly. The tag-set must be encoded as URL Query\n parameters.

\n

The default value is the empty value.

\n \n

\n Directory buckets - For directory buckets in a CopyObject operation, only the empty tag-set is supported. Any requests that attempt to write non-empty tags into directory buckets will receive a 501 Not Implemented status code. \nWhen the destination bucket is a directory bucket, you will receive a 501 Not Implemented response in any of the following situations:

\n
    \n
  • \n

    When you attempt to COPY the tag-set from an S3 source object that has non-empty tags.

    \n
  • \n
  • \n

    When you attempt to REPLACE the tag-set of a source object and set a non-empty value to x-amz-tagging.

    \n
  • \n
  • \n

    When you don't set the x-amz-tagging-directive header and the source object has non-empty tags. This is because the default value of x-amz-tagging-directive is COPY.

    \n
  • \n
\n

Because only the empty tag-set is supported for directory buckets in a CopyObject operation, the following situations are allowed:

\n
    \n
  • \n

    When you attempt to COPY the tag-set from a directory bucket source object that has no tags to a general purpose bucket. It copies an empty tag-set to the destination object.

    \n
  • \n
  • \n

    When you attempt to REPLACE the tag-set of a directory bucket source object and set the x-amz-tagging value of the directory bucket destination object to empty.

    \n
  • \n
  • \n

    When you attempt to REPLACE the tag-set of a general purpose bucket source object that has non-empty tags and set the x-amz-tagging value of the directory bucket destination object to empty.

    \n
  • \n
  • \n

    When you attempt to REPLACE the tag-set of a directory bucket source object and don't set the x-amz-tagging value of the directory bucket destination object. This is because the default value of x-amz-tagging is the empty value.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-tagging" } }, "ObjectLockMode": { "target": "com.amazonaws.s3#ObjectLockMode", "traits": { - "smithy.api#documentation": "

The Object Lock mode that you want to apply to the copied object.

", + "smithy.api#documentation": "

The Object Lock mode that you want to apply to the object copy.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-mode" } }, "ObjectLockRetainUntilDate": { "target": "com.amazonaws.s3#ObjectLockRetainUntilDate", "traits": { - "smithy.api#documentation": "

The date and time when you want the copied object's Object Lock to expire.

", + "smithy.api#documentation": "

The date and time when you want the Object Lock of the object copy to expire.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-retain-until-date" } }, "ObjectLockLegalHoldStatus": { "target": "com.amazonaws.s3#ObjectLockLegalHoldStatus", "traits": { - "smithy.api#documentation": "

Specifies whether you want to apply a legal hold to the copied object.

", + "smithy.api#documentation": "

Specifies whether you want to apply a legal hold to the object copy.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-legal-hold" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected destination bucket owner. If the destination bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected destination bucket owner. If the account ID that you provide does not match the actual owner of the destination bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, "ExpectedSourceBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected source bucket owner. If the source bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected source bucket owner. If the account ID that you provide does not match the actual owner of the source bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-source-expected-bucket-owner" } } @@ -17159,25 +18950,25 @@ "ChecksumCRC32": { "target": "com.amazonaws.s3#ChecksumCRC32", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. For more information, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumCRC32C": { "target": "com.amazonaws.s3#ChecksumCRC32C", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. For more information, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA1": { "target": "com.amazonaws.s3#ChecksumSHA1", "traits": { - "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. For more information, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA256": { "target": "com.amazonaws.s3#ChecksumSHA256", "traits": { - "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. For more information, see \n Checking object integrity in the Amazon S3 User Guide.

" } } }, @@ -17203,25 +18994,25 @@ "ChecksumCRC32": { "target": "com.amazonaws.s3#ChecksumCRC32", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumCRC32C": { "target": "com.amazonaws.s3#ChecksumCRC32C", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA1": { "target": "com.amazonaws.s3#ChecksumSHA1", "traits": { - "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. When you use the API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA256": { "target": "com.amazonaws.s3#ChecksumSHA256", "traits": { - "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } } }, @@ -17282,16 +19073,19 @@ } ], "traits": { - "smithy.api#documentation": "

Creates a new S3 bucket. To create a bucket, you must register with Amazon S3 and have a\n valid Amazon Web Services Access Key ID to authenticate requests. Anonymous requests are never allowed to\n create buckets. By creating the bucket, you become the bucket owner.

\n

Not every string is an acceptable bucket name. For information about bucket naming\n restrictions, see Bucket naming\n rules.

\n

If you want to create an Amazon S3 on Outposts bucket, see Create Bucket.

\n

By default, the bucket is created in the US East (N. Virginia) Region. You can\n optionally specify a Region in the request body. To constrain the bucket creation to a\n specific Region, you can use \n LocationConstraint\n condition key. You might choose a Region to\n optimize latency, minimize costs, or address regulatory requirements. For example, if you\n reside in Europe, you will probably find it advantageous to create buckets in the Europe\n (Ireland) Region. For more information, see Accessing a\n bucket.

\n \n

If you send your create bucket request to the s3.amazonaws.com endpoint,\n the request goes to the us-east-1 Region. Accordingly, the signature\n calculations in Signature Version 4 must use us-east-1 as the Region, even\n if the location constraint in the request specifies another Region where the bucket is\n to be created. If you create a bucket in a Region other than US East (N. Virginia), your\n application must be able to handle 307 redirect. For more information, see Virtual hosting of\n buckets.

\n
\n
\n
Permissions
\n
\n

In addition to s3:CreateBucket, the following permissions are\n required when your CreateBucket request includes specific\n headers:

\n
    \n
  • \n

    \n Access control lists (ACLs) - If your\n CreateBucket request specifies access control list (ACL)\n permissions and the ACL is public-read, public-read-write,\n authenticated-read, or if you specify access permissions explicitly through\n any other ACL, both s3:CreateBucket and\n s3:PutBucketAcl permissions are needed. If the ACL for the\n CreateBucket request is private or if the request doesn't\n specify any ACLs, only s3:CreateBucket permission is needed.\n

    \n
  • \n
  • \n

    \n Object Lock - If\n ObjectLockEnabledForBucket is set to true in your\n CreateBucket request,\n s3:PutBucketObjectLockConfiguration and\n s3:PutBucketVersioning permissions are required.

    \n
  • \n
  • \n

    \n S3 Object Ownership - If your\n CreateBucket request includes the\n x-amz-object-ownership header, then the\n s3:PutBucketOwnershipControls permission is required. By\n default, ObjectOwnership is set to\n BucketOWnerEnforced and ACLs are disabled. We recommend\n keeping ACLs disabled, except in uncommon use cases where you must control\n access for each object individually. If you want to change the\n ObjectOwnership setting, you can use the\n x-amz-object-ownership header in your\n CreateBucket request to set the ObjectOwnership\n setting of your choice. For more information about S3 Object Ownership, see\n Controlling\n object ownership in the\n Amazon S3 User Guide.

    \n
  • \n
  • \n

    \n S3 Block Public Access - If your\n specific use case requires granting public access to your S3 resources, you\n can disable Block Public Access. You can create a new bucket with Block\n Public Access enabled, then separately call the \n DeletePublicAccessBlock\n API. To use this operation, you must have the\n s3:PutBucketPublicAccessBlock permission. By default, all\n Block Public Access settings are enabled for new buckets. To avoid\n inadvertent exposure of your resources, we recommend keeping the S3 Block\n Public Access settings enabled. For more information about S3 Block Public\n Access, see Blocking\n public access to your Amazon S3 storage in the\n Amazon S3 User Guide.

    \n
  • \n
\n
\n
\n \n

If your CreateBucket request sets BucketOwnerEnforced for\n Amazon S3 Object Ownership and specifies a bucket ACL that provides access to an external\n Amazon Web Services account, your request fails with a 400 error and returns the\n InvalidBucketAcLWithObjectOwnership error code. For more information,\n see Setting Object\n Ownership on an existing bucket in the Amazon S3 User Guide.\n

\n
\n

The following operations are related to CreateBucket:

\n ", + "smithy.api#documentation": "\n

This action creates an Amazon S3 bucket. To create an Amazon S3 on Outposts bucket, see \n CreateBucket\n .

\n
\n

Creates a new S3 bucket. To create a bucket, you must set up Amazon S3 and have a\n valid Amazon Web Services Access Key ID to authenticate requests. Anonymous requests are never allowed to\n create buckets. By creating the bucket, you become the bucket owner.

\n

There are two types of buckets: general purpose buckets and directory buckets. For more\n information about these bucket types, see Creating, configuring, and\n working with Amazon S3 buckets in the Amazon S3 User Guide.

\n \n
    \n
  • \n

    \n General purpose buckets - If you send your CreateBucket request to the s3.amazonaws.com global endpoint,\n the request goes to the us-east-1 Region. So the signature\n calculations in Signature Version 4 must use us-east-1 as the Region, even\n if the location constraint in the request specifies another Region where the bucket is\n to be created. If you create a bucket in a Region other than US East (N. Virginia), your\n application must be able to handle 307 redirect. For more information, see Virtual hosting of\n buckets in the Amazon S3 User Guide.

    \n
  • \n
  • \n

    \n Directory buckets - For directory buckets, you must make requests for this API operation to the Regional endpoint. These endpoints support path-style requests in the format https://s3express-control.region_code.amazonaws.com/bucket-name\n . Virtual-hosted-style requests aren't supported. \nFor more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

    \n
  • \n
\n
\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - In addition to the s3:CreateBucket permission, the following permissions are\n required in a policy when your CreateBucket request includes specific\n headers:

    \n
      \n
    • \n

      \n Access control lists (ACLs) - In your CreateBucket request, if you specify an access control list (ACL) \n and set it to public-read, public-read-write,\n authenticated-read, or if you explicitly specify any other custom ACLs, both s3:CreateBucket and\n s3:PutBucketAcl permissions are required. In your CreateBucket request, if you set the ACL to private, \n or if you don't specify any ACLs, only the s3:CreateBucket permission is required.\n

      \n
    • \n
    • \n

      \n Object Lock - In your\n CreateBucket request, if you set \n x-amz-bucket-object-lock-enabled to true, the \n s3:PutBucketObjectLockConfiguration and\n s3:PutBucketVersioning permissions are required.

      \n
    • \n
    • \n

      \n S3 Object Ownership - If your\n CreateBucket request includes the\n x-amz-object-ownership header, then the\n s3:PutBucketOwnershipControls permission is required.

      \n \n

      If your CreateBucket request sets BucketOwnerEnforced for\n Amazon S3 Object Ownership and specifies a bucket ACL that provides access to an external\n Amazon Web Services account, your request fails with a 400 error and returns the\n InvalidBucketAcLWithObjectOwnership error code. For more information,\n see Setting Object\n Ownership on an existing bucket in the Amazon S3 User Guide.\n

      \n
      \n
    • \n
    • \n

      \n S3 Block Public Access - If your\n specific use case requires granting public access to your S3 resources, you\n can disable Block Public Access. Specifically, you can create a new bucket with Block\n Public Access enabled, then separately call the \n DeletePublicAccessBlock\n API. To use this operation, you must have the\n s3:PutBucketPublicAccessBlock permission. For more information about S3 Block Public\n Access, see Blocking\n public access to your Amazon S3 storage in the\n Amazon S3 User Guide.

      \n
    • \n
    \n
  • \n
  • \n

    \n Directory bucket permissions - You must have the s3express:CreateBucket permission in an IAM identity-based policy instead of a bucket policy. Cross-account access to this API operation isn't supported. This operation can only be performed by the Amazon Web Services account that owns the resource. For more information about directory bucket policies and permissions, see Amazon Web Services Identity and Access Management (IAM) for S3 Express One Zone in the Amazon S3 User Guide.

    \n \n

    The permissions for ACLs, Object Lock, S3 Object Ownership, and S3 Block Public Access are not supported for directory buckets. \n For directory buckets, all Block Public Access settings are enabled at the bucket level and S3 \n Object Ownership is set to Bucket owner enforced (ACLs disabled). These settings can't be modified.\n

    \n

    For more information about permissions for creating and working with \n directory buckets, see Directory buckets in the Amazon S3 User Guide. \n For more information about supported S3 features for directory buckets, see Features of S3 Express One Zone in the Amazon S3 User Guide.

    \n
    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is s3express-control.region.amazonaws.com.

\n
\n
\n

The following operations are related to CreateBucket:

\n ", "smithy.api#examples": [ { - "title": "To create a bucket ", - "documentation": "The following example creates a bucket.", + "title": "To create a bucket in a specific region", + "documentation": "The following example creates a bucket. The request specifies an AWS region where to create the bucket.", "input": { - "Bucket": "examplebucket" + "Bucket": "examplebucket", + "CreateBucketConfiguration": { + "LocationConstraint": "eu-west-1" + } }, "output": { - "Location": "/examplebucket" + "Location": "http://examplebucket..s3.amazonaws.com/" } } ], @@ -17301,6 +19095,9 @@ "code": 200 }, "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + }, "DisableAccessPoints": { "value": true } @@ -17313,7 +19110,19 @@ "LocationConstraint": { "target": "com.amazonaws.s3#BucketLocationConstraint", "traits": { - "smithy.api#documentation": "

Specifies the Region where the bucket will be created. If you don't specify a Region,\n the bucket is created in the US East (N. Virginia) Region (us-east-1).

" + "smithy.api#documentation": "

Specifies the Region where the bucket will be created. You might choose a Region to\n optimize latency, minimize costs, or address regulatory requirements. For example, if you\n reside in Europe, you will probably find it advantageous to create buckets in the Europe\n (Ireland) Region. For more information, see Accessing a\n bucket in the Amazon S3 User Guide.

\n

If you don't specify a Region,\n the bucket is created in the US East (N. Virginia) Region (us-east-1) by default.

\n \n

This functionality is not supported for directory buckets.

\n
" + } + }, + "Location": { + "target": "com.amazonaws.s3#LocationInfo", + "traits": { + "smithy.api#documentation": "

Specifies the location where the bucket will be created.

\n

For directory buckets, the location type is Availability Zone.

\n \n

This functionality is only supported by directory buckets.

\n
" + } + }, + "Bucket": { + "target": "com.amazonaws.s3#BucketInfo", + "traits": { + "smithy.api#documentation": "

Specifies the information about the bucket that will be created.

\n \n

This functionality is only supported by directory buckets.

\n
" } } }, @@ -17342,14 +19151,14 @@ "ACL": { "target": "com.amazonaws.s3#BucketCannedACL", "traits": { - "smithy.api#documentation": "

The canned ACL to apply to the bucket.

", + "smithy.api#documentation": "

The canned ACL to apply to the bucket.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-acl" } }, "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket to create.

", + "smithy.api#documentation": "

The name of the bucket to create.

\n

\n General purpose buckets - For information about bucket naming\n restrictions, see Bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use path-style requests in the format https://s3express-control.region_code.amazonaws.com/bucket-name\n . Virtual-hosted-style requests aren't supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must also follow the format \n bucket_base_name--az_id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming restrictions, see Directory bucket naming rules in the Amazon S3 User Guide\n

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -17368,43 +19177,42 @@ "GrantFullControl": { "target": "com.amazonaws.s3#GrantFullControl", "traits": { - "smithy.api#documentation": "

Allows grantee the read, write, read ACP, and write ACP permissions on the\n bucket.

", + "smithy.api#documentation": "

Allows grantee the read, write, read ACP, and write ACP permissions on the\n bucket.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-grant-full-control" } }, "GrantRead": { "target": "com.amazonaws.s3#GrantRead", "traits": { - "smithy.api#documentation": "

Allows grantee to list the objects in the bucket.

", + "smithy.api#documentation": "

Allows grantee to list the objects in the bucket.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-grant-read" } }, "GrantReadACP": { "target": "com.amazonaws.s3#GrantReadACP", "traits": { - "smithy.api#documentation": "

Allows grantee to read the bucket ACL.

", + "smithy.api#documentation": "

Allows grantee to read the bucket ACL.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-grant-read-acp" } }, "GrantWrite": { "target": "com.amazonaws.s3#GrantWrite", "traits": { - "smithy.api#documentation": "

Allows grantee to create new objects in the bucket.

\n

For the bucket and object owners of existing objects, also allows deletions and\n overwrites of those objects.

", + "smithy.api#documentation": "

Allows grantee to create new objects in the bucket.

\n

For the bucket and object owners of existing objects, also allows deletions and\n overwrites of those objects.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-grant-write" } }, "GrantWriteACP": { "target": "com.amazonaws.s3#GrantWriteACP", "traits": { - "smithy.api#documentation": "

Allows grantee to write the ACL for the applicable bucket.

", + "smithy.api#documentation": "

Allows grantee to write the ACL for the applicable bucket.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-grant-write-acp" } }, "ObjectLockEnabledForBucket": { "target": "com.amazonaws.s3#ObjectLockEnabledForBucket", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Specifies whether you want S3 Object Lock to be enabled for the new bucket.

", + "smithy.api#documentation": "

Specifies whether you want S3 Object Lock to be enabled for the new bucket.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-bucket-object-lock-enabled" } }, @@ -17428,7 +19236,7 @@ "target": "com.amazonaws.s3#CreateMultipartUploadOutput" }, "traits": { - "smithy.api#documentation": "

This action initiates a multipart upload and returns an upload ID. This upload ID is\n used to associate all of the parts in the specific multipart upload. You specify this\n upload ID in each of your subsequent upload part requests (see UploadPart). You also include this\n upload ID in the final request to either complete or abort the multipart upload\n request.

\n

For more information about multipart uploads, see Multipart Upload Overview.

\n

If you have configured a lifecycle rule to abort incomplete multipart uploads, the\n upload must complete within the number of days specified in the bucket lifecycle\n configuration. Otherwise, the incomplete multipart upload becomes eligible for an abort\n action and Amazon S3 aborts the multipart upload. For more information, see Aborting Incomplete Multipart Uploads Using a Bucket Lifecycle\n Configuration.

\n

For information about the permissions required to use the multipart upload API, see\n Multipart\n Upload and Permissions.

\n

For request signing, multipart upload is just a series of regular requests. You initiate\n a multipart upload, send one or more requests to upload parts, and then complete the\n multipart upload process. You sign each request individually. There is nothing special\n about signing multipart upload requests. For more information about signing, see Authenticating Requests (Amazon Web Services Signature Version 4).

\n \n

After you initiate a multipart upload and upload one or more parts, to stop being\n charged for storing the uploaded parts, you must either complete or abort the multipart\n upload. Amazon S3 frees up the space used to store the parts and stop charging you for\n storing them only after you either complete or abort a multipart upload.

\n
\n

Server-side encryption is for data encryption at rest. Amazon S3 encrypts your data as it\n writes it to disks in its data centers and decrypts it when you access it. Amazon S3\n automatically encrypts all new objects that are uploaded to an S3 bucket. When doing a\n multipart upload, if you don't specify encryption information in your request, the\n encryption setting of the uploaded parts is set to the default encryption configuration of\n the destination bucket. By default, all buckets have a base level of encryption\n configuration that uses server-side encryption with Amazon S3 managed keys (SSE-S3). If the\n destination bucket has a default encryption configuration that uses server-side encryption\n with an Key Management Service (KMS) key (SSE-KMS), or a customer-provided encryption key (SSE-C),\n Amazon S3 uses the corresponding KMS key, or a customer-provided key to encrypt the uploaded\n parts. When you perform a CreateMultipartUpload operation, if you want to use a different\n type of encryption setting for the uploaded parts, you can request that Amazon S3 encrypts the\n object with a KMS key, an Amazon S3 managed key, or a customer-provided key. If the encryption\n setting in your request is different from the default encryption configuration of the\n destination bucket, the encryption setting in your request takes precedence. If you choose\n to provide your own encryption key, the request headers you provide in UploadPart\n and UploadPartCopy requests must match the headers you used in the request to\n initiate the upload by using CreateMultipartUpload. You can request that Amazon S3\n save the uploaded parts encrypted with server-side encryption with an Amazon S3 managed key\n (SSE-S3), an Key Management Service (KMS) key (SSE-KMS), or a customer-provided encryption key\n (SSE-C).

\n

To perform a multipart upload with encryption by using an Amazon Web Services KMS key, the requester\n must have permission to the kms:Decrypt and kms:GenerateDataKey*\n actions on the key. These permissions are required because Amazon S3 must decrypt and read data\n from the encrypted file parts before it completes the multipart upload. For more\n information, see Multipart upload API\n and permissions and Protecting data using\n server-side encryption with Amazon Web Services KMS in the\n Amazon S3 User Guide.

\n

If your Identity and Access Management (IAM) user or role is in the same Amazon Web Services account as the KMS key,\n then you must have these permissions on the key policy. If your IAM user or role belongs\n to a different account than the key, then you must have the permissions on both the key\n policy and your IAM user or role.

\n

For more information, see Protecting Data Using Server-Side\n Encryption.

\n
\n
Access Permissions
\n
\n

When copying an object, you can optionally specify the accounts or groups that\n should be granted specific permissions on the new object. There are two ways to\n grant the permissions using the request headers:

\n
    \n
  • \n

    Specify a canned ACL with the x-amz-acl request header. For\n more information, see Canned\n ACL.

    \n
  • \n
  • \n

    Specify access permissions explicitly with the\n x-amz-grant-read, x-amz-grant-read-acp,\n x-amz-grant-write-acp, and\n x-amz-grant-full-control headers. These parameters map to\n the set of permissions that Amazon S3 supports in an ACL. For more information,\n see Access Control List (ACL) Overview.

    \n
  • \n
\n

You can use either a canned ACL or specify access permissions explicitly. You\n cannot do both.

\n
\n
Server-Side- Encryption-Specific Request Headers
\n
\n

Amazon S3 encrypts data by using server-side encryption with an Amazon S3 managed key\n (SSE-S3) by default. Server-side encryption is for data encryption at rest. Amazon S3\n encrypts your data as it writes it to disks in its data centers and decrypts it\n when you access it. You can request that Amazon S3 encrypts data at rest by using\n server-side encryption with other key options. The option you use depends on\n whether you want to use KMS keys (SSE-KMS) or provide your own encryption keys\n (SSE-C).

\n
    \n
  • \n

    Use KMS keys (SSE-KMS) that include the Amazon Web Services managed key\n (aws/s3) and KMS customer managed keys stored in Key Management Service (KMS) –\n If you want Amazon Web Services to manage the keys used to encrypt data, specify the\n following headers in the request.

    \n
      \n
    • \n

      \n x-amz-server-side-encryption\n

      \n
    • \n
    • \n

      \n x-amz-server-side-encryption-aws-kms-key-id\n

      \n
    • \n
    • \n

      \n x-amz-server-side-encryption-context\n

      \n
    • \n
    \n \n

    If you specify x-amz-server-side-encryption:aws:kms, but\n don't provide x-amz-server-side-encryption-aws-kms-key-id,\n Amazon S3 uses the Amazon Web Services managed key (aws/s3 key) in KMS to\n protect the data.

    \n
    \n \n

    All GET and PUT requests for an object\n protected by KMS fail if you don't make them by using Secure Sockets\n Layer (SSL), Transport Layer Security (TLS), or Signature Version\n 4.

    \n
    \n

    For more information about server-side encryption with KMS keys\n (SSE-KMS), see Protecting Data\n Using Server-Side Encryption with KMS keys.

    \n
  • \n
  • \n

    Use customer-provided encryption keys (SSE-C) – If you want to manage\n your own encryption keys, provide all the following headers in the\n request.

    \n
      \n
    • \n

      \n x-amz-server-side-encryption-customer-algorithm\n

      \n
    • \n
    • \n

      \n x-amz-server-side-encryption-customer-key\n

      \n
    • \n
    • \n

      \n x-amz-server-side-encryption-customer-key-MD5\n

      \n
    • \n
    \n

    For more information about server-side encryption with customer-provided\n encryption keys (SSE-C), see \n Protecting data using server-side encryption with customer-provided\n encryption keys (SSE-C).

    \n
  • \n
\n
\n
Access-Control-List (ACL)-Specific Request Headers
\n
\n

You also can use the following access control–related headers with this\n operation. By default, all objects are private. Only the owner has full access\n control. When adding a new object, you can grant permissions to individual\n Amazon Web Services accounts or to predefined groups defined by Amazon S3. These permissions are then\n added to the access control list (ACL) on the object. For more information, see\n Using ACLs. With this operation, you can grant access permissions\n using one of the following two methods:

\n
    \n
  • \n

    Specify a canned ACL (x-amz-acl) — Amazon S3 supports a set of\n predefined ACLs, known as canned ACLs. Each canned ACL\n has a predefined set of grantees and permissions. For more information, see\n Canned\n ACL.

    \n
  • \n
  • \n

    Specify access permissions explicitly — To explicitly grant access\n permissions to specific Amazon Web Services accounts or groups, use the following headers.\n Each header maps to specific permissions that Amazon S3 supports in an ACL. For\n more information, see Access Control List (ACL)\n Overview. In the header, you specify a list of grantees who get\n the specific permission. To grant permissions explicitly, use:

    \n
      \n
    • \n

      \n x-amz-grant-read\n

      \n
    • \n
    • \n

      \n x-amz-grant-write\n

      \n
    • \n
    • \n

      \n x-amz-grant-read-acp\n

      \n
    • \n
    • \n

      \n x-amz-grant-write-acp\n

      \n
    • \n
    • \n

      \n x-amz-grant-full-control\n

      \n
    • \n
    \n

    You specify each grantee as a type=value pair, where the type is one of\n the following:

    \n
      \n
    • \n

      \n id – if the value specified is the canonical user ID\n of an Amazon Web Services account

      \n
    • \n
    • \n

      \n uri – if you are granting permissions to a predefined\n group

      \n
    • \n
    • \n

      \n emailAddress – if the value specified is the email\n address of an Amazon Web Services account

      \n \n

      Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

      \n
        \n
      • \n

        US East (N. Virginia)

        \n
      • \n
      • \n

        US West (N. California)

        \n
      • \n
      • \n

        US West (Oregon)

        \n
      • \n
      • \n

        Asia Pacific (Singapore)

        \n
      • \n
      • \n

        Asia Pacific (Sydney)

        \n
      • \n
      • \n

        Asia Pacific (Tokyo)

        \n
      • \n
      • \n

        Europe (Ireland)

        \n
      • \n
      • \n

        South America (São Paulo)

        \n
      • \n
      \n

      For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

      \n
      \n
    • \n
    \n

    For example, the following x-amz-grant-read header grants the Amazon Web Services accounts identified by account IDs permissions to read object data and its metadata:

    \n

    \n x-amz-grant-read: id=\"11112222333\", id=\"444455556666\" \n

    \n
  • \n
\n
\n
\n

The following operations are related to CreateMultipartUpload:

\n ", + "smithy.api#documentation": "

This action initiates a multipart upload and returns an upload ID. This upload ID is\n used to associate all of the parts in the specific multipart upload. You specify this\n upload ID in each of your subsequent upload part requests (see UploadPart). You also include this\n upload ID in the final request to either complete or abort the multipart upload\n request. For more information about multipart uploads, see Multipart Upload Overview in the Amazon S3 User Guide.

\n \n

After you initiate a multipart upload and upload one or more parts, to stop being\n charged for storing the uploaded parts, you must either complete or abort the multipart\n upload. Amazon S3 frees up the space used to store the parts and stops charging you for\n storing them only after you either complete or abort a multipart upload.

\n
\n

If you have configured a lifecycle rule to abort incomplete multipart uploads, the created multipart \n upload must be completed within the number of days specified in the bucket lifecycle\n configuration. Otherwise, the incomplete multipart upload becomes eligible for an abort\n action and Amazon S3 aborts the multipart upload. For more information, see Aborting Incomplete Multipart Uploads Using a Bucket Lifecycle\n Configuration.

\n \n
    \n
  • \n

    \n Directory buckets - S3 Lifecycle is not supported by directory buckets.

    \n
  • \n
  • \n

    \n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

    \n
  • \n
\n
\n
\n
Request signing
\n
\n

For request signing, multipart upload is just a series of regular requests. You initiate\n a multipart upload, send one or more requests to upload parts, and then complete the\n multipart upload process. You sign each request individually. There is nothing special\n about signing multipart upload requests. For more information about signing, see Authenticating Requests (Amazon Web Services Signature Version 4) in the Amazon S3 User Guide.

\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - For information about the permissions required to use the multipart upload API, see\n Multipart\n upload and permissions in the Amazon S3 User Guide.

    \n

    To perform a multipart upload with encryption by using an Amazon Web Services KMS key, the requester\n must have permission to the kms:Decrypt and kms:GenerateDataKey*\n actions on the key. These permissions are required because Amazon S3 must decrypt and read data\n from the encrypted file parts before it completes the multipart upload. For more\n information, see Multipart upload API\n and permissions and Protecting data using\n server-side encryption with Amazon Web Services KMS in the\n Amazon S3 User Guide.

    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation on a directory bucket, we recommend that you use the \n CreateSession\n API operation for session-based authorization. Specifically, you grant the s3express:CreateSession permission to the directory bucket in a bucket policy or an IAM identity-based policy. Then, you make the CreateSession API call on the bucket to obtain a session token. With the session token in your request header, you can make API requests to this operation. After the session token expires, you make another CreateSession API call to generate a new session token for use. \nAmazon Web Services CLI or SDKs create session and refresh the session token automatically to avoid service interruptions when a session expires. For more information about authorization, see \n CreateSession\n .

    \n
  • \n
\n
\n
Encryption
\n
\n
    \n
  • \n

    \n General purpose buckets - Server-side encryption is for data encryption at rest. Amazon S3 encrypts your data as it\n writes it to disks in its data centers and decrypts it when you access it. Amazon S3\n automatically encrypts all new objects that are uploaded to an S3 bucket. When doing a\n multipart upload, if you don't specify encryption information in your request, the\n encryption setting of the uploaded parts is set to the default encryption configuration of\n the destination bucket. By default, all buckets have a base level of encryption\n configuration that uses server-side encryption with Amazon S3 managed keys (SSE-S3). If the\n destination bucket has a default encryption configuration that uses server-side encryption\n with an Key Management Service (KMS) key (SSE-KMS), or a customer-provided encryption key (SSE-C),\n Amazon S3 uses the corresponding KMS key, or a customer-provided key to encrypt the uploaded\n parts. When you perform a CreateMultipartUpload operation, if you want to use a different\n type of encryption setting for the uploaded parts, you can request that Amazon S3 encrypts the\n object with a different encryption key (such as an Amazon S3 managed key, a KMS key, or a customer-provided key). When the encryption\n setting in your request is different from the default encryption configuration of the\n destination bucket, the encryption setting in your request takes precedence. If you choose\n to provide your own encryption key, the request headers you provide in UploadPart\n and UploadPartCopy requests must match the headers you used in the CreateMultipartUpload request.

    \n
      \n
    • \n

      Use KMS keys (SSE-KMS) that include the Amazon Web Services managed key\n (aws/s3) and KMS customer managed keys stored in Key Management Service (KMS) –\n If you want Amazon Web Services to manage the keys used to encrypt data, specify the\n following headers in the request.

      \n
        \n
      • \n

        \n x-amz-server-side-encryption\n

        \n
      • \n
      • \n

        \n x-amz-server-side-encryption-aws-kms-key-id\n

        \n
      • \n
      • \n

        \n x-amz-server-side-encryption-context\n

        \n
      • \n
      \n \n
        \n
      • \n

        If you specify x-amz-server-side-encryption:aws:kms, but\n don't provide x-amz-server-side-encryption-aws-kms-key-id,\n Amazon S3 uses the Amazon Web Services managed key (aws/s3 key) in KMS to\n protect the data.

        \n
      • \n
      • \n

        To perform a multipart upload with encryption by using an Amazon Web Services KMS key, the requester\n must have permission to the kms:Decrypt and kms:GenerateDataKey*\n actions on the key. These permissions are required because Amazon S3 must decrypt and read data\n from the encrypted file parts before it completes the multipart upload. For more\n information, see Multipart upload API\n and permissions and Protecting data using\n server-side encryption with Amazon Web Services KMS in the\n Amazon S3 User Guide.

        \n
      • \n
      • \n

        If your Identity and Access Management (IAM) user or role is in the same Amazon Web Services account as the KMS key,\n then you must have these permissions on the key policy. If your IAM user or role is in a different account from the key, then you must have the permissions on both the key\n policy and your IAM user or role.

        \n
      • \n
      • \n

        All GET and PUT requests for an object\n protected by KMS fail if you don't make them by using Secure Sockets\n Layer (SSL), Transport Layer Security (TLS), or Signature Version\n 4. For information about configuring any of the officially supported Amazon Web Services\n SDKs and Amazon Web Services CLI, see Specifying the Signature Version in Request Authentication\n in the Amazon S3 User Guide.

        \n
      • \n
      \n
      \n

      For more information about server-side encryption with KMS keys\n (SSE-KMS), see Protecting Data\n Using Server-Side Encryption with KMS keys in the Amazon S3 User Guide.

      \n
    • \n
    • \n

      Use customer-provided encryption keys (SSE-C) – If you want to manage\n your own encryption keys, provide all the following headers in the\n request.

      \n
        \n
      • \n

        \n x-amz-server-side-encryption-customer-algorithm\n

        \n
      • \n
      • \n

        \n x-amz-server-side-encryption-customer-key\n

        \n
      • \n
      • \n

        \n x-amz-server-side-encryption-customer-key-MD5\n

        \n
      • \n
      \n

      For more information about server-side encryption with customer-provided\n encryption keys (SSE-C), see \n Protecting data using server-side encryption with customer-provided\n encryption keys (SSE-C) in the Amazon S3 User Guide.

      \n
    • \n
    \n
  • \n
  • \n

    \n Directory buckets -For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

The following operations are related to CreateMultipartUpload:

\n ", "smithy.api#examples": [ { "title": "To initiate a multipart upload", @@ -17457,21 +19265,21 @@ "AbortDate": { "target": "com.amazonaws.s3#AbortDate", "traits": { - "smithy.api#documentation": "

If the bucket has a lifecycle rule configured with an action to abort incomplete\n multipart uploads and the prefix in the lifecycle rule matches the object name in the\n request, the response includes this header. The header indicates when the initiated\n multipart upload becomes eligible for an abort operation. For more information, see \n Aborting Incomplete Multipart Uploads Using a Bucket Lifecycle\n Configuration.

\n

The response also includes the x-amz-abort-rule-id header that provides the\n ID of the lifecycle configuration rule that defines this action.

", + "smithy.api#documentation": "

If the bucket has a lifecycle rule configured with an action to abort incomplete\n multipart uploads and the prefix in the lifecycle rule matches the object name in the\n request, the response includes this header. The header indicates when the initiated\n multipart upload becomes eligible for an abort operation. For more information, see \n Aborting Incomplete Multipart Uploads Using a Bucket Lifecycle\n Configuration in the Amazon S3 User Guide.

\n

The response also includes the x-amz-abort-rule-id header that provides the\n ID of the lifecycle configuration rule that defines the abort action.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-abort-date" } }, "AbortRuleId": { "target": "com.amazonaws.s3#AbortRuleId", "traits": { - "smithy.api#documentation": "

This header is returned along with the x-amz-abort-date header. It\n identifies the applicable lifecycle configuration rule that defines the action to abort\n incomplete multipart uploads.

", + "smithy.api#documentation": "

This header is returned along with the x-amz-abort-date header. It\n identifies the applicable lifecycle configuration rule that defines the action to abort\n incomplete multipart uploads.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-abort-rule-id" } }, "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket to which the multipart upload was initiated. Does not return the\n access point ARN or access point alias if used.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket to which the multipart upload was initiated. Does not return the\n access point ARN or access point alias if used.

\n \n

Access points are not supported by directory buckets.

\n
", "smithy.api#xmlName": "Bucket" } }, @@ -17490,43 +19298,42 @@ "ServerSideEncryption": { "target": "com.amazonaws.s3#ServerSideEncryption", "traits": { - "smithy.api#documentation": "

The server-side encryption algorithm used when storing this object in Amazon S3 (for example,\n AES256, aws:kms).

", + "smithy.api#documentation": "

The server-side encryption algorithm used when you store this object in Amazon S3 (for example,\n AES256, aws:kms).

\n \n

For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption" } }, "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header confirming the encryption algorithm used.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to confirm the encryption algorithm that's used.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide round-trip message integrity verification of\n the customer-provided encryption key.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide the round-trip message integrity verification of\n the customer-provided encryption key.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, "SSEKMSKeyId": { "target": "com.amazonaws.s3#SSEKMSKeyId", "traits": { - "smithy.api#documentation": "

If present, specifies the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n that was used for the object.

", + "smithy.api#documentation": "

If present, indicates the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n that was used for the object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-aws-kms-key-id" } }, "SSEKMSEncryptionContext": { "target": "com.amazonaws.s3#SSEKMSEncryptionContext", "traits": { - "smithy.api#documentation": "

If present, specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The\n value of this header is a base64-encoded UTF-8 string holding JSON with the encryption\n context key-value pairs.

", + "smithy.api#documentation": "

If present, indicates the Amazon Web Services KMS Encryption Context to use for object encryption. The\n value of this header is a base64-encoded UTF-8 string holding JSON with the encryption\n context key-value pairs.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-context" } }, "BucketKeyEnabled": { "target": "com.amazonaws.s3#BucketKeyEnabled", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

", + "smithy.api#documentation": "

Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-bucket-key-enabled" } }, @@ -17555,14 +19362,14 @@ "ACL": { "target": "com.amazonaws.s3#ObjectCannedACL", "traits": { - "smithy.api#documentation": "

The canned ACL to apply to the object.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

The canned ACL to apply to the object. Amazon S3 supports a set of\n predefined ACLs, known as canned ACLs. Each canned ACL\n has a predefined set of grantees and permissions. For more information, see\n Canned\n ACL in the Amazon S3 User Guide.

\n

By default, all objects are private. Only the owner has full access\n control. When uploading an object, you can grant access permissions to individual\n Amazon Web Services accounts or to predefined groups defined by Amazon S3. These permissions are then\n added to the access control list (ACL) on the new object. For more information, see\n Using ACLs. One way to\n grant the permissions using the request headers is to specify a canned ACL with the x-amz-acl request header.

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-acl" } }, "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket to which to initiate the upload

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket where the multipart upload is initiated and where the object is uploaded.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -17587,14 +19394,14 @@ "ContentEncoding": { "target": "com.amazonaws.s3#ContentEncoding", "traits": { - "smithy.api#documentation": "

Specifies what content encodings have been applied to the object and thus what decoding\n mechanisms must be applied to obtain the media-type referenced by the Content-Type header\n field.

", + "smithy.api#documentation": "

Specifies what content encodings have been applied to the object and thus what decoding\n mechanisms must be applied to obtain the media-type referenced by the Content-Type header\n field.

\n \n

For directory buckets, only the aws-chunked value is supported in this header field.

\n
", "smithy.api#httpHeader": "Content-Encoding" } }, "ContentLanguage": { "target": "com.amazonaws.s3#ContentLanguage", "traits": { - "smithy.api#documentation": "

The language the content is in.

", + "smithy.api#documentation": "

The language that the content is in.

", "smithy.api#httpHeader": "Content-Language" } }, @@ -17615,28 +19422,28 @@ "GrantFullControl": { "target": "com.amazonaws.s3#GrantFullControl", "traits": { - "smithy.api#documentation": "

Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Specify access permissions explicitly to give the grantee READ, READ_ACP, and WRITE_ACP permissions on the object.

\n

By default, all objects are private. Only the owner has full access\n control. When uploading an object, you can use this header to explicitly grant access\n permissions to specific Amazon Web Services accounts or groups.\n This header maps to specific permissions that Amazon S3 supports in an ACL. For\n more information, see Access Control List (ACL)\n Overview in the Amazon S3 User Guide.

\n

You specify each grantee as a type=value pair, where the type is one of\n the following:

\n
    \n
  • \n

    \n id – if the value specified is the canonical user ID\n of an Amazon Web Services account

    \n
  • \n
  • \n

    \n uri – if you are granting permissions to a predefined\n group

    \n
  • \n
  • \n

    \n emailAddress – if the value specified is the email\n address of an Amazon Web Services account

    \n \n

    Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

    \n
      \n
    • \n

      US East (N. Virginia)

      \n
    • \n
    • \n

      US West (N. California)

      \n
    • \n
    • \n

      US West (Oregon)

      \n
    • \n
    • \n

      Asia Pacific (Singapore)

      \n
    • \n
    • \n

      Asia Pacific (Sydney)

      \n
    • \n
    • \n

      Asia Pacific (Tokyo)

      \n
    • \n
    • \n

      Europe (Ireland)

      \n
    • \n
    • \n

      South America (São Paulo)

      \n
    • \n
    \n

    For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

    \n
    \n
  • \n
\n

For example, the following x-amz-grant-read header grants the Amazon Web Services accounts identified by account IDs permissions to read object data and its metadata:

\n

\n x-amz-grant-read: id=\"11112222333\", id=\"444455556666\" \n

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-grant-full-control" } }, "GrantRead": { "target": "com.amazonaws.s3#GrantRead", "traits": { - "smithy.api#documentation": "

Allows grantee to read the object data and its metadata.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Specify access permissions explicitly to allow grantee to read the object data and its metadata.

\n

By default, all objects are private. Only the owner has full access\n control. When uploading an object, you can use this header to explicitly grant access\n permissions to specific Amazon Web Services accounts or groups.\n This header maps to specific permissions that Amazon S3 supports in an ACL. For\n more information, see Access Control List (ACL)\n Overview in the Amazon S3 User Guide.

\n

You specify each grantee as a type=value pair, where the type is one of\n the following:

\n
    \n
  • \n

    \n id – if the value specified is the canonical user ID\n of an Amazon Web Services account

    \n
  • \n
  • \n

    \n uri – if you are granting permissions to a predefined\n group

    \n
  • \n
  • \n

    \n emailAddress – if the value specified is the email\n address of an Amazon Web Services account

    \n \n

    Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

    \n
      \n
    • \n

      US East (N. Virginia)

      \n
    • \n
    • \n

      US West (N. California)

      \n
    • \n
    • \n

      US West (Oregon)

      \n
    • \n
    • \n

      Asia Pacific (Singapore)

      \n
    • \n
    • \n

      Asia Pacific (Sydney)

      \n
    • \n
    • \n

      Asia Pacific (Tokyo)

      \n
    • \n
    • \n

      Europe (Ireland)

      \n
    • \n
    • \n

      South America (São Paulo)

      \n
    • \n
    \n

    For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

    \n
    \n
  • \n
\n

For example, the following x-amz-grant-read header grants the Amazon Web Services accounts identified by account IDs permissions to read object data and its metadata:

\n

\n x-amz-grant-read: id=\"11112222333\", id=\"444455556666\" \n

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-grant-read" } }, "GrantReadACP": { "target": "com.amazonaws.s3#GrantReadACP", "traits": { - "smithy.api#documentation": "

Allows grantee to read the object ACL.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Specify access permissions explicitly to allows grantee to read the object ACL.

\n

By default, all objects are private. Only the owner has full access\n control. When uploading an object, you can use this header to explicitly grant access\n permissions to specific Amazon Web Services accounts or groups.\n This header maps to specific permissions that Amazon S3 supports in an ACL. For\n more information, see Access Control List (ACL)\n Overview in the Amazon S3 User Guide.

\n

You specify each grantee as a type=value pair, where the type is one of\n the following:

\n
    \n
  • \n

    \n id – if the value specified is the canonical user ID\n of an Amazon Web Services account

    \n
  • \n
  • \n

    \n uri – if you are granting permissions to a predefined\n group

    \n
  • \n
  • \n

    \n emailAddress – if the value specified is the email\n address of an Amazon Web Services account

    \n \n

    Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

    \n
      \n
    • \n

      US East (N. Virginia)

      \n
    • \n
    • \n

      US West (N. California)

      \n
    • \n
    • \n

      US West (Oregon)

      \n
    • \n
    • \n

      Asia Pacific (Singapore)

      \n
    • \n
    • \n

      Asia Pacific (Sydney)

      \n
    • \n
    • \n

      Asia Pacific (Tokyo)

      \n
    • \n
    • \n

      Europe (Ireland)

      \n
    • \n
    • \n

      South America (São Paulo)

      \n
    • \n
    \n

    For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

    \n
    \n
  • \n
\n

For example, the following x-amz-grant-read header grants the Amazon Web Services accounts identified by account IDs permissions to read object data and its metadata:

\n

\n x-amz-grant-read: id=\"11112222333\", id=\"444455556666\" \n

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-grant-read-acp" } }, "GrantWriteACP": { "target": "com.amazonaws.s3#GrantWriteACP", "traits": { - "smithy.api#documentation": "

Allows grantee to write the ACL for the applicable object.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Specify access permissions explicitly to allows grantee to allow grantee to write the ACL for the applicable object.

\n

By default, all objects are private. Only the owner has full access\n control. When uploading an object, you can use this header to explicitly grant access\n permissions to specific Amazon Web Services accounts or groups.\n This header maps to specific permissions that Amazon S3 supports in an ACL. For\n more information, see Access Control List (ACL)\n Overview in the Amazon S3 User Guide.

\n

You specify each grantee as a type=value pair, where the type is one of\n the following:

\n
    \n
  • \n

    \n id – if the value specified is the canonical user ID\n of an Amazon Web Services account

    \n
  • \n
  • \n

    \n uri – if you are granting permissions to a predefined\n group

    \n
  • \n
  • \n

    \n emailAddress – if the value specified is the email\n address of an Amazon Web Services account

    \n \n

    Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

    \n
      \n
    • \n

      US East (N. Virginia)

      \n
    • \n
    • \n

      US West (N. California)

      \n
    • \n
    • \n

      US West (Oregon)

      \n
    • \n
    • \n

      Asia Pacific (Singapore)

      \n
    • \n
    • \n

      Asia Pacific (Sydney)

      \n
    • \n
    • \n

      Asia Pacific (Tokyo)

      \n
    • \n
    • \n

      Europe (Ireland)

      \n
    • \n
    • \n

      South America (São Paulo)

      \n
    • \n
    \n

    For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

    \n
    \n
  • \n
\n

For example, the following x-amz-grant-read header grants the Amazon Web Services accounts identified by account IDs permissions to read object data and its metadata:

\n

\n x-amz-grant-read: id=\"11112222333\", id=\"444455556666\" \n

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-grant-write-acp" } }, @@ -17645,7 +19452,10 @@ "traits": { "smithy.api#documentation": "

Object key for which the multipart upload is to be initiated.

", "smithy.api#httpLabel": {}, - "smithy.api#required": {} + "smithy.api#required": {}, + "smithy.rules#contextParam": { + "name": "Key" + } } }, "Metadata": { @@ -17658,64 +19468,63 @@ "ServerSideEncryption": { "target": "com.amazonaws.s3#ServerSideEncryption", "traits": { - "smithy.api#documentation": "

The server-side encryption algorithm used when storing this object in Amazon S3 (for example,\n AES256, aws:kms).

", + "smithy.api#documentation": "

The server-side encryption algorithm used when you store this object in Amazon S3 (for example,\n AES256, aws:kms).

\n \n

For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption" } }, "StorageClass": { "target": "com.amazonaws.s3#StorageClass", "traits": { - "smithy.api#documentation": "

By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The\n STANDARD storage class provides high durability and high availability. Depending on\n performance needs, you can specify a different Storage Class. Amazon S3 on Outposts only uses\n the OUTPOSTS Storage Class. For more information, see Storage Classes in the\n Amazon S3 User Guide.

", + "smithy.api#documentation": "

By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The\n STANDARD storage class provides high durability and high availability. Depending on\n performance needs, you can specify a different Storage Class. For more information, see Storage Classes in the\n Amazon S3 User Guide.

\n \n
    \n
  • \n

    For directory buckets, only the S3 Express One Zone storage class is supported to store newly created objects.

    \n
  • \n
  • \n

    Amazon S3 on Outposts only uses\n the OUTPOSTS Storage Class.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-storage-class" } }, "WebsiteRedirectLocation": { "target": "com.amazonaws.s3#WebsiteRedirectLocation", "traits": { - "smithy.api#documentation": "

If the bucket is configured as a website, redirects requests for this object to another\n object in the same bucket or to an external URL. Amazon S3 stores the value of this header in\n the object metadata.

", + "smithy.api#documentation": "

If the bucket is configured as a website, redirects requests for this object to another\n object in the same bucket or to an external URL. Amazon S3 stores the value of this header in\n the object metadata.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-website-redirect-location" } }, "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

Specifies the algorithm to use to when encrypting the object (for example,\n AES256).

", + "smithy.api#documentation": "

Specifies the algorithm to use when encrypting the object (for example,\n AES256).

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKey": { "target": "com.amazonaws.s3#SSECustomerKey", "traits": { - "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header.

", + "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

", + "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the customer-provided encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, "SSEKMSKeyId": { "target": "com.amazonaws.s3#SSEKMSKeyId", "traits": { - "smithy.api#documentation": "

Specifies the ID (Key ID, Key ARN, or Key Alias) of the symmetric encryption customer managed key to use for object encryption.\n All GET and PUT requests for an object protected by KMS will fail if they're not made via\n SSL or using SigV4. For information about configuring any of the officially supported Amazon Web Services\n SDKs and Amazon Web Services CLI, see Specifying the Signature Version in Request Authentication\n in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

Specifies the ID (Key ID, Key ARN, or Key Alias) of the symmetric encryption customer managed key to use for object encryption.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-aws-kms-key-id" } }, "SSEKMSEncryptionContext": { "target": "com.amazonaws.s3#SSEKMSEncryptionContext", "traits": { - "smithy.api#documentation": "

Specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The value of\n this header is a base64-encoded UTF-8 string holding JSON with the encryption context\n key-value pairs.

", + "smithy.api#documentation": "

Specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The value of\n this header is a base64-encoded UTF-8 string holding JSON with the encryption context\n key-value pairs.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-context" } }, "BucketKeyEnabled": { "target": "com.amazonaws.s3#BucketKeyEnabled", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Specifies whether Amazon S3 should use an S3 Bucket Key for object encryption with\n server-side encryption using Key Management Service (KMS) keys (SSE-KMS). Setting this header to\n true causes Amazon S3 to use an S3 Bucket Key for object encryption with\n SSE-KMS.

\n

Specifying this header with an object action doesn’t affect bucket-level settings for S3\n Bucket Key.

", + "smithy.api#documentation": "

Specifies whether Amazon S3 should use an S3 Bucket Key for object encryption with\n server-side encryption using Key Management Service (KMS) keys (SSE-KMS). Setting this header to\n true causes Amazon S3 to use an S3 Bucket Key for object encryption with\n SSE-KMS.

\n

Specifying this header with an object action doesn’t affect bucket-level settings for S3\n Bucket Key.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-bucket-key-enabled" } }, @@ -17728,42 +19537,42 @@ "Tagging": { "target": "com.amazonaws.s3#TaggingHeader", "traits": { - "smithy.api#documentation": "

The tag-set for the object. The tag-set must be encoded as URL Query parameters.

", + "smithy.api#documentation": "

The tag-set for the object. The tag-set must be encoded as URL Query parameters.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-tagging" } }, "ObjectLockMode": { "target": "com.amazonaws.s3#ObjectLockMode", "traits": { - "smithy.api#documentation": "

Specifies the Object Lock mode that you want to apply to the uploaded object.

", + "smithy.api#documentation": "

Specifies the Object Lock mode that you want to apply to the uploaded object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-mode" } }, "ObjectLockRetainUntilDate": { "target": "com.amazonaws.s3#ObjectLockRetainUntilDate", "traits": { - "smithy.api#documentation": "

Specifies the date and time when you want the Object Lock to expire.

", + "smithy.api#documentation": "

Specifies the date and time when you want the Object Lock to expire.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-retain-until-date" } }, "ObjectLockLegalHoldStatus": { "target": "com.amazonaws.s3#ObjectLockLegalHoldStatus", "traits": { - "smithy.api#documentation": "

Specifies whether you want to apply a legal hold to the uploaded object.

", + "smithy.api#documentation": "

Specifies whether you want to apply a legal hold to the uploaded object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-legal-hold" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm you want Amazon S3 to use to create the checksum for the object. For more information, see\n Checking object integrity in\n the Amazon S3 User Guide.

", + "smithy.api#documentation": "

Indicates the algorithm that you want Amazon S3 to use to create the checksum for the object. For more information, see\n Checking object integrity in\n the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-algorithm" } } @@ -17772,9 +19581,89 @@ "smithy.api#input": {} } }, + "com.amazonaws.s3#CreateSession": { + "type": "operation", + "input": { + "target": "com.amazonaws.s3#CreateSessionRequest" + }, + "output": { + "target": "com.amazonaws.s3#CreateSessionOutput" + }, + "errors": [ + { + "target": "com.amazonaws.s3#NoSuchBucket" + } + ], + "traits": { + "smithy.api#documentation": "

Creates a session that establishes temporary security credentials to support fast authentication and authorization for the Zonal endpoint APIs on directory buckets. \n For more information about Zonal endpoint APIs that include the Availability Zone in the request endpoint, see \n S3 Express One Zone APIs in the Amazon S3 User Guide. \n

\n

To make Zonal endpoint API requests on a directory bucket, use the CreateSession\n API operation. Specifically, you grant s3express:CreateSession permission to a\n bucket in a bucket policy or an IAM identity-based policy. Then, you use IAM credentials to make the\n CreateSession API request on the bucket, which returns temporary security\n credentials that include the access key ID, secret access key, session token, and\n expiration. These credentials have associated permissions to access the Zonal endpoint APIs. After\n the session is created, you don’t need to use other policies to grant permissions to each\n Zonal endpoint API individually. Instead, in your Zonal endpoint API requests, you sign your requests by\n applying the temporary security credentials of the session to the request headers and\n following the SigV4 protocol for authentication. You also apply the session token to the\n x-amz-s3session-token request header for authorization. Temporary security\n credentials are scoped to the bucket and expire after 5 minutes. After the expiration time,\n any calls that you make with those credentials will fail. You must use IAM credentials\n again to make a CreateSession API request that generates a new set of\n temporary credentials for use. Temporary credentials cannot be extended or refreshed beyond\n the original specified interval.

\n

If you use Amazon Web Services SDKs, SDKs handle the session token refreshes automatically to avoid\n service interruptions when a session expires. We recommend that you use the Amazon Web Services SDKs to\n initiate and manage requests to the CreateSession API. For more information, see Performance guidelines and design patterns in the\n Amazon S3 User Guide.

\n \n
    \n
  • \n

    You must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

    \n
  • \n
  • \n

    \n \n CopyObject API operation - Unlike other Zonal endpoint APIs, the CopyObject API operation doesn't use the temporary security credentials returned from the CreateSession API operation for authentication and authorization. For information about authentication and authorization of the CopyObject API operation on directory buckets, see CopyObject.

    \n
  • \n
  • \n

    \n \n HeadBucket API operation - Unlike other Zonal endpoint APIs, the HeadBucket API operation doesn't use the temporary security credentials returned from the CreateSession API operation for authentication and authorization. For information about authentication and authorization of the HeadBucket API operation on directory buckets, see HeadBucket.

    \n
  • \n
\n
\n
\n
Permissions
\n
\n

To obtain temporary security credentials, you must create a bucket policy or an IAM identity-based policy that\n grants s3express:CreateSession permission to the bucket. In a\n policy, you can have the s3express:SessionMode condition key to\n control who can create a ReadWrite or ReadOnly session.\n For more information about ReadWrite or ReadOnly\n sessions, see \n x-amz-create-session-mode\n . For example policies, see\n Example bucket policies for S3 Express One Zone and Amazon Web Services Identity and Access Management (IAM) identity-based policies for S3 Express One Zone in the\n Amazon S3 User Guide.

\n

To grant cross-account access to Zonal endpoint APIs, the bucket policy should also grant both accounts the s3express:CreateSession permission.

\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
", + "smithy.api#http": { + "method": "GET", + "uri": "/{Bucket}?session", + "code": 200 + }, + "smithy.rules#staticContextParams": { + "DisableS3ExpressSessionAuth": { + "value": true + } + } + } + }, + "com.amazonaws.s3#CreateSessionOutput": { + "type": "structure", + "members": { + "Credentials": { + "target": "com.amazonaws.s3#SessionCredentials", + "traits": { + "smithy.api#documentation": "

The established temporary security credentials for the created session..

", + "smithy.api#required": {}, + "smithy.api#xmlName": "Credentials" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.s3#CreateSessionRequest": { + "type": "structure", + "members": { + "SessionMode": { + "target": "com.amazonaws.s3#SessionMode", + "traits": { + "smithy.api#documentation": "

Specifies the mode of the session that will be created, either ReadWrite or\n ReadOnly. By default, a ReadWrite session is created. A\n ReadWrite session is capable of executing all the Zonal endpoint APIs on a\n directory bucket. A ReadOnly session is constrained to execute the following\n Zonal endpoint APIs: GetObject, HeadObject, ListObjectsV2,\n GetObjectAttributes, ListParts, and\n ListMultipartUploads.

", + "smithy.api#httpHeader": "x-amz-create-session-mode" + } + }, + "Bucket": { + "target": "com.amazonaws.s3#BucketName", + "traits": { + "smithy.api#documentation": "

The name of the bucket that you create a session for.

", + "smithy.api#httpLabel": {}, + "smithy.api#required": {}, + "smithy.rules#contextParam": { + "name": "Bucket" + } + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, "com.amazonaws.s3#CreationDate": { "type": "timestamp" }, + "com.amazonaws.s3#DataRedundancy": { + "type": "enum", + "members": { + "SingleAvailabilityZone": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "SingleAvailabilityZone" + } + } + } + }, "com.amazonaws.s3#Date": { "type": "timestamp", "traits": { @@ -17782,16 +19671,10 @@ } }, "com.amazonaws.s3#Days": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#DaysAfterInitiation": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#DefaultRetention": { "type": "structure", @@ -17805,14 +19688,12 @@ "Days": { "target": "com.amazonaws.s3#Days", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The number of days that you want to specify for the default retention period. Must be\n used with Mode.

" } }, "Years": { "target": "com.amazonaws.s3#Years", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The number of years that you want to specify for the default retention period. Must be\n used with Mode.

" } } @@ -17827,7 +19708,7 @@ "Objects": { "target": "com.amazonaws.s3#ObjectIdentifierList", "traits": { - "smithy.api#documentation": "

The object to delete.

", + "smithy.api#documentation": "

The object to delete.

\n \n

\n Directory buckets - For directory buckets, an object that's composed entirely of \n whitespace characters is not supported by the DeleteObjects API operation. The request will receive a 400 Bad Request error \n and none of the objects in the request will be deleted.

\n
", "smithy.api#required": {}, "smithy.api#xmlFlattened": {}, "smithy.api#xmlName": "Object" @@ -17836,8 +19717,7 @@ "Quiet": { "target": "com.amazonaws.s3#Quiet", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Element to enable quiet mode for the request. When you add this element, you must set\n its value to true.

" + "smithy.api#documentation": "

Element to enable quiet mode for the request. When you add this element, you must set\n its value to true.

" } } }, @@ -17854,7 +19734,7 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Deletes the S3 bucket. All objects (including all object versions and delete markers) in\n the bucket must be deleted before the bucket itself can be deleted.

\n

The following operations are related to DeleteBucket:

\n ", + "smithy.api#documentation": "

Deletes the S3 bucket. All objects (including all object versions and delete markers) in\n the bucket must be deleted before the bucket itself can be deleted.

\n \n
    \n
  • \n

    \n Directory buckets - If multipart uploads in a directory bucket are in progress, you can't delete the bucket until all the in-progress multipart uploads are aborted or completed.

    \n
  • \n
  • \n

    \n Directory buckets - For directory buckets, you must make requests for this API operation to the Regional endpoint. These endpoints support path-style requests in the format https://s3express-control.region_code.amazonaws.com/bucket-name\n . Virtual-hosted-style requests aren't supported. \nFor more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

    \n
  • \n
\n
\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - You must have the s3:DeleteBucket permission on the specified bucket in a policy.

    \n
  • \n
  • \n

    \n Directory bucket permissions - You must have the s3express:DeleteBucket permission in an IAM identity-based policy instead of a bucket policy. Cross-account access to this API operation isn't supported. This operation can only be performed by the Amazon Web Services account that owns the resource. For more information about directory bucket policies and permissions, see Amazon Web Services Identity and Access Management (IAM) for S3 Express One Zone in the Amazon S3 User Guide.

    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is s3express-control.region.amazonaws.com.

\n
\n
\n

The following operations are related to DeleteBucket:

\n ", "smithy.api#examples": [ { "title": "To delete a bucket", @@ -17868,6 +19748,11 @@ "method": "DELETE", "uri": "/{Bucket}", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -17880,11 +19765,16 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Deletes an analytics configuration for the bucket (specified by the analytics\n configuration ID).

\n

To use this operation, you must have permissions to perform the\n s3:PutAnalyticsConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about the Amazon S3 analytics feature, see Amazon S3 Analytics – Storage Class\n Analysis.

\n

The following operations are related to\n DeleteBucketAnalyticsConfiguration:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Deletes an analytics configuration for the bucket (specified by the analytics\n configuration ID).

\n

To use this operation, you must have permissions to perform the\n s3:PutAnalyticsConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about the Amazon S3 analytics feature, see Amazon S3 Analytics – Storage Class\n Analysis.

\n

The following operations are related to\n DeleteBucketAnalyticsConfiguration:

\n ", "smithy.api#http": { "method": "DELETE", "uri": "/{Bucket}?analytics", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -17913,7 +19803,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -17931,7 +19821,7 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Deletes the cors configuration information set for the bucket.

\n

To use this operation, you must have permission to perform the\n s3:PutBucketCORS action. The bucket owner has this permission by default\n and can grant this permission to others.

\n

For information about cors, see Enabling Cross-Origin Resource Sharing in\n the Amazon S3 User Guide.

\n

\n Related Resources\n

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Deletes the cors configuration information set for the bucket.

\n

To use this operation, you must have permission to perform the\n s3:PutBucketCORS action. The bucket owner has this permission by default\n and can grant this permission to others.

\n

For information about cors, see Enabling Cross-Origin Resource Sharing in\n the Amazon S3 User Guide.

\n

\n Related Resources\n

\n ", "smithy.api#examples": [ { "title": "To delete cors configuration on a bucket.", @@ -17945,6 +19835,11 @@ "method": "DELETE", "uri": "/{Bucket}?cors", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -17965,7 +19860,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -17983,11 +19878,16 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

This implementation of the DELETE action resets the default encryption for the bucket as\n server-side encryption with Amazon S3 managed keys (SSE-S3). For information about the bucket\n default encryption feature, see Amazon S3 Bucket Default Encryption\n in the Amazon S3 User Guide.

\n

To use this operation, you must have permissions to perform the\n s3:PutEncryptionConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to your Amazon S3 Resources in the\n Amazon S3 User Guide.

\n

The following operations are related to DeleteBucketEncryption:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

This implementation of the DELETE action resets the default encryption for the bucket as\n server-side encryption with Amazon S3 managed keys (SSE-S3). For information about the bucket\n default encryption feature, see Amazon S3 Bucket Default Encryption\n in the Amazon S3 User Guide.

\n

To use this operation, you must have permissions to perform the\n s3:PutEncryptionConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to your Amazon S3 Resources in the\n Amazon S3 User Guide.

\n

The following operations are related to DeleteBucketEncryption:

\n ", "smithy.api#http": { "method": "DELETE", "uri": "/{Bucket}?encryption", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -18008,7 +19908,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -18026,11 +19926,16 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Deletes the S3 Intelligent-Tiering configuration from the specified bucket.

\n

The S3 Intelligent-Tiering storage class is designed to optimize storage costs by automatically moving data to the most cost-effective storage access tier, without performance impact or operational overhead. S3 Intelligent-Tiering delivers automatic cost savings in three low latency and high throughput access tiers. To get the lowest storage cost on data that can be accessed in minutes to hours, you can choose to activate additional archiving capabilities.

\n

The S3 Intelligent-Tiering storage class is the ideal storage class for data with unknown, changing, or unpredictable access patterns, independent of object size or retention period. If the size of an object is less than 128 KB, it is not monitored and not eligible for auto-tiering. Smaller objects can be stored, but they are always charged at the Frequent Access tier rates in the S3 Intelligent-Tiering storage class.

\n

For more information, see Storage class for automatically optimizing frequently and infrequently accessed objects.

\n

Operations related to DeleteBucketIntelligentTieringConfiguration include:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Deletes the S3 Intelligent-Tiering configuration from the specified bucket.

\n

The S3 Intelligent-Tiering storage class is designed to optimize storage costs by automatically moving data to the most cost-effective storage access tier, without performance impact or operational overhead. S3 Intelligent-Tiering delivers automatic cost savings in three low latency and high throughput access tiers. To get the lowest storage cost on data that can be accessed in minutes to hours, you can choose to activate additional archiving capabilities.

\n

The S3 Intelligent-Tiering storage class is the ideal storage class for data with unknown, changing, or unpredictable access patterns, independent of object size or retention period. If the size of an object is less than 128 KB, it is not monitored and not eligible for auto-tiering. Smaller objects can be stored, but they are always charged at the Frequent Access tier rates in the S3 Intelligent-Tiering storage class.

\n

For more information, see Storage class for automatically optimizing frequently and infrequently accessed objects.

\n

Operations related to DeleteBucketIntelligentTieringConfiguration include:

\n ", "smithy.api#http": { "method": "DELETE", "uri": "/{Bucket}?intelligent-tiering", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -18070,11 +19975,16 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Deletes an inventory configuration (identified by the inventory ID) from the\n bucket.

\n

To use this operation, you must have permissions to perform the\n s3:PutInventoryConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about the Amazon S3 inventory feature, see Amazon S3 Inventory.

\n

Operations related to DeleteBucketInventoryConfiguration include:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Deletes an inventory configuration (identified by the inventory ID) from the\n bucket.

\n

To use this operation, you must have permissions to perform the\n s3:PutInventoryConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about the Amazon S3 inventory feature, see Amazon S3 Inventory.

\n

Operations related to DeleteBucketInventoryConfiguration include:

\n ", "smithy.api#http": { "method": "DELETE", "uri": "/{Bucket}?inventory", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -18103,7 +20013,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -18121,7 +20031,7 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Deletes the lifecycle configuration from the specified bucket. Amazon S3 removes all the\n lifecycle configuration rules in the lifecycle subresource associated with the bucket. Your\n objects never expire, and Amazon S3 no longer automatically deletes any objects on the basis of\n rules contained in the deleted lifecycle configuration.

\n

To use this operation, you must have permission to perform the\n s3:PutLifecycleConfiguration action. By default, the bucket owner has this\n permission and the bucket owner can grant this permission to others.

\n

There is usually some time lag before lifecycle configuration deletion is fully\n propagated to all the Amazon S3 systems.

\n

For more information about the object expiration, see Elements to Describe Lifecycle Actions.

\n

Related actions include:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Deletes the lifecycle configuration from the specified bucket. Amazon S3 removes all the\n lifecycle configuration rules in the lifecycle subresource associated with the bucket. Your\n objects never expire, and Amazon S3 no longer automatically deletes any objects on the basis of\n rules contained in the deleted lifecycle configuration.

\n

To use this operation, you must have permission to perform the\n s3:PutLifecycleConfiguration action. By default, the bucket owner has this\n permission and the bucket owner can grant this permission to others.

\n

There is usually some time lag before lifecycle configuration deletion is fully\n propagated to all the Amazon S3 systems.

\n

For more information about the object expiration, see Elements to Describe Lifecycle Actions.

\n

Related actions include:

\n ", "smithy.api#examples": [ { "title": "To delete lifecycle configuration on a bucket.", @@ -18135,6 +20045,11 @@ "method": "DELETE", "uri": "/{Bucket}?lifecycle", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -18155,7 +20070,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -18173,11 +20088,16 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Deletes a metrics configuration for the Amazon CloudWatch request metrics (specified by the\n metrics configuration ID) from the bucket. Note that this doesn't include the daily storage\n metrics.

\n

To use this operation, you must have permissions to perform the\n s3:PutMetricsConfiguration action. The bucket owner has this permission by\n default. The bucket owner can grant this permission to others. For more information about\n permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about CloudWatch request metrics for Amazon S3, see Monitoring Metrics with\n Amazon CloudWatch.

\n

The following operations are related to\n DeleteBucketMetricsConfiguration:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Deletes a metrics configuration for the Amazon CloudWatch request metrics (specified by the\n metrics configuration ID) from the bucket. Note that this doesn't include the daily storage\n metrics.

\n

To use this operation, you must have permissions to perform the\n s3:PutMetricsConfiguration action. The bucket owner has this permission by\n default. The bucket owner can grant this permission to others. For more information about\n permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about CloudWatch request metrics for Amazon S3, see Monitoring Metrics with\n Amazon CloudWatch.

\n

The following operations are related to\n DeleteBucketMetricsConfiguration:

\n ", "smithy.api#http": { "method": "DELETE", "uri": "/{Bucket}?metrics", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -18206,7 +20126,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -18224,11 +20144,16 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Removes OwnershipControls for an Amazon S3 bucket. To use this operation, you\n must have the s3:PutBucketOwnershipControls permission. For more information\n about Amazon S3 permissions, see Specifying Permissions in a\n Policy.

\n

For information about Amazon S3 Object Ownership, see Using Object Ownership.

\n

The following operations are related to\n DeleteBucketOwnershipControls:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Removes OwnershipControls for an Amazon S3 bucket. To use this operation, you\n must have the s3:PutBucketOwnershipControls permission. For more information\n about Amazon S3 permissions, see Specifying Permissions in a\n Policy.

\n

For information about Amazon S3 Object Ownership, see Using Object Ownership.

\n

The following operations are related to\n DeleteBucketOwnershipControls:

\n ", "smithy.api#http": { "method": "DELETE", "uri": "/{Bucket}?ownershipControls", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -18249,7 +20174,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -18267,7 +20192,7 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

This implementation of the DELETE action uses the policy subresource to delete the\n policy of a specified bucket. If you are using an identity other than the root user of the\n Amazon Web Services account that owns the bucket, the calling identity must have the\n DeleteBucketPolicy permissions on the specified bucket and belong to the\n bucket owner's account to use this operation.

\n

If you don't have DeleteBucketPolicy permissions, Amazon S3 returns a 403\n Access Denied error. If you have the correct permissions, but you're not using an\n identity that belongs to the bucket owner's account, Amazon S3 returns a 405 Method Not\n Allowed error.

\n \n

To ensure that bucket owners don't inadvertently lock themselves out of their own\n buckets, the root principal in a bucket owner's Amazon Web Services account can perform the\n GetBucketPolicy, PutBucketPolicy, and\n DeleteBucketPolicy API actions, even if their bucket policy explicitly\n denies the root principal's access. Bucket owner root principals can only be blocked\n from performing these API actions by VPC endpoint policies and Amazon Web Services Organizations\n policies.

\n
\n

For more information about bucket policies, see Using Bucket Policies and\n UserPolicies.

\n

The following operations are related to DeleteBucketPolicy\n

\n ", + "smithy.api#documentation": "

Deletes the\n policy of a specified bucket.

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Regional endpoint. These endpoints support path-style requests in the format https://s3express-control.region_code.amazonaws.com/bucket-name\n . Virtual-hosted-style requests aren't supported. \nFor more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n

If you are using an identity other than the\n root user of the Amazon Web Services account that owns the bucket, the calling identity must both have the\n DeleteBucketPolicy permissions on the specified bucket and belong to the\n bucket owner's account in order to use this operation.

\n

If you don't have DeleteBucketPolicy permissions, Amazon S3 returns a 403\n Access Denied error. If you have the correct permissions, but you're not using an\n identity that belongs to the bucket owner's account, Amazon S3 returns a 405 Method Not\n Allowed error.

\n \n

To ensure that bucket owners don't inadvertently lock themselves out of their own\n buckets, the root principal in a bucket owner's Amazon Web Services account can perform the\n GetBucketPolicy, PutBucketPolicy, and\n DeleteBucketPolicy API actions, even if their bucket policy explicitly\n denies the root principal's access. Bucket owner root principals can only be blocked\n from performing these API actions by VPC endpoint policies and Amazon Web Services Organizations\n policies.

\n
\n
    \n
  • \n

    \n General purpose bucket permissions - The s3:DeleteBucketPolicy permission is required in a policy. \n For more information about general purpose buckets bucket policies, see Using Bucket Policies and User\n Policies in the Amazon S3 User Guide.

    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation, you must have the s3express:DeleteBucketPolicy permission in an IAM identity-based policy instead of a bucket policy. Cross-account access to this API operation isn't supported. This operation can only be performed by the Amazon Web Services account that owns the resource. For more information about directory bucket policies and permissions, see Amazon Web Services Identity and Access Management (IAM) for S3 Express One Zone in the Amazon S3 User Guide.

    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is s3express-control.region.amazonaws.com.

\n
\n
\n

The following operations are related to DeleteBucketPolicy\n

\n ", "smithy.api#examples": [ { "title": "To delete bucket policy", @@ -18281,6 +20206,11 @@ "method": "DELETE", "uri": "/{Bucket}?policy", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -18290,7 +20220,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name.

", + "smithy.api#documentation": "

The bucket name.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use path-style requests in the format https://s3express-control.region_code.amazonaws.com/bucket-name\n . Virtual-hosted-style requests aren't supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must also follow the format \n bucket_base_name--az_id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming restrictions, see Directory bucket naming rules in the Amazon S3 User Guide\n

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -18301,7 +20231,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

\n \n

For directory buckets, this header is not supported in this API operation. If you specify this header, the request fails with the HTTP status code \n501 Not Implemented.

\n
", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -18319,7 +20249,7 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Deletes the replication configuration from the bucket.

\n

To use this operation, you must have permissions to perform the\n s3:PutReplicationConfiguration action. The bucket owner has these\n permissions by default and can grant it to others. For more information about permissions,\n see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n \n

It can take a while for the deletion of a replication configuration to fully\n propagate.

\n
\n

For information about replication configuration, see Replication in the\n Amazon S3 User Guide.

\n

The following operations are related to DeleteBucketReplication:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Deletes the replication configuration from the bucket.

\n

To use this operation, you must have permissions to perform the\n s3:PutReplicationConfiguration action. The bucket owner has these\n permissions by default and can grant it to others. For more information about permissions,\n see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n \n

It can take a while for the deletion of a replication configuration to fully\n propagate.

\n
\n

For information about replication configuration, see Replication in the\n Amazon S3 User Guide.

\n

The following operations are related to DeleteBucketReplication:

\n ", "smithy.api#examples": [ { "title": "To delete bucket replication configuration", @@ -18333,6 +20263,11 @@ "method": "DELETE", "uri": "/{Bucket}?replication", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -18353,7 +20288,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -18368,7 +20303,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

Specifies the bucket being deleted.

", + "smithy.api#documentation": "

Specifies the bucket being deleted.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use path-style requests in the format https://s3express-control.region_code.amazonaws.com/bucket-name\n . Virtual-hosted-style requests aren't supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must also follow the format \n bucket_base_name--az_id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming restrictions, see Directory bucket naming rules in the Amazon S3 User Guide\n

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -18379,7 +20314,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

\n \n

For directory buckets, this header is not supported in this API operation. If you specify this header, the request fails with the HTTP status code \n501 Not Implemented.

\n
", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -18397,7 +20332,7 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Deletes the tags from the bucket.

\n

To use this operation, you must have permission to perform the\n s3:PutBucketTagging action. By default, the bucket owner has this\n permission and can grant this permission to others.

\n

The following operations are related to DeleteBucketTagging:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Deletes the tags from the bucket.

\n

To use this operation, you must have permission to perform the\n s3:PutBucketTagging action. By default, the bucket owner has this\n permission and can grant this permission to others.

\n

The following operations are related to DeleteBucketTagging:

\n ", "smithy.api#examples": [ { "title": "To delete bucket tags", @@ -18411,6 +20346,11 @@ "method": "DELETE", "uri": "/{Bucket}?tagging", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -18431,7 +20371,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -18449,7 +20389,7 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

This action removes the website configuration for a bucket. Amazon S3 returns a 200\n OK response upon successfully deleting a website configuration on the specified\n bucket. You will get a 200 OK response if the website configuration you are\n trying to delete does not exist on the bucket. Amazon S3 returns a 404 response if\n the bucket specified in the request does not exist.

\n

This DELETE action requires the S3:DeleteBucketWebsite permission. By\n default, only the bucket owner can delete the website configuration attached to a bucket.\n However, bucket owners can grant other users permission to delete the website configuration\n by writing a bucket policy granting them the S3:DeleteBucketWebsite\n permission.

\n

For more information about hosting websites, see Hosting Websites on Amazon S3.

\n

The following operations are related to DeleteBucketWebsite:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

This action removes the website configuration for a bucket. Amazon S3 returns a 200\n OK response upon successfully deleting a website configuration on the specified\n bucket. You will get a 200 OK response if the website configuration you are\n trying to delete does not exist on the bucket. Amazon S3 returns a 404 response if\n the bucket specified in the request does not exist.

\n

This DELETE action requires the S3:DeleteBucketWebsite permission. By\n default, only the bucket owner can delete the website configuration attached to a bucket.\n However, bucket owners can grant other users permission to delete the website configuration\n by writing a bucket policy granting them the S3:DeleteBucketWebsite\n permission.

\n

For more information about hosting websites, see Hosting Websites on Amazon S3.

\n

The following operations are related to DeleteBucketWebsite:

\n ", "smithy.api#examples": [ { "title": "To delete bucket website configuration", @@ -18463,6 +20403,11 @@ "method": "DELETE", "uri": "/{Bucket}?website", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -18483,7 +20428,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -18493,10 +20438,7 @@ } }, "com.amazonaws.s3#DeleteMarker": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#DeleteMarkerEntry": { "type": "structure", @@ -18522,14 +20464,13 @@ "IsLatest": { "target": "com.amazonaws.s3#IsLatest", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Specifies whether the object is (true) or is not (false) the latest version of an\n object.

" } }, "LastModified": { "target": "com.amazonaws.s3#LastModified", "traits": { - "smithy.api#documentation": "

Date and time the object was last modified.

" + "smithy.api#documentation": "

Date and time when the object was last modified.

" } } }, @@ -18586,15 +20527,16 @@ "target": "com.amazonaws.s3#DeleteObjectOutput" }, "traits": { - "smithy.api#documentation": "

Removes the null version (if there is one) of an object and inserts a delete marker,\n which becomes the latest version of the object. If there isn't a null version, Amazon S3 does\n not remove any objects but will still respond that the command was successful.

\n

To remove a specific version, you must use the version Id subresource. Using this\n subresource permanently deletes the version. If the object deleted is a delete marker, Amazon S3\n sets the response header, x-amz-delete-marker, to true.

\n

If the object you want to delete is in a bucket where the bucket versioning\n configuration is MFA Delete enabled, you must include the x-amz-mfa request\n header in the DELETE versionId request. Requests that include\n x-amz-mfa must use HTTPS.

\n

For more information about MFA Delete, see Using MFA Delete. To see sample\n requests that use versioning, see Sample\n Request.

\n

You can delete objects by explicitly calling DELETE Object or configure its lifecycle\n (PutBucketLifecycle) to enable Amazon S3 to remove them for you. If you want to block\n users or accounts from removing or deleting objects from your bucket, you must deny them\n the s3:DeleteObject, s3:DeleteObjectVersion, and\n s3:PutLifeCycleConfiguration actions.

\n

The following action is related to DeleteObject:

\n ", + "smithy.api#documentation": "

Removes an object from a bucket. The behavior depends on the bucket's versioning state:

\n
    \n
  • \n

    If versioning is enabled, the operation removes the null version (if there is one) of an object and inserts a delete marker,\n which becomes the latest version of the object. If there isn't a null version, Amazon S3 does\n not remove any objects but will still respond that the command was successful.

    \n
  • \n
  • \n

    If versioning is suspended or not enabled, the operation permanently deletes the object.

    \n
  • \n
\n \n
    \n
  • \n

    \n Directory buckets - S3 Versioning isn't enabled and supported for directory buckets. For this API operation, only the null value of the version ID is supported by directory buckets. You can only specify null \n to the versionId query parameter in the request.

    \n
  • \n
  • \n

    \n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

    \n
  • \n
\n
\n

To remove a specific version, you must use the versionId query parameter. Using this\n query parameter permanently deletes the version. If the object deleted is a delete marker, Amazon S3\n sets the response header x-amz-delete-marker to true.

\n

If the object you want to delete is in a bucket where the bucket versioning\n configuration is MFA Delete enabled, you must include the x-amz-mfa request\n header in the DELETE versionId request. Requests that include\n x-amz-mfa must use HTTPS. For more information about MFA Delete, see Using MFA Delete in the Amazon S3\n User Guide. To see sample\n requests that use versioning, see Sample\n Request.

\n \n

\n Directory buckets - MFA delete is not supported by directory buckets.

\n
\n

You can delete objects by explicitly calling DELETE Object or calling \n (PutBucketLifecycle) to enable Amazon S3 to remove them for you. If you want to block\n users or accounts from removing or deleting objects from your bucket, you must deny them\n the s3:DeleteObject, s3:DeleteObjectVersion, and\n s3:PutLifeCycleConfiguration actions.

\n \n

\n Directory buckets - S3 Lifecycle is not supported by directory buckets.

\n
\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - The following permissions are required in your policies when your \n DeleteObjects request includes specific headers.

    \n
      \n
    • \n

      \n \n s3:DeleteObject\n - To delete an object from a bucket, you must always have the s3:DeleteObject permission.

      \n
    • \n
    • \n

      \n \n s3:DeleteObjectVersion\n - To delete a specific version of an object from a versiong-enabled bucket, you must have the s3:DeleteObjectVersion permission.

      \n
    • \n
    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation on a directory bucket, we recommend that you use the \n CreateSession\n API operation for session-based authorization. Specifically, you grant the s3express:CreateSession permission to the directory bucket in a bucket policy or an IAM identity-based policy. Then, you make the CreateSession API call on the bucket to obtain a session token. With the session token in your request header, you can make API requests to this operation. After the session token expires, you make another CreateSession API call to generate a new session token for use. \nAmazon Web Services CLI or SDKs create session and refresh the session token automatically to avoid service interruptions when a session expires. For more information about authorization, see \n CreateSession\n .

    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

The following action is related to DeleteObject:

\n ", "smithy.api#examples": [ { - "title": "To delete an object (from a non-versioned bucket)", - "documentation": "The following example deletes an object from a non-versioned bucket.", + "title": "To delete an object", + "documentation": "The following example deletes an object from an S3 bucket.", "input": { - "Bucket": "ExampleBucket", - "Key": "HappyFace.jpg" - } + "Bucket": "examplebucket", + "Key": "objectkey.jpg" + }, + "output": {} } ], "smithy.api#http": { @@ -18610,15 +20552,14 @@ "DeleteMarker": { "target": "com.amazonaws.s3#DeleteMarker", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Indicates whether the specified object version that was permanently deleted was (true) or was\n not (false) a delete marker before deletion. In a simple DELETE, this header indicates whether (true) or\n not (false) the current version of the object is a delete marker.

", + "smithy.api#documentation": "

Indicates whether the specified object version that was permanently deleted was (true) or was\n not (false) a delete marker before deletion. In a simple DELETE, this header indicates whether (true) or\n not (false) the current version of the object is a delete marker.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-delete-marker" } }, "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

Returns the version ID of the delete marker created as a result of the DELETE\n operation.

", + "smithy.api#documentation": "

Returns the version ID of the delete marker created as a result of the DELETE\n operation.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-version-id" } }, @@ -18639,7 +20580,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name of the bucket containing the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name of the bucket containing the object.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -18652,20 +20593,23 @@ "traits": { "smithy.api#documentation": "

Key name of the object to delete.

", "smithy.api#httpLabel": {}, - "smithy.api#required": {} + "smithy.api#required": {}, + "smithy.rules#contextParam": { + "name": "Key" + } } }, "MFA": { "target": "com.amazonaws.s3#MFA", "traits": { - "smithy.api#documentation": "

The concatenation of the authentication device's serial number, a space, and the value\n that is displayed on your authentication device. Required to permanently delete a versioned\n object if versioning is configured with MFA delete enabled.

", + "smithy.api#documentation": "

The concatenation of the authentication device's serial number, a space, and the value\n that is displayed on your authentication device. Required to permanently delete a versioned\n object if versioning is configured with MFA delete enabled.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-mfa" } }, "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

VersionId used to reference a specific version of the object.

", + "smithy.api#documentation": "

Version ID used to reference a specific version of the object.

\n \n

For directory buckets in this API operation, only the null value of the version ID is supported.

\n
", "smithy.api#httpQuery": "versionId" } }, @@ -18678,15 +20622,14 @@ "BypassGovernanceRetention": { "target": "com.amazonaws.s3#BypassGovernanceRetention", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Indicates whether S3 Object Lock should bypass Governance-mode restrictions to process\n this operation. To use this header, you must have the\n s3:BypassGovernanceRetention permission.

", + "smithy.api#documentation": "

Indicates whether S3 Object Lock should bypass Governance-mode restrictions to process\n this operation. To use this header, you must have the\n s3:BypassGovernanceRetention permission.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-bypass-governance-retention" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -18704,7 +20647,7 @@ "target": "com.amazonaws.s3#DeleteObjectTaggingOutput" }, "traits": { - "smithy.api#documentation": "

Removes the entire tag set from the specified object. For more information about\n managing object tags, see Object Tagging.

\n

To use this operation, you must have permission to perform the\n s3:DeleteObjectTagging action.

\n

To delete tags of a specific object version, add the versionId query\n parameter in the request. You will need permission for the\n s3:DeleteObjectVersionTagging action.

\n

The following operations are related to DeleteObjectTagging:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Removes the entire tag set from the specified object. For more information about\n managing object tags, see Object Tagging.

\n

To use this operation, you must have permission to perform the\n s3:DeleteObjectTagging action.

\n

To delete tags of a specific object version, add the versionId query\n parameter in the request. You will need permission for the\n s3:DeleteObjectVersionTagging action.

\n

The following operations are related to DeleteObjectTagging:

\n ", "smithy.api#examples": [ { "title": "To remove tag set from an object version", @@ -18747,7 +20690,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the objects from which to remove the tags.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the objects from which to remove the tags.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -18773,7 +20716,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -18795,7 +20738,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

This action enables you to delete multiple objects from a bucket using a single HTTP\n request. If you know the object keys that you want to delete, then this action provides a\n suitable alternative to sending individual delete requests, reducing per-request\n overhead.

\n

The request contains a list of up to 1000 keys that you want to delete. In the XML, you\n provide the object key names, and optionally, version IDs if you want to delete a specific\n version of the object from a versioning-enabled bucket. For each key, Amazon S3 performs a\n delete action and returns the result of that delete, success, or failure, in the response.\n Note that if the object specified in the request is not found, Amazon S3 returns the result as\n deleted.

\n

The action supports two modes for the response: verbose and quiet. By default, the\n action uses verbose mode in which the response includes the result of deletion of each key\n in your request. In quiet mode the response includes only keys where the delete action\n encountered an error. For a successful deletion, the action does not return any information\n about the delete in the response body.

\n

When performing this action on an MFA Delete enabled bucket, that attempts to delete any\n versioned objects, you must include an MFA token. If you do not provide one, the entire\n request will fail, even if there are non-versioned objects you are trying to delete. If you\n provide an invalid token, whether there are versioned keys in the request or not, the\n entire Multi-Object Delete request will fail. For information about MFA Delete, see MFA\n Delete.

\n

Finally, the Content-MD5 header is required for all Multi-Object Delete requests. Amazon S3\n uses the header value to ensure that your request body has not been altered in\n transit.

\n

The following operations are related to DeleteObjects:

\n ", + "smithy.api#documentation": "

This operation enables you to delete multiple objects from a bucket using a single HTTP\n request. If you know the object keys that you want to delete, then this operation provides a\n suitable alternative to sending individual delete requests, reducing per-request\n overhead.

\n

The request can contain a list of up to 1000 keys that you want to delete. In the XML, you\n provide the object key names, and optionally, version IDs if you want to delete a specific\n version of the object from a versioning-enabled bucket. For each key, Amazon S3 performs a\n delete operation and returns the result of that delete, success or failure, in the response.\n Note that if the object specified in the request is not found, Amazon S3 returns the result as\n deleted.

\n \n
    \n
  • \n

    \n Directory buckets - S3 Versioning isn't enabled and supported for directory buckets.

    \n
  • \n
  • \n

    \n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

    \n
  • \n
\n
\n

The operation supports two modes for the response: verbose and quiet. By default, the\n operation uses verbose mode in which the response includes the result of deletion of each key\n in your request. In quiet mode the response includes only keys where the delete operation \n encountered an error. For a successful deletion in a quiet mode, the operation does not return any information\n about the delete in the response body.

\n

When performing this action on an MFA Delete enabled bucket, that attempts to delete any\n versioned objects, you must include an MFA token. If you do not provide one, the entire\n request will fail, even if there are non-versioned objects you are trying to delete. If you\n provide an invalid token, whether there are versioned keys in the request or not, the\n entire Multi-Object Delete request will fail. For information about MFA Delete, see MFA\n Delete in the Amazon S3\n User Guide.

\n \n

\n Directory buckets - MFA delete is not supported by directory buckets.

\n
\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - The following permissions are required in your policies when your \n DeleteObjects request includes specific headers.

    \n
      \n
    • \n

      \n \n s3:DeleteObject\n - To delete an object from a bucket, you must always specify the s3:DeleteObject permission.

      \n
    • \n
    • \n

      \n \n s3:DeleteObjectVersion\n - To delete a specific version of an object from a versiong-enabled bucket, you must specify the s3:DeleteObjectVersion permission.

      \n
    • \n
    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation on a directory bucket, we recommend that you use the \n CreateSession\n API operation for session-based authorization. Specifically, you grant the s3express:CreateSession permission to the directory bucket in a bucket policy or an IAM identity-based policy. Then, you make the CreateSession API call on the bucket to obtain a session token. With the session token in your request header, you can make API requests to this operation. After the session token expires, you make another CreateSession API call to generate a new session token for use. \nAmazon Web Services CLI or SDKs create session and refresh the session token automatically to avoid service interruptions when a session expires. For more information about authorization, see \n CreateSession\n .

    \n
  • \n
\n
\n
Content-MD5 request header
\n
\n
    \n
  • \n

    \n General purpose bucket - The Content-MD5 request header is required for all Multi-Object Delete requests. Amazon S3\n uses the header value to ensure that your request body has not been altered in\n transit.

    \n
  • \n
  • \n

    \n Directory bucket - The Content-MD5 request header or a additional checksum request header \n (including x-amz-checksum-crc32, x-amz-checksum-crc32c, x-amz-checksum-sha1, or \n x-amz-checksum-sha256) is required for all Multi-Object Delete requests.

    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

The following operations are related to DeleteObjects:

\n ", "smithy.api#examples": [ { "title": "To delete multiple object versions from a versioned bucket", @@ -18873,7 +20816,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the objects to delete.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the objects to delete.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -18893,7 +20836,7 @@ "MFA": { "target": "com.amazonaws.s3#MFA", "traits": { - "smithy.api#documentation": "

The concatenation of the authentication device's serial number, a space, and the value\n that is displayed on your authentication device. Required to permanently delete a versioned\n object if versioning is configured with MFA delete enabled.

", + "smithy.api#documentation": "

The concatenation of the authentication device's serial number, a space, and the value\n that is displayed on your authentication device. Required to permanently delete a versioned\n object if versioning is configured with MFA delete enabled.

\n

When performing the DeleteObjects operation on an MFA delete enabled bucket, which attempts to delete the specified \n versioned objects, you must include an MFA token. If you don't provide an MFA token, the entire\n request will fail, even if there are non-versioned objects that you are trying to delete. If you\n provide an invalid token, whether there are versioned object keys in the request or not, the\n entire Multi-Object Delete request will fail. For information about MFA Delete, see MFA\n Delete in the Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-mfa" } }, @@ -18906,22 +20849,21 @@ "BypassGovernanceRetention": { "target": "com.amazonaws.s3#BypassGovernanceRetention", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Specifies whether you want to delete this object even if it has a Governance-type Object\n Lock in place. To use this header, you must have the\n s3:BypassGovernanceRetention permission.

", + "smithy.api#documentation": "

Specifies whether you want to delete this object even if it has a Governance-type Object\n Lock in place. To use this header, you must have the\n s3:BypassGovernanceRetention permission.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-bypass-governance-retention" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

\n

This checksum algorithm must be the same for all parts and it match the checksum value\n supplied in the CreateMultipartUpload request.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum-algorithm\n or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request.

\n

For the x-amz-checksum-algorithm\n header, replace \n algorithm\n with the supported algorithm from the following list:

\n
    \n
  • \n

    CRC32

    \n
  • \n
  • \n

    CRC32C

    \n
  • \n
  • \n

    SHA1

    \n
  • \n
  • \n

    SHA256

    \n
  • \n
\n

For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If the individual checksum value you provide through x-amz-checksum-algorithm\n doesn't match the checksum algorithm you set through x-amz-sdk-checksum-algorithm, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter and uses the checksum algorithm that matches the provided value in x-amz-checksum-algorithm\n .

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } } @@ -18939,11 +20881,16 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Removes the PublicAccessBlock configuration for an Amazon S3 bucket. To use this\n operation, you must have the s3:PutBucketPublicAccessBlock permission. For\n more information about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

The following operations are related to DeletePublicAccessBlock:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Removes the PublicAccessBlock configuration for an Amazon S3 bucket. To use this\n operation, you must have the s3:PutBucketPublicAccessBlock permission. For\n more information about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

The following operations are related to DeletePublicAccessBlock:

\n ", "smithy.api#http": { "method": "DELETE", "uri": "/{Bucket}?publicAccessBlock", "code": 204 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -18964,7 +20911,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -18985,20 +20932,19 @@ "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

The version ID of the deleted object.

" + "smithy.api#documentation": "

The version ID of the deleted object.

\n \n

This functionality is not supported for directory buckets.

\n
" } }, "DeleteMarker": { "target": "com.amazonaws.s3#DeleteMarker", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Indicates whether the specified object version that was permanently deleted was (true) or was\n not (false) a delete marker before deletion. In a simple DELETE, this header indicates whether (true) or\n not (false) the current version of the object is a delete marker.

" + "smithy.api#documentation": "

Indicates whether the specified object version that was permanently deleted was (true) or was\n not (false) a delete marker before deletion. In a simple DELETE, this header indicates whether (true) or\n not (false) the current version of the object is a delete marker.

\n \n

This functionality is not supported for directory buckets.

\n
" } }, "DeleteMarkerVersionId": { "target": "com.amazonaws.s3#DeleteMarkerVersionId", "traits": { - "smithy.api#documentation": "

The version ID of the delete marker created as a result of the DELETE operation. If you\n delete a specific object version, the value returned by this header is the version ID of\n the object version deleted.

" + "smithy.api#documentation": "

The version ID of the delete marker created as a result of the DELETE operation. If you\n delete a specific object version, the value returned by this header is the version ID of\n the object version deleted.

\n \n

This functionality is not supported for directory buckets.

\n
" } } }, @@ -19069,6 +21015,15 @@ "smithy.api#documentation": "

Specifies information about where to publish analysis or configuration results for an\n Amazon S3 bucket and S3 Replication Time Control (S3 RTC).

" } }, + "com.amazonaws.s3#DirectoryBucketToken": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 0, + "max": 1024 + } + } + }, "com.amazonaws.s3#DisplayName": { "type": "string" }, @@ -19079,10 +21034,7 @@ "type": "string" }, "com.amazonaws.s3#EnableRequestProgress": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#EncodingType": { "type": "enum", @@ -19140,10 +21092,7 @@ } }, "com.amazonaws.s3#End": { - "type": "long", - "traits": { - "smithy.api#default": 0 - } + "type": "long" }, "com.amazonaws.s3#EndEvent": { "type": "structure", @@ -19164,7 +21113,7 @@ "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

The version ID of the error.

" + "smithy.api#documentation": "

The version ID of the error.

\n \n

This functionality is not supported for directory buckets.

\n
" } }, "Code": { @@ -19447,10 +21396,7 @@ } }, "com.amazonaws.s3#ExpiredObjectDeleteMarker": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#Expires": { "type": "timestamp" @@ -19479,10 +21425,7 @@ } }, "com.amazonaws.s3#FetchOwner": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#FieldDelimiter": { "type": "string" @@ -19568,11 +21511,16 @@ "target": "com.amazonaws.s3#GetBucketAccelerateConfigurationOutput" }, "traits": { - "smithy.api#documentation": "

This implementation of the GET action uses the accelerate subresource to\n return the Transfer Acceleration state of a bucket, which is either Enabled or\n Suspended. Amazon S3 Transfer Acceleration is a bucket-level feature that\n enables you to perform faster data transfers to and from Amazon S3.

\n

To use this operation, you must have permission to perform the\n s3:GetAccelerateConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to your Amazon S3 Resources in the\n Amazon S3 User Guide.

\n

You set the Transfer Acceleration state of an existing bucket to Enabled or\n Suspended by using the PutBucketAccelerateConfiguration operation.

\n

A GET accelerate request does not return a state value for a bucket that\n has no transfer acceleration state. A bucket has no Transfer Acceleration state if a state\n has never been set on the bucket.

\n

For more information about transfer acceleration, see Transfer Acceleration in\n the Amazon S3 User Guide.

\n

The following operations are related to\n GetBucketAccelerateConfiguration:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

This implementation of the GET action uses the accelerate subresource to\n return the Transfer Acceleration state of a bucket, which is either Enabled or\n Suspended. Amazon S3 Transfer Acceleration is a bucket-level feature that\n enables you to perform faster data transfers to and from Amazon S3.

\n

To use this operation, you must have permission to perform the\n s3:GetAccelerateConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to your Amazon S3 Resources in the\n Amazon S3 User Guide.

\n

You set the Transfer Acceleration state of an existing bucket to Enabled or\n Suspended by using the PutBucketAccelerateConfiguration operation.

\n

A GET accelerate request does not return a state value for a bucket that\n has no transfer acceleration state. A bucket has no Transfer Acceleration state if a state\n has never been set on the bucket.

\n

For more information about transfer acceleration, see Transfer Acceleration in\n the Amazon S3 User Guide.

\n

The following operations are related to\n GetBucketAccelerateConfiguration:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?accelerate", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -19614,7 +21562,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -19638,11 +21586,16 @@ "target": "com.amazonaws.s3#GetBucketAclOutput" }, "traits": { - "smithy.api#documentation": "

This implementation of the GET action uses the acl subresource\n to return the access control list (ACL) of a bucket. To use GET to return the\n ACL of the bucket, you must have READ_ACP access to the bucket. If\n READ_ACP permission is granted to the anonymous user, you can return the\n ACL of the bucket without using an authorization header.

\n

To use this API operation against an access point, provide the alias of the access point in place of the bucket name.

\n

To use this API operation against an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

\n \n

If your bucket uses the bucket owner enforced setting for S3 Object Ownership,\n requests to read ACLs are still supported and return the\n bucket-owner-full-control ACL with the owner being the account that\n created the bucket. For more information, see Controlling object\n ownership and disabling ACLs in the\n Amazon S3 User Guide.

\n
\n

The following operations are related to GetBucketAcl:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

This implementation of the GET action uses the acl subresource\n to return the access control list (ACL) of a bucket. To use GET to return the\n ACL of the bucket, you must have the READ_ACP access to the bucket. If\n READ_ACP permission is granted to the anonymous user, you can return the\n ACL of the bucket without using an authorization header.

\n

When you use this API operation with an access point, provide the alias of the access point in place of the bucket name.

\n

When you use this API operation with an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

\n \n

If your bucket uses the bucket owner enforced setting for S3 Object Ownership,\n requests to read ACLs are still supported and return the\n bucket-owner-full-control ACL with the owner being the account that\n created the bucket. For more information, see Controlling object\n ownership and disabling ACLs in the\n Amazon S3 User Guide.

\n
\n

The following operations are related to GetBucketAcl:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?acl", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -19674,7 +21627,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

Specifies the S3 bucket whose ACL is being requested.

\n

To use this API operation against an access point, provide the alias of the access point in place of the bucket name.

\n

To use this API operation against an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

", + "smithy.api#documentation": "

Specifies the S3 bucket whose ACL is being requested.

\n

When you use this API operation with an access point, provide the alias of the access point in place of the bucket name.

\n

When you use this API operation with an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -19685,7 +21638,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -19703,11 +21656,16 @@ "target": "com.amazonaws.s3#GetBucketAnalyticsConfigurationOutput" }, "traits": { - "smithy.api#documentation": "

This implementation of the GET action returns an analytics configuration (identified by\n the analytics configuration ID) from the bucket.

\n

To use this operation, you must have permissions to perform the\n s3:GetAnalyticsConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources in the\n Amazon S3 User Guide.

\n

For information about Amazon S3 analytics feature, see Amazon S3 Analytics – Storage Class\n Analysis in the Amazon S3 User Guide.

\n

The following operations are related to\n GetBucketAnalyticsConfiguration:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

This implementation of the GET action returns an analytics configuration (identified by\n the analytics configuration ID) from the bucket.

\n

To use this operation, you must have permissions to perform the\n s3:GetAnalyticsConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources in the\n Amazon S3 User Guide.

\n

For information about Amazon S3 analytics feature, see Amazon S3 Analytics – Storage Class\n Analysis in the Amazon S3 User Guide.

\n

The following operations are related to\n GetBucketAnalyticsConfiguration:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?analytics&x-id=GetBucketAnalyticsConfiguration", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -19751,7 +21709,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -19769,7 +21727,7 @@ "target": "com.amazonaws.s3#GetBucketCorsOutput" }, "traits": { - "smithy.api#documentation": "

Returns the Cross-Origin Resource Sharing (CORS) configuration information set for the\n bucket.

\n

To use this operation, you must have permission to perform the\n s3:GetBucketCORS action. By default, the bucket owner has this permission\n and can grant it to others.

\n

To use this API operation against an access point, provide the alias of the access point in place of the bucket name.

\n

To use this API operation against an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

\n

For more information about CORS, see Enabling Cross-Origin Resource\n Sharing.

\n

The following operations are related to GetBucketCors:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns the Cross-Origin Resource Sharing (CORS) configuration information set for the\n bucket.

\n

To use this operation, you must have permission to perform the\n s3:GetBucketCORS action. By default, the bucket owner has this permission\n and can grant it to others.

\n

When you use this API operation with an access point, provide the alias of the access point in place of the bucket name.

\n

When you use this API operation with an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

\n

For more information about CORS, see Enabling Cross-Origin Resource\n Sharing.

\n

The following operations are related to GetBucketCors:

\n ", "smithy.api#examples": [ { "title": "To get cors configuration set on a bucket", @@ -19799,6 +21757,11 @@ "method": "GET", "uri": "/{Bucket}?cors", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -19825,7 +21788,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name for which to get the cors configuration.

\n

To use this API operation against an access point, provide the alias of the access point in place of the bucket name.

\n

To use this API operation against an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

", + "smithy.api#documentation": "

The bucket name for which to get the cors configuration.

\n

When you use this API operation with an access point, provide the alias of the access point in place of the bucket name.

\n

When you use this API operation with an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -19836,7 +21799,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -19854,11 +21817,16 @@ "target": "com.amazonaws.s3#GetBucketEncryptionOutput" }, "traits": { - "smithy.api#documentation": "

Returns the default encryption configuration for an Amazon S3 bucket. By default, all buckets\n have a default encryption configuration that uses server-side encryption with Amazon S3 managed\n keys (SSE-S3). For information about the bucket default encryption feature, see Amazon S3 Bucket\n Default Encryption in the Amazon S3 User Guide.

\n

To use this operation, you must have permission to perform the\n s3:GetEncryptionConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

The following operations are related to GetBucketEncryption:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns the default encryption configuration for an Amazon S3 bucket. By default, all buckets\n have a default encryption configuration that uses server-side encryption with Amazon S3 managed\n keys (SSE-S3). For information about the bucket default encryption feature, see Amazon S3 Bucket\n Default Encryption in the Amazon S3 User Guide.

\n

To use this operation, you must have permission to perform the\n s3:GetEncryptionConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

The following operations are related to GetBucketEncryption:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?encryption", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -19893,7 +21861,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -19911,11 +21879,16 @@ "target": "com.amazonaws.s3#GetBucketIntelligentTieringConfigurationOutput" }, "traits": { - "smithy.api#documentation": "

Gets the S3 Intelligent-Tiering configuration from the specified bucket.

\n

The S3 Intelligent-Tiering storage class is designed to optimize storage costs by automatically moving data to the most cost-effective storage access tier, without performance impact or operational overhead. S3 Intelligent-Tiering delivers automatic cost savings in three low latency and high throughput access tiers. To get the lowest storage cost on data that can be accessed in minutes to hours, you can choose to activate additional archiving capabilities.

\n

The S3 Intelligent-Tiering storage class is the ideal storage class for data with unknown, changing, or unpredictable access patterns, independent of object size or retention period. If the size of an object is less than 128 KB, it is not monitored and not eligible for auto-tiering. Smaller objects can be stored, but they are always charged at the Frequent Access tier rates in the S3 Intelligent-Tiering storage class.

\n

For more information, see Storage class for automatically optimizing frequently and infrequently accessed objects.

\n

Operations related to GetBucketIntelligentTieringConfiguration include:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Gets the S3 Intelligent-Tiering configuration from the specified bucket.

\n

The S3 Intelligent-Tiering storage class is designed to optimize storage costs by automatically moving data to the most cost-effective storage access tier, without performance impact or operational overhead. S3 Intelligent-Tiering delivers automatic cost savings in three low latency and high throughput access tiers. To get the lowest storage cost on data that can be accessed in minutes to hours, you can choose to activate additional archiving capabilities.

\n

The S3 Intelligent-Tiering storage class is the ideal storage class for data with unknown, changing, or unpredictable access patterns, independent of object size or retention period. If the size of an object is less than 128 KB, it is not monitored and not eligible for auto-tiering. Smaller objects can be stored, but they are always charged at the Frequent Access tier rates in the S3 Intelligent-Tiering storage class.

\n

For more information, see Storage class for automatically optimizing frequently and infrequently accessed objects.

\n

Operations related to GetBucketIntelligentTieringConfiguration include:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?intelligent-tiering&x-id=GetBucketIntelligentTieringConfiguration", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -19970,11 +21943,16 @@ "target": "com.amazonaws.s3#GetBucketInventoryConfigurationOutput" }, "traits": { - "smithy.api#documentation": "

Returns an inventory configuration (identified by the inventory configuration ID) from\n the bucket.

\n

To use this operation, you must have permissions to perform the\n s3:GetInventoryConfiguration action. The bucket owner has this permission\n by default and can grant this permission to others. For more information about permissions,\n see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about the Amazon S3 inventory feature, see Amazon S3 Inventory.

\n

The following operations are related to\n GetBucketInventoryConfiguration:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns an inventory configuration (identified by the inventory configuration ID) from\n the bucket.

\n

To use this operation, you must have permissions to perform the\n s3:GetInventoryConfiguration action. The bucket owner has this permission\n by default and can grant this permission to others. For more information about permissions,\n see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about the Amazon S3 inventory feature, see Amazon S3 Inventory.

\n

The following operations are related to\n GetBucketInventoryConfiguration:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?inventory&x-id=GetBucketInventoryConfiguration", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20018,7 +21996,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20036,7 +22014,7 @@ "target": "com.amazonaws.s3#GetBucketLifecycleConfigurationOutput" }, "traits": { - "smithy.api#documentation": "\n

Bucket lifecycle configuration now supports specifying a lifecycle rule using an\n object key name prefix, one or more object tags, or a combination of both. Accordingly,\n this section describes the latest API. The response describes the new filter element\n that you can use to specify a filter to select a subset of objects to which the rule\n applies. If you are using a previous version of the lifecycle configuration, it still\n works. For the earlier action, see GetBucketLifecycle.

\n
\n

Returns the lifecycle configuration information set on the bucket. For information about\n lifecycle configuration, see Object Lifecycle\n Management.

\n

To use this operation, you must have permission to perform the\n s3:GetLifecycleConfiguration action. The bucket owner has this permission,\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

\n GetBucketLifecycleConfiguration has the following special error:

\n
    \n
  • \n

    Error code: NoSuchLifecycleConfiguration\n

    \n
      \n
    • \n

      Description: The lifecycle configuration does not exist.

      \n
    • \n
    • \n

      HTTP Status Code: 404 Not Found

      \n
    • \n
    • \n

      SOAP Fault Code Prefix: Client

      \n
    • \n
    \n
  • \n
\n

The following operations are related to\n GetBucketLifecycleConfiguration:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n \n

Bucket lifecycle configuration now supports specifying a lifecycle rule using an\n object key name prefix, one or more object tags, or a combination of both. Accordingly,\n this section describes the latest API. The response describes the new filter element\n that you can use to specify a filter to select a subset of objects to which the rule\n applies. If you are using a previous version of the lifecycle configuration, it still\n works. For the earlier action, see GetBucketLifecycle.

\n
\n

Returns the lifecycle configuration information set on the bucket. For information about\n lifecycle configuration, see Object Lifecycle\n Management.

\n

To use this operation, you must have permission to perform the\n s3:GetLifecycleConfiguration action. The bucket owner has this permission,\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

\n GetBucketLifecycleConfiguration has the following special error:

\n
    \n
  • \n

    Error code: NoSuchLifecycleConfiguration\n

    \n
      \n
    • \n

      Description: The lifecycle configuration does not exist.

      \n
    • \n
    • \n

      HTTP Status Code: 404 Not Found

      \n
    • \n
    • \n

      SOAP Fault Code Prefix: Client

      \n
    • \n
    \n
  • \n
\n

The following operations are related to\n GetBucketLifecycleConfiguration:

\n ", "smithy.api#examples": [ { "title": "To get lifecycle configuration on a bucket", @@ -20065,6 +22043,11 @@ "method": "GET", "uri": "/{Bucket}?lifecycle", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20102,7 +22085,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20121,7 +22104,7 @@ }, "traits": { "aws.customizations#s3UnwrappedXmlOutput": {}, - "smithy.api#documentation": "

Returns the Region the bucket resides in. You set the bucket's Region using the\n LocationConstraint request parameter in a CreateBucket\n request. For more information, see CreateBucket.

\n

To use this API operation against an access point, provide the alias of the access point in place of the bucket name.

\n

To use this API operation against an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

\n \n

We recommend that you use HeadBucket to return the Region\n that a bucket resides in. For backward compatibility, Amazon S3 continues to support\n GetBucketLocation.

\n
\n

The following operations are related to GetBucketLocation:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns the Region the bucket resides in. You set the bucket's Region using the\n LocationConstraint request parameter in a CreateBucket\n request. For more information, see CreateBucket.

\n

When you use this API operation with an access point, provide the alias of the access point in place of the bucket name.

\n

When you use this API operation with an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

\n \n

We recommend that you use HeadBucket to return the Region\n that a bucket resides in. For backward compatibility, Amazon S3 continues to support\n GetBucketLocation.

\n
\n

The following operations are related to GetBucketLocation:

\n ", "smithy.api#examples": [ { "title": "To get bucket location", @@ -20138,6 +22121,11 @@ "method": "GET", "uri": "/{Bucket}?location", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20162,7 +22150,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket for which to get the location.

\n

To use this API operation against an access point, provide the alias of the access point in place of the bucket name.

\n

To use this API operation against an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

", + "smithy.api#documentation": "

The name of the bucket for which to get the location.

\n

When you use this API operation with an access point, provide the alias of the access point in place of the bucket name.

\n

When you use this API operation with an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -20173,7 +22161,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20191,11 +22179,16 @@ "target": "com.amazonaws.s3#GetBucketLoggingOutput" }, "traits": { - "smithy.api#documentation": "

Returns the logging status of a bucket and the permissions users have to view and modify\n that status.

\n

The following operations are related to GetBucketLogging:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns the logging status of a bucket and the permissions users have to view and modify\n that status.

\n

The following operations are related to GetBucketLogging:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?logging", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20228,7 +22221,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20246,11 +22239,16 @@ "target": "com.amazonaws.s3#GetBucketMetricsConfigurationOutput" }, "traits": { - "smithy.api#documentation": "

Gets a metrics configuration (specified by the metrics configuration ID) from the\n bucket. Note that this doesn't include the daily storage metrics.

\n

To use this operation, you must have permissions to perform the\n s3:GetMetricsConfiguration action. The bucket owner has this permission by\n default. The bucket owner can grant this permission to others. For more information about\n permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about CloudWatch request metrics for Amazon S3, see Monitoring\n Metrics with Amazon CloudWatch.

\n

The following operations are related to\n GetBucketMetricsConfiguration:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Gets a metrics configuration (specified by the metrics configuration ID) from the\n bucket. Note that this doesn't include the daily storage metrics.

\n

To use this operation, you must have permissions to perform the\n s3:GetMetricsConfiguration action. The bucket owner has this permission by\n default. The bucket owner can grant this permission to others. For more information about\n permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about CloudWatch request metrics for Amazon S3, see Monitoring\n Metrics with Amazon CloudWatch.

\n

The following operations are related to\n GetBucketMetricsConfiguration:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?metrics&x-id=GetBucketMetricsConfiguration", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20294,7 +22292,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20312,11 +22310,16 @@ "target": "com.amazonaws.s3#NotificationConfiguration" }, "traits": { - "smithy.api#documentation": "

Returns the notification configuration of a bucket.

\n

If notifications are not enabled on the bucket, the action returns an empty\n NotificationConfiguration element.

\n

By default, you must be the bucket owner to read the notification configuration of a\n bucket. However, the bucket owner can use a bucket policy to grant permission to other\n users to read this configuration with the s3:GetBucketNotification\n permission.

\n

To use this API operation against an access point, provide the alias of the access point in place of the bucket name.

\n

To use this API operation against an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

\n

For more information about setting and reading the notification configuration on a\n bucket, see Setting Up Notification of Bucket Events. For more information about bucket\n policies, see Using Bucket Policies.

\n

The following action is related to GetBucketNotification:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns the notification configuration of a bucket.

\n

If notifications are not enabled on the bucket, the action returns an empty\n NotificationConfiguration element.

\n

By default, you must be the bucket owner to read the notification configuration of a\n bucket. However, the bucket owner can use a bucket policy to grant permission to other\n users to read this configuration with the s3:GetBucketNotification\n permission.

\n

When you use this API operation with an access point, provide the alias of the access point in place of the bucket name.

\n

When you use this API operation with an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

\n

For more information about setting and reading the notification configuration on a\n bucket, see Setting Up Notification of Bucket Events. For more information about bucket\n policies, see Using Bucket Policies.

\n

The following action is related to GetBucketNotification:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?notification", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20326,7 +22329,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket for which to get the notification configuration.

\n

To use this API operation against an access point, provide the alias of the access point in place of the bucket name.

\n

To use this API operation against an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

", + "smithy.api#documentation": "

The name of the bucket for which to get the notification configuration.

\n

When you use this API operation with an access point, provide the alias of the access point in place of the bucket name.

\n

When you use this API operation with an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -20337,7 +22340,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20355,11 +22358,16 @@ "target": "com.amazonaws.s3#GetBucketOwnershipControlsOutput" }, "traits": { - "smithy.api#documentation": "

Retrieves OwnershipControls for an Amazon S3 bucket. To use this operation, you\n must have the s3:GetBucketOwnershipControls permission. For more information\n about Amazon S3 permissions, see Specifying permissions in a\n policy.

\n

For information about Amazon S3 Object Ownership, see Using Object\n Ownership.

\n

The following operations are related to GetBucketOwnershipControls:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Retrieves OwnershipControls for an Amazon S3 bucket. To use this operation, you\n must have the s3:GetBucketOwnershipControls permission. For more information\n about Amazon S3 permissions, see Specifying permissions in a\n policy.

\n

For information about Amazon S3 Object Ownership, see Using Object\n Ownership.

\n

The following operations are related to GetBucketOwnershipControls:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?ownershipControls", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20395,7 +22403,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20413,7 +22421,7 @@ "target": "com.amazonaws.s3#GetBucketPolicyOutput" }, "traits": { - "smithy.api#documentation": "

Returns the policy of a specified bucket. If you are using an identity other than the\n root user of the Amazon Web Services account that owns the bucket, the calling identity must have the\n GetBucketPolicy permissions on the specified bucket and belong to the\n bucket owner's account in order to use this operation.

\n

If you don't have GetBucketPolicy permissions, Amazon S3 returns a 403\n Access Denied error. If you have the correct permissions, but you're not using an\n identity that belongs to the bucket owner's account, Amazon S3 returns a 405 Method Not\n Allowed error.

\n \n

To ensure that bucket owners don't inadvertently lock themselves out of their own\n buckets, the root principal in a bucket owner's Amazon Web Services account can perform the\n GetBucketPolicy, PutBucketPolicy, and\n DeleteBucketPolicy API actions, even if their bucket policy explicitly\n denies the root principal's access. Bucket owner root principals can only be blocked\n from performing these API actions by VPC endpoint policies and Amazon Web Services Organizations\n policies.

\n
\n

To use this API operation against an access point, provide the alias of the access point in place of the bucket name.

\n

To use this API operation against an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

\n

For more information about bucket policies, see Using Bucket Policies and User\n Policies.

\n

The following action is related to GetBucketPolicy:

\n ", + "smithy.api#documentation": "

Returns the policy of a specified bucket.

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Regional endpoint. These endpoints support path-style requests in the format https://s3express-control.region_code.amazonaws.com/bucket-name\n . Virtual-hosted-style requests aren't supported. \nFor more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n

If you are using an identity other than the\n root user of the Amazon Web Services account that owns the bucket, the calling identity must both have the\n GetBucketPolicy permissions on the specified bucket and belong to the\n bucket owner's account in order to use this operation.

\n

If you don't have GetBucketPolicy permissions, Amazon S3 returns a 403\n Access Denied error. If you have the correct permissions, but you're not using an\n identity that belongs to the bucket owner's account, Amazon S3 returns a 405 Method Not\n Allowed error.

\n \n

To ensure that bucket owners don't inadvertently lock themselves out of their own\n buckets, the root principal in a bucket owner's Amazon Web Services account can perform the\n GetBucketPolicy, PutBucketPolicy, and\n DeleteBucketPolicy API actions, even if their bucket policy explicitly\n denies the root principal's access. Bucket owner root principals can only be blocked\n from performing these API actions by VPC endpoint policies and Amazon Web Services Organizations\n policies.

\n
\n
    \n
  • \n

    \n General purpose bucket permissions - The s3:GetBucketPolicy permission is required in a policy. \n For more information about general purpose buckets bucket policies, see Using Bucket Policies and User\n Policies in the Amazon S3 User Guide.

    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation, you must have the s3express:GetBucketPolicy permission in an IAM identity-based policy instead of a bucket policy. Cross-account access to this API operation isn't supported. This operation can only be performed by the Amazon Web Services account that owns the resource. For more information about directory bucket policies and permissions, see Amazon Web Services Identity and Access Management (IAM) for S3 Express One Zone in the Amazon S3 User Guide.

    \n
  • \n
\n
\n
Example bucket policies
\n
\n

\n General purpose buckets example bucket policies - See Bucket policy examples in the Amazon S3 User Guide.

\n

\n Directory bucket example bucket policies - See Example bucket policies for S3 Express One Zone in the Amazon S3 User Guide.

\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is s3express-control.region.amazonaws.com.

\n
\n
\n

The following action is related to GetBucketPolicy:

\n ", "smithy.api#examples": [ { "title": "To get bucket policy", @@ -20430,6 +22438,11 @@ "method": "GET", "uri": "/{Bucket}?policy", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20454,7 +22467,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name for which to get the bucket policy.

\n

To use this API operation against an access point, provide the alias of the access point in place of the bucket name.

\n

To use this API operation against an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

", + "smithy.api#documentation": "

The bucket name to get the bucket policy for.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use path-style requests in the format https://s3express-control.region_code.amazonaws.com/bucket-name\n . Virtual-hosted-style requests aren't supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must also follow the format \n bucket_base_name--az_id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming restrictions, see Directory bucket naming rules in the Amazon S3 User Guide\n

\n

\n Access points - When you use this API operation with an access point, provide the alias of the access point in place of the bucket name.

\n

\n Object Lambda access points - When you use this API operation with an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -20465,7 +22478,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

\n \n

For directory buckets, this header is not supported in this API operation. If you specify this header, the request fails with the HTTP status code \n501 Not Implemented.

\n
", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20483,11 +22496,16 @@ "target": "com.amazonaws.s3#GetBucketPolicyStatusOutput" }, "traits": { - "smithy.api#documentation": "

Retrieves the policy status for an Amazon S3 bucket, indicating whether the bucket is public.\n In order to use this operation, you must have the s3:GetBucketPolicyStatus\n permission. For more information about Amazon S3 permissions, see Specifying Permissions in a\n Policy.

\n

For more information about when Amazon S3 considers a bucket public, see The Meaning of \"Public\".

\n

The following operations are related to GetBucketPolicyStatus:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Retrieves the policy status for an Amazon S3 bucket, indicating whether the bucket is public.\n In order to use this operation, you must have the s3:GetBucketPolicyStatus\n permission. For more information about Amazon S3 permissions, see Specifying Permissions in a\n Policy.

\n

For more information about when Amazon S3 considers a bucket public, see The Meaning of \"Public\".

\n

The following operations are related to GetBucketPolicyStatus:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?policyStatus", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20523,7 +22541,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20541,7 +22559,7 @@ "target": "com.amazonaws.s3#GetBucketReplicationOutput" }, "traits": { - "smithy.api#documentation": "

Returns the replication configuration of a bucket.

\n \n

It can take a while to propagate the put or delete a replication configuration to\n all Amazon S3 systems. Therefore, a get request soon after put or delete can return a wrong\n result.

\n
\n

For information about replication configuration, see Replication in the\n Amazon S3 User Guide.

\n

This action requires permissions for the s3:GetReplicationConfiguration\n action. For more information about permissions, see Using Bucket Policies and User\n Policies.

\n

If you include the Filter element in a replication configuration, you must\n also include the DeleteMarkerReplication and Priority elements.\n The response also returns those elements.

\n

For information about GetBucketReplication errors, see List of\n replication-related error codes\n

\n

The following operations are related to GetBucketReplication:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns the replication configuration of a bucket.

\n \n

It can take a while to propagate the put or delete a replication configuration to\n all Amazon S3 systems. Therefore, a get request soon after put or delete can return a wrong\n result.

\n
\n

For information about replication configuration, see Replication in the\n Amazon S3 User Guide.

\n

This action requires permissions for the s3:GetReplicationConfiguration\n action. For more information about permissions, see Using Bucket Policies and User\n Policies.

\n

If you include the Filter element in a replication configuration, you must\n also include the DeleteMarkerReplication and Priority elements.\n The response also returns those elements.

\n

For information about GetBucketReplication errors, see List of\n replication-related error codes\n

\n

The following operations are related to GetBucketReplication:

\n ", "smithy.api#examples": [ { "title": "To get replication configuration set on a bucket", @@ -20570,6 +22588,11 @@ "method": "GET", "uri": "/{Bucket}?replication", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20604,7 +22627,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20622,7 +22645,7 @@ "target": "com.amazonaws.s3#GetBucketRequestPaymentOutput" }, "traits": { - "smithy.api#documentation": "

Returns the request payment configuration of a bucket. To use this version of the\n operation, you must be the bucket owner. For more information, see Requester Pays\n Buckets.

\n

The following operations are related to GetBucketRequestPayment:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns the request payment configuration of a bucket. To use this version of the\n operation, you must be the bucket owner. For more information, see Requester Pays\n Buckets.

\n

The following operations are related to GetBucketRequestPayment:

\n ", "smithy.api#examples": [ { "title": "To get bucket versioning configuration", @@ -20639,6 +22662,11 @@ "method": "GET", "uri": "/{Bucket}?requestPayment", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20674,7 +22702,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20692,7 +22720,7 @@ "target": "com.amazonaws.s3#GetBucketTaggingOutput" }, "traits": { - "smithy.api#documentation": "

Returns the tag set associated with the bucket.

\n

To use this operation, you must have permission to perform the\n s3:GetBucketTagging action. By default, the bucket owner has this\n permission and can grant this permission to others.

\n

\n GetBucketTagging has the following special error:

\n
    \n
  • \n

    Error code: NoSuchTagSet\n

    \n
      \n
    • \n

      Description: There is no tag set associated with the bucket.

      \n
    • \n
    \n
  • \n
\n

The following operations are related to GetBucketTagging:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns the tag set associated with the bucket.

\n

To use this operation, you must have permission to perform the\n s3:GetBucketTagging action. By default, the bucket owner has this\n permission and can grant this permission to others.

\n

\n GetBucketTagging has the following special error:

\n
    \n
  • \n

    Error code: NoSuchTagSet\n

    \n
      \n
    • \n

      Description: There is no tag set associated with the bucket.

      \n
    • \n
    \n
  • \n
\n

The following operations are related to GetBucketTagging:

\n ", "smithy.api#examples": [ { "title": "To get tag set associated with a bucket", @@ -20718,6 +22746,11 @@ "method": "GET", "uri": "/{Bucket}?tagging", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20754,7 +22787,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20772,7 +22805,7 @@ "target": "com.amazonaws.s3#GetBucketVersioningOutput" }, "traits": { - "smithy.api#documentation": "

Returns the versioning state of a bucket.

\n

To retrieve the versioning state of a bucket, you must be the bucket owner.

\n

This implementation also returns the MFA Delete status of the versioning state. If the\n MFA Delete status is enabled, the bucket owner must use an authentication\n device to change the versioning state of the bucket.

\n

The following operations are related to GetBucketVersioning:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns the versioning state of a bucket.

\n

To retrieve the versioning state of a bucket, you must be the bucket owner.

\n

This implementation also returns the MFA Delete status of the versioning state. If the\n MFA Delete status is enabled, the bucket owner must use an authentication\n device to change the versioning state of the bucket.

\n

The following operations are related to GetBucketVersioning:

\n ", "smithy.api#examples": [ { "title": "To get bucket versioning configuration", @@ -20790,6 +22823,11 @@ "method": "GET", "uri": "/{Bucket}?versioning", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20832,7 +22870,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20850,7 +22888,7 @@ "target": "com.amazonaws.s3#GetBucketWebsiteOutput" }, "traits": { - "smithy.api#documentation": "

Returns the website configuration for a bucket. To host website on Amazon S3, you can\n configure a bucket as website by adding a website configuration. For more information about\n hosting websites, see Hosting Websites on Amazon S3.

\n

This GET action requires the S3:GetBucketWebsite permission. By default,\n only the bucket owner can read the bucket website configuration. However, bucket owners can\n allow other users to read the website configuration by writing a bucket policy granting\n them the S3:GetBucketWebsite permission.

\n

The following operations are related to GetBucketWebsite:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns the website configuration for a bucket. To host website on Amazon S3, you can\n configure a bucket as website by adding a website configuration. For more information about\n hosting websites, see Hosting Websites on Amazon S3.

\n

This GET action requires the S3:GetBucketWebsite permission. By default,\n only the bucket owner can read the bucket website configuration. However, bucket owners can\n allow other users to read the website configuration by writing a bucket policy granting\n them the S3:GetBucketWebsite permission.

\n

The following operations are related to GetBucketWebsite:

\n ", "smithy.api#examples": [ { "title": "To get bucket website configuration", @@ -20872,6 +22910,11 @@ "method": "GET", "uri": "/{Bucket}?website", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -20925,7 +22968,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -20960,7 +23003,7 @@ "SHA1" ] }, - "smithy.api#documentation": "

Retrieves objects from Amazon S3. To use GET, you must have READ\n access to the object. If you grant READ access to the anonymous user, you can\n return the object without using an authorization header.

\n

An Amazon S3 bucket has no directory hierarchy such as you would find in a typical computer\n file system. You can, however, create a logical hierarchy by using object key names that\n imply a folder structure. For example, instead of naming an object sample.jpg,\n you can name it photos/2006/February/sample.jpg.

\n

To get an object from such a logical hierarchy, specify the full key name for the object\n in the GET operation. For a virtual hosted-style request example, if you have\n the object photos/2006/February/sample.jpg, specify the resource as\n /photos/2006/February/sample.jpg. For a path-style request example, if you\n have the object photos/2006/February/sample.jpg in the bucket named\n examplebucket, specify the resource as\n /examplebucket/photos/2006/February/sample.jpg. For more information about\n request types, see HTTP Host\n Header Bucket Specification.

\n

For more information about returning the ACL of an object, see GetObjectAcl.

\n

If the object you are retrieving is stored in the S3 Glacier Flexible Retrieval or\n S3 Glacier Deep Archive storage class, or S3 Intelligent-Tiering Archive or\n S3 Intelligent-Tiering Deep Archive tiers, before you can retrieve the object you must first restore a\n copy using RestoreObject. Otherwise, this action returns an\n InvalidObjectState error. For information about restoring archived objects,\n see Restoring\n Archived Objects.

\n

Encryption request headers, like x-amz-server-side-encryption, should not\n be sent for GET requests if your object uses server-side encryption with Key Management Service (KMS)\n keys (SSE-KMS), dual-layer server-side encryption with Amazon Web Services KMS keys (DSSE-KMS), or\n server-side encryption with Amazon S3 managed encryption keys (SSE-S3). If your object does use\n these types of keys, you’ll get an HTTP 400 Bad Request error.

\n

If you encrypt an object by using server-side encryption with customer-provided\n encryption keys (SSE-C) when you store the object in Amazon S3, then when you GET the object,\n you must use the following headers:

\n
    \n
  • \n

    \n x-amz-server-side-encryption-customer-algorithm\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key-MD5\n

    \n
  • \n
\n

For more information about SSE-C, see Server-Side Encryption\n (Using Customer-Provided Encryption Keys).

\n

Assuming you have the relevant permission to read object tags, the response also returns\n the x-amz-tagging-count header that provides the count of number of tags\n associated with the object. You can use GetObjectTagging to retrieve\n the tag set associated with an object.

\n
\n
Permissions
\n
\n

You need the relevant read object (or version) permission for this operation.\n For more information, see Specifying Permissions in\n a Policy. If the object that you request doesn’t exist, the error that\n Amazon S3 returns depends on whether you also have the s3:ListBucket\n permission.

\n

If you have the s3:ListBucket permission on the bucket, Amazon S3\n returns an HTTP status code 404 (Not Found) error.

\n

If you don’t have the s3:ListBucket permission, Amazon S3 returns an\n HTTP status code 403 (\"access denied\") error.

\n
\n
Versioning
\n
\n

By default, the GET action returns the current version of an\n object. To return a different version, use the versionId\n subresource.

\n \n
    \n
  • \n

    If you supply a versionId, you need the\n s3:GetObjectVersion permission to access a specific\n version of an object. If you request a specific version, you do not need\n to have the s3:GetObject permission. If you request the\n current version without a specific version ID, only\n s3:GetObject permission is required.\n s3:GetObjectVersion permission won't be required.

    \n
  • \n
  • \n

    If the current version of the object is a delete marker, Amazon S3 behaves\n as if the object was deleted and includes x-amz-delete-marker:\n true in the response.

    \n
  • \n
\n
\n

For more information about versioning, see PutBucketVersioning.

\n
\n
Overriding Response Header Values
\n
\n

There are times when you want to override certain response header values in a\n GET response. For example, you might override the\n Content-Disposition response header value in your GET\n request.

\n

You can override values for a set of response headers using the following query\n parameters. These response header values are sent only on a successful request,\n that is, when status code 200 OK is returned. The set of headers you can override\n using these parameters is a subset of the headers that Amazon S3 accepts when you\n create an object. The response headers that you can override for the\n GET response are Content-Type,\n Content-Language, Expires,\n Cache-Control, Content-Disposition, and\n Content-Encoding. To override these header values in the\n GET response, you use the following request parameters.

\n \n

You must sign the request, either using an Authorization header or a\n presigned URL, when using these parameters. They cannot be used with an\n unsigned (anonymous) request.

\n
\n
    \n
  • \n

    \n response-content-type\n

    \n
  • \n
  • \n

    \n response-content-language\n

    \n
  • \n
  • \n

    \n response-expires\n

    \n
  • \n
  • \n

    \n response-cache-control\n

    \n
  • \n
  • \n

    \n response-content-disposition\n

    \n
  • \n
  • \n

    \n response-content-encoding\n

    \n
  • \n
\n
\n
Overriding Response Header Values
\n
\n

If both of the If-Match and If-Unmodified-Since\n headers are present in the request as follows: If-Match condition\n evaluates to true, and; If-Unmodified-Since condition\n evaluates to false; then, S3 returns 200 OK and the data requested.

\n

If both of the If-None-Match and If-Modified-Since\n headers are present in the request as follows: If-None-Match\n condition evaluates to false, and; If-Modified-Since\n condition evaluates to true; then, S3 returns 304 Not Modified\n response code.

\n

For more information about conditional requests, see RFC 7232.

\n
\n
\n

The following operations are related to GetObject:

\n ", + "smithy.api#documentation": "

Retrieves an object from Amazon S3.

\n

In the GetObject request, specify the full key name for the object.

\n

\n General purpose buckets - Both the virtual-hosted-style requests and the path-style requests are supported. For a virtual hosted-style request example, if you have\n the object photos/2006/February/sample.jpg, specify the object key name as\n /photos/2006/February/sample.jpg. For a path-style request example, if you\n have the object photos/2006/February/sample.jpg in the bucket named\n examplebucket, specify the object key name as\n /examplebucket/photos/2006/February/sample.jpg. For more information about\n request types, see HTTP Host\n Header Bucket Specification in the Amazon S3 User Guide.

\n

\n Directory buckets - Only virtual-hosted-style requests are supported. For a virtual hosted-style request example, if you have the object photos/2006/February/sample.jpg in the bucket named examplebucket--use1-az5--x-s3, specify the object key name as /photos/2006/February/sample.jpg. Also, when you make requests to this API operation, your requests are sent to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - You must have the required permissions in a policy. To use GetObject, you must have the READ\n access to the object (or version). If you grant READ access to the anonymous user, the GetObject operation \n returns the object without using an authorization header. For more information, see Specifying permissions in\n a policy in the Amazon S3 User Guide.

    \n

    If you include a versionId in your request header, you must have the\n s3:GetObjectVersion permission to access a specific\n version of an object. The s3:GetObject permission is not required in this scenario.

    \n

    If you request the\n current version of an object without a specific versionId in the request header, only\n the s3:GetObject permission is required. The s3:GetObjectVersion permission is not required in this scenario.\n

    \n

    If the object that you request doesn’t exist, the error that\n Amazon S3 returns depends on whether you also have the s3:ListBucket\n permission.

    \n
      \n
    • \n

      If you have the s3:ListBucket permission on the bucket, Amazon S3\n returns an HTTP status code 404 Not Found error.

      \n
    • \n
    • \n

      If you don’t have the s3:ListBucket permission, Amazon S3 returns an\n HTTP status code 403 Access Denied error.

      \n
    • \n
    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation on a directory bucket, we recommend that you use the \n CreateSession\n API operation for session-based authorization. Specifically, you grant the s3express:CreateSession permission to the directory bucket in a bucket policy or an IAM identity-based policy. Then, you make the CreateSession API call on the bucket to obtain a session token. With the session token in your request header, you can make API requests to this operation. After the session token expires, you make another CreateSession API call to generate a new session token for use. \nAmazon Web Services CLI or SDKs create session and refresh the session token automatically to avoid service interruptions when a session expires. For more information about authorization, see \n CreateSession\n .

    \n
  • \n
\n
\n
Storage classes
\n
\n

If the object you are retrieving is stored in the S3 Glacier Flexible Retrieval storage class, the \n S3 Glacier Deep Archive storage class, the S3 Intelligent-Tiering Archive Access tier, or the \n S3 Intelligent-Tiering Deep Archive Access tier, before you can retrieve the object you must first restore a\n copy using RestoreObject. Otherwise, this operation returns an\n InvalidObjectState error. For information about restoring archived objects,\n see Restoring\n Archived Objects in the Amazon S3 User Guide.

\n

\n Directory buckets - For directory buckets, only the S3 Express One Zone storage class is supported to store newly created objects. \nUnsupported storage class values won't write a destination object and will respond with the HTTP status code 400 Bad Request.

\n
\n
Encryption
\n
\n

Encryption request headers, like x-amz-server-side-encryption, should not\n be sent for the GetObject requests, if your object uses server-side encryption with Amazon S3 managed encryption keys (SSE-S3), server-side encryption with Key Management Service (KMS)\n keys (SSE-KMS), or dual-layer server-side encryption with Amazon Web Services KMS keys (DSSE-KMS). If you include the header in your GetObject requests for the object that uses \n these types of keys, you’ll get an HTTP 400 Bad Request error.

\n
\n
Overriding response header values through the request
\n
\n

There are times when you want to override certain response header values of a\n GetObject response. For example, you might override the\n Content-Disposition response header value through your GetObject\n request.

\n

You can override values for a set of response headers. These modified response header values are included only in a successful response, that is, when the HTTP status code 200 OK is returned. \n The headers you can override using the following query parameters in the request are a subset of the headers that Amazon S3 accepts when you create an object. \n

\n

The response headers that you can override for the\n GetObject response are Cache-Control, Content-Disposition, \n Content-Encoding, Content-Language, Content-Type, and Expires.

\n

To override values for a set of response headers in the\n GetObject response, you can use the following query\n parameters in the request.

\n
    \n
  • \n

    \n response-cache-control\n

    \n
  • \n
  • \n

    \n response-content-disposition\n

    \n
  • \n
  • \n

    \n response-content-encoding\n

    \n
  • \n
  • \n

    \n response-content-language\n

    \n
  • \n
  • \n

    \n response-content-type\n

    \n
  • \n
  • \n

    \n response-expires\n

    \n
  • \n
\n \n

When you use these parameters, you must sign the request by using either an Authorization header or a\n presigned URL. These parameters cannot be used with an\n unsigned (anonymous) request.

\n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

The following operations are related to GetObject:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}/{Key+}?x-id=GetObject", @@ -20982,7 +23025,7 @@ } ], "traits": { - "smithy.api#documentation": "

Returns the access control list (ACL) of an object. To use this operation, you must have\n s3:GetObjectAcl permissions or READ_ACP access to the object.\n For more information, see Mapping of ACL permissions and access policy permissions in the Amazon S3\n User Guide\n

\n

This action is not supported by Amazon S3 on Outposts.

\n

By default, GET returns ACL information about the current version of an object. To\n return ACL information about a different version, use the versionId subresource.

\n \n

If your bucket uses the bucket owner enforced setting for S3 Object Ownership,\n requests to read ACLs are still supported and return the\n bucket-owner-full-control ACL with the owner being the account that\n created the bucket. For more information, see Controlling object\n ownership and disabling ACLs in the\n Amazon S3 User Guide.

\n
\n

The following operations are related to GetObjectAcl:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns the access control list (ACL) of an object. To use this operation, you must have\n s3:GetObjectAcl permissions or READ_ACP access to the object.\n For more information, see Mapping of ACL permissions and access policy permissions in the Amazon S3\n User Guide\n

\n

This functionality is not supported for Amazon S3 on Outposts.

\n

By default, GET returns ACL information about the current version of an object. To\n return ACL information about a different version, use the versionId subresource.

\n \n

If your bucket uses the bucket owner enforced setting for S3 Object Ownership,\n requests to read ACLs are still supported and return the\n bucket-owner-full-control ACL with the owner being the account that\n created the bucket. For more information, see Controlling object\n ownership and disabling ACLs in the\n Amazon S3 User Guide.

\n
\n

The following operations are related to GetObjectAcl:

\n ", "smithy.api#examples": [ { "title": "To retrieve object ACL", @@ -21074,7 +23117,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name that contains the object for which to get the ACL information.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name that contains the object for which to get the ACL information.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -21087,13 +23130,16 @@ "traits": { "smithy.api#documentation": "

The key of the object for which to get the ACL information.

", "smithy.api#httpLabel": {}, - "smithy.api#required": {} + "smithy.api#required": {}, + "smithy.rules#contextParam": { + "name": "Key" + } } }, "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

VersionId used to reference a specific version of the object.

", + "smithy.api#documentation": "

Version ID used to reference a specific version of the object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpQuery": "versionId" } }, @@ -21106,7 +23152,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -21129,7 +23175,7 @@ } ], "traits": { - "smithy.api#documentation": "

Retrieves all the metadata from an object without returning the object itself. This\n action is useful if you're interested only in an object's metadata. To use\n GetObjectAttributes, you must have READ access to the object.

\n

\n GetObjectAttributes combines the functionality of HeadObject\n and ListParts. All of the data returned with each of those individual calls\n can be returned with a single call to GetObjectAttributes.

\n

If you encrypt an object by using server-side encryption with customer-provided\n encryption keys (SSE-C) when you store the object in Amazon S3, then when you retrieve the\n metadata from the object, you must use the following headers:

\n
    \n
  • \n

    \n x-amz-server-side-encryption-customer-algorithm\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key-MD5\n

    \n
  • \n
\n

For more information about SSE-C, see Server-Side Encryption\n (Using Customer-Provided Encryption Keys) in the\n Amazon S3 User Guide.

\n \n
    \n
  • \n

    Encryption request headers, such as x-amz-server-side-encryption,\n should not be sent for GET requests if your object uses server-side encryption\n with Amazon Web Services KMS keys stored in Amazon Web Services Key Management Service (SSE-KMS) or\n server-side encryption with Amazon S3 managed keys (SSE-S3). If your object does use\n these types of keys, you'll get an HTTP 400 Bad Request error.

    \n
  • \n
  • \n

    The last modified property in this case is the creation date of the\n object.

    \n
  • \n
\n
\n

Consider the following when using request headers:

\n
    \n
  • \n

    If both of the If-Match and If-Unmodified-Since headers\n are present in the request as follows, then Amazon S3 returns the HTTP status code\n 200 OK and the data requested:

    \n
      \n
    • \n

      \n If-Match condition evaluates to true.

      \n
    • \n
    • \n

      \n If-Unmodified-Since condition evaluates to\n false.

      \n
    • \n
    \n
  • \n
  • \n

    If both of the If-None-Match and If-Modified-Since\n headers are present in the request as follows, then Amazon S3 returns the HTTP status code\n 304 Not Modified:

    \n
      \n
    • \n

      \n If-None-Match condition evaluates to false.

      \n
    • \n
    • \n

      \n If-Modified-Since condition evaluates to\n true.

      \n
    • \n
    \n
  • \n
\n

For more information about conditional requests, see RFC 7232.

\n
\n
Permissions
\n
\n

The permissions that you need to use this operation depend on whether the\n bucket is versioned. If the bucket is versioned, you need both the\n s3:GetObjectVersion and s3:GetObjectVersionAttributes\n permissions for this operation. If the bucket is not versioned, you need the\n s3:GetObject and s3:GetObjectAttributes permissions.\n For more information, see Specifying Permissions in\n a Policy in the Amazon S3 User Guide. If the object\n that you request does not exist, the error Amazon S3 returns depends on whether you\n also have the s3:ListBucket permission.

\n
    \n
  • \n

    If you have the s3:ListBucket permission on the bucket, Amazon S3\n returns an HTTP status code 404 Not Found (\"no such key\")\n error.

    \n
  • \n
  • \n

    If you don't have the s3:ListBucket permission, Amazon S3 returns\n an HTTP status code 403 Forbidden (\"access denied\")\n error.

    \n
  • \n
\n
\n
\n

The following actions are related to GetObjectAttributes:

\n ", + "smithy.api#documentation": "

Retrieves all the metadata from an object without returning the object itself. This\n operation is useful if you're interested only in an object's metadata.

\n

\n GetObjectAttributes combines the functionality of HeadObject\n and ListParts. All of the data returned with each of those individual calls\n can be returned with a single call to GetObjectAttributes.

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - To use\n GetObjectAttributes, you must have READ access to the object. The permissions that you need to use this operation with depend on whether the\n bucket is versioned. If the bucket is versioned, you need both the\n s3:GetObjectVersion and s3:GetObjectVersionAttributes\n permissions for this operation. If the bucket is not versioned, you need the\n s3:GetObject and s3:GetObjectAttributes permissions.\n For more information, see Specifying Permissions in\n a Policy in the Amazon S3 User Guide. If the object\n that you request does not exist, the error Amazon S3 returns depends on whether you\n also have the s3:ListBucket permission.

    \n
      \n
    • \n

      If you have the s3:ListBucket permission on the bucket, Amazon S3\n returns an HTTP status code 404 Not Found (\"no such key\")\n error.

      \n
    • \n
    • \n

      If you don't have the s3:ListBucket permission, Amazon S3 returns\n an HTTP status code 403 Forbidden (\"access denied\")\n error.

      \n
    • \n
    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation on a directory bucket, we recommend that you use the \n CreateSession\n API operation for session-based authorization. Specifically, you grant the s3express:CreateSession permission to the directory bucket in a bucket policy or an IAM identity-based policy. Then, you make the CreateSession API call on the bucket to obtain a session token. With the session token in your request header, you can make API requests to this operation. After the session token expires, you make another CreateSession API call to generate a new session token for use. \nAmazon Web Services CLI or SDKs create session and refresh the session token automatically to avoid service interruptions when a session expires. For more information about authorization, see \n CreateSession\n .

    \n
  • \n
\n
\n
Encryption
\n
\n \n

Encryption request headers, like x-amz-server-side-encryption,\n should not be sent for HEAD requests if your object uses server-side\n encryption with Key Management Service (KMS) keys (SSE-KMS), dual-layer server-side\n encryption with Amazon Web Services KMS keys (DSSE-KMS), or server-side encryption with Amazon S3\n managed encryption keys (SSE-S3). The x-amz-server-side-encryption header is used when you PUT an object to S3 and want to specify the encryption method. \n If you include this header in a GET request for an object that uses these types of keys, \n you’ll get an HTTP 400 Bad Request error. It's because the encryption method can't be changed when you retrieve the object.

\n
\n

If you encrypt an object by using server-side encryption with customer-provided\n encryption keys (SSE-C) when you store the object in Amazon S3, then when you retrieve the\n metadata from the object, you must use the following headers to provide the encryption key for the server to be able to retrieve the object's metadata. The headers are:

\n
    \n
  • \n

    \n x-amz-server-side-encryption-customer-algorithm\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key-MD5\n

    \n
  • \n
\n

For more information about SSE-C, see Server-Side Encryption\n (Using Customer-Provided Encryption Keys) in the Amazon S3\n User Guide.

\n \n

\n Directory bucket permissions - For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

\n
\n
\n
Versioning
\n
\n

\n Directory buckets - S3 Versioning isn't enabled and supported for directory buckets. For this API operation, only the null value of the version ID is supported by directory buckets. You can only specify null \n to the versionId query parameter in the request.

\n
\n
Conditional request headers
\n
\n

Consider the following when using request headers:

\n
    \n
  • \n

    If both of the If-Match and If-Unmodified-Since headers\n are present in the request as follows, then Amazon S3 returns the HTTP status code\n 200 OK and the data requested:

    \n
      \n
    • \n

      \n If-Match condition evaluates to true.

      \n
    • \n
    • \n

      \n If-Unmodified-Since condition evaluates to\n false.

      \n
    • \n
    \n

    For more information about conditional requests, see RFC 7232.

    \n
  • \n
  • \n

    If both of the If-None-Match and If-Modified-Since\n headers are present in the request as follows, then Amazon S3 returns the HTTP status code\n 304 Not Modified:

    \n
      \n
    • \n

      \n If-None-Match condition evaluates to false.

      \n
    • \n
    • \n

      \n If-Modified-Since condition evaluates to\n true.

      \n
    • \n
    \n

    For more information about conditional requests, see RFC 7232.

    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

The following actions are related to GetObjectAttributes:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}/{Key+}?attributes", @@ -21143,8 +23189,7 @@ "DeleteMarker": { "target": "com.amazonaws.s3#DeleteMarker", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Specifies whether the object retrieved was (true) or was not\n (false) a delete marker. If false, this response header does\n not appear in the response.

", + "smithy.api#documentation": "

Specifies whether the object retrieved was (true) or was not\n (false) a delete marker. If false, this response header does\n not appear in the response.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-delete-marker" } }, @@ -21158,7 +23203,7 @@ "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

The version ID of the object.

", + "smithy.api#documentation": "

The version ID of the object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-version-id" } }, @@ -21189,13 +23234,12 @@ "StorageClass": { "target": "com.amazonaws.s3#StorageClass", "traits": { - "smithy.api#documentation": "

Provides the storage class information of the object. Amazon S3 returns this header for all\n objects except for S3 Standard storage class objects.

\n

For more information, see Storage Classes.

" + "smithy.api#documentation": "

Provides the storage class information of the object. Amazon S3 returns this header for all\n objects except for S3 Standard storage class objects.

\n

For more information, see Storage Classes.

\n \n

\n Directory buckets - Only the S3 Express One Zone storage class is supported by directory buckets to store objects.

\n
" } }, "ObjectSize": { "target": "com.amazonaws.s3#ObjectSize", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The size of the object in bytes.

" } } @@ -21210,7 +23254,6 @@ "TotalPartsCount": { "target": "com.amazonaws.s3#PartsCount", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The total number of parts.

", "smithy.api#xmlName": "PartsCount" } @@ -21230,21 +23273,19 @@ "MaxParts": { "target": "com.amazonaws.s3#MaxParts", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The maximum number of parts allowed in the response.

" } }, "IsTruncated": { "target": "com.amazonaws.s3#IsTruncated", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Indicates whether the returned list of parts is truncated. A value of true\n indicates that the list was truncated. A list can be truncated if the number of parts\n exceeds the limit returned in the MaxParts element.

" } }, "Parts": { "target": "com.amazonaws.s3#PartsList", "traits": { - "smithy.api#documentation": "

A container for elements related to a particular part. A response can contain zero or\n more Parts elements.

", + "smithy.api#documentation": "

A container for elements related to a particular part. A response can contain zero or\n more Parts elements.

\n \n
    \n
  • \n

    \n General purpose buckets - For GetObjectAttributes, if a additional checksum (including x-amz-checksum-crc32, \n x-amz-checksum-crc32c, x-amz-checksum-sha1, or \n x-amz-checksum-sha256) isn't applied to the object specified in the request, the response doesn't return Part.

    \n
  • \n
  • \n

    \n Directory buckets - For GetObjectAttributes, no matter whether a additional checksum is applied to the object specified in the request, the response returns Part.

    \n
  • \n
\n
", "smithy.api#xmlFlattened": {}, "smithy.api#xmlName": "Part" } @@ -21260,7 +23301,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket that contains the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket that contains the object.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -21279,14 +23320,13 @@ "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

The version ID used to reference a specific version of the object.

", + "smithy.api#documentation": "

The version ID used to reference a specific version of the object.

\n \n

S3 Versioning isn't enabled and supported for directory buckets. For this API operation, only the null value of the version ID is supported by directory buckets. You can only specify null \n to the versionId query parameter in the request.

\n
", "smithy.api#httpQuery": "versionId" } }, "MaxParts": { "target": "com.amazonaws.s3#MaxParts", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Sets the maximum number of parts to return.

", "smithy.api#httpHeader": "x-amz-max-parts" } @@ -21301,21 +23341,21 @@ "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

Specifies the algorithm to use when encrypting the object (for example, AES256).

", + "smithy.api#documentation": "

Specifies the algorithm to use when encrypting the object (for example, AES256).

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKey": { "target": "com.amazonaws.s3#SSECustomerKey", "traits": { - "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header.

", + "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

", + "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, @@ -21328,7 +23368,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -21354,7 +23394,7 @@ "target": "com.amazonaws.s3#GetObjectLegalHoldOutput" }, "traits": { - "smithy.api#documentation": "

Gets an object's current legal hold status. For more information, see Locking\n Objects.

\n

This action is not supported by Amazon S3 on Outposts.

\n

The following action is related to GetObjectLegalHold:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Gets an object's current legal hold status. For more information, see Locking\n Objects.

\n

This functionality is not supported for Amazon S3 on Outposts.

\n

The following action is related to GetObjectLegalHold:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}/{Key+}?legal-hold", @@ -21383,7 +23423,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the object whose legal hold status you want to retrieve.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the object whose legal hold status you want to retrieve.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -21415,7 +23455,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -21433,7 +23473,7 @@ "target": "com.amazonaws.s3#GetObjectLockConfigurationOutput" }, "traits": { - "smithy.api#documentation": "

Gets the Object Lock configuration for a bucket. The rule specified in the Object Lock\n configuration will be applied by default to every new object placed in the specified\n bucket. For more information, see Locking Objects.

\n

The following action is related to GetObjectLockConfiguration:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Gets the Object Lock configuration for a bucket. The rule specified in the Object Lock\n configuration will be applied by default to every new object placed in the specified\n bucket. For more information, see Locking Objects.

\n

The following action is related to GetObjectLockConfiguration:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?object-lock", @@ -21462,7 +23502,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket whose Object Lock configuration you want to retrieve.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket whose Object Lock configuration you want to retrieve.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -21473,7 +23513,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -21496,43 +23536,41 @@ "DeleteMarker": { "target": "com.amazonaws.s3#DeleteMarker", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Specifies whether the object retrieved was (true) or was not (false) a Delete Marker. If\n false, this response header does not appear in the response.

", + "smithy.api#documentation": "

Indicates whether the object retrieved was (true) or was not (false) a Delete Marker. If\n false, this response header does not appear in the response.

\n \n
    \n
  • \n

    If the current version of the object is a delete marker, Amazon S3 behaves as if the object was deleted and includes x-amz-delete-marker: true in the response.

    \n
  • \n
  • \n

    If the specified version in the request is a delete marker, the response returns a 405 Method Not Allowed error and the Last-Modified: timestamp response header.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-delete-marker" } }, "AcceptRanges": { "target": "com.amazonaws.s3#AcceptRanges", "traits": { - "smithy.api#documentation": "

Indicates that a range of bytes was specified.

", + "smithy.api#documentation": "

Indicates that a range of bytes was specified in the request.

", "smithy.api#httpHeader": "accept-ranges" } }, "Expiration": { "target": "com.amazonaws.s3#Expiration", "traits": { - "smithy.api#documentation": "

If the object expiration is configured (see PUT Bucket lifecycle), the response includes\n this header. It includes the expiry-date and rule-id key-value\n pairs providing object expiration information. The value of the rule-id is\n URL-encoded.

", + "smithy.api#documentation": "

If the object expiration is configured (see \n PutBucketLifecycleConfiguration\n ), the response includes\n this header. It includes the expiry-date and rule-id key-value\n pairs providing object expiration information. The value of the rule-id is\n URL-encoded.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-expiration" } }, "Restore": { "target": "com.amazonaws.s3#Restore", "traits": { - "smithy.api#documentation": "

Provides information about object restoration action and expiration time of the restored\n object copy.

", + "smithy.api#documentation": "

Provides information about object restoration action and expiration time of the restored\n object copy.

\n \n

This functionality is not supported for directory buckets. Only the S3 Express One Zone storage class is supported by directory buckets to store objects.

\n
", "smithy.api#httpHeader": "x-amz-restore" } }, "LastModified": { "target": "com.amazonaws.s3#LastModified", "traits": { - "smithy.api#documentation": "

Creation date of the object.

", + "smithy.api#documentation": "

Date and time when the object was last modified.

\n

\n General purpose buckets - When you specify a versionId of the object in your request, if the specified version in the request is a delete marker, the response returns a 405 Method Not Allowed error and the Last-Modified: timestamp response header.

", "smithy.api#httpHeader": "Last-Modified" } }, "ContentLength": { "target": "com.amazonaws.s3#ContentLength", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Size of the body in bytes.

", "smithy.api#httpHeader": "Content-Length" } @@ -21547,43 +23585,42 @@ "ChecksumCRC32": { "target": "com.amazonaws.s3#ChecksumCRC32", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. For more information, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-crc32" } }, "ChecksumCRC32C": { "target": "com.amazonaws.s3#ChecksumCRC32C", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. For more information, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-crc32c" } }, "ChecksumSHA1": { "target": "com.amazonaws.s3#ChecksumSHA1", "traits": { - "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. For more information, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-sha1" } }, "ChecksumSHA256": { "target": "com.amazonaws.s3#ChecksumSHA256", "traits": { - "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. For more information, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-sha256" } }, "MissingMeta": { "target": "com.amazonaws.s3#MissingMeta", "traits": { - "smithy.api#default": 0, - "smithy.api#documentation": "

This is set to the number of metadata entries not returned in x-amz-meta\n headers. This can happen if you create metadata using an API like SOAP that supports more\n flexible metadata than the REST API. For example, using SOAP, you can create metadata whose\n values are not legal HTTP headers.

", + "smithy.api#documentation": "

This is set to the number of metadata entries not returned in the headers that are prefixed with x-amz-meta-. This can happen if you create metadata using an API like SOAP that supports more\n flexible metadata than the REST API. For example, using SOAP, you can create metadata whose\n values are not legal HTTP headers.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-missing-meta" } }, "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

Version of the object.

", + "smithy.api#documentation": "

Version ID of the object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-version-id" } }, @@ -21604,7 +23641,7 @@ "ContentEncoding": { "target": "com.amazonaws.s3#ContentEncoding", "traits": { - "smithy.api#documentation": "

Specifies what content encodings have been applied to the object and thus what decoding\n mechanisms must be applied to obtain the media-type referenced by the Content-Type header\n field.

", + "smithy.api#documentation": "

Indicates what content encodings have been applied to the object and thus what decoding\n mechanisms must be applied to obtain the media-type referenced by the Content-Type header\n field.

", "smithy.api#httpHeader": "Content-Encoding" } }, @@ -21639,14 +23676,14 @@ "WebsiteRedirectLocation": { "target": "com.amazonaws.s3#WebsiteRedirectLocation", "traits": { - "smithy.api#documentation": "

If the bucket is configured as a website, redirects requests for this object to another\n object in the same bucket or to an external URL. Amazon S3 stores the value of this header in\n the object metadata.

", + "smithy.api#documentation": "

If the bucket is configured as a website, redirects requests for this object to another\n object in the same bucket or to an external URL. Amazon S3 stores the value of this header in\n the object metadata.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-website-redirect-location" } }, "ServerSideEncryption": { "target": "com.amazonaws.s3#ServerSideEncryption", "traits": { - "smithy.api#documentation": "

The server-side encryption algorithm used when storing this object in Amazon S3 (for example,\n AES256, aws:kms, aws:kms:dsse).

", + "smithy.api#documentation": "

The server-side encryption algorithm used when you store this object in Amazon S3 (for example,\n AES256, aws:kms, aws:kms:dsse).

\n \n

For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption" } }, @@ -21660,36 +23697,35 @@ "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header confirming the encryption algorithm used.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to confirm the encryption algorithm that's used.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide round-trip message integrity verification of\n the customer-provided encryption key.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide the round-trip message integrity verification of\n the customer-provided encryption key.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, "SSEKMSKeyId": { "target": "com.amazonaws.s3#SSEKMSKeyId", "traits": { - "smithy.api#documentation": "

If present, specifies the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n that was used for the object.

", + "smithy.api#documentation": "

If present, indicates the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n that was used for the object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-aws-kms-key-id" } }, "BucketKeyEnabled": { "target": "com.amazonaws.s3#BucketKeyEnabled", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Indicates whether the object uses an S3 Bucket Key for server-side encryption with\n Key Management Service (KMS) keys (SSE-KMS).

", + "smithy.api#documentation": "

Indicates whether the object uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-bucket-key-enabled" } }, "StorageClass": { "target": "com.amazonaws.s3#StorageClass", "traits": { - "smithy.api#documentation": "

Provides storage class information of the object. Amazon S3 returns this header for all\n objects except for S3 Standard storage class objects.

", + "smithy.api#documentation": "

Provides storage class information of the object. Amazon S3 returns this header for all\n objects except for S3 Standard storage class objects.

\n \n

\n Directory buckets - Only the S3 Express One Zone storage class is supported by directory buckets to store objects.

\n
", "smithy.api#httpHeader": "x-amz-storage-class" } }, @@ -21702,14 +23738,13 @@ "ReplicationStatus": { "target": "com.amazonaws.s3#ReplicationStatus", "traits": { - "smithy.api#documentation": "

Amazon S3 can return this if your request involves a bucket that is either a source or\n destination in a replication rule.

", + "smithy.api#documentation": "

Amazon S3 can return this if your request involves a bucket that is either a source or\n destination in a replication rule.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-replication-status" } }, "PartsCount": { "target": "com.amazonaws.s3#PartsCount", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The count of parts this object has. This value is only returned if you specify\n partNumber in your request and the object was uploaded as a multipart\n upload.

", "smithy.api#httpHeader": "x-amz-mp-parts-count" } @@ -21717,29 +23752,28 @@ "TagCount": { "target": "com.amazonaws.s3#TagCount", "traits": { - "smithy.api#default": 0, - "smithy.api#documentation": "

The number of tags, if any, on the object.

", + "smithy.api#documentation": "

The number of tags, if any, on the object, when you have the relevant permission to read object tags.

\n

You can use GetObjectTagging to retrieve\n the tag set associated with an object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-tagging-count" } }, "ObjectLockMode": { "target": "com.amazonaws.s3#ObjectLockMode", "traits": { - "smithy.api#documentation": "

The Object Lock mode currently in place for this object.

", + "smithy.api#documentation": "

The Object Lock mode that's currently in place for this object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-mode" } }, "ObjectLockRetainUntilDate": { "target": "com.amazonaws.s3#ObjectLockRetainUntilDate", "traits": { - "smithy.api#documentation": "

The date and time when this object's Object Lock will expire.

", + "smithy.api#documentation": "

The date and time when this object's Object Lock will expire.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-retain-until-date" } }, "ObjectLockLegalHoldStatus": { "target": "com.amazonaws.s3#ObjectLockLegalHoldStatus", "traits": { - "smithy.api#documentation": "

Indicates whether this object has an active legal hold. This field is only returned if\n you have permission to view an object's legal hold status.

", + "smithy.api#documentation": "

Indicates whether this object has an active legal hold. This field is only returned if\n you have permission to view an object's legal hold status.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-legal-hold" } } @@ -21754,7 +23788,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When using an Object Lambda access point the hostname takes the form AccessPointName-AccountId.s3-object-lambda.Region.amazonaws.com.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the object.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

\n Object Lambda access points - When you use this action with an Object Lambda access point, you must direct requests to the Object Lambda access point hostname. The Object Lambda access point hostname takes the form AccessPointName-AccountId.s3-object-lambda.Region.amazonaws.com.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -21765,28 +23799,28 @@ "IfMatch": { "target": "com.amazonaws.s3#IfMatch", "traits": { - "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is the same as the one specified;\n otherwise, return a 412 (precondition failed) error.

", + "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is the same as the one specified in this header;\n otherwise, return a 412 Precondition Failed error.

\n

If both of the If-Match and If-Unmodified-Since headers are present in the request as follows: If-Match condition \n evaluates to true, and; If-Unmodified-Since condition evaluates to false; then, S3 returns 200 OK and the data requested.

\n

For more information about conditional requests, see RFC 7232.

", "smithy.api#httpHeader": "If-Match" } }, "IfModifiedSince": { "target": "com.amazonaws.s3#IfModifiedSince", "traits": { - "smithy.api#documentation": "

Return the object only if it has been modified since the specified time; otherwise,\n return a 304 (not modified) error.

", + "smithy.api#documentation": "

Return the object only if it has been modified since the specified time; otherwise,\n return a 304 Not Modified error.

\n

If both of the If-None-Match and If-Modified-Since headers are present in the request as follows: If-None-Match \n condition evaluates to false, and; If-Modified-Since condition evaluates to true; then, S3 returns 304 Not Modified \n status code.

\n

For more information about conditional requests, see RFC 7232.

", "smithy.api#httpHeader": "If-Modified-Since" } }, "IfNoneMatch": { "target": "com.amazonaws.s3#IfNoneMatch", "traits": { - "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is different from the one specified;\n otherwise, return a 304 (not modified) error.

", + "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is different from the one specified in this header;\n otherwise, return a 304 Not Modified error.

\n

If both of the If-None-Match and If-Modified-Since \n headers are present in the request as follows: If-None-Match \n condition evaluates to false, and; If-Modified-Since \n condition evaluates to true; then, S3 returns 304 Not Modified HTTP status code.

\n

For more information about conditional requests, see RFC 7232.

", "smithy.api#httpHeader": "If-None-Match" } }, "IfUnmodifiedSince": { "target": "com.amazonaws.s3#IfUnmodifiedSince", "traits": { - "smithy.api#documentation": "

Return the object only if it has not been modified since the specified time; otherwise,\n return a 412 (precondition failed) error.

", + "smithy.api#documentation": "

Return the object only if it has not been modified since the specified time; otherwise,\n return a 412 Precondition Failed error.

\n

If both of the If-Match and If-Unmodified-Since\n headers are present in the request as follows: If-Match condition\n evaluates to true, and; If-Unmodified-Since condition\n evaluates to false; then, S3 returns 200 OK and the data requested.

\n

For more information about conditional requests, see RFC 7232.

", "smithy.api#httpHeader": "If-Unmodified-Since" } }, @@ -21795,13 +23829,16 @@ "traits": { "smithy.api#documentation": "

Key of the object to get.

", "smithy.api#httpLabel": {}, - "smithy.api#required": {} + "smithy.api#required": {}, + "smithy.rules#contextParam": { + "name": "Key" + } } }, "Range": { "target": "com.amazonaws.s3#Range", "traits": { - "smithy.api#documentation": "

Downloads the specified range bytes of an object. For more information about the HTTP\n Range header, see https://www.rfc-editor.org/rfc/rfc9110.html#name-range.

\n \n

Amazon S3 doesn't support retrieving multiple ranges of data per GET\n request.

\n
", + "smithy.api#documentation": "

Downloads the specified byte range of an object. For more information about the HTTP\n Range header, see https://www.rfc-editor.org/rfc/rfc9110.html#name-range.

\n \n

Amazon S3 doesn't support retrieving multiple ranges of data per GET\n request.

\n
", "smithy.api#httpHeader": "Range" } }, @@ -21815,7 +23852,7 @@ "ResponseContentDisposition": { "target": "com.amazonaws.s3#ResponseContentDisposition", "traits": { - "smithy.api#documentation": "

Sets the Content-Disposition header of the response

", + "smithy.api#documentation": "

Sets the Content-Disposition header of the response.

", "smithy.api#httpQuery": "response-content-disposition" } }, @@ -21850,28 +23887,28 @@ "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

VersionId used to reference a specific version of the object.

", + "smithy.api#documentation": "

Version ID used to reference a specific version of the object.

\n

By default, the GetObject operation returns the current version of an object. To return a different version, use the versionId subresource.

\n \n
    \n
  • \n

    If you include a versionId in your request header, you must have the s3:GetObjectVersion permission to access a specific version of an object. The s3:GetObject permission is not required in this scenario.

    \n
  • \n
  • \n

    If you request the current version of an object without a specific versionId in the request header, only the s3:GetObject permission is required. The s3:GetObjectVersion permission is not required in this scenario.

    \n
  • \n
  • \n

    \n Directory buckets - S3 Versioning isn't enabled and supported for directory buckets. For this API operation, only the null value of the version ID is supported by directory buckets. You can only specify null \n to the versionId query parameter in the request.

    \n
  • \n
\n
\n

For more information about versioning, see PutBucketVersioning.

", "smithy.api#httpQuery": "versionId" } }, "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

Specifies the algorithm to use to when decrypting the object (for example,\n AES256).

", + "smithy.api#documentation": "

Specifies the algorithm to use when decrypting the object (for example,\n AES256).

\n

If you encrypt an object by using server-side encryption with customer-provided\n encryption keys (SSE-C) when you store the object in Amazon S3, then when you GET the object,\n you must use the following headers:

\n
    \n
  • \n

    \n x-amz-server-side-encryption-customer-algorithm\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key-MD5\n

    \n
  • \n
\n

For more information about SSE-C, see Server-Side Encryption\n (Using Customer-Provided Encryption Keys) in the Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKey": { "target": "com.amazonaws.s3#SSECustomerKey", "traits": { - "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 used to encrypt the data. This\n value is used to decrypt the object when recovering it and must match the one used when\n storing the data. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header.

", + "smithy.api#documentation": "

Specifies the customer-provided encryption key that you originally provided for Amazon S3 to encrypt the data before storing it. This\n value is used to decrypt the object when recovering it and must match the one used when\n storing the data. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header.

\n

If you encrypt an object by using server-side encryption with customer-provided\n encryption keys (SSE-C) when you store the object in Amazon S3, then when you GET the object,\n you must use the following headers:

\n
    \n
  • \n

    \n x-amz-server-side-encryption-customer-algorithm\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key-MD5\n

    \n
  • \n
\n

For more information about SSE-C, see Server-Side Encryption\n (Using Customer-Provided Encryption Keys) in the Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

", + "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the customer-provided encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

\n

If you encrypt an object by using server-side encryption with customer-provided\n encryption keys (SSE-C) when you store the object in Amazon S3, then when you GET the object,\n you must use the following headers:

\n
    \n
  • \n

    \n x-amz-server-side-encryption-customer-algorithm\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key-MD5\n

    \n
  • \n
\n

For more information about SSE-C, see Server-Side Encryption\n (Using Customer-Provided Encryption Keys) in the Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, @@ -21884,7 +23921,6 @@ "PartNumber": { "target": "com.amazonaws.s3#PartNumber", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Part number of the object being read. This is a positive integer between 1 and 10,000.\n Effectively performs a 'ranged' GET request for the part specified. Useful for downloading\n just a part of an object.

", "smithy.api#httpQuery": "partNumber" } @@ -21892,7 +23928,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -21909,10 +23945,7 @@ } }, "com.amazonaws.s3#GetObjectResponseStatusCode": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#GetObjectRetention": { "type": "operation", @@ -21923,7 +23956,7 @@ "target": "com.amazonaws.s3#GetObjectRetentionOutput" }, "traits": { - "smithy.api#documentation": "

Retrieves an object's retention settings. For more information, see Locking\n Objects.

\n

This action is not supported by Amazon S3 on Outposts.

\n

The following action is related to GetObjectRetention:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Retrieves an object's retention settings. For more information, see Locking\n Objects.

\n

This functionality is not supported for Amazon S3 on Outposts.

\n

The following action is related to GetObjectRetention:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}/{Key+}?retention", @@ -21952,7 +23985,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the object whose retention settings you want to retrieve.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the object whose retention settings you want to retrieve.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -21984,7 +24017,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -22002,7 +24035,7 @@ "target": "com.amazonaws.s3#GetObjectTaggingOutput" }, "traits": { - "smithy.api#documentation": "

Returns the tag-set of an object. You send the GET request against the tagging\n subresource associated with the object.

\n

To use this operation, you must have permission to perform the\n s3:GetObjectTagging action. By default, the GET action returns information\n about current version of an object. For a versioned bucket, you can have multiple versions\n of an object in your bucket. To retrieve tags of any other version, use the versionId query\n parameter. You also need permission for the s3:GetObjectVersionTagging\n action.

\n

By default, the bucket owner has this permission and can grant this permission to\n others.

\n

For information about the Amazon S3 object tagging feature, see Object Tagging.

\n

The following actions are related to GetObjectTagging:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns the tag-set of an object. You send the GET request against the tagging\n subresource associated with the object.

\n

To use this operation, you must have permission to perform the\n s3:GetObjectTagging action. By default, the GET action returns information\n about current version of an object. For a versioned bucket, you can have multiple versions\n of an object in your bucket. To retrieve tags of any other version, use the versionId query\n parameter. You also need permission for the s3:GetObjectVersionTagging\n action.

\n

By default, the bucket owner has this permission and can grant this permission to\n others.

\n

For information about the Amazon S3 object tagging feature, see Object Tagging.

\n

The following actions are related to GetObjectTagging:

\n ", "smithy.api#examples": [ { "title": "To retrieve tag set of an object", @@ -22062,7 +24095,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the object for which to get the tagging information.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the object for which to get the tagging information.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -22088,7 +24121,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -22112,7 +24145,7 @@ "target": "com.amazonaws.s3#GetObjectTorrentOutput" }, "traits": { - "smithy.api#documentation": "

Returns torrent files from a bucket. BitTorrent can save you bandwidth when you're\n distributing large files.

\n \n

You can get torrent only for objects that are less than 5 GB in size, and that are\n not encrypted using server-side encryption with a customer-provided encryption\n key.

\n
\n

To use GET, you must have READ access to the object.

\n

This action is not supported by Amazon S3 on Outposts.

\n

The following action is related to GetObjectTorrent:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns torrent files from a bucket. BitTorrent can save you bandwidth when you're\n distributing large files.

\n \n

You can get torrent only for objects that are less than 5 GB in size, and that are\n not encrypted using server-side encryption with a customer-provided encryption\n key.

\n
\n

To use GET, you must have READ access to the object.

\n

This functionality is not supported for Amazon S3 on Outposts.

\n

The following action is related to GetObjectTorrent:

\n ", "smithy.api#examples": [ { "title": "To retrieve torrent files for an object", @@ -22184,7 +24217,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -22202,11 +24235,16 @@ "target": "com.amazonaws.s3#GetPublicAccessBlockOutput" }, "traits": { - "smithy.api#documentation": "

Retrieves the PublicAccessBlock configuration for an Amazon S3 bucket. To use\n this operation, you must have the s3:GetBucketPublicAccessBlock permission.\n For more information about Amazon S3 permissions, see Specifying Permissions in a\n Policy.

\n \n

When Amazon S3 evaluates the PublicAccessBlock configuration for a bucket or\n an object, it checks the PublicAccessBlock configuration for both the\n bucket (or the bucket that contains the object) and the bucket owner's account. If the\n PublicAccessBlock settings are different between the bucket and the\n account, Amazon S3 uses the most restrictive combination of the bucket-level and\n account-level settings.

\n
\n

For more information about when Amazon S3 considers a bucket or an object public, see The Meaning of \"Public\".

\n

The following operations are related to GetPublicAccessBlock:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Retrieves the PublicAccessBlock configuration for an Amazon S3 bucket. To use\n this operation, you must have the s3:GetBucketPublicAccessBlock permission.\n For more information about Amazon S3 permissions, see Specifying Permissions in a\n Policy.

\n \n

When Amazon S3 evaluates the PublicAccessBlock configuration for a bucket or\n an object, it checks the PublicAccessBlock configuration for both the\n bucket (or the bucket that contains the object) and the bucket owner's account. If the\n PublicAccessBlock settings are different between the bucket and the\n account, Amazon S3 uses the most restrictive combination of the bucket-level and\n account-level settings.

\n
\n

For more information about when Amazon S3 considers a bucket or an object public, see The Meaning of \"Public\".

\n

The following operations are related to GetPublicAccessBlock:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?publicAccessBlock", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -22242,7 +24280,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -22361,7 +24399,7 @@ "target": "com.amazonaws.s3#HeadBucketRequest" }, "output": { - "target": "smithy.api#Unit" + "target": "com.amazonaws.s3#HeadBucketOutput" }, "errors": [ { @@ -22369,7 +24407,7 @@ } ], "traits": { - "smithy.api#documentation": "

This action is useful to determine if a bucket exists and you have permission to access\n it. The action returns a 200 OK if the bucket exists and you have permission\n to access it.

\n

If the bucket does not exist or you do not have permission to access it, the\n HEAD request returns a generic 400 Bad Request, 403\n Forbidden or 404 Not Found code. A message body is not included, so\n you cannot determine the exception beyond these error codes.

\n

To use this operation, you must have permissions to perform the\n s3:ListBucket action. The bucket owner has this permission by default and\n can grant this permission to others. For more information about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

To use this API operation against an access point, you must provide the alias of the access point in\n place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct\n requests to the access point hostname. The access point hostname takes the form\n AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com.\n When using the Amazon Web Services SDKs, you provide the ARN in place of the bucket name. For more\n information, see Using access points.

\n

To use this API operation against an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

", + "smithy.api#documentation": "

You can use this operation to determine if a bucket exists and if you have permission to access it. The action returns a 200 OK if the bucket exists and you have permission\n to access it.

\n

If the bucket does not exist or you do not have permission to access it, the\n HEAD request returns a generic 400 Bad Request, 403\n Forbidden or 404 Not Found code. A message body is not included, so\n you cannot determine the exception beyond these error codes.

\n \n

\n Directory buckets - You must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Authentication and authorization
\n
\n

All HeadBucket requests must be authenticated and signed by using IAM credentials (access key ID and secret access key for the IAM identities). All headers with the x-amz- prefix, including\n x-amz-copy-source, must be signed. For more information, see REST Authentication.

\n

\n Directory bucket - You must use IAM credentials to authenticate and authorize your access to the HeadBucket API operation, instead of using the \n temporary security credentials through the CreateSession API operation.

\n

Amazon Web Services CLI or SDKs handles authentication and authorization on your behalf.

\n
\n
Permissions
\n
\n

\n \n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
", "smithy.api#examples": [ { "title": "To determine if bucket exists", @@ -22416,13 +24454,49 @@ } } }, + "com.amazonaws.s3#HeadBucketOutput": { + "type": "structure", + "members": { + "BucketLocationType": { + "target": "com.amazonaws.s3#LocationType", + "traits": { + "smithy.api#documentation": "

The type of location where the bucket is created.

\n \n

This functionality is only supported by directory buckets.

\n
", + "smithy.api#httpHeader": "x-amz-bucket-location-type" + } + }, + "BucketLocationName": { + "target": "com.amazonaws.s3#BucketLocationName", + "traits": { + "smithy.api#documentation": "

The name of the location where the bucket will be created.

\n

For directory buckets, the AZ ID of the Availability Zone where the bucket is created. An example AZ ID value is usw2-az2.

\n \n

This functionality is only supported by directory buckets.

\n
", + "smithy.api#httpHeader": "x-amz-bucket-location-name" + } + }, + "BucketRegion": { + "target": "com.amazonaws.s3#Region", + "traits": { + "smithy.api#documentation": "

The Region that the bucket is located.

\n \n

This functionality is not supported for directory buckets.

\n
", + "smithy.api#httpHeader": "x-amz-bucket-region" + } + }, + "AccessPointAlias": { + "target": "com.amazonaws.s3#AccessPointAlias", + "traits": { + "smithy.api#documentation": "

Indicates whether the bucket name used in the request is an access point alias.

\n \n

This functionality is not supported for directory buckets.

\n
", + "smithy.api#httpHeader": "x-amz-access-point-alias" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, "com.amazonaws.s3#HeadBucketRequest": { "type": "structure", "members": { "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with an Object Lambda access point, provide the alias of the Object Lambda access point in place of the\n bucket name. If the Object Lambda access point alias in a request is not valid, the error code\n InvalidAccessPointAliasError is returned. For more information about\n InvalidAccessPointAliasError, see List of Error\n Codes.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

\n Object Lambda access points - When you use this API operation with an Object Lambda access point, provide the alias of the Object Lambda access point in place of the bucket name. \nIf the Object Lambda access point alias in a request is not valid, the error code InvalidAccessPointAliasError is returned. \nFor more information about InvalidAccessPointAliasError, see List of\n Error Codes.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -22433,7 +24507,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -22456,7 +24530,7 @@ } ], "traits": { - "smithy.api#documentation": "

The HEAD action retrieves metadata from an object without returning the\n object itself. This action is useful if you're only interested in an object's metadata. To\n use HEAD, you must have READ access to the object.

\n

A HEAD request has the same options as a GET action on an\n object. The response is identical to the GET response except that there is no\n response body. Because of this, if the HEAD request generates an error, it\n returns a generic 400 Bad Request, 403 Forbidden or 404 Not\n Found code. It is not possible to retrieve the exact exception beyond these error\n codes.

\n

If you encrypt an object by using server-side encryption with customer-provided\n encryption keys (SSE-C) when you store the object in Amazon S3, then when you retrieve the\n metadata from the object, you must use the following headers:

\n
    \n
  • \n

    \n x-amz-server-side-encryption-customer-algorithm\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key-MD5\n

    \n
  • \n
\n

For more information about SSE-C, see Server-Side Encryption\n (Using Customer-Provided Encryption Keys).

\n \n
    \n
  • \n

    Encryption request headers, like x-amz-server-side-encryption,\n should not be sent for GET requests if your object uses server-side\n encryption with Key Management Service (KMS) keys (SSE-KMS), dual-layer server-side\n encryption with Amazon Web Services KMS keys (DSSE-KMS), or server-side encryption with Amazon S3\n managed encryption keys (SSE-S3). If your object does use these types of keys,\n you’ll get an HTTP 400 Bad Request error.

    \n
  • \n
  • \n

    The last modified property in this case is the creation date of the\n object.

    \n
  • \n
\n
\n

Request headers are limited to 8 KB in size. For more information, see Common\n Request Headers.

\n

Consider the following when using request headers:

\n
    \n
  • \n

    Consideration 1 – If both of the If-Match and\n If-Unmodified-Since headers are present in the request as\n follows:

    \n
      \n
    • \n

      \n If-Match condition evaluates to true, and;

      \n
    • \n
    • \n

      \n If-Unmodified-Since condition evaluates to\n false;

      \n
    • \n
    \n

    Then Amazon S3 returns 200 OK and the data requested.

    \n
  • \n
  • \n

    Consideration 2 – If both of the If-None-Match and\n If-Modified-Since headers are present in the request as\n follows:

    \n
      \n
    • \n

      \n If-None-Match condition evaluates to false,\n and;

      \n
    • \n
    • \n

      \n If-Modified-Since condition evaluates to\n true;

      \n
    • \n
    \n

    Then Amazon S3 returns the 304 Not Modified response code.

    \n
  • \n
\n

For more information about conditional requests, see RFC 7232.

\n
\n
Permissions
\n
\n

You need the relevant read object (or version) permission for this operation.\n For more information, see Actions, resources, and condition\n keys for Amazon S3. If the object you request doesn't exist, the error that\n Amazon S3 returns depends on whether you also have the s3:ListBucket permission.

\n
    \n
  • \n

    If you have the s3:ListBucket permission on the bucket, Amazon S3\n returns an HTTP status code 404 error.

    \n
  • \n
  • \n

    If you don’t have the s3:ListBucket permission, Amazon S3 returns\n an HTTP status code 403 error.

    \n
  • \n
\n
\n
\n

The following actions are related to HeadObject:

\n ", + "smithy.api#documentation": "

The HEAD operation retrieves metadata from an object without returning the\n object itself. This operation is useful if you're interested only in an object's metadata.

\n

A HEAD request has the same options as a GET operation on an\n object. The response is identical to the GET response except that there is no\n response body. Because of this, if the HEAD request generates an error, it\n returns a generic code, such as 400 Bad Request, 403 Forbidden, 404 Not\n Found, 405 Method Not Allowed, 412 Precondition Failed, or 304 Not Modified. \n It's not possible to retrieve the exact exception of these error codes.

\n

Request headers are limited to 8 KB in size. For more information, see Common\n Request Headers.

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n

\n
    \n
  • \n

    \n General purpose bucket permissions - To\n use HEAD, you must have the s3:GetObject permission. You need the relevant read object (or version) permission for this operation.\n For more information, see Actions, resources, and condition\n keys for Amazon S3 in the Amazon S3\n User Guide.

    \n

    If the object you request doesn't exist, the error that\n Amazon S3 returns depends on whether you also have the s3:ListBucket permission.

    \n
      \n
    • \n

      If you have the s3:ListBucket permission on the bucket, Amazon S3\n returns an HTTP status code 404 Not Found error.

      \n
    • \n
    • \n

      If you don’t have the s3:ListBucket permission, Amazon S3 returns\n an HTTP status code 403 Forbidden error.

      \n
    • \n
    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation on a directory bucket, we recommend that you use the \n CreateSession\n API operation for session-based authorization. Specifically, you grant the s3express:CreateSession permission to the directory bucket in a bucket policy or an IAM identity-based policy. Then, you make the CreateSession API call on the bucket to obtain a session token. With the session token in your request header, you can make API requests to this operation. After the session token expires, you make another CreateSession API call to generate a new session token for use. \nAmazon Web Services CLI or SDKs create session and refresh the session token automatically to avoid service interruptions when a session expires. For more information about authorization, see \n CreateSession\n .

    \n
  • \n
\n
\n
Encryption
\n
\n \n

Encryption request headers, like x-amz-server-side-encryption,\n should not be sent for HEAD requests if your object uses server-side\n encryption with Key Management Service (KMS) keys (SSE-KMS), dual-layer server-side\n encryption with Amazon Web Services KMS keys (DSSE-KMS), or server-side encryption with Amazon S3\n managed encryption keys (SSE-S3). The x-amz-server-side-encryption header is used when you PUT an object to S3 and want to specify the encryption method. \n If you include this header in a HEAD request for an object that uses these types of keys, \n you’ll get an HTTP 400 Bad Request error. It's because the encryption method can't be changed when you retrieve the object.

\n
\n

If you encrypt an object by using server-side encryption with customer-provided\n encryption keys (SSE-C) when you store the object in Amazon S3, then when you retrieve the\n metadata from the object, you must use the following headers to provide the encryption key for the server to be able to retrieve the object's metadata. The headers are:

\n
    \n
  • \n

    \n x-amz-server-side-encryption-customer-algorithm\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key\n

    \n
  • \n
  • \n

    \n x-amz-server-side-encryption-customer-key-MD5\n

    \n
  • \n
\n

For more information about SSE-C, see Server-Side Encryption\n (Using Customer-Provided Encryption Keys) in the Amazon S3\n User Guide.

\n \n

\n Directory bucket permissions - For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

\n
\n
\n
Versioning
\n
\n
    \n
  • \n

    If the current version of the object is a delete marker, Amazon S3 behaves as if the object was deleted and includes x-amz-delete-marker: true in the response.

    \n
  • \n
  • \n

    If the specified version is a delete marker, the response returns a 405 Method Not Allowed error and the Last-Modified: timestamp response header.

    \n
  • \n
\n \n
    \n
  • \n

    \n Directory buckets - Delete marker is not supported by directory buckets.

    \n
  • \n
  • \n

    \n Directory buckets - S3 Versioning isn't enabled and supported for directory buckets. For this API operation, only the null value of the version ID is supported by directory buckets. You can only specify null \n to the versionId query parameter in the request.

    \n
  • \n
\n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

The following actions are related to HeadObject:

\n ", "smithy.api#http": { "method": "HEAD", "uri": "/{Bucket}/{Key+}", @@ -22500,8 +24574,7 @@ "DeleteMarker": { "target": "com.amazonaws.s3#DeleteMarker", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Specifies whether the object retrieved was (true) or was not (false) a Delete Marker. If\n false, this response header does not appear in the response.

", + "smithy.api#documentation": "

Specifies whether the object retrieved was (true) or was not (false) a Delete Marker. If\n false, this response header does not appear in the response.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-delete-marker" } }, @@ -22515,35 +24588,34 @@ "Expiration": { "target": "com.amazonaws.s3#Expiration", "traits": { - "smithy.api#documentation": "

If the object expiration is configured (see PUT Bucket lifecycle), the response includes\n this header. It includes the expiry-date and rule-id key-value\n pairs providing object expiration information. The value of the rule-id is\n URL-encoded.

", + "smithy.api#documentation": "

If the object expiration is configured (see \n PutBucketLifecycleConfiguration\n ), the response includes\n this header. It includes the expiry-date and rule-id key-value\n pairs providing object expiration information. The value of the rule-id is\n URL-encoded.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-expiration" } }, "Restore": { "target": "com.amazonaws.s3#Restore", "traits": { - "smithy.api#documentation": "

If the object is an archived object (an object whose storage class is GLACIER), the\n response includes this header if either the archive restoration is in progress (see RestoreObject or an archive copy is already restored.

\n

If an archive copy is already restored, the header value indicates when Amazon S3 is\n scheduled to delete the object copy. For example:

\n

\n x-amz-restore: ongoing-request=\"false\", expiry-date=\"Fri, 21 Dec 2012 00:00:00\n GMT\"\n

\n

If the object restoration is in progress, the header returns the value\n ongoing-request=\"true\".

\n

For more information about archiving objects, see Transitioning Objects: General Considerations.

", + "smithy.api#documentation": "

If the object is an archived object (an object whose storage class is GLACIER), the\n response includes this header if either the archive restoration is in progress (see RestoreObject or an archive copy is already restored.

\n

If an archive copy is already restored, the header value indicates when Amazon S3 is\n scheduled to delete the object copy. For example:

\n

\n x-amz-restore: ongoing-request=\"false\", expiry-date=\"Fri, 21 Dec 2012 00:00:00\n GMT\"\n

\n

If the object restoration is in progress, the header returns the value\n ongoing-request=\"true\".

\n

For more information about archiving objects, see Transitioning Objects: General Considerations.

\n \n

This functionality is not supported for directory buckets. Only the S3 Express One Zone storage class is supported by directory buckets to store objects.

\n
", "smithy.api#httpHeader": "x-amz-restore" } }, "ArchiveStatus": { "target": "com.amazonaws.s3#ArchiveStatus", "traits": { - "smithy.api#documentation": "

The archive state of the head object.

", + "smithy.api#documentation": "

The archive state of the head object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-archive-status" } }, "LastModified": { "target": "com.amazonaws.s3#LastModified", "traits": { - "smithy.api#documentation": "

Creation date of the object.

", + "smithy.api#documentation": "

Date and time when the object was last modified.

", "smithy.api#httpHeader": "Last-Modified" } }, "ContentLength": { "target": "com.amazonaws.s3#ContentLength", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Size of the body in bytes.

", "smithy.api#httpHeader": "Content-Length" } @@ -22551,28 +24623,28 @@ "ChecksumCRC32": { "target": "com.amazonaws.s3#ChecksumCRC32", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-crc32" } }, "ChecksumCRC32C": { "target": "com.amazonaws.s3#ChecksumCRC32C", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-crc32c" } }, "ChecksumSHA1": { "target": "com.amazonaws.s3#ChecksumSHA1", "traits": { - "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. When you use the API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-sha1" } }, "ChecksumSHA256": { "target": "com.amazonaws.s3#ChecksumSHA256", "traits": { - "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-sha256" } }, @@ -22586,15 +24658,14 @@ "MissingMeta": { "target": "com.amazonaws.s3#MissingMeta", "traits": { - "smithy.api#default": 0, - "smithy.api#documentation": "

This is set to the number of metadata entries not returned in x-amz-meta\n headers. This can happen if you create metadata using an API like SOAP that supports more\n flexible metadata than the REST API. For example, using SOAP, you can create metadata whose\n values are not legal HTTP headers.

", + "smithy.api#documentation": "

This is set to the number of metadata entries not returned in x-amz-meta\n headers. This can happen if you create metadata using an API like SOAP that supports more\n flexible metadata than the REST API. For example, using SOAP, you can create metadata whose\n values are not legal HTTP headers.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-missing-meta" } }, "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

Version of the object.

", + "smithy.api#documentation": "

Version ID of the object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-version-id" } }, @@ -22615,7 +24686,7 @@ "ContentEncoding": { "target": "com.amazonaws.s3#ContentEncoding", "traits": { - "smithy.api#documentation": "

Specifies what content encodings have been applied to the object and thus what decoding\n mechanisms must be applied to obtain the media-type referenced by the Content-Type header\n field.

", + "smithy.api#documentation": "

Indicates what content encodings have been applied to the object and thus what decoding\n mechanisms must be applied to obtain the media-type referenced by the Content-Type header\n field.

", "smithy.api#httpHeader": "Content-Encoding" } }, @@ -22643,14 +24714,14 @@ "WebsiteRedirectLocation": { "target": "com.amazonaws.s3#WebsiteRedirectLocation", "traits": { - "smithy.api#documentation": "

If the bucket is configured as a website, redirects requests for this object to another\n object in the same bucket or to an external URL. Amazon S3 stores the value of this header in\n the object metadata.

", + "smithy.api#documentation": "

If the bucket is configured as a website, redirects requests for this object to another\n object in the same bucket or to an external URL. Amazon S3 stores the value of this header in\n the object metadata.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-website-redirect-location" } }, "ServerSideEncryption": { "target": "com.amazonaws.s3#ServerSideEncryption", "traits": { - "smithy.api#documentation": "

The server-side encryption algorithm used when storing this object in Amazon S3 (for example,\n AES256, aws:kms, aws:kms:dsse).

", + "smithy.api#documentation": "

The server-side encryption algorithm used when you store this object in Amazon S3 (for example,\n AES256, aws:kms, aws:kms:dsse).

\n \n

For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption" } }, @@ -22664,36 +24735,35 @@ "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header confirming the encryption algorithm used.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to confirm the encryption algorithm that's used.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide round-trip message integrity verification of\n the customer-provided encryption key.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide the round-trip message integrity verification of\n the customer-provided encryption key.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, "SSEKMSKeyId": { "target": "com.amazonaws.s3#SSEKMSKeyId", "traits": { - "smithy.api#documentation": "

If present, specifies the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n that was used for the object.

", + "smithy.api#documentation": "

If present, indicates the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n that was used for the object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-aws-kms-key-id" } }, "BucketKeyEnabled": { "target": "com.amazonaws.s3#BucketKeyEnabled", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Indicates whether the object uses an S3 Bucket Key for server-side encryption with\n Key Management Service (KMS) keys (SSE-KMS).

", + "smithy.api#documentation": "

Indicates whether the object uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-bucket-key-enabled" } }, "StorageClass": { "target": "com.amazonaws.s3#StorageClass", "traits": { - "smithy.api#documentation": "

Provides storage class information of the object. Amazon S3 returns this header for all\n objects except for S3 Standard storage class objects.

\n

For more information, see Storage Classes.

", + "smithy.api#documentation": "

Provides storage class information of the object. Amazon S3 returns this header for all\n objects except for S3 Standard storage class objects.

\n

For more information, see Storage Classes.

\n \n

\n Directory buckets - Only the S3 Express One Zone storage class is supported by directory buckets to store objects.

\n
", "smithy.api#httpHeader": "x-amz-storage-class" } }, @@ -22706,14 +24776,13 @@ "ReplicationStatus": { "target": "com.amazonaws.s3#ReplicationStatus", "traits": { - "smithy.api#documentation": "

Amazon S3 can return this header if your request involves a bucket that is either a source or\n a destination in a replication rule.

\n

In replication, you have a source bucket on which you configure replication and\n destination bucket or buckets where Amazon S3 stores object replicas. When you request an object\n (GetObject) or object metadata (HeadObject) from these\n buckets, Amazon S3 will return the x-amz-replication-status header in the response\n as follows:

\n
    \n
  • \n

    \n If requesting an object from the source bucket,\n Amazon S3 will return the x-amz-replication-status header if the object in\n your request is eligible for replication.

    \n

    For example, suppose that in your replication configuration, you specify object\n prefix TaxDocs requesting Amazon S3 to replicate objects with key prefix\n TaxDocs. Any objects you upload with this key name prefix, for\n example TaxDocs/document1.pdf, are eligible for replication. For any\n object request with this key name prefix, Amazon S3 will return the\n x-amz-replication-status header with value PENDING, COMPLETED or\n FAILED indicating object replication status.

    \n
  • \n
  • \n

    \n If requesting an object from a destination\n bucket, Amazon S3 will return the x-amz-replication-status header\n with value REPLICA if the object in your request is a replica that Amazon S3 created and\n there is no replica modification replication in progress.

    \n
  • \n
  • \n

    \n When replicating objects to multiple destination\n buckets, the x-amz-replication-status header acts\n differently. The header of the source object will only return a value of COMPLETED\n when replication is successful to all destinations. The header will remain at value\n PENDING until replication has completed for all destinations. If one or more\n destinations fails replication the header will return FAILED.

    \n
  • \n
\n

For more information, see Replication.

", + "smithy.api#documentation": "

Amazon S3 can return this header if your request involves a bucket that is either a source or\n a destination in a replication rule.

\n

In replication, you have a source bucket on which you configure replication and\n destination bucket or buckets where Amazon S3 stores object replicas. When you request an object\n (GetObject) or object metadata (HeadObject) from these\n buckets, Amazon S3 will return the x-amz-replication-status header in the response\n as follows:

\n
    \n
  • \n

    \n If requesting an object from the source bucket,\n Amazon S3 will return the x-amz-replication-status header if the object in\n your request is eligible for replication.

    \n

    For example, suppose that in your replication configuration, you specify object\n prefix TaxDocs requesting Amazon S3 to replicate objects with key prefix\n TaxDocs. Any objects you upload with this key name prefix, for\n example TaxDocs/document1.pdf, are eligible for replication. For any\n object request with this key name prefix, Amazon S3 will return the\n x-amz-replication-status header with value PENDING, COMPLETED or\n FAILED indicating object replication status.

    \n
  • \n
  • \n

    \n If requesting an object from a destination\n bucket, Amazon S3 will return the x-amz-replication-status header\n with value REPLICA if the object in your request is a replica that Amazon S3 created and\n there is no replica modification replication in progress.

    \n
  • \n
  • \n

    \n When replicating objects to multiple destination\n buckets, the x-amz-replication-status header acts\n differently. The header of the source object will only return a value of COMPLETED\n when replication is successful to all destinations. The header will remain at value\n PENDING until replication has completed for all destinations. If one or more\n destinations fails replication the header will return FAILED.

    \n
  • \n
\n

For more information, see Replication.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-replication-status" } }, "PartsCount": { "target": "com.amazonaws.s3#PartsCount", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The count of parts this object has. This value is only returned if you specify\n partNumber in your request and the object was uploaded as a multipart\n upload.

", "smithy.api#httpHeader": "x-amz-mp-parts-count" } @@ -22721,21 +24790,21 @@ "ObjectLockMode": { "target": "com.amazonaws.s3#ObjectLockMode", "traits": { - "smithy.api#documentation": "

The Object Lock mode, if any, that's in effect for this object. This header is only\n returned if the requester has the s3:GetObjectRetention permission. For more\n information about S3 Object Lock, see Object Lock.

", + "smithy.api#documentation": "

The Object Lock mode, if any, that's in effect for this object. This header is only\n returned if the requester has the s3:GetObjectRetention permission. For more\n information about S3 Object Lock, see Object Lock.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-mode" } }, "ObjectLockRetainUntilDate": { "target": "com.amazonaws.s3#ObjectLockRetainUntilDate", "traits": { - "smithy.api#documentation": "

The date and time when the Object Lock retention period expires. This header is only\n returned if the requester has the s3:GetObjectRetention permission.

", + "smithy.api#documentation": "

The date and time when the Object Lock retention period expires. This header is only\n returned if the requester has the s3:GetObjectRetention permission.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-retain-until-date" } }, "ObjectLockLegalHoldStatus": { "target": "com.amazonaws.s3#ObjectLockLegalHoldStatus", "traits": { - "smithy.api#documentation": "

Specifies whether a legal hold is in effect for this object. This header is only\n returned if the requester has the s3:GetObjectLegalHold permission. This\n header is not returned if the specified version of this object has never had a legal hold\n applied. For more information about S3 Object Lock, see Object Lock.

", + "smithy.api#documentation": "

Specifies whether a legal hold is in effect for this object. This header is only\n returned if the requester has the s3:GetObjectLegalHold permission. This\n header is not returned if the specified version of this object has never had a legal hold\n applied. For more information about S3 Object Lock, see Object Lock.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-legal-hold" } } @@ -22750,7 +24819,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket containing the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket that contains the object.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -22761,28 +24830,28 @@ "IfMatch": { "target": "com.amazonaws.s3#IfMatch", "traits": { - "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is the same as the one specified;\n otherwise, return a 412 (precondition failed) error.

", + "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is the same as the one specified;\n otherwise, return a 412 (precondition failed) error.

\n

If both of the If-Match and\n If-Unmodified-Since headers are present in the request as\n follows:

\n
    \n
  • \n

    \n If-Match condition evaluates to true, and;

    \n
  • \n
  • \n

    \n If-Unmodified-Since condition evaluates to\n false;

    \n
  • \n
\n

Then Amazon S3 returns 200 OK and the data requested.

\n

For more information about conditional requests, see RFC 7232.

", "smithy.api#httpHeader": "If-Match" } }, "IfModifiedSince": { "target": "com.amazonaws.s3#IfModifiedSince", "traits": { - "smithy.api#documentation": "

Return the object only if it has been modified since the specified time; otherwise,\n return a 304 (not modified) error.

", + "smithy.api#documentation": "

Return the object only if it has been modified since the specified time; otherwise,\n return a 304 (not modified) error.

\n

If both of the If-None-Match and\n If-Modified-Since headers are present in the request as\n follows:

\n
    \n
  • \n

    \n If-None-Match condition evaluates to false,\n and;

    \n
  • \n
  • \n

    \n If-Modified-Since condition evaluates to\n true;

    \n
  • \n
\n

Then Amazon S3 returns the 304 Not Modified response code.

\n

For more information about conditional requests, see RFC 7232.

", "smithy.api#httpHeader": "If-Modified-Since" } }, "IfNoneMatch": { "target": "com.amazonaws.s3#IfNoneMatch", "traits": { - "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is different from the one specified;\n otherwise, return a 304 (not modified) error.

", + "smithy.api#documentation": "

Return the object only if its entity tag (ETag) is different from the one specified;\n otherwise, return a 304 (not modified) error.

\n

If both of the If-None-Match and\n If-Modified-Since headers are present in the request as\n follows:

\n
    \n
  • \n

    \n If-None-Match condition evaluates to false,\n and;

    \n
  • \n
  • \n

    \n If-Modified-Since condition evaluates to\n true;

    \n
  • \n
\n

Then Amazon S3 returns the 304 Not Modified response code.

\n

For more information about conditional requests, see RFC 7232.

", "smithy.api#httpHeader": "If-None-Match" } }, "IfUnmodifiedSince": { "target": "com.amazonaws.s3#IfUnmodifiedSince", "traits": { - "smithy.api#documentation": "

Return the object only if it has not been modified since the specified time; otherwise,\n return a 412 (precondition failed) error.

", + "smithy.api#documentation": "

Return the object only if it has not been modified since the specified time; otherwise,\n return a 412 (precondition failed) error.

\n

If both of the If-Match and\n If-Unmodified-Since headers are present in the request as\n follows:

\n
    \n
  • \n

    \n If-Match condition evaluates to true, and;

    \n
  • \n
  • \n

    \n If-Unmodified-Since condition evaluates to\n false;

    \n
  • \n
\n

Then Amazon S3 returns 200 OK and the data requested.

\n

For more information about conditional requests, see RFC 7232.

", "smithy.api#httpHeader": "If-Unmodified-Since" } }, @@ -22791,7 +24860,10 @@ "traits": { "smithy.api#documentation": "

The object key.

", "smithy.api#httpLabel": {}, - "smithy.api#required": {} + "smithy.api#required": {}, + "smithy.rules#contextParam": { + "name": "Key" + } } }, "Range": { @@ -22804,28 +24876,28 @@ "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

VersionId used to reference a specific version of the object.

", + "smithy.api#documentation": "

Version ID used to reference a specific version of the object.

\n \n

For directory buckets in this API operation, only the null value of the version ID is supported.

\n
", "smithy.api#httpQuery": "versionId" } }, "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

Specifies the algorithm to use to when encrypting the object (for example,\n AES256).

", + "smithy.api#documentation": "

Specifies the algorithm to use when encrypting the object (for example,\n AES256).

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKey": { "target": "com.amazonaws.s3#SSECustomerKey", "traits": { - "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header.

", + "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

", + "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, @@ -22838,7 +24910,6 @@ "PartNumber": { "target": "com.amazonaws.s3#PartNumber", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Part number of the object being read. This is a positive integer between 1 and 10,000.\n Effectively performs a 'ranged' HEAD request for the part specified. Useful querying about\n the size of the part and the number of parts in this object.

", "smithy.api#httpQuery": "partNumber" } @@ -22846,7 +24917,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -22910,13 +24981,13 @@ "ID": { "target": "com.amazonaws.s3#ID", "traits": { - "smithy.api#documentation": "

If the principal is an Amazon Web Services account, it provides the Canonical User ID. If the\n principal is an IAM User, it provides a user ARN value.

" + "smithy.api#documentation": "

If the principal is an Amazon Web Services account, it provides the Canonical User ID. If the\n principal is an IAM User, it provides a user ARN value.

\n \n

\n Directory buckets - If the principal is an Amazon Web Services account, it provides the Amazon Web Services account ID. If the\n principal is an IAM User, it provides a user ARN value.

\n
" } }, "DisplayName": { "target": "com.amazonaws.s3#DisplayName", "traits": { - "smithy.api#documentation": "

Name of the Principal.

" + "smithy.api#documentation": "

Name of the Principal.

\n \n

This functionality is not supported for directory buckets.

\n
" } } }, @@ -23039,10 +25110,7 @@ } }, "com.amazonaws.s3#IntelligentTieringDays": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#IntelligentTieringFilter": { "type": "structure", @@ -23098,8 +25166,9 @@ } }, "traits": { - "smithy.api#documentation": "

Object is archived and inaccessible until restored.

", - "smithy.api#error": "client" + "smithy.api#documentation": "

Object is archived and inaccessible until restored.

\n

If the object you are retrieving is stored in the S3 Glacier Flexible Retrieval storage class, the \n S3 Glacier Deep Archive storage class, the S3 Intelligent-Tiering Archive Access tier, or the \n S3 Intelligent-Tiering Deep Archive Access tier, before you can retrieve the object you must first restore a\n copy using RestoreObject. Otherwise, this operation returns an\n InvalidObjectState error. For information about restoring archived objects,\n see Restoring\n Archived Objects in the Amazon S3 User Guide.

", + "smithy.api#error": "client", + "smithy.api#httpError": 403 } }, "com.amazonaws.s3#InventoryConfiguration": { @@ -23115,7 +25184,6 @@ "IsEnabled": { "target": "com.amazonaws.s3#IsEnabled", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Specifies whether the inventory is enabled or disabled. If set to True, an\n inventory list is generated. If set to False, no inventory list is\n generated.

", "smithy.api#required": {} } @@ -23436,34 +25504,19 @@ } }, "com.amazonaws.s3#IsEnabled": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#IsLatest": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#IsPublic": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#IsRestoreInProgress": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#IsTruncated": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#JSONInput": { "type": "structure", @@ -23514,10 +25567,7 @@ "type": "string" }, "com.amazonaws.s3#KeyCount": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#KeyMarker": { "type": "string" @@ -23580,14 +25630,12 @@ "Days": { "target": "com.amazonaws.s3#Days", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Indicates the lifetime, in days, of the objects that are subject to the rule. The value\n must be a non-zero positive integer.

" } }, "ExpiredObjectDeleteMarker": { "target": "com.amazonaws.s3#ExpiredObjectDeleteMarker", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Indicates whether Amazon S3 will remove a delete marker with no noncurrent versions. If set\n to true, the delete marker will be expired; if set to false the policy takes no action.\n This cannot be specified with Days or Date in a Lifecycle Expiration Policy.

" } } @@ -23678,14 +25726,12 @@ "ObjectSizeGreaterThan": { "target": "com.amazonaws.s3#ObjectSizeGreaterThanBytes", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Minimum object size to which the rule applies.

" } }, "ObjectSizeLessThan": { "target": "com.amazonaws.s3#ObjectSizeLessThanBytes", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Maximum object size to which the rule applies.

" } } @@ -23744,11 +25790,16 @@ "target": "com.amazonaws.s3#ListBucketAnalyticsConfigurationsOutput" }, "traits": { - "smithy.api#documentation": "

Lists the analytics configurations for the bucket. You can have up to 1,000 analytics\n configurations per bucket.

\n

This action supports list pagination and does not return more than 100 configurations at\n a time. You should always check the IsTruncated element in the response. If\n there are no more configurations to list, IsTruncated is set to false. If\n there are more configurations to list, IsTruncated is set to true, and there\n will be a value in NextContinuationToken. You use the\n NextContinuationToken value to continue the pagination of the list by\n passing the value in continuation-token in the request to GET the next\n page.

\n

To use this operation, you must have permissions to perform the\n s3:GetAnalyticsConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about Amazon S3 analytics feature, see Amazon S3 Analytics – Storage Class\n Analysis.

\n

The following operations are related to\n ListBucketAnalyticsConfigurations:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Lists the analytics configurations for the bucket. You can have up to 1,000 analytics\n configurations per bucket.

\n

This action supports list pagination and does not return more than 100 configurations at\n a time. You should always check the IsTruncated element in the response. If\n there are no more configurations to list, IsTruncated is set to false. If\n there are more configurations to list, IsTruncated is set to true, and there\n will be a value in NextContinuationToken. You use the\n NextContinuationToken value to continue the pagination of the list by\n passing the value in continuation-token in the request to GET the next\n page.

\n

To use this operation, you must have permissions to perform the\n s3:GetAnalyticsConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about Amazon S3 analytics feature, see Amazon S3 Analytics – Storage Class\n Analysis.

\n

The following operations are related to\n ListBucketAnalyticsConfigurations:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?analytics&x-id=ListBucketAnalyticsConfigurations", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -23758,7 +25809,6 @@ "IsTruncated": { "target": "com.amazonaws.s3#IsTruncated", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Indicates whether the returned list of analytics configurations is complete. A value of\n true indicates that the list is not complete and the NextContinuationToken will be provided\n for a subsequent request.

" } }, @@ -23812,7 +25862,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -23830,11 +25880,16 @@ "target": "com.amazonaws.s3#ListBucketIntelligentTieringConfigurationsOutput" }, "traits": { - "smithy.api#documentation": "

Lists the S3 Intelligent-Tiering configuration from the specified bucket.

\n

The S3 Intelligent-Tiering storage class is designed to optimize storage costs by automatically moving data to the most cost-effective storage access tier, without performance impact or operational overhead. S3 Intelligent-Tiering delivers automatic cost savings in three low latency and high throughput access tiers. To get the lowest storage cost on data that can be accessed in minutes to hours, you can choose to activate additional archiving capabilities.

\n

The S3 Intelligent-Tiering storage class is the ideal storage class for data with unknown, changing, or unpredictable access patterns, independent of object size or retention period. If the size of an object is less than 128 KB, it is not monitored and not eligible for auto-tiering. Smaller objects can be stored, but they are always charged at the Frequent Access tier rates in the S3 Intelligent-Tiering storage class.

\n

For more information, see Storage class for automatically optimizing frequently and infrequently accessed objects.

\n

Operations related to ListBucketIntelligentTieringConfigurations include:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Lists the S3 Intelligent-Tiering configuration from the specified bucket.

\n

The S3 Intelligent-Tiering storage class is designed to optimize storage costs by automatically moving data to the most cost-effective storage access tier, without performance impact or operational overhead. S3 Intelligent-Tiering delivers automatic cost savings in three low latency and high throughput access tiers. To get the lowest storage cost on data that can be accessed in minutes to hours, you can choose to activate additional archiving capabilities.

\n

The S3 Intelligent-Tiering storage class is the ideal storage class for data with unknown, changing, or unpredictable access patterns, independent of object size or retention period. If the size of an object is less than 128 KB, it is not monitored and not eligible for auto-tiering. Smaller objects can be stored, but they are always charged at the Frequent Access tier rates in the S3 Intelligent-Tiering storage class.

\n

For more information, see Storage class for automatically optimizing frequently and infrequently accessed objects.

\n

Operations related to ListBucketIntelligentTieringConfigurations include:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?intelligent-tiering&x-id=ListBucketIntelligentTieringConfigurations", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -23844,7 +25899,6 @@ "IsTruncated": { "target": "com.amazonaws.s3#IsTruncated", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Indicates whether the returned list of analytics configurations is complete. A value of\n true indicates that the list is not complete and the\n NextContinuationToken will be provided for a subsequent request.

" } }, @@ -23908,11 +25962,16 @@ "target": "com.amazonaws.s3#ListBucketInventoryConfigurationsOutput" }, "traits": { - "smithy.api#documentation": "

Returns a list of inventory configurations for the bucket. You can have up to 1,000\n analytics configurations per bucket.

\n

This action supports list pagination and does not return more than 100 configurations at\n a time. Always check the IsTruncated element in the response. If there are no\n more configurations to list, IsTruncated is set to false. If there are more\n configurations to list, IsTruncated is set to true, and there is a value in\n NextContinuationToken. You use the NextContinuationToken value\n to continue the pagination of the list by passing the value in continuation-token in the\n request to GET the next page.

\n

To use this operation, you must have permissions to perform the\n s3:GetInventoryConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about the Amazon S3 inventory feature, see Amazon S3 Inventory\n

\n

The following operations are related to\n ListBucketInventoryConfigurations:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns a list of inventory configurations for the bucket. You can have up to 1,000\n analytics configurations per bucket.

\n

This action supports list pagination and does not return more than 100 configurations at\n a time. Always check the IsTruncated element in the response. If there are no\n more configurations to list, IsTruncated is set to false. If there are more\n configurations to list, IsTruncated is set to true, and there is a value in\n NextContinuationToken. You use the NextContinuationToken value\n to continue the pagination of the list by passing the value in continuation-token in the\n request to GET the next page.

\n

To use this operation, you must have permissions to perform the\n s3:GetInventoryConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about the Amazon S3 inventory feature, see Amazon S3 Inventory\n

\n

The following operations are related to\n ListBucketInventoryConfigurations:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?inventory&x-id=ListBucketInventoryConfigurations", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -23936,7 +25995,6 @@ "IsTruncated": { "target": "com.amazonaws.s3#IsTruncated", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Tells whether the returned list of inventory configurations is complete. A value of true\n indicates that the list is not complete and the NextContinuationToken is provided for a\n subsequent request.

" } }, @@ -23976,7 +26034,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -23994,7 +26052,7 @@ "target": "com.amazonaws.s3#ListBucketMetricsConfigurationsOutput" }, "traits": { - "smithy.api#documentation": "

Lists the metrics configurations for the bucket. The metrics configurations are only for\n the request metrics of the bucket and do not provide information on daily storage metrics.\n You can have up to 1,000 configurations per bucket.

\n

This action supports list pagination and does not return more than 100 configurations at\n a time. Always check the IsTruncated element in the response. If there are no\n more configurations to list, IsTruncated is set to false. If there are more\n configurations to list, IsTruncated is set to true, and there is a value in\n NextContinuationToken. You use the NextContinuationToken value\n to continue the pagination of the list by passing the value in\n continuation-token in the request to GET the next page.

\n

To use this operation, you must have permissions to perform the\n s3:GetMetricsConfiguration action. The bucket owner has this permission by\n default. The bucket owner can grant this permission to others. For more information about\n permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For more information about metrics configurations and CloudWatch request metrics, see\n Monitoring Metrics with Amazon CloudWatch.

\n

The following operations are related to\n ListBucketMetricsConfigurations:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Lists the metrics configurations for the bucket. The metrics configurations are only for\n the request metrics of the bucket and do not provide information on daily storage metrics.\n You can have up to 1,000 configurations per bucket.

\n

This action supports list pagination and does not return more than 100 configurations at\n a time. Always check the IsTruncated element in the response. If there are no\n more configurations to list, IsTruncated is set to false. If there are more\n configurations to list, IsTruncated is set to true, and there is a value in\n NextContinuationToken. You use the NextContinuationToken value\n to continue the pagination of the list by passing the value in\n continuation-token in the request to GET the next page.

\n

To use this operation, you must have permissions to perform the\n s3:GetMetricsConfiguration action. The bucket owner has this permission by\n default. The bucket owner can grant this permission to others. For more information about\n permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For more information about metrics configurations and CloudWatch request metrics, see\n Monitoring Metrics with Amazon CloudWatch.

\n

The following operations are related to\n ListBucketMetricsConfigurations:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?metrics&x-id=ListBucketMetricsConfigurations", @@ -24008,7 +26066,6 @@ "IsTruncated": { "target": "com.amazonaws.s3#IsTruncated", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Indicates whether the returned list of metrics configurations is complete. A value of\n true indicates that the list is not complete and the NextContinuationToken will be provided\n for a subsequent request.

" } }, @@ -24062,7 +26119,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -24080,7 +26137,7 @@ "target": "com.amazonaws.s3#ListBucketsOutput" }, "traits": { - "smithy.api#documentation": "

Returns a list of all buckets owned by the authenticated sender of the request. To use\n this operation, you must have the s3:ListAllMyBuckets permission.

\n

For information about Amazon S3 buckets, see Creating, configuring, and\n working with Amazon S3 buckets.

", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns a list of all buckets owned by the authenticated sender of the request. To use\n this operation, you must have the s3:ListAllMyBuckets permission.

\n

For information about Amazon S3 buckets, see Creating, configuring, and\n working with Amazon S3 buckets.

", "smithy.api#examples": [ { "title": "To list all buckets", @@ -24109,7 +26166,7 @@ ], "smithy.api#http": { "method": "GET", - "uri": "/", + "uri": "/?x-id=ListBuckets", "code": 200 } } @@ -24135,6 +26192,76 @@ "smithy.api#xmlName": "ListAllMyBucketsResult" } }, + "com.amazonaws.s3#ListDirectoryBuckets": { + "type": "operation", + "input": { + "target": "com.amazonaws.s3#ListDirectoryBucketsRequest" + }, + "output": { + "target": "com.amazonaws.s3#ListDirectoryBucketsOutput" + }, + "traits": { + "smithy.api#documentation": "

Returns a list of all Amazon S3 directory buckets owned by the authenticated sender of the request. For more information about directory buckets, see Directory buckets in the Amazon S3 User Guide.

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Regional endpoint. These endpoints support path-style requests in the format https://s3express-control.region_code.amazonaws.com/bucket-name\n . Virtual-hosted-style requests aren't supported. \nFor more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n

You must have the s3express:ListAllMyDirectoryBuckets permission in an IAM identity-based policy instead of a bucket policy. Cross-account access to this API operation isn't supported. This operation can only be performed by the Amazon Web Services account that owns the resource. For more information about directory bucket policies and permissions, see Amazon Web Services Identity and Access Management (IAM) for S3 Express One Zone in the Amazon S3 User Guide.

\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is s3express-control.region.amazonaws.com.

\n
\n
", + "smithy.api#http": { + "method": "GET", + "uri": "/?x-id=ListDirectoryBuckets", + "code": 200 + }, + "smithy.api#paginated": { + "inputToken": "ContinuationToken", + "outputToken": "ContinuationToken", + "items": "Buckets", + "pageSize": "MaxDirectoryBuckets" + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } + } + } + }, + "com.amazonaws.s3#ListDirectoryBucketsOutput": { + "type": "structure", + "members": { + "Buckets": { + "target": "com.amazonaws.s3#Buckets", + "traits": { + "smithy.api#documentation": "

The list of buckets owned by the requester.

" + } + }, + "ContinuationToken": { + "target": "com.amazonaws.s3#DirectoryBucketToken", + "traits": { + "smithy.api#documentation": "

If ContinuationToken was sent with the request, it is included in the\n response. You can use the returned ContinuationToken for pagination of the list response.

" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.s3#ListDirectoryBucketsRequest": { + "type": "structure", + "members": { + "ContinuationToken": { + "target": "com.amazonaws.s3#DirectoryBucketToken", + "traits": { + "smithy.api#documentation": "

\n ContinuationToken indicates to Amazon S3 that the list is being continued on\n this bucket with a token. ContinuationToken is obfuscated and is not a real\n key. You can use this ContinuationToken for pagination of the list results.

", + "smithy.api#httpQuery": "continuation-token" + } + }, + "MaxDirectoryBuckets": { + "target": "com.amazonaws.s3#MaxDirectoryBuckets", + "traits": { + "smithy.api#documentation": "

Maximum number of buckets to be returned in response. When the number is more than the count of buckets that are owned by an Amazon Web Services account, return all the buckets in response.

", + "smithy.api#httpQuery": "max-directory-buckets" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, "com.amazonaws.s3#ListMultipartUploads": { "type": "operation", "input": { @@ -24144,48 +26271,7 @@ "target": "com.amazonaws.s3#ListMultipartUploadsOutput" }, "traits": { - "smithy.api#documentation": "

This action lists in-progress multipart uploads. An in-progress multipart upload is a\n multipart upload that has been initiated using the Initiate Multipart Upload request, but\n has not yet been completed or aborted.

\n

This action returns at most 1,000 multipart uploads in the response. 1,000 multipart\n uploads is the maximum number of uploads a response can include, which is also the default\n value. You can further limit the number of uploads in a response by specifying the\n max-uploads parameter in the response. If additional multipart uploads\n satisfy the list criteria, the response will contain an IsTruncated element\n with the value true. To list the additional multipart uploads, use the\n key-marker and upload-id-marker request parameters.

\n

In the response, the uploads are sorted by key. If your application has initiated more\n than one multipart upload using the same object key, then uploads in the response are first\n sorted by key. Additionally, uploads are sorted in ascending order within each key by the\n upload initiation time.

\n

For more information on multipart uploads, see Uploading Objects Using Multipart\n Upload.

\n

For information on permissions required to use the multipart upload API, see Multipart Upload\n and Permissions.

\n

The following operations are related to ListMultipartUploads:

\n ", - "smithy.api#examples": [ - { - "title": "To list in-progress multipart uploads on a bucket", - "documentation": "The following example lists in-progress multipart uploads on a specific bucket.", - "input": { - "Bucket": "examplebucket" - }, - "output": { - "Uploads": [ - { - "Initiator": { - "DisplayName": "display-name", - "ID": "examplee7a2f25102679df27bb0ae12b3f85be6f290b936c4393484be31bebcc" - }, - "Initiated": "2014-05-01T05:40:58.000Z", - "UploadId": "examplelUa.CInXklLQtSMJITdUnoZ1Y5GACB5UckOtspm5zbDMCkPF_qkfZzMiFZ6dksmcnqxJyIBvQMG9X9Q--", - "StorageClass": "STANDARD", - "Key": "JavaFile", - "Owner": { - "DisplayName": "display-name", - "ID": "examplee7a2f25102679df27bb0ae12b3f85be6f290b936c4393484be31bebcc" - } - }, - { - "Initiator": { - "DisplayName": "display-name", - "ID": "examplee7a2f25102679df27bb0ae12b3f85be6f290b936c4393484be31bebcc" - }, - "Initiated": "2014-05-01T05:41:27.000Z", - "UploadId": "examplelo91lv1iwvWpvCiJWugw2xXLPAD7Z8cJyX9.WiIRgNrdG6Ldsn.9FtS63TCl1Uf5faTB.1U5Ckcbmdw--", - "StorageClass": "STANDARD", - "Key": "JavaFile", - "Owner": { - "DisplayName": "display-name", - "ID": "examplee7a2f25102679df27bb0ae12b3f85be6f290b936c4393484be31bebcc" - } - } - ] - } - } - ], + "smithy.api#documentation": "

This operation lists in-progress multipart uploads in a bucket. An in-progress multipart upload is a\n multipart upload that has been initiated by the CreateMultipartUpload request, but\n has not yet been completed or aborted.

\n \n

\n Directory buckets - \n If multipart uploads in a directory bucket are in progress, you can't delete the bucket until all the in-progress multipart uploads are aborted or completed.\n

\n
\n

The ListMultipartUploads operation returns a maximum of 1,000 multipart uploads in the response. The limit of 1,000 multipart\n uploads is also the default\n value. You can further limit the number of uploads in a response by specifying the\n max-uploads request parameter. If there are more than 1,000 multipart uploads that \n satisfy your ListMultipartUploads request, the response returns an IsTruncated element\n with the value of true, a NextKeyMarker element, and a NextUploadIdMarker element. \n To list the remaining multipart uploads, you need to make subsequent ListMultipartUploads requests. \n In these requests, include two query parameters: key-marker and upload-id-marker. \n Set the value of key-marker to the NextKeyMarker value from the previous response. \n Similarly, set the value of upload-id-marker to the NextUploadIdMarker value from the previous response.

\n \n

\n Directory buckets - The upload-id-marker element and \n the NextUploadIdMarker element aren't supported by directory buckets. \n To list the additional multipart uploads, you only need to set the value of key-marker to the NextKeyMarker value from the previous response.

\n
\n

For more information about multipart uploads, see Uploading Objects Using Multipart\n Upload in the Amazon S3\n User Guide.

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - For information about permissions required to use the multipart upload API, see Multipart Upload\n and Permissions in the Amazon S3\n User Guide.

    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation on a directory bucket, we recommend that you use the \n CreateSession\n API operation for session-based authorization. Specifically, you grant the s3express:CreateSession permission to the directory bucket in a bucket policy or an IAM identity-based policy. Then, you make the CreateSession API call on the bucket to obtain a session token. With the session token in your request header, you can make API requests to this operation. After the session token expires, you make another CreateSession API call to generate a new session token for use. \nAmazon Web Services CLI or SDKs create session and refresh the session token automatically to avoid service interruptions when a session expires. For more information about authorization, see \n CreateSession\n .

    \n
  • \n
\n
\n
Sorting of multipart uploads in response
\n
\n
    \n
  • \n

    \n General purpose bucket - In the ListMultipartUploads response, the multipart uploads are sorted based on two criteria:

    \n
      \n
    • \n

      Key-based sorting - Multipart uploads are initially sorted in ascending order based on their object keys.

      \n
    • \n
    • \n

      Time-based sorting - For uploads that share the same object key, \n they are further sorted in ascending order based on the upload initiation time. Among uploads with the same key, the one that was initiated first will appear before the ones that were initiated later.

      \n
    • \n
    \n
  • \n
  • \n

    \n Directory bucket - In the ListMultipartUploads response, the multipart uploads aren't sorted lexicographically based on the object keys. \n \n

    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

The following operations are related to ListMultipartUploads:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?uploads", @@ -24211,7 +26297,7 @@ "UploadIdMarker": { "target": "com.amazonaws.s3#UploadIdMarker", "traits": { - "smithy.api#documentation": "

Upload ID after which listing began.

" + "smithy.api#documentation": "

Upload ID after which listing began.

\n \n

This functionality is not supported for directory buckets.

\n
" } }, "NextKeyMarker": { @@ -24223,32 +26309,30 @@ "Prefix": { "target": "com.amazonaws.s3#Prefix", "traits": { - "smithy.api#documentation": "

When a prefix is provided in the request, this field contains the specified prefix. The\n result contains only keys starting with the specified prefix.

" + "smithy.api#documentation": "

When a prefix is provided in the request, this field contains the specified prefix. The\n result contains only keys starting with the specified prefix.

\n \n

\n Directory buckets - For directory buckets, only prefixes that end in a delimiter (/) are supported.

\n
" } }, "Delimiter": { "target": "com.amazonaws.s3#Delimiter", "traits": { - "smithy.api#documentation": "

Contains the delimiter you specified in the request. If you don't specify a delimiter in\n your request, this element is absent from the response.

" + "smithy.api#documentation": "

Contains the delimiter you specified in the request. If you don't specify a delimiter in\n your request, this element is absent from the response.

\n \n

\n Directory buckets - For directory buckets, / is the only supported delimiter.

\n
" } }, "NextUploadIdMarker": { "target": "com.amazonaws.s3#NextUploadIdMarker", "traits": { - "smithy.api#documentation": "

When a list is truncated, this element specifies the value that should be used for the\n upload-id-marker request parameter in a subsequent request.

" + "smithy.api#documentation": "

When a list is truncated, this element specifies the value that should be used for the\n upload-id-marker request parameter in a subsequent request.

\n \n

This functionality is not supported for directory buckets.

\n
" } }, "MaxUploads": { "target": "com.amazonaws.s3#MaxUploads", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Maximum number of multipart uploads that could have been included in the\n response.

" } }, "IsTruncated": { "target": "com.amazonaws.s3#IsTruncated", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Indicates whether the returned list of multipart uploads is truncated. A value of true\n indicates that the list was truncated. The list can be truncated if the number of multipart\n uploads exceeds the limit allowed or specified by max uploads.

" } }, @@ -24263,7 +26347,7 @@ "CommonPrefixes": { "target": "com.amazonaws.s3#CommonPrefixList", "traits": { - "smithy.api#documentation": "

If you specify a delimiter in the request, then the result returns each distinct key\n prefix containing the delimiter in a CommonPrefixes element. The distinct key\n prefixes are returned in the Prefix child element.

", + "smithy.api#documentation": "

If you specify a delimiter in the request, then the result returns each distinct key\n prefix containing the delimiter in a CommonPrefixes element. The distinct key\n prefixes are returned in the Prefix child element.

\n \n

\n Directory buckets - For directory buckets, only prefixes that end in a delimiter (/) are supported.

\n
", "smithy.api#xmlFlattened": {} } }, @@ -24291,7 +26375,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket to which the multipart upload was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket to which the multipart upload was initiated.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -24302,7 +26386,7 @@ "Delimiter": { "target": "com.amazonaws.s3#Delimiter", "traits": { - "smithy.api#documentation": "

Character you use to group keys.

\n

All keys that contain the same string between the prefix, if specified, and the first\n occurrence of the delimiter after the prefix are grouped under a single result element,\n CommonPrefixes. If you don't specify the prefix parameter, then the\n substring starts at the beginning of the key. The keys that are grouped under\n CommonPrefixes result element are not returned elsewhere in the\n response.

", + "smithy.api#documentation": "

Character you use to group keys.

\n

All keys that contain the same string between the prefix, if specified, and the first\n occurrence of the delimiter after the prefix are grouped under a single result element,\n CommonPrefixes. If you don't specify the prefix parameter, then the\n substring starts at the beginning of the key. The keys that are grouped under\n CommonPrefixes result element are not returned elsewhere in the\n response.

\n \n

\n Directory buckets - For directory buckets, / is the only supported delimiter.

\n
", "smithy.api#httpQuery": "delimiter" } }, @@ -24315,14 +26399,13 @@ "KeyMarker": { "target": "com.amazonaws.s3#KeyMarker", "traits": { - "smithy.api#documentation": "

Together with upload-id-marker, this parameter specifies the multipart\n upload after which listing should begin.

\n

If upload-id-marker is not specified, only the keys lexicographically\n greater than the specified key-marker will be included in the list.

\n

If upload-id-marker is specified, any multipart uploads for a key equal to\n the key-marker might also be included, provided those multipart uploads have\n upload IDs lexicographically greater than the specified\n upload-id-marker.

", + "smithy.api#documentation": "

Specifies the multipart upload after which listing should begin.

\n \n
    \n
  • \n

    \n General purpose buckets - For general purpose buckets, key-marker \n is an object key. Together with upload-id-marker, this parameter specifies the multipart\n upload after which listing should begin.

    \n

    If upload-id-marker is not specified, only the keys lexicographically\n greater than the specified key-marker will be included in the list.

    \n

    If upload-id-marker is specified, any multipart uploads for a key equal to\n the key-marker might also be included, provided those multipart uploads have\n upload IDs lexicographically greater than the specified\n upload-id-marker.

    \n
  • \n
  • \n

    \n Directory buckets - For directory buckets, key-marker \n is obfuscated and isn't a real object key. \n The upload-id-marker parameter isn't supported by directory buckets. \n To list the additional multipart uploads, you only need to set the value of key-marker to the NextKeyMarker value from the previous response. \n

    \n

    In the ListMultipartUploads response, the multipart uploads aren't sorted lexicographically based on the object keys. \n \n

    \n
  • \n
\n
", "smithy.api#httpQuery": "key-marker" } }, "MaxUploads": { "target": "com.amazonaws.s3#MaxUploads", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Sets the maximum number of multipart uploads, from 1 to 1,000, to return in the response\n body. 1,000 is the maximum number of uploads that can be returned in a response.

", "smithy.api#httpQuery": "max-uploads" } @@ -24330,21 +26413,24 @@ "Prefix": { "target": "com.amazonaws.s3#Prefix", "traits": { - "smithy.api#documentation": "

Lists in-progress uploads only for those keys that begin with the specified prefix. You\n can use prefixes to separate a bucket into different grouping of keys. (You can think of\n using prefix to make groups in the same way that you'd use a folder in a file\n system.)

", - "smithy.api#httpQuery": "prefix" + "smithy.api#documentation": "

Lists in-progress uploads only for those keys that begin with the specified prefix. You\n can use prefixes to separate a bucket into different grouping of keys. (You can think of\n using prefix to make groups in the same way that you'd use a folder in a file\n system.)

\n \n

\n Directory buckets - For directory buckets, only prefixes that end in a delimiter (/) are supported.

\n
", + "smithy.api#httpQuery": "prefix", + "smithy.rules#contextParam": { + "name": "Prefix" + } } }, "UploadIdMarker": { "target": "com.amazonaws.s3#UploadIdMarker", "traits": { - "smithy.api#documentation": "

Together with key-marker, specifies the multipart upload after which listing should\n begin. If key-marker is not specified, the upload-id-marker parameter is ignored.\n Otherwise, any multipart uploads for a key equal to the key-marker might be included in the\n list only if they have an upload ID lexicographically greater than the specified\n upload-id-marker.

", + "smithy.api#documentation": "

Together with key-marker, specifies the multipart upload after which listing should\n begin. If key-marker is not specified, the upload-id-marker parameter is ignored.\n Otherwise, any multipart uploads for a key equal to the key-marker might be included in the\n list only if they have an upload ID lexicographically greater than the specified\n upload-id-marker.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpQuery": "upload-id-marker" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -24368,7 +26454,7 @@ "target": "com.amazonaws.s3#ListObjectVersionsOutput" }, "traits": { - "smithy.api#documentation": "

Returns metadata about all versions of the objects in a bucket. You can also use request\n parameters as selection criteria to return metadata about a subset of all the object\n versions.

\n \n

To use this operation, you must have permission to perform the\n s3:ListBucketVersions action. Be aware of the name difference.

\n
\n \n

A 200 OK response can contain valid or invalid XML. Make sure to design\n your application to parse the contents of the response and handle it\n appropriately.

\n
\n

To use this operation, you must have READ access to the bucket.

\n

This action is not supported by Amazon S3 on Outposts.

\n

The following operations are related to ListObjectVersions:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns metadata about all versions of the objects in a bucket. You can also use request\n parameters as selection criteria to return metadata about a subset of all the object\n versions.

\n \n

To use this operation, you must have permission to perform the\n s3:ListBucketVersions action. Be aware of the name difference.

\n
\n \n

A 200 OK response can contain valid or invalid XML. Make sure to design\n your application to parse the contents of the response and handle it\n appropriately.

\n
\n

To use this operation, you must have READ access to the bucket.

\n

The following operations are related to ListObjectVersions:

\n ", "smithy.api#examples": [ { "title": "To list object versions", @@ -24422,7 +26508,6 @@ "IsTruncated": { "target": "com.amazonaws.s3#IsTruncated", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

A flag that indicates whether Amazon S3 returned all of the results that satisfied the search\n criteria. If your results were truncated, you can make a follow-up paginated request by\n using the NextKeyMarker and NextVersionIdMarker response\n parameters as a starting place in another request to return the rest of the results.

" } }, @@ -24487,7 +26572,6 @@ "MaxKeys": { "target": "com.amazonaws.s3#MaxKeys", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Specifies the maximum number of objects to return.

" } }, @@ -24553,7 +26637,6 @@ "MaxKeys": { "target": "com.amazonaws.s3#MaxKeys", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Sets the maximum number of keys returned in the response. By default, the action returns\n up to 1,000 key names. The response might contain fewer keys but will never contain more.\n If additional keys satisfy the search criteria, but were not returned because\n max-keys was exceeded, the response contains\n true. To return the additional keys,\n see key-marker and version-id-marker.

", "smithy.api#httpQuery": "max-keys" } @@ -24562,7 +26645,10 @@ "target": "com.amazonaws.s3#Prefix", "traits": { "smithy.api#documentation": "

Use this parameter to select only those keys that begin with the specified prefix. You\n can use prefixes to separate a bucket into different groupings of keys. (You can think of\n using prefix to make groups in the same way that you'd use a folder in a file\n system.) You can use prefix with delimiter to roll up numerous\n objects into a single result under CommonPrefixes.

", - "smithy.api#httpQuery": "prefix" + "smithy.api#httpQuery": "prefix", + "smithy.rules#contextParam": { + "name": "Prefix" + } } }, "VersionIdMarker": { @@ -24575,7 +26661,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -24611,7 +26697,7 @@ } ], "traits": { - "smithy.api#documentation": "

Returns some or all (up to 1,000) of the objects in a bucket. You can use the request\n parameters as selection criteria to return a subset of the objects in a bucket. A 200 OK\n response can contain valid or invalid XML. Be sure to design your application to parse the\n contents of the response and handle it appropriately.

\n \n

This action has been revised. We recommend that you use the newer version, ListObjectsV2, when developing applications. For backward compatibility,\n Amazon S3 continues to support ListObjects.

\n
\n

The following operations are related to ListObjects:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Returns some or all (up to 1,000) of the objects in a bucket. You can use the request\n parameters as selection criteria to return a subset of the objects in a bucket. A 200 OK\n response can contain valid or invalid XML. Be sure to design your application to parse the\n contents of the response and handle it appropriately.

\n \n

This action has been revised. We recommend that you use the newer version, ListObjectsV2, when developing applications. For backward compatibility,\n Amazon S3 continues to support ListObjects.

\n
\n

The following operations are related to ListObjects:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}", @@ -24625,7 +26711,6 @@ "IsTruncated": { "target": "com.amazonaws.s3#IsTruncated", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

A flag that indicates whether Amazon S3 returned all of the results that satisfied the search\n criteria.

" } }, @@ -24669,7 +26754,6 @@ "MaxKeys": { "target": "com.amazonaws.s3#MaxKeys", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The maximum number of keys returned in the response body.

" } }, @@ -24704,7 +26788,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket containing the objects.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket containing the objects.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -24735,7 +26819,6 @@ "MaxKeys": { "target": "com.amazonaws.s3#MaxKeys", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Sets the maximum number of keys returned in the response. By default, the action returns\n up to 1,000 key names. The response might contain fewer keys but will never contain more.\n

", "smithy.api#httpQuery": "max-keys" } @@ -24744,7 +26827,10 @@ "target": "com.amazonaws.s3#Prefix", "traits": { "smithy.api#documentation": "

Limits the response to keys that begin with the specified prefix.

", - "smithy.api#httpQuery": "prefix" + "smithy.api#httpQuery": "prefix", + "smithy.rules#contextParam": { + "name": "Prefix" + } } }, "RequestPayer": { @@ -24757,7 +26843,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -24787,7 +26873,7 @@ } ], "traits": { - "smithy.api#documentation": "

Returns some or all (up to 1,000) of the objects in a bucket with each request. You can\n use the request parameters as selection criteria to return a subset of the objects in a\n bucket. A 200 OK response can contain valid or invalid XML. Make sure to\n design your application to parse the contents of the response and handle it appropriately.\n Objects are returned sorted in an ascending order of the respective key names in the list.\n For more information about listing objects, see Listing object keys\n programmatically in the Amazon S3 User Guide.

\n

To use this operation, you must have READ access to the bucket.

\n

To use this action in an Identity and Access Management (IAM) policy, you must have permission to perform\n the s3:ListBucket action. The bucket owner has this permission by default and\n can grant this permission to others. For more information about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources in the\n Amazon S3 User Guide.

\n \n

This section describes the latest revision of this action. We recommend that you use\n this revised API operation for application development. For backward compatibility, Amazon S3\n continues to support the prior version of this API operation, ListObjects.

\n
\n

To get a list of your buckets, see ListBuckets.

\n

The following operations are related to ListObjectsV2:

\n ", + "smithy.api#documentation": "

Returns some or all (up to 1,000) of the objects in a bucket with each request. You can\n use the request parameters as selection criteria to return a subset of the objects in a\n bucket. A 200 OK response can contain valid or invalid XML. Make sure to\n design your application to parse the contents of the response and handle it appropriately.\n \n For more information about listing objects, see Listing object keys\n programmatically in the Amazon S3 User Guide. To get a list of your buckets, see ListBuckets.

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - To use this operation, you must have READ access to the bucket. You must have permission to perform\n the s3:ListBucket action. The bucket owner has this permission by default and\n can grant this permission to others. For more information about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources in the\n Amazon S3 User Guide.

    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation on a directory bucket, we recommend that you use the \n CreateSession\n API operation for session-based authorization. Specifically, you grant the s3express:CreateSession permission to the directory bucket in a bucket policy or an IAM identity-based policy. Then, you make the CreateSession API call on the bucket to obtain a session token. With the session token in your request header, you can make API requests to this operation. After the session token expires, you make another CreateSession API call to generate a new session token for use. \nAmazon Web Services CLI or SDKs create session and refresh the session token automatically to avoid service interruptions when a session expires. For more information about authorization, see \n CreateSession\n .

    \n
  • \n
\n
\n
Sorting order of returned objects
\n
\n
    \n
  • \n

    \n General purpose bucket - For general purpose buckets, ListObjectsV2 returns objects in lexicographical order based on their key names.

    \n
  • \n
  • \n

    \n Directory bucket - For directory buckets, ListObjectsV2 does not return objects in lexicographical order.

    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n \n

This section describes the latest revision of this action. We recommend that you use\n this revised API operation for application development. For backward compatibility, Amazon S3\n continues to support the prior version of this API operation, ListObjects.

\n
\n

The following operations are related to ListObjectsV2:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}?list-type=2", @@ -24806,7 +26892,6 @@ "IsTruncated": { "target": "com.amazonaws.s3#IsTruncated", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Set to false if all of the results were returned. Set to true\n if more keys are available to return. If the number of results exceeds that specified by\n MaxKeys, all of the results might not be returned.

" } }, @@ -24820,32 +26905,31 @@ "Name": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The bucket name.

" } }, "Prefix": { "target": "com.amazonaws.s3#Prefix", "traits": { - "smithy.api#documentation": "

Keys that begin with the indicated prefix.

" + "smithy.api#documentation": "

Keys that begin with the indicated prefix.

\n \n

\n Directory buckets - For directory buckets, only prefixes that end in a delimiter (/) are supported.

\n
" } }, "Delimiter": { "target": "com.amazonaws.s3#Delimiter", "traits": { - "smithy.api#documentation": "

Causes keys that contain the same string between the prefix and the first\n occurrence of the delimiter to be rolled up into a single result element in the\n CommonPrefixes collection. These rolled-up keys are not returned elsewhere\n in the response. Each rolled-up result counts as only one return against the\n MaxKeys value.

" + "smithy.api#documentation": "

Causes keys that contain the same string between the prefix and the first\n occurrence of the delimiter to be rolled up into a single result element in the\n CommonPrefixes collection. These rolled-up keys are not returned elsewhere\n in the response. Each rolled-up result counts as only one return against the\n MaxKeys value.

\n \n

\n Directory buckets - For directory buckets, / is the only supported delimiter.

\n
" } }, "MaxKeys": { "target": "com.amazonaws.s3#MaxKeys", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Sets the maximum number of keys returned in the response. By default, the action returns\n up to 1,000 key names. The response might contain fewer keys but will never contain\n more.

" } }, "CommonPrefixes": { "target": "com.amazonaws.s3#CommonPrefixList", "traits": { - "smithy.api#documentation": "

All of the keys (up to 1,000) rolled up into a common prefix count as a single return\n when calculating the number of returns.

\n

A response can contain CommonPrefixes only if you specify a\n delimiter.

\n

\n CommonPrefixes contains all (if there are any) keys between\n Prefix and the next occurrence of the string specified by a\n delimiter.

\n

\n CommonPrefixes lists keys that act like subdirectories in the directory\n specified by Prefix.

\n

For example, if the prefix is notes/ and the delimiter is a slash\n (/) as in notes/summer/july, the common prefix is\n notes/summer/. All of the keys that roll up into a common prefix count as a\n single return when calculating the number of returns.

", + "smithy.api#documentation": "

All of the keys (up to 1,000) that share the same prefix are grouped together. When counting the total numbers of returns by this API operation, \n this group of keys is considered as one item.

\n

A response can contain CommonPrefixes only if you specify a\n delimiter.

\n

\n CommonPrefixes contains all (if there are any) keys between\n Prefix and the next occurrence of the string specified by a\n delimiter.

\n

\n CommonPrefixes lists keys that act like subdirectories in the directory\n specified by Prefix.

\n

For example, if the prefix is notes/ and the delimiter is a slash\n (/) as in notes/summer/july, the common prefix is\n notes/summer/. All of the keys that roll up into a common prefix count as a\n single return when calculating the number of returns.

\n \n
    \n
  • \n

    \n Directory buckets - For directory buckets, only prefixes that end in a delimiter (/) are supported.

    \n
  • \n
  • \n

    \n Directory buckets - When you query ListObjectsV2 with a delimiter during in-progress multipart uploads, the \n CommonPrefixes response parameter contains the prefixes that are associated with the in-progress multipart uploads. \n For more information about multipart uploads, see Multipart Upload Overview in the Amazon S3 User Guide.

    \n
  • \n
\n
", "smithy.api#xmlFlattened": {} } }, @@ -24858,14 +26942,13 @@ "KeyCount": { "target": "com.amazonaws.s3#KeyCount", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

\n KeyCount is the number of keys returned with this request.\n KeyCount will always be less than or equal to the MaxKeys\n field. For example, if you ask for 50 keys, your result will include 50 keys or\n fewer.

" } }, "ContinuationToken": { "target": "com.amazonaws.s3#Token", "traits": { - "smithy.api#documentation": "

If ContinuationToken was sent with the request, it is included in the\n response.

" + "smithy.api#documentation": "

If ContinuationToken was sent with the request, it is included in the\n response. You can use the returned ContinuationToken for pagination of the list response. You can use this ContinuationToken for pagination of the list results.

" } }, "NextContinuationToken": { @@ -24877,7 +26960,7 @@ "StartAfter": { "target": "com.amazonaws.s3#StartAfter", "traits": { - "smithy.api#documentation": "

If StartAfter was sent with the request, it is included in the response.

" + "smithy.api#documentation": "

If StartAfter was sent with the request, it is included in the response.

\n \n

This functionality is not supported for directory buckets.

\n
" } }, "RequestCharged": { @@ -24898,7 +26981,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

Bucket name to list.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -24909,7 +26992,7 @@ "Delimiter": { "target": "com.amazonaws.s3#Delimiter", "traits": { - "smithy.api#documentation": "

A delimiter is a character that you use to group keys.

", + "smithy.api#documentation": "

A delimiter is a character that you use to group keys.

\n \n
    \n
  • \n

    \n Directory buckets - For directory buckets, / is the only supported delimiter.

    \n
  • \n
  • \n

    \n Directory buckets - When you query ListObjectsV2 with a delimiter during in-progress multipart uploads, the \n CommonPrefixes response parameter contains the prefixes that are associated with the in-progress multipart uploads. \n For more information about multipart uploads, see Multipart Upload Overview in the Amazon S3 User Guide.

    \n
  • \n
\n
", "smithy.api#httpQuery": "delimiter" } }, @@ -24923,7 +27006,6 @@ "MaxKeys": { "target": "com.amazonaws.s3#MaxKeys", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Sets the maximum number of keys returned in the response. By default, the action returns\n up to 1,000 key names. The response might contain fewer keys but will never contain\n more.

", "smithy.api#httpQuery": "max-keys" } @@ -24931,50 +27013,52 @@ "Prefix": { "target": "com.amazonaws.s3#Prefix", "traits": { - "smithy.api#documentation": "

Limits the response to keys that begin with the specified prefix.

", - "smithy.api#httpQuery": "prefix" + "smithy.api#documentation": "

Limits the response to keys that begin with the specified prefix.

\n \n

\n Directory buckets - For directory buckets, only prefixes that end in a delimiter (/) are supported.

\n
", + "smithy.api#httpQuery": "prefix", + "smithy.rules#contextParam": { + "name": "Prefix" + } } }, "ContinuationToken": { "target": "com.amazonaws.s3#Token", "traits": { - "smithy.api#documentation": "

\n ContinuationToken indicates to Amazon S3 that the list is being continued on\n this bucket with a token. ContinuationToken is obfuscated and is not a real\n key.

", + "smithy.api#documentation": "

\n ContinuationToken indicates to Amazon S3 that the list is being continued on\n this bucket with a token. ContinuationToken is obfuscated and is not a real\n key. You can use this ContinuationToken for pagination of the list results.

", "smithy.api#httpQuery": "continuation-token" } }, "FetchOwner": { "target": "com.amazonaws.s3#FetchOwner", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

The owner field is not present in ListObjectsV2 by default. If you want to\n return the owner field with each key in the result, then set the FetchOwner\n field to true.

", + "smithy.api#documentation": "

The owner field is not present in ListObjectsV2 by default. If you want to\n return the owner field with each key in the result, then set the FetchOwner\n field to true.

\n \n

\n Directory buckets - For directory buckets, the bucket owner is returned as the object owner for all objects.

\n
", "smithy.api#httpQuery": "fetch-owner" } }, "StartAfter": { "target": "com.amazonaws.s3#StartAfter", "traits": { - "smithy.api#documentation": "

StartAfter is where you want Amazon S3 to start listing from. Amazon S3 starts listing after this\n specified key. StartAfter can be any key in the bucket.

", + "smithy.api#documentation": "

StartAfter is where you want Amazon S3 to start listing from. Amazon S3 starts listing after this\n specified key. StartAfter can be any key in the bucket.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpQuery": "start-after" } }, "RequestPayer": { "target": "com.amazonaws.s3#RequestPayer", "traits": { - "smithy.api#documentation": "

Confirms that the requester knows that she or he will be charged for the list objects\n request in V2 style. Bucket owners need not specify this parameter in their\n requests.

", + "smithy.api#documentation": "

Confirms that the requester knows that she or he will be charged for the list objects\n request in V2 style. Bucket owners need not specify this parameter in their\n requests.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-request-payer" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, "OptionalObjectAttributes": { "target": "com.amazonaws.s3#OptionalObjectAttributesList", "traits": { - "smithy.api#documentation": "

Specifies the optional fields that you want returned in the response. Fields that you do\n not specify are not returned.

", + "smithy.api#documentation": "

Specifies the optional fields that you want returned in the response. Fields that you do\n not specify are not returned.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-optional-object-attributes" } } @@ -24992,7 +27076,7 @@ "target": "com.amazonaws.s3#ListPartsOutput" }, "traits": { - "smithy.api#documentation": "

Lists the parts that have been uploaded for a specific multipart upload. This operation\n must include the upload ID, which you obtain by sending the initiate multipart upload\n request (see CreateMultipartUpload).\n This request returns a maximum of 1,000 uploaded parts. The default number of parts\n returned is 1,000 parts. You can restrict the number of parts returned by specifying the\n max-parts request parameter. If your multipart upload consists of more than\n 1,000 parts, the response returns an IsTruncated field with the value of true,\n and a NextPartNumberMarker element. In subsequent ListParts\n requests you can include the part-number-marker query string parameter and set its value to\n the NextPartNumberMarker field value from the previous response.

\n

If the upload was created using a checksum algorithm, you will need to have permission\n to the kms:Decrypt action for the request to succeed.

\n

For more information on multipart uploads, see Uploading Objects Using Multipart\n Upload.

\n

For information on permissions required to use the multipart upload API, see Multipart Upload\n and Permissions.

\n

The following operations are related to ListParts:

\n ", + "smithy.api#documentation": "

Lists the parts that have been uploaded for a specific multipart upload.

\n

To use this operation, you must provide the upload ID in the request. You obtain this uploadID by sending the initiate multipart upload\n request through CreateMultipartUpload.

\n

The ListParts request returns a maximum of 1,000 uploaded parts. The limit of 1,000 parts is also the default value. You can restrict the number of parts in a response by specifying the\n max-parts request parameter. If your multipart upload consists of more than\n 1,000 parts, the response returns an IsTruncated field with the value of true,\n and a NextPartNumberMarker element. To list remaining uploaded parts, in subsequent ListParts\n requests, include the part-number-marker query string parameter and set its value to\n the NextPartNumberMarker field value from the previous response.

\n

For more information on multipart uploads, see Uploading Objects Using Multipart\n Upload in the Amazon S3\n User Guide.

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - For information about permissions required to use the multipart upload API, see Multipart Upload\n and Permissions in the Amazon S3\n User Guide.

    \n

    If the upload was created using server-side encryption with Key Management Service (KMS) keys\n (SSE-KMS) or dual-layer server-side encryption with Amazon Web Services KMS keys (DSSE-KMS), you must have permission\n to the kms:Decrypt action for the ListParts request to succeed.

    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation on a directory bucket, we recommend that you use the \n CreateSession\n API operation for session-based authorization. Specifically, you grant the s3express:CreateSession permission to the directory bucket in a bucket policy or an IAM identity-based policy. Then, you make the CreateSession API call on the bucket to obtain a session token. With the session token in your request header, you can make API requests to this operation. After the session token expires, you make another CreateSession API call to generate a new session token for use. \nAmazon Web Services CLI or SDKs create session and refresh the session token automatically to avoid service interruptions when a session expires. For more information about authorization, see \n CreateSession\n .

    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

The following operations are related to ListParts:

\n ", "smithy.api#http": { "method": "GET", "uri": "/{Bucket}/{Key+}?x-id=ListParts", @@ -25012,14 +27096,14 @@ "AbortDate": { "target": "com.amazonaws.s3#AbortDate", "traits": { - "smithy.api#documentation": "

If the bucket has a lifecycle rule configured with an action to abort incomplete\n multipart uploads and the prefix in the lifecycle rule matches the object name in the\n request, then the response includes this header indicating when the initiated multipart\n upload will become eligible for abort operation. For more information, see Aborting Incomplete Multipart Uploads Using a Bucket Lifecycle\n Configuration.

\n

The response will also include the x-amz-abort-rule-id header that will\n provide the ID of the lifecycle configuration rule that defines this action.

", + "smithy.api#documentation": "

If the bucket has a lifecycle rule configured with an action to abort incomplete\n multipart uploads and the prefix in the lifecycle rule matches the object name in the\n request, then the response includes this header indicating when the initiated multipart\n upload will become eligible for abort operation. For more information, see Aborting Incomplete Multipart Uploads Using a Bucket Lifecycle\n Configuration.

\n

The response will also include the x-amz-abort-rule-id header that will\n provide the ID of the lifecycle configuration rule that defines this action.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-abort-date" } }, "AbortRuleId": { "target": "com.amazonaws.s3#AbortRuleId", "traits": { - "smithy.api#documentation": "

This header is returned along with the x-amz-abort-date header. It\n identifies applicable lifecycle configuration rule that defines the action to abort\n incomplete multipart uploads.

", + "smithy.api#documentation": "

This header is returned along with the x-amz-abort-date header. It\n identifies applicable lifecycle configuration rule that defines the action to abort\n incomplete multipart uploads.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-abort-rule-id" } }, @@ -25056,21 +27140,19 @@ "MaxParts": { "target": "com.amazonaws.s3#MaxParts", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Maximum number of parts that were allowed in the response.

" } }, "IsTruncated": { "target": "com.amazonaws.s3#IsTruncated", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Indicates whether the returned list of parts is truncated. A true value indicates that\n the list was truncated. A list can be truncated if the number of parts exceeds the limit\n returned in the MaxParts element.

" } }, "Parts": { "target": "com.amazonaws.s3#Parts", "traits": { - "smithy.api#documentation": "

Container for elements related to a particular part. A response can contain zero or\n more Part elements.

", + "smithy.api#documentation": "

Container for elements related to a particular part. A response can contain zero or\n more Part elements.

", "smithy.api#xmlFlattened": {}, "smithy.api#xmlName": "Part" } @@ -25084,13 +27166,13 @@ "Owner": { "target": "com.amazonaws.s3#Owner", "traits": { - "smithy.api#documentation": "

Container element that identifies the object owner, after the object is created. If\n multipart upload is initiated by an IAM user, this element provides the parent account ID\n and display name.

" + "smithy.api#documentation": "

Container element that identifies the object owner, after the object is created. If\n multipart upload is initiated by an IAM user, this element provides the parent account ID\n and display name.

\n \n

\n Directory buckets - The bucket owner is returned as the object owner for all the parts.

\n
" } }, "StorageClass": { "target": "com.amazonaws.s3#StorageClass", "traits": { - "smithy.api#documentation": "

Class of storage (STANDARD or REDUCED_REDUNDANCY) used to store the uploaded\n object.

" + "smithy.api#documentation": "

The class of storage used to store the uploaded\n object.

\n \n

\n Directory buckets - Only the S3 Express One Zone storage class is supported by directory buckets to store objects.

\n
" } }, "RequestCharged": { @@ -25117,7 +27199,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket to which the parts are being uploaded.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket to which the parts are being uploaded.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -25130,13 +27212,15 @@ "traits": { "smithy.api#documentation": "

Object key for which the multipart upload was initiated.

", "smithy.api#httpLabel": {}, - "smithy.api#required": {} + "smithy.api#required": {}, + "smithy.rules#contextParam": { + "name": "Key" + } } }, "MaxParts": { "target": "com.amazonaws.s3#MaxParts", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Sets the maximum number of parts to return.

", "smithy.api#httpQuery": "max-parts" } @@ -25165,28 +27249,28 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

The server-side encryption (SSE) algorithm used to encrypt the object. This parameter is needed only when the object was created \n using a checksum algorithm. For more information,\n see Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", + "smithy.api#documentation": "

The server-side encryption (SSE) algorithm used to encrypt the object. This parameter is needed only when the object was created \n using a checksum algorithm. For more information,\n see Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKey": { "target": "com.amazonaws.s3#SSECustomerKey", "traits": { - "smithy.api#documentation": "

The server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum algorithm. \n For more information, see\n Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", + "smithy.api#documentation": "

The server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum algorithm. \n For more information, see\n Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

The MD5 server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum \n algorithm. For more information,\n see Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

", + "smithy.api#documentation": "

The MD5 server-side encryption (SSE) customer managed key. This parameter is needed only when the object was created using a checksum \n algorithm. For more information,\n see Protecting data using SSE-C keys in the\n Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } } @@ -25198,9 +27282,43 @@ "com.amazonaws.s3#Location": { "type": "string" }, + "com.amazonaws.s3#LocationInfo": { + "type": "structure", + "members": { + "Type": { + "target": "com.amazonaws.s3#LocationType", + "traits": { + "smithy.api#documentation": "

The type of location where the bucket will be created.

" + } + }, + "Name": { + "target": "com.amazonaws.s3#LocationNameAsString", + "traits": { + "smithy.api#documentation": "

The name of the location where the bucket will be created.

\n

For directory buckets, the AZ ID of the Availability Zone where the bucket will be created. An example AZ ID value is usw2-az2.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Specifies the location where the bucket will be created.

\n

For directory buckets, the location type is Availability Zone. For more information about directory buckets, see \n Directory buckets in the Amazon S3 User Guide.

\n \n

This functionality is only supported by directory buckets.

\n
" + } + }, + "com.amazonaws.s3#LocationNameAsString": { + "type": "string" + }, "com.amazonaws.s3#LocationPrefix": { "type": "string" }, + "com.amazonaws.s3#LocationType": { + "type": "enum", + "members": { + "AvailabilityZone": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "AvailabilityZone" + } + } + } + }, "com.amazonaws.s3#LoggingEnabled": { "type": "structure", "members": { @@ -25223,6 +27341,12 @@ "smithy.api#documentation": "

A prefix for all log object keys. If you store log files from multiple Amazon S3 buckets in a\n single bucket, you can use a prefix to distinguish which log files came from which\n bucket.

", "smithy.api#required": {} } + }, + "TargetObjectKeyFormat": { + "target": "com.amazonaws.s3#TargetObjectKeyFormat", + "traits": { + "smithy.api#documentation": "

Amazon S3 key format for log objects.

" + } } }, "traits": { @@ -25270,28 +27394,25 @@ "type": "string" }, "com.amazonaws.s3#MaxAgeSeconds": { + "type": "integer" + }, + "com.amazonaws.s3#MaxDirectoryBuckets": { "type": "integer", "traits": { - "smithy.api#default": 0 + "smithy.api#range": { + "min": 0, + "max": 1000 + } } }, "com.amazonaws.s3#MaxKeys": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#MaxParts": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#MaxUploads": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#Message": { "type": "string" @@ -25477,16 +27598,10 @@ } }, "com.amazonaws.s3#Minutes": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#MissingMeta": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#MultipartUpload": { "type": "structure", @@ -25512,13 +27627,13 @@ "StorageClass": { "target": "com.amazonaws.s3#StorageClass", "traits": { - "smithy.api#documentation": "

The class of storage used to store the object.

" + "smithy.api#documentation": "

The class of storage used to store the object.

\n \n

\n Directory buckets - Only the S3 Express One Zone storage class is supported by directory buckets to store objects.

\n
" } }, "Owner": { "target": "com.amazonaws.s3#Owner", "traits": { - "smithy.api#documentation": "

Specifies the owner of the object that is part of the multipart upload.

" + "smithy.api#documentation": "

Specifies the owner of the object that is part of the multipart upload.

\n \n

\n Directory buckets - The bucket owner is returned as the object owner for all the objects.

\n
" } }, "Initiator": { @@ -25570,7 +27685,8 @@ "members": {}, "traits": { "smithy.api#documentation": "

The specified bucket does not exist.

", - "smithy.api#error": "client" + "smithy.api#error": "client", + "smithy.api#httpError": 404 } }, "com.amazonaws.s3#NoSuchKey": { @@ -25578,7 +27694,8 @@ "members": {}, "traits": { "smithy.api#documentation": "

The specified key does not exist.

", - "smithy.api#error": "client" + "smithy.api#error": "client", + "smithy.api#httpError": 404 } }, "com.amazonaws.s3#NoSuchUpload": { @@ -25586,7 +27703,8 @@ "members": {}, "traits": { "smithy.api#documentation": "

The specified multipart upload does not exist.

", - "smithy.api#error": "client" + "smithy.api#error": "client", + "smithy.api#httpError": 404 } }, "com.amazonaws.s3#NoncurrentVersionExpiration": { @@ -25595,15 +27713,13 @@ "NoncurrentDays": { "target": "com.amazonaws.s3#Days", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Specifies the number of days an object is noncurrent before Amazon S3 can perform the\n associated action. The value must be a non-zero positive integer. For information about the\n noncurrent days calculations, see How\n Amazon S3 Calculates When an Object Became Noncurrent in the\n Amazon S3 User Guide.

" } }, "NewerNoncurrentVersions": { "target": "com.amazonaws.s3#VersionCount", "traits": { - "smithy.api#default": 0, - "smithy.api#documentation": "

Specifies how many noncurrent versions Amazon S3 will retain. If there are this many more\n recent noncurrent versions, Amazon S3 will take the associated action. For more information\n about noncurrent versions, see Lifecycle configuration\n elements in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

Specifies how many newer noncurrent versions must exist before Amazon S3 can perform the\n associated action on a given version. If there are this many more recent noncurrent\n versions, Amazon S3 will take the associated action. For more information about noncurrent\n versions, see Lifecycle configuration\n elements in the Amazon S3 User Guide.

" } } }, @@ -25617,7 +27733,6 @@ "NoncurrentDays": { "target": "com.amazonaws.s3#Days", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Specifies the number of days an object is noncurrent before Amazon S3 can perform the\n associated action. For information about the noncurrent days calculations, see How\n Amazon S3 Calculates How Long an Object Has Been Noncurrent in the\n Amazon S3 User Guide.

" } }, @@ -25630,8 +27745,7 @@ "NewerNoncurrentVersions": { "target": "com.amazonaws.s3#VersionCount", "traits": { - "smithy.api#default": 0, - "smithy.api#documentation": "

Specifies how many noncurrent versions Amazon S3 will retain. If there are this many more\n recent noncurrent versions, Amazon S3 will take the associated action. For more information\n about noncurrent versions, see Lifecycle configuration\n elements in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

Specifies how many newer noncurrent versions must exist before Amazon S3 can perform the\n associated action on a given version. If there are this many more recent noncurrent\n versions, Amazon S3 will take the associated action. For more information about noncurrent\n versions, see Lifecycle configuration\n elements in the Amazon S3 User Guide.

" } } }, @@ -25729,7 +27843,7 @@ "ETag": { "target": "com.amazonaws.s3#ETag", "traits": { - "smithy.api#documentation": "

The entity tag is a hash of the object. The ETag reflects changes only to the contents\n of an object, not its metadata. The ETag may or may not be an MD5 digest of the object\n data. Whether or not it is depends on how the object was created and how it is encrypted as\n described below:

\n
    \n
  • \n

    Objects created by the PUT Object, POST Object, or Copy operation, or through the\n Amazon Web Services Management Console, and are encrypted by SSE-S3 or plaintext, have ETags that\n are an MD5 digest of their object data.

    \n
  • \n
  • \n

    Objects created by the PUT Object, POST Object, or Copy operation, or through the\n Amazon Web Services Management Console, and are encrypted by SSE-C or SSE-KMS, have ETags that are\n not an MD5 digest of their object data.

    \n
  • \n
  • \n

    If an object is created by either the Multipart Upload or Part Copy operation, the\n ETag is not an MD5 digest, regardless of the method of encryption. If an object is\n larger than 16 MB, the Amazon Web Services Management Console will upload or copy that object as a\n Multipart Upload, and therefore the ETag will not be an MD5 digest.

    \n
  • \n
" + "smithy.api#documentation": "

The entity tag is a hash of the object. The ETag reflects changes only to the contents\n of an object, not its metadata. The ETag may or may not be an MD5 digest of the object\n data. Whether or not it is depends on how the object was created and how it is encrypted as\n described below:

\n
    \n
  • \n

    Objects created by the PUT Object, POST Object, or Copy operation, or through the\n Amazon Web Services Management Console, and are encrypted by SSE-S3 or plaintext, have ETags that\n are an MD5 digest of their object data.

    \n
  • \n
  • \n

    Objects created by the PUT Object, POST Object, or Copy operation, or through the\n Amazon Web Services Management Console, and are encrypted by SSE-C or SSE-KMS, have ETags that are\n not an MD5 digest of their object data.

    \n
  • \n
  • \n

    If an object is created by either the Multipart Upload or Part Copy operation, the\n ETag is not an MD5 digest, regardless of the method of encryption. If an object is\n larger than 16 MB, the Amazon Web Services Management Console will upload or copy that object as a\n Multipart Upload, and therefore the ETag will not be an MD5 digest.

    \n
  • \n
\n \n

\n Directory buckets - MD5 is not supported by directory buckets.

\n
" } }, "ChecksumAlgorithm": { @@ -25742,26 +27856,25 @@ "Size": { "target": "com.amazonaws.s3#Size", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Size in bytes of the object

" } }, "StorageClass": { "target": "com.amazonaws.s3#ObjectStorageClass", "traits": { - "smithy.api#documentation": "

The class of storage used to store the object.

" + "smithy.api#documentation": "

The class of storage used to store the object.

\n \n

\n Directory buckets - Only the S3 Express One Zone storage class is supported by directory buckets to store objects.

\n
" } }, "Owner": { "target": "com.amazonaws.s3#Owner", "traits": { - "smithy.api#documentation": "

The owner of the object

" + "smithy.api#documentation": "

The owner of the object

\n \n

\n Directory buckets - The bucket owner is returned as the object owner.

\n
" } }, "RestoreStatus": { "target": "com.amazonaws.s3#RestoreStatus", "traits": { - "smithy.api#documentation": "

Specifies the restoration status of an object. Objects in certain storage classes must\n be restored before they can be retrieved. For more information about these storage classes\n and how to work with archived objects, see Working with archived\n objects in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

Specifies the restoration status of an object. Objects in certain storage classes must\n be restored before they can be retrieved. For more information about these storage classes\n and how to work with archived objects, see Working with archived\n objects in the Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets. Only the S3 Express One Zone storage class is supported by directory buckets to store objects.

\n
" } } }, @@ -25774,7 +27887,8 @@ "members": {}, "traits": { "smithy.api#documentation": "

This action is not allowed against this storage tier.

", - "smithy.api#error": "client" + "smithy.api#error": "client", + "smithy.api#httpError": 403 } }, "com.amazonaws.s3#ObjectAttributes": { @@ -25878,7 +27992,7 @@ "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

VersionId for the specific version of the object to delete.

" + "smithy.api#documentation": "

Version ID for the specific version of the object to delete.

\n \n

This functionality is not supported for directory buckets.

\n
" } } }, @@ -25938,10 +28052,7 @@ } }, "com.amazonaws.s3#ObjectLockEnabledForBucket": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#ObjectLockLegalHold": { "type": "structure", @@ -26056,7 +28167,8 @@ "members": {}, "traits": { "smithy.api#documentation": "

The source object of the COPY action is not in the active tier and is only stored in\n Amazon S3 Glacier.

", - "smithy.api#error": "client" + "smithy.api#error": "client", + "smithy.api#httpError": 403 } }, "com.amazonaws.s3#ObjectOwnership": { @@ -26082,7 +28194,7 @@ } }, "traits": { - "smithy.api#documentation": "

The container element for object ownership for a bucket's ownership controls.

\n

BucketOwnerPreferred - Objects uploaded to the bucket change ownership to the bucket\n owner if the objects are uploaded with the bucket-owner-full-control canned\n ACL.

\n

ObjectWriter - The uploading account will own the object if the object is uploaded with\n the bucket-owner-full-control canned ACL.

\n

BucketOwnerEnforced - Access control lists (ACLs) are disabled and no longer affect\n permissions. The bucket owner automatically owns and has full control over every object in\n the bucket. The bucket only accepts PUT requests that don't specify an ACL or bucket owner\n full control ACLs, such as the bucket-owner-full-control canned ACL or an\n equivalent form of this ACL expressed in the XML format.

" + "smithy.api#documentation": "

The container element for object ownership for a bucket's ownership controls.

\n

\n BucketOwnerPreferred - Objects uploaded to the bucket change ownership to the bucket\n owner if the objects are uploaded with the bucket-owner-full-control canned\n ACL.

\n

\n ObjectWriter - The uploading account will own the object if the object is uploaded with\n the bucket-owner-full-control canned ACL.

\n

\n BucketOwnerEnforced - Access control lists (ACLs) are disabled and no longer affect\n permissions. The bucket owner automatically owns and has full control over every object in\n the bucket. The bucket only accepts PUT requests that don't specify an ACL or specify bucket owner\n full control ACLs (such as the predefined bucket-owner-full-control canned ACL or a custom ACL \n in XML format that grants the same permissions).

\n

By default, ObjectOwnership is set to BucketOwnerEnforced and ACLs are disabled. We recommend\n keeping ACLs disabled, except in uncommon use cases where you must control access for each object individually. For more information about S3 Object Ownership, see\n Controlling ownership of objects and disabling ACLs for your bucket in the Amazon S3 User Guide.\n

\n \n

This functionality is not supported for directory buckets. Directory buckets use the bucket owner enforced setting for S3 Object Ownership.

\n
" } }, "com.amazonaws.s3#ObjectPart": { @@ -26091,14 +28203,12 @@ "PartNumber": { "target": "com.amazonaws.s3#PartNumber", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The part number identifying the part. This value is a positive integer between 1 and\n 10,000.

" } }, "Size": { "target": "com.amazonaws.s3#Size", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The size of the uploaded part in bytes.

" } }, @@ -26111,19 +28221,19 @@ "ChecksumCRC32C": { "target": "com.amazonaws.s3#ChecksumCRC32C", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA1": { "target": "com.amazonaws.s3#ChecksumSHA1", "traits": { - "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. When you use the API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA256": { "target": "com.amazonaws.s3#ChecksumSHA256", "traits": { - "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } } }, @@ -26132,22 +28242,13 @@ } }, "com.amazonaws.s3#ObjectSize": { - "type": "long", - "traits": { - "smithy.api#default": 0 - } + "type": "long" }, "com.amazonaws.s3#ObjectSizeGreaterThanBytes": { - "type": "long", - "traits": { - "smithy.api#default": 0 - } + "type": "long" }, "com.amazonaws.s3#ObjectSizeLessThanBytes": { - "type": "long", - "traits": { - "smithy.api#default": 0 - } + "type": "long" }, "com.amazonaws.s3#ObjectStorageClass": { "type": "enum", @@ -26211,6 +28312,12 @@ "traits": { "smithy.api#enumValue": "SNOW" } + }, + "EXPRESS_ONEZONE": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "EXPRESS_ONEZONE" + } } } }, @@ -26233,7 +28340,6 @@ "Size": { "target": "com.amazonaws.s3#Size", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Size in bytes of the object.

" } }, @@ -26258,14 +28364,13 @@ "IsLatest": { "target": "com.amazonaws.s3#IsLatest", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Specifies whether the object is (true) or is not (false) the latest version of an\n object.

" } }, "LastModified": { "target": "com.amazonaws.s3#LastModified", "traits": { - "smithy.api#documentation": "

Date and time the object was last modified.

" + "smithy.api#documentation": "

Date and time when the object was last modified.

" } }, "Owner": { @@ -26362,7 +28467,7 @@ "DisplayName": { "target": "com.amazonaws.s3#DisplayName", "traits": { - "smithy.api#documentation": "

Container for the display name of the owner. This value is only supported in the\n following Amazon Web Services Regions:

\n
    \n
  • \n

    US East (N. Virginia)

    \n
  • \n
  • \n

    US West (N. California)

    \n
  • \n
  • \n

    US West (Oregon)

    \n
  • \n
  • \n

    Asia Pacific (Singapore)

    \n
  • \n
  • \n

    Asia Pacific (Sydney)

    \n
  • \n
  • \n

    Asia Pacific (Tokyo)

    \n
  • \n
  • \n

    Europe (Ireland)

    \n
  • \n
  • \n

    South America (São Paulo)

    \n
  • \n
" + "smithy.api#documentation": "

Container for the display name of the owner. This value is only supported in the\n following Amazon Web Services Regions:

\n
    \n
  • \n

    US East (N. Virginia)

    \n
  • \n
  • \n

    US West (N. California)

    \n
  • \n
  • \n

    US West (Oregon)

    \n
  • \n
  • \n

    Asia Pacific (Singapore)

    \n
  • \n
  • \n

    Asia Pacific (Sydney)

    \n
  • \n
  • \n

    Asia Pacific (Tokyo)

    \n
  • \n
  • \n

    Europe (Ireland)

    \n
  • \n
  • \n

    South America (São Paulo)

    \n
  • \n
\n \n

This functionality is not supported for directory buckets.

\n
" } }, "ID": { @@ -26437,7 +28542,6 @@ "PartNumber": { "target": "com.amazonaws.s3#PartNumber", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Part number identifying the part. This is a positive integer between 1 and\n 10,000.

" } }, @@ -26456,7 +28560,6 @@ "Size": { "target": "com.amazonaws.s3#Size", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Size in bytes of the uploaded part data.

" } }, @@ -26469,13 +28572,13 @@ "ChecksumCRC32C": { "target": "com.amazonaws.s3#ChecksumCRC32C", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA1": { "target": "com.amazonaws.s3#ChecksumSHA1", "traits": { - "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. When you use the API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

" } }, "ChecksumSHA256": { @@ -26490,14 +28593,43 @@ } }, "com.amazonaws.s3#PartNumber": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#PartNumberMarker": { "type": "string" }, + "com.amazonaws.s3#PartitionDateSource": { + "type": "enum", + "members": { + "EventTime": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "EventTime" + } + }, + "DeliveryTime": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "DeliveryTime" + } + } + } + }, + "com.amazonaws.s3#PartitionedPrefix": { + "type": "structure", + "members": { + "PartitionDateSource": { + "target": "com.amazonaws.s3#PartitionDateSource", + "traits": { + "smithy.api#documentation": "

Specifies the partition date source for the partitioned prefix. PartitionDateSource can be EventTime or DeliveryTime.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Amazon S3 keys for log objects are partitioned in the following format:

\n

\n [DestinationPrefix][SourceAccountId]/[SourceRegion]/[SourceBucket]/[YYYY]/[MM]/[DD]/[YYYY]-[MM]-[DD]-[hh]-[mm]-[ss]-[UniqueString]\n

\n

PartitionedPrefix defaults to EventTime delivery when server access logs are delivered.

", + "smithy.api#xmlName": "PartitionedPrefix" + } + }, "com.amazonaws.s3#Parts": { "type": "list", "member": { @@ -26505,10 +28637,7 @@ } }, "com.amazonaws.s3#PartsCount": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#PartsList": { "type": "list", @@ -26577,7 +28706,6 @@ "IsPublic": { "target": "com.amazonaws.s3#IsPublic", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

The policy status for this bucket. TRUE indicates that this bucket is\n public. FALSE indicates that the bucket is not public.

", "smithy.api#xmlName": "IsPublic" } @@ -26591,10 +28719,7 @@ "type": "string" }, "com.amazonaws.s3#Priority": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#Progress": { "type": "structure", @@ -26602,21 +28727,18 @@ "BytesScanned": { "target": "com.amazonaws.s3#BytesScanned", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The current number of object bytes scanned.

" } }, "BytesProcessed": { "target": "com.amazonaws.s3#BytesProcessed", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The current number of uncompressed object bytes processed.

" } }, "BytesReturned": { "target": "com.amazonaws.s3#BytesReturned", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The current number of bytes of records payload data returned.

" } } @@ -26663,7 +28785,6 @@ "BlockPublicAcls": { "target": "com.amazonaws.s3#Setting", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Specifies whether Amazon S3 should block public access control lists (ACLs) for this bucket\n and objects in this bucket. Setting this element to TRUE causes the following\n behavior:

\n
    \n
  • \n

    PUT Bucket ACL and PUT Object ACL calls fail if the specified ACL is\n public.

    \n
  • \n
  • \n

    PUT Object calls fail if the request includes a public ACL.

    \n
  • \n
  • \n

    PUT Bucket calls fail if the request includes a public ACL.

    \n
  • \n
\n

Enabling this setting doesn't affect existing policies or ACLs.

", "smithy.api#xmlName": "BlockPublicAcls" } @@ -26671,7 +28792,6 @@ "IgnorePublicAcls": { "target": "com.amazonaws.s3#Setting", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Specifies whether Amazon S3 should ignore public ACLs for this bucket and objects in this\n bucket. Setting this element to TRUE causes Amazon S3 to ignore all public ACLs on\n this bucket and objects in this bucket.

\n

Enabling this setting doesn't affect the persistence of any existing ACLs and doesn't\n prevent new public ACLs from being set.

", "smithy.api#xmlName": "IgnorePublicAcls" } @@ -26679,7 +28799,6 @@ "BlockPublicPolicy": { "target": "com.amazonaws.s3#Setting", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Specifies whether Amazon S3 should block public bucket policies for this bucket. Setting this\n element to TRUE causes Amazon S3 to reject calls to PUT Bucket policy if the\n specified bucket policy allows public access.

\n

Enabling this setting doesn't affect existing bucket policies.

", "smithy.api#xmlName": "BlockPublicPolicy" } @@ -26687,7 +28806,6 @@ "RestrictPublicBuckets": { "target": "com.amazonaws.s3#Setting", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Specifies whether Amazon S3 should restrict public bucket policies for this bucket. Setting\n this element to TRUE restricts access to this bucket to only Amazon Web Service principals and authorized users within this account if the bucket has\n a public policy.

\n

Enabling this setting doesn't affect previously stored bucket policies, except that\n public and cross-account access within any public bucket policy, including non-public\n delegation to specific accounts, is blocked.

", "smithy.api#xmlName": "RestrictPublicBuckets" } @@ -26709,11 +28827,16 @@ "aws.protocols#httpChecksum": { "requestAlgorithmMember": "ChecksumAlgorithm" }, - "smithy.api#documentation": "

Sets the accelerate configuration of an existing bucket. Amazon S3 Transfer Acceleration is a\n bucket-level feature that enables you to perform faster data transfers to Amazon S3.

\n

To use this operation, you must have permission to perform the\n s3:PutAccelerateConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

The Transfer Acceleration state of a bucket can be set to one of the following two\n values:

\n
    \n
  • \n

    Enabled – Enables accelerated data transfers to the bucket.

    \n
  • \n
  • \n

    Suspended – Disables accelerated data transfers to the bucket.

    \n
  • \n
\n

The GetBucketAccelerateConfiguration action returns the transfer acceleration state\n of a bucket.

\n

After setting the Transfer Acceleration state of a bucket to Enabled, it might take up\n to thirty minutes before the data transfer rates to the bucket increase.

\n

The name of the bucket used for Transfer Acceleration must be DNS-compliant and must\n not contain periods (\".\").

\n

For more information about transfer acceleration, see Transfer\n Acceleration.

\n

The following operations are related to\n PutBucketAccelerateConfiguration:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Sets the accelerate configuration of an existing bucket. Amazon S3 Transfer Acceleration is a\n bucket-level feature that enables you to perform faster data transfers to Amazon S3.

\n

To use this operation, you must have permission to perform the\n s3:PutAccelerateConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

The Transfer Acceleration state of a bucket can be set to one of the following two\n values:

\n
    \n
  • \n

    Enabled – Enables accelerated data transfers to the bucket.

    \n
  • \n
  • \n

    Suspended – Disables accelerated data transfers to the bucket.

    \n
  • \n
\n

The GetBucketAccelerateConfiguration action returns the transfer acceleration state\n of a bucket.

\n

After setting the Transfer Acceleration state of a bucket to Enabled, it might take up\n to thirty minutes before the data transfer rates to the bucket increase.

\n

The name of the bucket used for Transfer Acceleration must be DNS-compliant and must\n not contain periods (\".\").

\n

For more information about transfer acceleration, see Transfer\n Acceleration.

\n

The following operations are related to\n PutBucketAccelerateConfiguration:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?accelerate", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -26743,14 +28866,14 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } } @@ -26772,7 +28895,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Sets the permissions on an existing bucket using access control lists (ACL). For more\n information, see Using ACLs. To set the ACL of a\n bucket, you must have WRITE_ACP permission.

\n

You can use one of the following two ways to set a bucket's permissions:

\n
    \n
  • \n

    Specify the ACL in the request body

    \n
  • \n
  • \n

    Specify permissions using request headers

    \n
  • \n
\n \n

You cannot specify access permission using both the body and the request\n headers.

\n
\n

Depending on your application needs, you may choose to set the ACL on a bucket using\n either the request body or the headers. For example, if you have an existing application\n that updates a bucket ACL using the request body, then you can continue to use that\n approach.

\n \n

If your bucket uses the bucket owner enforced setting for S3 Object Ownership, ACLs\n are disabled and no longer affect permissions. You must use policies to grant access to\n your bucket and the objects in it. Requests to set ACLs or update ACLs fail and return\n the AccessControlListNotSupported error code. Requests to read ACLs are\n still supported. For more information, see Controlling object\n ownership in the Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n

You can set access permissions by using one of the following methods:

\n
    \n
  • \n

    Specify a canned ACL with the x-amz-acl request header. Amazon S3\n supports a set of predefined ACLs, known as canned\n ACLs. Each canned ACL has a predefined set of grantees and\n permissions. Specify the canned ACL name as the value of\n x-amz-acl. If you use this header, you cannot use other\n access control-specific headers in your request. For more information, see\n Canned\n ACL.

    \n
  • \n
  • \n

    Specify access permissions explicitly with the\n x-amz-grant-read, x-amz-grant-read-acp,\n x-amz-grant-write-acp, and\n x-amz-grant-full-control headers. When using these headers,\n you specify explicit access permissions and grantees (Amazon Web Services accounts or Amazon S3\n groups) who will receive the permission. If you use these ACL-specific\n headers, you cannot use the x-amz-acl header to set a canned\n ACL. These parameters map to the set of permissions that Amazon S3 supports in an\n ACL. For more information, see Access Control List (ACL)\n Overview.

    \n

    You specify each grantee as a type=value pair, where the type is one of\n the following:

    \n
      \n
    • \n

      \n id – if the value specified is the canonical user ID\n of an Amazon Web Services account

      \n
    • \n
    • \n

      \n uri – if you are granting permissions to a predefined\n group

      \n
    • \n
    • \n

      \n emailAddress – if the value specified is the email\n address of an Amazon Web Services account

      \n \n

      Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

      \n
        \n
      • \n

        US East (N. Virginia)

        \n
      • \n
      • \n

        US West (N. California)

        \n
      • \n
      • \n

        US West (Oregon)

        \n
      • \n
      • \n

        Asia Pacific (Singapore)

        \n
      • \n
      • \n

        Asia Pacific (Sydney)

        \n
      • \n
      • \n

        Asia Pacific (Tokyo)

        \n
      • \n
      • \n

        Europe (Ireland)

        \n
      • \n
      • \n

        South America (São Paulo)

        \n
      • \n
      \n

      For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

      \n
      \n
    • \n
    \n

    For example, the following x-amz-grant-write header grants\n create, overwrite, and delete objects permission to LogDelivery group\n predefined by Amazon S3 and two Amazon Web Services accounts identified by their email\n addresses.

    \n

    \n x-amz-grant-write:\n uri=\"http://acs.amazonaws.com/groups/s3/LogDelivery\", id=\"111122223333\",\n id=\"555566667777\" \n

    \n
  • \n
\n

You can use either a canned ACL or specify access permissions explicitly. You\n cannot do both.

\n
\n
Grantee Values
\n
\n

You can specify the person (grantee) to whom you're assigning access rights\n (using request elements) in the following ways:

\n
    \n
  • \n

    By the person's ID:

    \n

    \n <>ID<><>GranteesEmail<>\n \n

    \n

    DisplayName is optional and ignored in the request

    \n
  • \n
  • \n

    By URI:

    \n

    \n <>http://acs.amazonaws.com/groups/global/AuthenticatedUsers<>\n

    \n
  • \n
  • \n

    By Email address:

    \n

    \n <>Grantees@email.com<>&\n

    \n

    The grantee is resolved to the CanonicalUser and, in a response to a GET\n Object acl request, appears as the CanonicalUser.

    \n \n

    Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

    \n
      \n
    • \n

      US East (N. Virginia)

      \n
    • \n
    • \n

      US West (N. California)

      \n
    • \n
    • \n

      US West (Oregon)

      \n
    • \n
    • \n

      Asia Pacific (Singapore)

      \n
    • \n
    • \n

      Asia Pacific (Sydney)

      \n
    • \n
    • \n

      Asia Pacific (Tokyo)

      \n
    • \n
    • \n

      Europe (Ireland)

      \n
    • \n
    • \n

      South America (São Paulo)

      \n
    • \n
    \n

    For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

    \n
    \n
  • \n
\n
\n
\n

The following operations are related to PutBucketAcl:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Sets the permissions on an existing bucket using access control lists (ACL). For more\n information, see Using ACLs. To set the ACL of a\n bucket, you must have the WRITE_ACP permission.

\n

You can use one of the following two ways to set a bucket's permissions:

\n
    \n
  • \n

    Specify the ACL in the request body

    \n
  • \n
  • \n

    Specify permissions using request headers

    \n
  • \n
\n \n

You cannot specify access permission using both the body and the request\n headers.

\n
\n

Depending on your application needs, you may choose to set the ACL on a bucket using\n either the request body or the headers. For example, if you have an existing application\n that updates a bucket ACL using the request body, then you can continue to use that\n approach.

\n \n

If your bucket uses the bucket owner enforced setting for S3 Object Ownership, ACLs\n are disabled and no longer affect permissions. You must use policies to grant access to\n your bucket and the objects in it. Requests to set ACLs or update ACLs fail and return\n the AccessControlListNotSupported error code. Requests to read ACLs are\n still supported. For more information, see Controlling object\n ownership in the Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n

You can set access permissions by using one of the following methods:

\n
    \n
  • \n

    Specify a canned ACL with the x-amz-acl request header. Amazon S3\n supports a set of predefined ACLs, known as canned\n ACLs. Each canned ACL has a predefined set of grantees and\n permissions. Specify the canned ACL name as the value of\n x-amz-acl. If you use this header, you cannot use other\n access control-specific headers in your request. For more information, see\n Canned\n ACL.

    \n
  • \n
  • \n

    Specify access permissions explicitly with the\n x-amz-grant-read, x-amz-grant-read-acp,\n x-amz-grant-write-acp, and\n x-amz-grant-full-control headers. When using these headers,\n you specify explicit access permissions and grantees (Amazon Web Services accounts or Amazon S3\n groups) who will receive the permission. If you use these ACL-specific\n headers, you cannot use the x-amz-acl header to set a canned\n ACL. These parameters map to the set of permissions that Amazon S3 supports in an\n ACL. For more information, see Access Control List (ACL)\n Overview.

    \n

    You specify each grantee as a type=value pair, where the type is one of\n the following:

    \n
      \n
    • \n

      \n id – if the value specified is the canonical user ID\n of an Amazon Web Services account

      \n
    • \n
    • \n

      \n uri – if you are granting permissions to a predefined\n group

      \n
    • \n
    • \n

      \n emailAddress – if the value specified is the email\n address of an Amazon Web Services account

      \n \n

      Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

      \n
        \n
      • \n

        US East (N. Virginia)

        \n
      • \n
      • \n

        US West (N. California)

        \n
      • \n
      • \n

        US West (Oregon)

        \n
      • \n
      • \n

        Asia Pacific (Singapore)

        \n
      • \n
      • \n

        Asia Pacific (Sydney)

        \n
      • \n
      • \n

        Asia Pacific (Tokyo)

        \n
      • \n
      • \n

        Europe (Ireland)

        \n
      • \n
      • \n

        South America (São Paulo)

        \n
      • \n
      \n

      For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

      \n
      \n
    • \n
    \n

    For example, the following x-amz-grant-write header grants\n create, overwrite, and delete objects permission to LogDelivery group\n predefined by Amazon S3 and two Amazon Web Services accounts identified by their email\n addresses.

    \n

    \n x-amz-grant-write:\n uri=\"http://acs.amazonaws.com/groups/s3/LogDelivery\", id=\"111122223333\",\n id=\"555566667777\" \n

    \n
  • \n
\n

You can use either a canned ACL or specify access permissions explicitly. You\n cannot do both.

\n
\n
Grantee Values
\n
\n

You can specify the person (grantee) to whom you're assigning access rights\n (using request elements) in the following ways:

\n
    \n
  • \n

    By the person's ID:

    \n

    \n <>ID<><>GranteesEmail<>\n \n

    \n

    DisplayName is optional and ignored in the request

    \n
  • \n
  • \n

    By URI:

    \n

    \n <>http://acs.amazonaws.com/groups/global/AuthenticatedUsers<>\n

    \n
  • \n
  • \n

    By Email address:

    \n

    \n <>Grantees@email.com<>&\n

    \n

    The grantee is resolved to the CanonicalUser and, in a response to a GET\n Object acl request, appears as the CanonicalUser.

    \n \n

    Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

    \n
      \n
    • \n

      US East (N. Virginia)

      \n
    • \n
    • \n

      US West (N. California)

      \n
    • \n
    • \n

      US West (Oregon)

      \n
    • \n
    • \n

      Asia Pacific (Singapore)

      \n
    • \n
    • \n

      Asia Pacific (Sydney)

      \n
    • \n
    • \n

      Asia Pacific (Tokyo)

      \n
    • \n
    • \n

      Europe (Ireland)

      \n
    • \n
    • \n

      South America (São Paulo)

      \n
    • \n
    \n

    For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

    \n
    \n
  • \n
\n
\n
\n

The following operations are related to PutBucketAcl:

\n ", "smithy.api#examples": [ { "title": "Put bucket acl", @@ -26788,6 +28911,11 @@ "method": "PUT", "uri": "/{Bucket}?acl", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -26830,7 +28958,7 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, @@ -26872,7 +29000,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -26890,11 +29018,16 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Sets an analytics configuration for the bucket (specified by the analytics configuration\n ID). You can have up to 1,000 analytics configurations per bucket.

\n

You can choose to have storage class analysis export analysis reports sent to a\n comma-separated values (CSV) flat file. See the DataExport request element.\n Reports are updated daily and are based on the object filters that you configure. When\n selecting data export, you specify a destination bucket and an optional destination prefix\n where the file is written. You can export the data to a destination bucket in a different\n account. However, the destination bucket must be in the same Region as the bucket that you\n are making the PUT analytics configuration to. For more information, see Amazon S3\n Analytics – Storage Class Analysis.

\n \n

You must create a bucket policy on the destination bucket where the exported file is\n written to grant permissions to Amazon S3 to write objects to the bucket. For an example\n policy, see Granting Permissions for Amazon S3 Inventory and Storage Class Analysis.

\n
\n

To use this operation, you must have permissions to perform the\n s3:PutAnalyticsConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

\n PutBucketAnalyticsConfiguration has the following special errors:

\n
    \n
  • \n
      \n
    • \n

      \n HTTP Error: HTTP 400 Bad Request\n

      \n
    • \n
    • \n

      \n Code: InvalidArgument\n

      \n
    • \n
    • \n

      \n Cause: Invalid argument.\n

      \n
    • \n
    \n
  • \n
  • \n
      \n
    • \n

      \n HTTP Error: HTTP 400 Bad Request\n

      \n
    • \n
    • \n

      \n Code: TooManyConfigurations\n

      \n
    • \n
    • \n

      \n Cause: You are attempting to create a new configuration but have\n already reached the 1,000-configuration limit.\n

      \n
    • \n
    \n
  • \n
  • \n
      \n
    • \n

      \n HTTP Error: HTTP 403 Forbidden\n

      \n
    • \n
    • \n

      \n Code: AccessDenied\n

      \n
    • \n
    • \n

      \n Cause: You are not the owner of the specified bucket, or you do\n not have the s3:PutAnalyticsConfiguration bucket permission to set the\n configuration on the bucket.\n

      \n
    • \n
    \n
  • \n
\n

The following operations are related to\n PutBucketAnalyticsConfiguration:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Sets an analytics configuration for the bucket (specified by the analytics configuration\n ID). You can have up to 1,000 analytics configurations per bucket.

\n

You can choose to have storage class analysis export analysis reports sent to a\n comma-separated values (CSV) flat file. See the DataExport request element.\n Reports are updated daily and are based on the object filters that you configure. When\n selecting data export, you specify a destination bucket and an optional destination prefix\n where the file is written. You can export the data to a destination bucket in a different\n account. However, the destination bucket must be in the same Region as the bucket that you\n are making the PUT analytics configuration to. For more information, see Amazon S3\n Analytics – Storage Class Analysis.

\n \n

You must create a bucket policy on the destination bucket where the exported file is\n written to grant permissions to Amazon S3 to write objects to the bucket. For an example\n policy, see Granting Permissions for Amazon S3 Inventory and Storage Class Analysis.

\n
\n

To use this operation, you must have permissions to perform the\n s3:PutAnalyticsConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

\n PutBucketAnalyticsConfiguration has the following special errors:

\n
    \n
  • \n
      \n
    • \n

      \n HTTP Error: HTTP 400 Bad Request\n

      \n
    • \n
    • \n

      \n Code: InvalidArgument\n

      \n
    • \n
    • \n

      \n Cause: Invalid argument.\n

      \n
    • \n
    \n
  • \n
  • \n
      \n
    • \n

      \n HTTP Error: HTTP 400 Bad Request\n

      \n
    • \n
    • \n

      \n Code: TooManyConfigurations\n

      \n
    • \n
    • \n

      \n Cause: You are attempting to create a new configuration but have\n already reached the 1,000-configuration limit.\n

      \n
    • \n
    \n
  • \n
  • \n
      \n
    • \n

      \n HTTP Error: HTTP 403 Forbidden\n

      \n
    • \n
    • \n

      \n Code: AccessDenied\n

      \n
    • \n
    • \n

      \n Cause: You are not the owner of the specified bucket, or you do\n not have the s3:PutAnalyticsConfiguration bucket permission to set the\n configuration on the bucket.\n

      \n
    • \n
    \n
  • \n
\n

The following operations are related to\n PutBucketAnalyticsConfiguration:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?analytics", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -26932,7 +29065,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -26954,7 +29087,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Sets the cors configuration for your bucket. If the configuration exists,\n Amazon S3 replaces it.

\n

To use this operation, you must be allowed to perform the s3:PutBucketCORS\n action. By default, the bucket owner has this permission and can grant it to others.

\n

You set this configuration on a bucket so that the bucket can service cross-origin\n requests. For example, you might want to enable a request whose origin is\n http://www.example.com to access your Amazon S3 bucket at\n my.example.bucket.com by using the browser's XMLHttpRequest\n capability.

\n

To enable cross-origin resource sharing (CORS) on a bucket, you add the\n cors subresource to the bucket. The cors subresource is an XML\n document in which you configure rules that identify origins and the HTTP methods that can\n be executed on your bucket. The document is limited to 64 KB in size.

\n

When Amazon S3 receives a cross-origin request (or a pre-flight OPTIONS request) against a\n bucket, it evaluates the cors configuration on the bucket and uses the first\n CORSRule rule that matches the incoming browser request to enable a\n cross-origin request. For a rule to match, the following conditions must be met:

\n
    \n
  • \n

    The request's Origin header must match AllowedOrigin\n elements.

    \n
  • \n
  • \n

    The request method (for example, GET, PUT, HEAD, and so on) or the\n Access-Control-Request-Method header in case of a pre-flight\n OPTIONS request must be one of the AllowedMethod\n elements.

    \n
  • \n
  • \n

    Every header specified in the Access-Control-Request-Headers request\n header of a pre-flight request must match an AllowedHeader element.\n

    \n
  • \n
\n

For more information about CORS, go to Enabling Cross-Origin Resource Sharing in\n the Amazon S3 User Guide.

\n

The following operations are related to PutBucketCors:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Sets the cors configuration for your bucket. If the configuration exists,\n Amazon S3 replaces it.

\n

To use this operation, you must be allowed to perform the s3:PutBucketCORS\n action. By default, the bucket owner has this permission and can grant it to others.

\n

You set this configuration on a bucket so that the bucket can service cross-origin\n requests. For example, you might want to enable a request whose origin is\n http://www.example.com to access your Amazon S3 bucket at\n my.example.bucket.com by using the browser's XMLHttpRequest\n capability.

\n

To enable cross-origin resource sharing (CORS) on a bucket, you add the\n cors subresource to the bucket. The cors subresource is an XML\n document in which you configure rules that identify origins and the HTTP methods that can\n be executed on your bucket. The document is limited to 64 KB in size.

\n

When Amazon S3 receives a cross-origin request (or a pre-flight OPTIONS request) against a\n bucket, it evaluates the cors configuration on the bucket and uses the first\n CORSRule rule that matches the incoming browser request to enable a\n cross-origin request. For a rule to match, the following conditions must be met:

\n
    \n
  • \n

    The request's Origin header must match AllowedOrigin\n elements.

    \n
  • \n
  • \n

    The request method (for example, GET, PUT, HEAD, and so on) or the\n Access-Control-Request-Method header in case of a pre-flight\n OPTIONS request must be one of the AllowedMethod\n elements.

    \n
  • \n
  • \n

    Every header specified in the Access-Control-Request-Headers request\n header of a pre-flight request must match an AllowedHeader element.\n

    \n
  • \n
\n

For more information about CORS, go to Enabling Cross-Origin Resource Sharing in\n the Amazon S3 User Guide.

\n

The following operations are related to PutBucketCors:

\n ", "smithy.api#examples": [ { "title": "To set cors configuration on a bucket.", @@ -27002,6 +29135,11 @@ "method": "PUT", "uri": "/{Bucket}?cors", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -27038,14 +29176,14 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -27067,11 +29205,16 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

This action uses the encryption subresource to configure default encryption\n and Amazon S3 Bucket Keys for an existing bucket.

\n

By default, all buckets have a default encryption configuration that uses server-side\n encryption with Amazon S3 managed keys (SSE-S3). You can optionally configure default encryption\n for a bucket by using server-side encryption with Key Management Service (KMS) keys (SSE-KMS) or\n dual-layer server-side encryption with Amazon Web Services KMS keys (DSSE-KMS). If you specify default encryption by using\n SSE-KMS, you can also configure Amazon S3 Bucket\n Keys. If you use PutBucketEncryption to set your default bucket encryption to SSE-KMS, you should verify that your KMS key ID is correct. Amazon S3 does not validate the KMS key ID provided in PutBucketEncryption requests.

\n \n

This action requires Amazon Web Services Signature Version 4. For more information, see \n Authenticating Requests (Amazon Web Services Signature Version 4).

\n
\n

To use this operation, you must have permission to perform the\n s3:PutEncryptionConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources in the\n Amazon S3 User Guide.

\n

The following operations are related to PutBucketEncryption:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

This action uses the encryption subresource to configure default encryption\n and Amazon S3 Bucket Keys for an existing bucket.

\n

By default, all buckets have a default encryption configuration that uses server-side\n encryption with Amazon S3 managed keys (SSE-S3). You can optionally configure default encryption\n for a bucket by using server-side encryption with Key Management Service (KMS) keys (SSE-KMS) or\n dual-layer server-side encryption with Amazon Web Services KMS keys (DSSE-KMS). If you specify default encryption by using\n SSE-KMS, you can also configure Amazon S3 Bucket\n Keys. If you use PutBucketEncryption to set your default bucket encryption to SSE-KMS, you should verify that your KMS key ID is correct. Amazon S3 does not validate the KMS key ID provided in PutBucketEncryption requests.

\n \n

This action requires Amazon Web Services Signature Version 4. For more information, see \n Authenticating Requests (Amazon Web Services Signature Version 4).

\n
\n

To use this operation, you must have permission to perform the\n s3:PutEncryptionConfiguration action. The bucket owner has this permission\n by default. The bucket owner can grant this permission to others. For more information\n about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources in the\n Amazon S3 User Guide.

\n

The following operations are related to PutBucketEncryption:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?encryption", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -27099,7 +29242,7 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, @@ -27114,7 +29257,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -27132,11 +29275,16 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Puts a S3 Intelligent-Tiering configuration to the specified bucket. You can have up to\n 1,000 S3 Intelligent-Tiering configurations per bucket.

\n

The S3 Intelligent-Tiering storage class is designed to optimize storage costs by automatically moving data to the most cost-effective storage access tier, without performance impact or operational overhead. S3 Intelligent-Tiering delivers automatic cost savings in three low latency and high throughput access tiers. To get the lowest storage cost on data that can be accessed in minutes to hours, you can choose to activate additional archiving capabilities.

\n

The S3 Intelligent-Tiering storage class is the ideal storage class for data with unknown, changing, or unpredictable access patterns, independent of object size or retention period. If the size of an object is less than 128 KB, it is not monitored and not eligible for auto-tiering. Smaller objects can be stored, but they are always charged at the Frequent Access tier rates in the S3 Intelligent-Tiering storage class.

\n

For more information, see Storage class for automatically optimizing frequently and infrequently accessed objects.

\n

Operations related to PutBucketIntelligentTieringConfiguration include:

\n \n \n

You only need S3 Intelligent-Tiering enabled on a bucket if you want to automatically\n move objects stored in the S3 Intelligent-Tiering storage class to the Archive Access\n or Deep Archive Access tier.

\n
\n

\n PutBucketIntelligentTieringConfiguration has the following special\n errors:

\n
\n
HTTP 400 Bad Request Error
\n
\n

\n Code: InvalidArgument

\n

\n Cause: Invalid Argument

\n
\n
HTTP 400 Bad Request Error
\n
\n

\n Code: TooManyConfigurations

\n

\n Cause: You are attempting to create a new configuration\n but have already reached the 1,000-configuration limit.

\n
\n
HTTP 403 Forbidden Error
\n
\n

\n Cause: You are not the owner of the specified bucket, or\n you do not have the s3:PutIntelligentTieringConfiguration bucket\n permission to set the configuration on the bucket.

\n
\n
", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Puts a S3 Intelligent-Tiering configuration to the specified bucket. You can have up to\n 1,000 S3 Intelligent-Tiering configurations per bucket.

\n

The S3 Intelligent-Tiering storage class is designed to optimize storage costs by automatically moving data to the most cost-effective storage access tier, without performance impact or operational overhead. S3 Intelligent-Tiering delivers automatic cost savings in three low latency and high throughput access tiers. To get the lowest storage cost on data that can be accessed in minutes to hours, you can choose to activate additional archiving capabilities.

\n

The S3 Intelligent-Tiering storage class is the ideal storage class for data with unknown, changing, or unpredictable access patterns, independent of object size or retention period. If the size of an object is less than 128 KB, it is not monitored and not eligible for auto-tiering. Smaller objects can be stored, but they are always charged at the Frequent Access tier rates in the S3 Intelligent-Tiering storage class.

\n

For more information, see Storage class for automatically optimizing frequently and infrequently accessed objects.

\n

Operations related to PutBucketIntelligentTieringConfiguration include:

\n \n \n

You only need S3 Intelligent-Tiering enabled on a bucket if you want to automatically\n move objects stored in the S3 Intelligent-Tiering storage class to the Archive Access\n or Deep Archive Access tier.

\n
\n

\n PutBucketIntelligentTieringConfiguration has the following special\n errors:

\n
\n
HTTP 400 Bad Request Error
\n
\n

\n Code: InvalidArgument

\n

\n Cause: Invalid Argument

\n
\n
HTTP 400 Bad Request Error
\n
\n

\n Code: TooManyConfigurations

\n

\n Cause: You are attempting to create a new configuration\n but have already reached the 1,000-configuration limit.

\n
\n
HTTP 403 Forbidden Error
\n
\n

\n Cause: You are not the owner of the specified bucket, or\n you do not have the s3:PutIntelligentTieringConfiguration bucket\n permission to set the configuration on the bucket.

\n
\n
", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?intelligent-tiering", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -27185,11 +29333,16 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

This implementation of the PUT action adds an inventory configuration\n (identified by the inventory ID) to the bucket. You can have up to 1,000 inventory\n configurations per bucket.

\n

Amazon S3 inventory generates inventories of the objects in the bucket on a daily or weekly\n basis, and the results are published to a flat file. The bucket that is inventoried is\n called the source bucket, and the bucket where the inventory flat file\n is stored is called the destination bucket. The\n destination bucket must be in the same Amazon Web Services Region as the\n source bucket.

\n

When you configure an inventory for a source bucket, you specify\n the destination bucket where you want the inventory to be stored, and\n whether to generate the inventory daily or weekly. You can also configure what object\n metadata to include and whether to inventory all object versions or only current versions.\n For more information, see Amazon S3 Inventory in the\n Amazon S3 User Guide.

\n \n

You must create a bucket policy on the destination bucket to\n grant permissions to Amazon S3 to write objects to the bucket in the defined location. For an\n example policy, see Granting Permissions for Amazon S3 Inventory and Storage Class Analysis.

\n
\n
\n
Permissions
\n
\n

To use this operation, you must have permission to perform the\n s3:PutInventoryConfiguration action. The bucket owner has this\n permission by default and can grant this permission to others.

\n

The s3:PutInventoryConfiguration permission allows a user to\n create an S3 Inventory\n report that includes all object metadata fields available and to specify the\n destination bucket to store the inventory. A user with read access to objects in\n the destination bucket can also access all object metadata fields that are\n available in the inventory report.

\n

To restrict access to an inventory report, see Restricting access to an Amazon S3 Inventory report in the\n Amazon S3 User Guide. For more information about the metadata\n fields available in S3 Inventory, see Amazon S3 Inventory lists in the Amazon S3 User Guide. For\n more information about permissions, see Permissions related to bucket subresource operations and Identity and access management in Amazon S3 in the\n Amazon S3 User Guide.

\n
\n
\n

\n PutBucketInventoryConfiguration has the following special errors:

\n
\n
HTTP 400 Bad Request Error
\n
\n

\n Code: InvalidArgument

\n

\n Cause: Invalid Argument

\n
\n
HTTP 400 Bad Request Error
\n
\n

\n Code: TooManyConfigurations

\n

\n Cause: You are attempting to create a new configuration\n but have already reached the 1,000-configuration limit.

\n
\n
HTTP 403 Forbidden Error
\n
\n

\n Cause: You are not the owner of the specified bucket, or\n you do not have the s3:PutInventoryConfiguration bucket permission to\n set the configuration on the bucket.

\n
\n
\n

The following operations are related to\n PutBucketInventoryConfiguration:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

This implementation of the PUT action adds an inventory configuration\n (identified by the inventory ID) to the bucket. You can have up to 1,000 inventory\n configurations per bucket.

\n

Amazon S3 inventory generates inventories of the objects in the bucket on a daily or weekly\n basis, and the results are published to a flat file. The bucket that is inventoried is\n called the source bucket, and the bucket where the inventory flat file\n is stored is called the destination bucket. The\n destination bucket must be in the same Amazon Web Services Region as the\n source bucket.

\n

When you configure an inventory for a source bucket, you specify\n the destination bucket where you want the inventory to be stored, and\n whether to generate the inventory daily or weekly. You can also configure what object\n metadata to include and whether to inventory all object versions or only current versions.\n For more information, see Amazon S3 Inventory in the\n Amazon S3 User Guide.

\n \n

You must create a bucket policy on the destination bucket to\n grant permissions to Amazon S3 to write objects to the bucket in the defined location. For an\n example policy, see Granting Permissions for Amazon S3 Inventory and Storage Class Analysis.

\n
\n
\n
Permissions
\n
\n

To use this operation, you must have permission to perform the\n s3:PutInventoryConfiguration action. The bucket owner has this\n permission by default and can grant this permission to others.

\n

The s3:PutInventoryConfiguration permission allows a user to\n create an S3 Inventory\n report that includes all object metadata fields available and to specify the\n destination bucket to store the inventory. A user with read access to objects in\n the destination bucket can also access all object metadata fields that are\n available in the inventory report.

\n

To restrict access to an inventory report, see Restricting access to an Amazon S3 Inventory report in the\n Amazon S3 User Guide. For more information about the metadata\n fields available in S3 Inventory, see Amazon S3 Inventory lists in the Amazon S3 User Guide. For\n more information about permissions, see Permissions related to bucket subresource operations and Identity and access management in Amazon S3 in the\n Amazon S3 User Guide.

\n
\n
\n

\n PutBucketInventoryConfiguration has the following special errors:

\n
\n
HTTP 400 Bad Request Error
\n
\n

\n Code: InvalidArgument

\n

\n Cause: Invalid Argument

\n
\n
HTTP 400 Bad Request Error
\n
\n

\n Code: TooManyConfigurations

\n

\n Cause: You are attempting to create a new configuration\n but have already reached the 1,000-configuration limit.

\n
\n
HTTP 403 Forbidden Error
\n
\n

\n Cause: You are not the owner of the specified bucket, or\n you do not have the s3:PutInventoryConfiguration bucket permission to\n set the configuration on the bucket.

\n
\n
\n

The following operations are related to\n PutBucketInventoryConfiguration:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?inventory", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -27227,7 +29380,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -27249,7 +29402,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Creates a new lifecycle configuration for the bucket or replaces an existing lifecycle\n configuration. Keep in mind that this will overwrite an existing lifecycle configuration,\n so if you want to retain any configuration details, they must be included in the new\n lifecycle configuration. For information about lifecycle configuration, see Managing\n your storage lifecycle.

\n \n

Bucket lifecycle configuration now supports specifying a lifecycle rule using an\n object key name prefix, one or more object tags, or a combination of both. Accordingly,\n this section describes the latest API. The previous version of the API supported\n filtering based only on an object key name prefix, which is supported for backward\n compatibility. For the related API description, see PutBucketLifecycle.

\n
\n
\n
Rules
\n
\n

You specify the lifecycle configuration in your request body. The lifecycle\n configuration is specified as XML consisting of one or more rules. An Amazon S3\n Lifecycle configuration can have up to 1,000 rules. This limit is not adjustable.\n Each rule consists of the following:

\n
    \n
  • \n

    A filter identifying a subset of objects to which the rule applies. The\n filter can be based on a key name prefix, object tags, or a combination of\n both.

    \n
  • \n
  • \n

    A status indicating whether the rule is in effect.

    \n
  • \n
  • \n

    One or more lifecycle transition and expiration actions that you want\n Amazon S3 to perform on the objects identified by the filter. If the state of\n your bucket is versioning-enabled or versioning-suspended, you can have many\n versions of the same object (one current version and zero or more noncurrent\n versions). Amazon S3 provides predefined actions that you can specify for current\n and noncurrent object versions.

    \n
  • \n
\n

For more information, see Object Lifecycle\n Management and Lifecycle Configuration\n Elements.

\n
\n
Permissions
\n
\n

By default, all Amazon S3 resources are private, including buckets, objects, and\n related subresources (for example, lifecycle configuration and website\n configuration). Only the resource owner (that is, the Amazon Web Services account that created\n it) can access the resource. The resource owner can optionally grant access\n permissions to others by writing an access policy. For this operation, a user must\n get the s3:PutLifecycleConfiguration permission.

\n

You can also explicitly deny permissions. An explicit deny also supersedes any\n other permissions. If you want to block users or accounts from removing or\n deleting objects from your bucket, you must deny them permissions for the\n following actions:

\n
    \n
  • \n

    \n s3:DeleteObject\n

    \n
  • \n
  • \n

    \n s3:DeleteObjectVersion\n

    \n
  • \n
  • \n

    \n s3:PutLifecycleConfiguration\n

    \n
  • \n
\n

For more information about permissions, see Managing Access\n Permissions to Your Amazon S3 Resources.

\n
\n
\n

The following operations are related to\n PutBucketLifecycleConfiguration:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Creates a new lifecycle configuration for the bucket or replaces an existing lifecycle\n configuration. Keep in mind that this will overwrite an existing lifecycle configuration,\n so if you want to retain any configuration details, they must be included in the new\n lifecycle configuration. For information about lifecycle configuration, see Managing\n your storage lifecycle.

\n \n

Bucket lifecycle configuration now supports specifying a lifecycle rule using an\n object key name prefix, one or more object tags, or a combination of both. Accordingly,\n this section describes the latest API. The previous version of the API supported\n filtering based only on an object key name prefix, which is supported for backward\n compatibility. For the related API description, see PutBucketLifecycle.

\n
\n
\n
Rules
\n
\n

You specify the lifecycle configuration in your request body. The lifecycle\n configuration is specified as XML consisting of one or more rules. An Amazon S3\n Lifecycle configuration can have up to 1,000 rules. This limit is not adjustable.\n Each rule consists of the following:

\n
    \n
  • \n

    A filter identifying a subset of objects to which the rule applies. The\n filter can be based on a key name prefix, object tags, or a combination of\n both.

    \n
  • \n
  • \n

    A status indicating whether the rule is in effect.

    \n
  • \n
  • \n

    One or more lifecycle transition and expiration actions that you want\n Amazon S3 to perform on the objects identified by the filter. If the state of\n your bucket is versioning-enabled or versioning-suspended, you can have many\n versions of the same object (one current version and zero or more noncurrent\n versions). Amazon S3 provides predefined actions that you can specify for current\n and noncurrent object versions.

    \n
  • \n
\n

For more information, see Object Lifecycle\n Management and Lifecycle Configuration\n Elements.

\n
\n
Permissions
\n
\n

By default, all Amazon S3 resources are private, including buckets, objects, and\n related subresources (for example, lifecycle configuration and website\n configuration). Only the resource owner (that is, the Amazon Web Services account that created\n it) can access the resource. The resource owner can optionally grant access\n permissions to others by writing an access policy. For this operation, a user must\n get the s3:PutLifecycleConfiguration permission.

\n

You can also explicitly deny permissions. An explicit deny also supersedes any\n other permissions. If you want to block users or accounts from removing or\n deleting objects from your bucket, you must deny them permissions for the\n following actions:

\n
    \n
  • \n

    \n s3:DeleteObject\n

    \n
  • \n
  • \n

    \n s3:DeleteObjectVersion\n

    \n
  • \n
  • \n

    \n s3:PutLifecycleConfiguration\n

    \n
  • \n
\n

For more information about permissions, see Managing Access\n Permissions to Your Amazon S3 Resources.

\n
\n
\n

The following operations are related to\n PutBucketLifecycleConfiguration:

\n ", "smithy.api#examples": [ { "title": "Put bucket lifecycle", @@ -27283,6 +29436,11 @@ "method": "PUT", "uri": "/{Bucket}?lifecycle", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -27303,7 +29461,7 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, @@ -27318,7 +29476,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -27340,7 +29498,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Set the logging parameters for a bucket and to specify permissions for who can view and\n modify the logging parameters. All logs are saved to buckets in the same Amazon Web Services Region as\n the source bucket. To set the logging status of a bucket, you must be the bucket\n owner.

\n

The bucket owner is automatically granted FULL_CONTROL to all logs. You use the\n Grantee request element to grant access to other people. The\n Permissions request element specifies the kind of access the grantee has to\n the logs.

\n \n

If the target bucket for log delivery uses the bucket owner enforced setting for S3\n Object Ownership, you can't use the Grantee request element to grant access\n to others. Permissions can only be granted using policies. For more information, see\n Permissions for server access log delivery in the\n Amazon S3 User Guide.

\n
\n
\n
Grantee Values
\n
\n

You can specify the person (grantee) to whom you're assigning access rights (by\n using request elements) in the following ways:

\n
    \n
  • \n

    By the person's ID:

    \n

    \n <>ID<><>GranteesEmail<>\n \n

    \n

    \n DisplayName is optional and ignored in the request.

    \n
  • \n
  • \n

    By Email address:

    \n

    \n <>Grantees@email.com<>\n

    \n

    The grantee is resolved to the CanonicalUser and, in a\n response to a GETObjectAcl request, appears as the\n CanonicalUser.

    \n
  • \n
  • \n

    By URI:

    \n

    \n <>http://acs.amazonaws.com/groups/global/AuthenticatedUsers<>\n

    \n
  • \n
\n
\n
\n

To enable logging, you use LoggingEnabled and its children request\n elements. To disable logging, you use an empty BucketLoggingStatus request\n element:

\n

\n \n

\n

For more information about server access logging, see Server Access Logging in the\n Amazon S3 User Guide.

\n

For more information about creating a bucket, see CreateBucket. For more\n information about returning the logging status of a bucket, see GetBucketLogging.

\n

The following operations are related to PutBucketLogging:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Set the logging parameters for a bucket and to specify permissions for who can view and\n modify the logging parameters. All logs are saved to buckets in the same Amazon Web Services Region as\n the source bucket. To set the logging status of a bucket, you must be the bucket\n owner.

\n

The bucket owner is automatically granted FULL_CONTROL to all logs. You use the\n Grantee request element to grant access to other people. The\n Permissions request element specifies the kind of access the grantee has to\n the logs.

\n \n

If the target bucket for log delivery uses the bucket owner enforced setting for S3\n Object Ownership, you can't use the Grantee request element to grant access\n to others. Permissions can only be granted using policies. For more information, see\n Permissions for server access log delivery in the\n Amazon S3 User Guide.

\n
\n
\n
Grantee Values
\n
\n

You can specify the person (grantee) to whom you're assigning access rights (by\n using request elements) in the following ways:

\n
    \n
  • \n

    By the person's ID:

    \n

    \n <>ID<><>GranteesEmail<>\n \n

    \n

    \n DisplayName is optional and ignored in the request.

    \n
  • \n
  • \n

    By Email address:

    \n

    \n <>Grantees@email.com<>\n

    \n

    The grantee is resolved to the CanonicalUser and, in a\n response to a GETObjectAcl request, appears as the\n CanonicalUser.

    \n
  • \n
  • \n

    By URI:

    \n

    \n <>http://acs.amazonaws.com/groups/global/AuthenticatedUsers<>\n

    \n
  • \n
\n
\n
\n

To enable logging, you use LoggingEnabled and its children request\n elements. To disable logging, you use an empty BucketLoggingStatus request\n element:

\n

\n \n

\n

For more information about server access logging, see Server Access Logging in the\n Amazon S3 User Guide.

\n

For more information about creating a bucket, see CreateBucket. For more\n information about returning the logging status of a bucket, see GetBucketLogging.

\n

The following operations are related to PutBucketLogging:

\n ", "smithy.api#examples": [ { "title": "Set logging configuration for a bucket", @@ -27369,6 +29527,11 @@ "method": "PUT", "uri": "/{Bucket}?logging", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -27405,14 +29568,14 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -27430,11 +29593,16 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Sets a metrics configuration (specified by the metrics configuration ID) for the bucket.\n You can have up to 1,000 metrics configurations per bucket. If you're updating an existing\n metrics configuration, note that this is a full replacement of the existing metrics\n configuration. If you don't include the elements you want to keep, they are erased.

\n

To use this operation, you must have permissions to perform the\n s3:PutMetricsConfiguration action. The bucket owner has this permission by\n default. The bucket owner can grant this permission to others. For more information about\n permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about CloudWatch request metrics for Amazon S3, see Monitoring\n Metrics with Amazon CloudWatch.

\n

The following operations are related to\n PutBucketMetricsConfiguration:

\n \n

\n PutBucketMetricsConfiguration has the following special error:

\n
    \n
  • \n

    Error code: TooManyConfigurations\n

    \n
      \n
    • \n

      Description: You are attempting to create a new configuration but have\n already reached the 1,000-configuration limit.

      \n
    • \n
    • \n

      HTTP Status Code: HTTP 400 Bad Request

      \n
    • \n
    \n
  • \n
", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Sets a metrics configuration (specified by the metrics configuration ID) for the bucket.\n You can have up to 1,000 metrics configurations per bucket. If you're updating an existing\n metrics configuration, note that this is a full replacement of the existing metrics\n configuration. If you don't include the elements you want to keep, they are erased.

\n

To use this operation, you must have permissions to perform the\n s3:PutMetricsConfiguration action. The bucket owner has this permission by\n default. The bucket owner can grant this permission to others. For more information about\n permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

For information about CloudWatch request metrics for Amazon S3, see Monitoring\n Metrics with Amazon CloudWatch.

\n

The following operations are related to\n PutBucketMetricsConfiguration:

\n \n

\n PutBucketMetricsConfiguration has the following special error:

\n
    \n
  • \n

    Error code: TooManyConfigurations\n

    \n
      \n
    • \n

      Description: You are attempting to create a new configuration but have\n already reached the 1,000-configuration limit.

      \n
    • \n
    • \n

      HTTP Status Code: HTTP 400 Bad Request

      \n
    • \n
    \n
  • \n
", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?metrics", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -27472,7 +29640,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -27490,7 +29658,7 @@ "target": "smithy.api#Unit" }, "traits": { - "smithy.api#documentation": "

Enables notifications of specified events for a bucket. For more information about event\n notifications, see Configuring Event\n Notifications.

\n

Using this API, you can replace an existing notification configuration. The\n configuration is an XML file that defines the event types that you want Amazon S3 to publish and\n the destination where you want Amazon S3 to publish an event notification when it detects an\n event of the specified type.

\n

By default, your bucket has no event notifications configured. That is, the notification\n configuration will be an empty NotificationConfiguration.

\n

\n \n

\n

\n \n

\n

This action replaces the existing notification configuration with the configuration you\n include in the request body.

\n

After Amazon S3 receives this request, it first verifies that any Amazon Simple Notification\n Service (Amazon SNS) or Amazon Simple Queue Service (Amazon SQS) destination exists, and\n that the bucket owner has permission to publish to it by sending a test notification. In\n the case of Lambda destinations, Amazon S3 verifies that the Lambda function permissions\n grant Amazon S3 permission to invoke the function from the Amazon S3 bucket. For more information,\n see Configuring Notifications for Amazon S3 Events.

\n

You can disable notifications by adding the empty NotificationConfiguration\n element.

\n

For more information about the number of event notification configurations that you can\n create per bucket, see Amazon S3 service quotas in Amazon Web Services\n General Reference.

\n

By default, only the bucket owner can configure notifications on a bucket. However,\n bucket owners can use a bucket policy to grant permission to other users to set this\n configuration with the required s3:PutBucketNotification permission.

\n \n

The PUT notification is an atomic operation. For example, suppose your notification\n configuration includes SNS topic, SQS queue, and Lambda function configurations. When\n you send a PUT request with this configuration, Amazon S3 sends test messages to your SNS\n topic. If the message fails, the entire PUT action will fail, and Amazon S3 will not add the\n configuration to your bucket.

\n
\n

If the configuration in the request body includes only one\n TopicConfiguration specifying only the\n s3:ReducedRedundancyLostObject event type, the response will also include\n the x-amz-sns-test-message-id header containing the message ID of the test\n notification sent to the topic.

\n

The following action is related to\n PutBucketNotificationConfiguration:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Enables notifications of specified events for a bucket. For more information about event\n notifications, see Configuring Event\n Notifications.

\n

Using this API, you can replace an existing notification configuration. The\n configuration is an XML file that defines the event types that you want Amazon S3 to publish and\n the destination where you want Amazon S3 to publish an event notification when it detects an\n event of the specified type.

\n

By default, your bucket has no event notifications configured. That is, the notification\n configuration will be an empty NotificationConfiguration.

\n

\n \n

\n

\n \n

\n

This action replaces the existing notification configuration with the configuration you\n include in the request body.

\n

After Amazon S3 receives this request, it first verifies that any Amazon Simple Notification\n Service (Amazon SNS) or Amazon Simple Queue Service (Amazon SQS) destination exists, and\n that the bucket owner has permission to publish to it by sending a test notification. In\n the case of Lambda destinations, Amazon S3 verifies that the Lambda function permissions\n grant Amazon S3 permission to invoke the function from the Amazon S3 bucket. For more information,\n see Configuring Notifications for Amazon S3 Events.

\n

You can disable notifications by adding the empty NotificationConfiguration\n element.

\n

For more information about the number of event notification configurations that you can\n create per bucket, see Amazon S3 service quotas in Amazon Web Services\n General Reference.

\n

By default, only the bucket owner can configure notifications on a bucket. However,\n bucket owners can use a bucket policy to grant permission to other users to set this\n configuration with the required s3:PutBucketNotification permission.

\n \n

The PUT notification is an atomic operation. For example, suppose your notification\n configuration includes SNS topic, SQS queue, and Lambda function configurations. When\n you send a PUT request with this configuration, Amazon S3 sends test messages to your SNS\n topic. If the message fails, the entire PUT action will fail, and Amazon S3 will not add the\n configuration to your bucket.

\n
\n

If the configuration in the request body includes only one\n TopicConfiguration specifying only the\n s3:ReducedRedundancyLostObject event type, the response will also include\n the x-amz-sns-test-message-id header containing the message ID of the test\n notification sent to the topic.

\n

The following action is related to\n PutBucketNotificationConfiguration:

\n ", "smithy.api#examples": [ { "title": "Set notification configuration for a bucket", @@ -27514,6 +29682,11 @@ "method": "PUT", "uri": "/{Bucket}?notification", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -27542,14 +29715,13 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, "SkipDestinationValidation": { "target": "com.amazonaws.s3#SkipValidation", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Skips validation of Amazon SQS, Amazon SNS, and Lambda\n destinations. True or false value.

", "smithy.api#httpHeader": "x-amz-skip-destination-validation" } @@ -27571,11 +29743,16 @@ "aws.protocols#httpChecksum": { "requestChecksumRequired": true }, - "smithy.api#documentation": "

Creates or modifies OwnershipControls for an Amazon S3 bucket. To use this\n operation, you must have the s3:PutBucketOwnershipControls permission. For\n more information about Amazon S3 permissions, see Specifying permissions in a\n policy.

\n

For information about Amazon S3 Object Ownership, see Using object\n ownership.

\n

The following operations are related to PutBucketOwnershipControls:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Creates or modifies OwnershipControls for an Amazon S3 bucket. To use this\n operation, you must have the s3:PutBucketOwnershipControls permission. For\n more information about Amazon S3 permissions, see Specifying permissions in a\n policy.

\n

For information about Amazon S3 Object Ownership, see Using object\n ownership.

\n

The following operations are related to PutBucketOwnershipControls:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?ownershipControls", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -27603,7 +29780,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -27634,7 +29811,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Applies an Amazon S3 bucket policy to an Amazon S3 bucket. If you are using an identity other than\n the root user of the Amazon Web Services account that owns the bucket, the calling identity must have the\n PutBucketPolicy permissions on the specified bucket and belong to the\n bucket owner's account in order to use this operation.

\n

If you don't have PutBucketPolicy permissions, Amazon S3 returns a 403\n Access Denied error. If you have the correct permissions, but you're not using an\n identity that belongs to the bucket owner's account, Amazon S3 returns a 405 Method Not\n Allowed error.

\n \n

To ensure that bucket owners don't inadvertently lock themselves out of their own\n buckets, the root principal in a bucket owner's Amazon Web Services account can perform the\n GetBucketPolicy, PutBucketPolicy, and\n DeleteBucketPolicy API actions, even if their bucket policy explicitly\n denies the root principal's access. Bucket owner root principals can only be blocked\n from performing these API actions by VPC endpoint policies and Amazon Web Services Organizations\n policies.

\n
\n

For more information, see Bucket policy\n examples.

\n

The following operations are related to PutBucketPolicy:

\n ", + "smithy.api#documentation": "

Applies an Amazon S3 bucket policy to an Amazon S3 bucket.

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Regional endpoint. These endpoints support path-style requests in the format https://s3express-control.region_code.amazonaws.com/bucket-name\n . Virtual-hosted-style requests aren't supported. \nFor more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n

If you are using an identity other than the\n root user of the Amazon Web Services account that owns the bucket, the calling identity must both have the\n PutBucketPolicy permissions on the specified bucket and belong to the\n bucket owner's account in order to use this operation.

\n

If you don't have PutBucketPolicy permissions, Amazon S3 returns a 403\n Access Denied error. If you have the correct permissions, but you're not using an\n identity that belongs to the bucket owner's account, Amazon S3 returns a 405 Method Not\n Allowed error.

\n \n

To ensure that bucket owners don't inadvertently lock themselves out of their own\n buckets, the root principal in a bucket owner's Amazon Web Services account can perform the\n GetBucketPolicy, PutBucketPolicy, and\n DeleteBucketPolicy API actions, even if their bucket policy explicitly\n denies the root principal's access. Bucket owner root principals can only be blocked\n from performing these API actions by VPC endpoint policies and Amazon Web Services Organizations\n policies.

\n
\n
    \n
  • \n

    \n General purpose bucket permissions - The s3:PutBucketPolicy permission is required in a policy. \n For more information about general purpose buckets bucket policies, see Using Bucket Policies and User\n Policies in the Amazon S3 User Guide.

    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation, you must have the s3express:PutBucketPolicy permission in an IAM identity-based policy instead of a bucket policy. Cross-account access to this API operation isn't supported. This operation can only be performed by the Amazon Web Services account that owns the resource. For more information about directory bucket policies and permissions, see Amazon Web Services Identity and Access Management (IAM) for S3 Express One Zone in the Amazon S3 User Guide.

    \n
  • \n
\n
\n
Example bucket policies
\n
\n

\n General purpose buckets example bucket policies - See Bucket policy examples in the Amazon S3 User Guide.

\n

\n Directory bucket example bucket policies - See Example bucket policies for S3 Express One Zone in the Amazon S3 User Guide.

\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is s3express-control.region.amazonaws.com.

\n
\n
\n

The following operations are related to PutBucketPolicy:

\n ", "smithy.api#examples": [ { "title": "Set bucket policy", @@ -27649,6 +29826,11 @@ "method": "PUT", "uri": "/{Bucket}?policy", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -27658,7 +29840,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket.

", + "smithy.api#documentation": "

The name of the bucket.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use path-style requests in the format https://s3express-control.region_code.amazonaws.com/bucket-name\n . Virtual-hosted-style requests aren't supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must also follow the format \n bucket_base_name--az_id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming restrictions, see Directory bucket naming rules in the Amazon S3 User Guide\n

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -27669,29 +29851,28 @@ "ContentMD5": { "target": "com.amazonaws.s3#ContentMD5", "traits": { - "smithy.api#documentation": "

The MD5 hash of the request body.

\n

For requests made using the Amazon Web Services Command Line Interface (CLI) or Amazon Web Services SDKs, this field is calculated automatically.

", + "smithy.api#documentation": "

The MD5 hash of the request body.

\n

For requests made using the Amazon Web Services Command Line Interface (CLI) or Amazon Web Services SDKs, this field is calculated automatically.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "Content-MD5" } }, "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum-algorithm\n or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request.

\n

For the x-amz-checksum-algorithm\n header, replace \n algorithm\n with the supported algorithm from the following list:

\n
    \n
  • \n

    CRC32

    \n
  • \n
  • \n

    CRC32C

    \n
  • \n
  • \n

    SHA1

    \n
  • \n
  • \n

    SHA256

    \n
  • \n
\n

For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If the individual checksum value you provide through x-amz-checksum-algorithm\n doesn't match the checksum algorithm you set through x-amz-sdk-checksum-algorithm, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter and uses the checksum algorithm that matches the provided value in x-amz-checksum-algorithm\n .

\n \n

For directory buckets, when you use Amazon Web Services SDKs, CRC32 is the default checksum algorithm that's used for performance.

\n
", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, "ConfirmRemoveSelfBucketAccess": { "target": "com.amazonaws.s3#ConfirmRemoveSelfBucketAccess", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Set this parameter to true to confirm that you want to remove your permissions to change\n this bucket policy in the future.

", + "smithy.api#documentation": "

Set this parameter to true to confirm that you want to remove your permissions to change\n this bucket policy in the future.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-confirm-remove-self-bucket-access" } }, "Policy": { "target": "com.amazonaws.s3#Policy", "traits": { - "smithy.api#documentation": "

The bucket policy as a JSON document.

", + "smithy.api#documentation": "

The bucket policy as a JSON document.

\n

For directory buckets, the only IAM action supported in the bucket policy is s3express:CreateSession.

", "smithy.api#httpPayload": {}, "smithy.api#required": {} } @@ -27699,7 +29880,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

\n \n

For directory buckets, this header is not supported in this API operation. If you specify this header, the request fails with the HTTP status code \n501 Not Implemented.

\n
", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -27721,7 +29902,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Creates a replication configuration or replaces an existing one. For more information,\n see Replication in the Amazon S3 User Guide.

\n

Specify the replication configuration in the request body. In the replication\n configuration, you provide the name of the destination bucket or buckets where you want\n Amazon S3 to replicate objects, the IAM role that Amazon S3 can assume to replicate objects on your\n behalf, and other relevant information. You can invoke this request for a specific\n Amazon Web Services Region by using the \n \n aws:RequestedRegion\n condition key.

\n

A replication configuration must include at least one rule, and can contain a maximum of\n 1,000. Each rule identifies a subset of objects to replicate by filtering the objects in\n the source bucket. To choose additional subsets of objects to replicate, add a rule for\n each subset.

\n

To specify a subset of the objects in the source bucket to apply a replication rule to,\n add the Filter element as a child of the Rule element. You can filter objects based on an\n object key prefix, one or more object tags, or both. When you add the Filter element in the\n configuration, you must also add the following elements:\n DeleteMarkerReplication, Status, and\n Priority.

\n \n

If you are using an earlier version of the replication configuration, Amazon S3 handles\n replication of delete markers differently. For more information, see Backward Compatibility.

\n
\n

For information about enabling versioning on a bucket, see Using Versioning.

\n
\n
Handling Replication of Encrypted Objects
\n
\n

By default, Amazon S3 doesn't replicate objects that are stored at rest using\n server-side encryption with KMS keys. To replicate Amazon Web Services KMS-encrypted objects,\n add the following: SourceSelectionCriteria,\n SseKmsEncryptedObjects, Status,\n EncryptionConfiguration, and ReplicaKmsKeyID. For\n information about replication configuration, see Replicating\n Objects Created with SSE Using KMS keys.

\n

For information on PutBucketReplication errors, see List of\n replication-related error codes\n

\n
\n
Permissions
\n
\n

To create a PutBucketReplication request, you must have\n s3:PutReplicationConfiguration permissions for the bucket.\n \n

\n

By default, a resource owner, in this case the Amazon Web Services account that created the\n bucket, can perform this operation. The resource owner can also grant others\n permissions to perform the operation. For more information about permissions, see\n Specifying Permissions in\n a Policy and Managing Access\n Permissions to Your Amazon S3 Resources.

\n \n

To perform this operation, the user or role performing the action must have\n the iam:PassRole\n permission.

\n
\n
\n
\n

The following operations are related to PutBucketReplication:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Creates a replication configuration or replaces an existing one. For more information,\n see Replication in the Amazon S3 User Guide.

\n

Specify the replication configuration in the request body. In the replication\n configuration, you provide the name of the destination bucket or buckets where you want\n Amazon S3 to replicate objects, the IAM role that Amazon S3 can assume to replicate objects on your\n behalf, and other relevant information. You can invoke this request for a specific\n Amazon Web Services Region by using the \n \n aws:RequestedRegion\n condition key.

\n

A replication configuration must include at least one rule, and can contain a maximum of\n 1,000. Each rule identifies a subset of objects to replicate by filtering the objects in\n the source bucket. To choose additional subsets of objects to replicate, add a rule for\n each subset.

\n

To specify a subset of the objects in the source bucket to apply a replication rule to,\n add the Filter element as a child of the Rule element. You can filter objects based on an\n object key prefix, one or more object tags, or both. When you add the Filter element in the\n configuration, you must also add the following elements:\n DeleteMarkerReplication, Status, and\n Priority.

\n \n

If you are using an earlier version of the replication configuration, Amazon S3 handles\n replication of delete markers differently. For more information, see Backward Compatibility.

\n
\n

For information about enabling versioning on a bucket, see Using Versioning.

\n
\n
Handling Replication of Encrypted Objects
\n
\n

By default, Amazon S3 doesn't replicate objects that are stored at rest using\n server-side encryption with KMS keys. To replicate Amazon Web Services KMS-encrypted objects,\n add the following: SourceSelectionCriteria,\n SseKmsEncryptedObjects, Status,\n EncryptionConfiguration, and ReplicaKmsKeyID. For\n information about replication configuration, see Replicating\n Objects Created with SSE Using KMS keys.

\n

For information on PutBucketReplication errors, see List of\n replication-related error codes\n

\n
\n
Permissions
\n
\n

To create a PutBucketReplication request, you must have\n s3:PutReplicationConfiguration permissions for the bucket.\n \n

\n

By default, a resource owner, in this case the Amazon Web Services account that created the\n bucket, can perform this operation. The resource owner can also grant others\n permissions to perform the operation. For more information about permissions, see\n Specifying Permissions in\n a Policy and Managing Access\n Permissions to Your Amazon S3 Resources.

\n \n

To perform this operation, the user or role performing the action must have\n the iam:PassRole\n permission.

\n
\n
\n
\n

The following operations are related to PutBucketReplication:

\n ", "smithy.api#examples": [ { "title": "Set replication configuration on a bucket", @@ -27748,6 +29929,11 @@ "method": "PUT", "uri": "/{Bucket}?replication", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -27775,7 +29961,7 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, @@ -27797,7 +29983,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -27819,7 +30005,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Sets the request payment configuration for a bucket. By default, the bucket owner pays\n for downloads from the bucket. This configuration parameter enables the bucket owner (only)\n to specify that the person requesting the download will be charged for the download. For\n more information, see Requester Pays\n Buckets.

\n

The following operations are related to PutBucketRequestPayment:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Sets the request payment configuration for a bucket. By default, the bucket owner pays\n for downloads from the bucket. This configuration parameter enables the bucket owner (only)\n to specify that the person requesting the download will be charged for the download. For\n more information, see Requester Pays\n Buckets.

\n

The following operations are related to PutBucketRequestPayment:

\n ", "smithy.api#examples": [ { "title": "Set request payment configuration on a bucket.", @@ -27836,6 +30022,11 @@ "method": "PUT", "uri": "/{Bucket}?requestPayment", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -27863,7 +30054,7 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, @@ -27879,7 +30070,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -27901,7 +30092,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Sets the tags for a bucket.

\n

Use tags to organize your Amazon Web Services bill to reflect your own cost structure. To do this,\n sign up to get your Amazon Web Services account bill with tag key values included. Then, to see the cost\n of combined resources, organize your billing information according to resources with the\n same tag key values. For example, you can tag several resources with a specific application\n name, and then organize your billing information to see the total cost of that application\n across several services. For more information, see Cost Allocation and\n Tagging and Using Cost Allocation in Amazon S3\n Bucket Tags.

\n \n

When this operation sets the tags for a bucket, it will overwrite any current tags\n the bucket already has. You cannot use this operation to add tags to an existing list of\n tags.

\n
\n

To use this operation, you must have permissions to perform the\n s3:PutBucketTagging action. The bucket owner has this permission by default\n and can grant this permission to others. For more information about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

\n PutBucketTagging has the following special errors. For more Amazon S3 errors\n see, Error\n Responses.

\n
    \n
  • \n

    \n InvalidTag - The tag provided was not a valid tag. This error\n can occur if the tag did not pass input validation. For more information, see Using\n Cost Allocation in Amazon S3 Bucket Tags.

    \n
  • \n
  • \n

    \n MalformedXML - The XML provided does not match the\n schema.

    \n
  • \n
  • \n

    \n OperationAborted - A conflicting conditional action is\n currently in progress against this resource. Please try again.

    \n
  • \n
  • \n

    \n InternalError - The service was unable to apply the provided\n tag to the bucket.

    \n
  • \n
\n

The following operations are related to PutBucketTagging:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Sets the tags for a bucket.

\n

Use tags to organize your Amazon Web Services bill to reflect your own cost structure. To do this,\n sign up to get your Amazon Web Services account bill with tag key values included. Then, to see the cost\n of combined resources, organize your billing information according to resources with the\n same tag key values. For example, you can tag several resources with a specific application\n name, and then organize your billing information to see the total cost of that application\n across several services. For more information, see Cost Allocation and\n Tagging and Using Cost Allocation in Amazon S3\n Bucket Tags.

\n \n

When this operation sets the tags for a bucket, it will overwrite any current tags\n the bucket already has. You cannot use this operation to add tags to an existing list of\n tags.

\n
\n

To use this operation, you must have permissions to perform the\n s3:PutBucketTagging action. The bucket owner has this permission by default\n and can grant this permission to others. For more information about permissions, see Permissions Related to Bucket Subresource Operations and Managing\n Access Permissions to Your Amazon S3 Resources.

\n

\n PutBucketTagging has the following special errors. For more Amazon S3 errors\n see, Error\n Responses.

\n
    \n
  • \n

    \n InvalidTag - The tag provided was not a valid tag. This error\n can occur if the tag did not pass input validation. For more information, see Using\n Cost Allocation in Amazon S3 Bucket Tags.

    \n
  • \n
  • \n

    \n MalformedXML - The XML provided does not match the\n schema.

    \n
  • \n
  • \n

    \n OperationAborted - A conflicting conditional action is\n currently in progress against this resource. Please try again.

    \n
  • \n
  • \n

    \n InternalError - The service was unable to apply the provided\n tag to the bucket.

    \n
  • \n
\n

The following operations are related to PutBucketTagging:

\n ", "smithy.api#examples": [ { "title": "Set tags on a bucket", @@ -27927,6 +30118,11 @@ "method": "PUT", "uri": "/{Bucket}?tagging", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -27954,7 +30150,7 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, @@ -27970,7 +30166,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -27992,7 +30188,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Sets the versioning state of an existing bucket.

\n

You can set the versioning state with one of the following values:

\n

\n Enabled—Enables versioning for the objects in the\n bucket. All objects added to the bucket receive a unique version ID.

\n

\n Suspended—Disables versioning for the objects in the\n bucket. All objects added to the bucket receive the version ID null.

\n

If the versioning state has never been set on a bucket, it has no versioning state; a\n GetBucketVersioning request does not return a versioning state value.

\n

In order to enable MFA Delete, you must be the bucket owner. If you are the bucket owner\n and want to enable MFA Delete in the bucket versioning configuration, you must include the\n x-amz-mfa request header and the Status and the\n MfaDelete request elements in a request to set the versioning state of the\n bucket.

\n \n

If you have an object expiration lifecycle configuration in your non-versioned bucket\n and you want to maintain the same permanent delete behavior when you enable versioning,\n you must add a noncurrent expiration policy. The noncurrent expiration lifecycle\n configuration will manage the deletes of the noncurrent object versions in the\n version-enabled bucket. (A version-enabled bucket maintains one current and zero or more\n noncurrent object versions.) For more information, see Lifecycle and Versioning.

\n
\n

The following operations are related to PutBucketVersioning:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Sets the versioning state of an existing bucket.

\n

You can set the versioning state with one of the following values:

\n

\n Enabled—Enables versioning for the objects in the\n bucket. All objects added to the bucket receive a unique version ID.

\n

\n Suspended—Disables versioning for the objects in the\n bucket. All objects added to the bucket receive the version ID null.

\n

If the versioning state has never been set on a bucket, it has no versioning state; a\n GetBucketVersioning request does not return a versioning state value.

\n

In order to enable MFA Delete, you must be the bucket owner. If you are the bucket owner\n and want to enable MFA Delete in the bucket versioning configuration, you must include the\n x-amz-mfa request header and the Status and the\n MfaDelete request elements in a request to set the versioning state of the\n bucket.

\n \n

If you have an object expiration lifecycle configuration in your non-versioned bucket\n and you want to maintain the same permanent delete behavior when you enable versioning,\n you must add a noncurrent expiration policy. The noncurrent expiration lifecycle\n configuration will manage the deletes of the noncurrent object versions in the\n version-enabled bucket. (A version-enabled bucket maintains one current and zero or more\n noncurrent object versions.) For more information, see Lifecycle and Versioning.

\n
\n

The following operations are related to PutBucketVersioning:

\n ", "smithy.api#examples": [ { "title": "Set versioning configuration on a bucket", @@ -28010,6 +30206,11 @@ "method": "PUT", "uri": "/{Bucket}?versioning", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -28037,7 +30238,7 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, @@ -28060,7 +30261,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -28082,7 +30283,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Sets the configuration of the website that is specified in the website\n subresource. To configure a bucket as a website, you can add this subresource on the bucket\n with website configuration information such as the file name of the index document and any\n redirect rules. For more information, see Hosting Websites on Amazon S3.

\n

This PUT action requires the S3:PutBucketWebsite permission. By default,\n only the bucket owner can configure the website attached to a bucket; however, bucket\n owners can allow other users to set the website configuration by writing a bucket policy\n that grants them the S3:PutBucketWebsite permission.

\n

To redirect all website requests sent to the bucket's website endpoint, you add a\n website configuration with the following elements. Because all requests are sent to another\n website, you don't need to provide index document name for the bucket.

\n
    \n
  • \n

    \n WebsiteConfiguration\n

    \n
  • \n
  • \n

    \n RedirectAllRequestsTo\n

    \n
  • \n
  • \n

    \n HostName\n

    \n
  • \n
  • \n

    \n Protocol\n

    \n
  • \n
\n

If you want granular control over redirects, you can use the following elements to add\n routing rules that describe conditions for redirecting requests and information about the\n redirect destination. In this case, the website configuration must provide an index\n document for the bucket, because some requests might not be redirected.

\n
    \n
  • \n

    \n WebsiteConfiguration\n

    \n
  • \n
  • \n

    \n IndexDocument\n

    \n
  • \n
  • \n

    \n Suffix\n

    \n
  • \n
  • \n

    \n ErrorDocument\n

    \n
  • \n
  • \n

    \n Key\n

    \n
  • \n
  • \n

    \n RoutingRules\n

    \n
  • \n
  • \n

    \n RoutingRule\n

    \n
  • \n
  • \n

    \n Condition\n

    \n
  • \n
  • \n

    \n HttpErrorCodeReturnedEquals\n

    \n
  • \n
  • \n

    \n KeyPrefixEquals\n

    \n
  • \n
  • \n

    \n Redirect\n

    \n
  • \n
  • \n

    \n Protocol\n

    \n
  • \n
  • \n

    \n HostName\n

    \n
  • \n
  • \n

    \n ReplaceKeyPrefixWith\n

    \n
  • \n
  • \n

    \n ReplaceKeyWith\n

    \n
  • \n
  • \n

    \n HttpRedirectCode\n

    \n
  • \n
\n

Amazon S3 has a limitation of 50 routing rules per website configuration. If you require more\n than 50 routing rules, you can use object redirect. For more information, see Configuring an\n Object Redirect in the Amazon S3 User Guide.

\n

The maximum request length is limited to 128 KB.

", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Sets the configuration of the website that is specified in the website\n subresource. To configure a bucket as a website, you can add this subresource on the bucket\n with website configuration information such as the file name of the index document and any\n redirect rules. For more information, see Hosting Websites on Amazon S3.

\n

This PUT action requires the S3:PutBucketWebsite permission. By default,\n only the bucket owner can configure the website attached to a bucket; however, bucket\n owners can allow other users to set the website configuration by writing a bucket policy\n that grants them the S3:PutBucketWebsite permission.

\n

To redirect all website requests sent to the bucket's website endpoint, you add a\n website configuration with the following elements. Because all requests are sent to another\n website, you don't need to provide index document name for the bucket.

\n
    \n
  • \n

    \n WebsiteConfiguration\n

    \n
  • \n
  • \n

    \n RedirectAllRequestsTo\n

    \n
  • \n
  • \n

    \n HostName\n

    \n
  • \n
  • \n

    \n Protocol\n

    \n
  • \n
\n

If you want granular control over redirects, you can use the following elements to add\n routing rules that describe conditions for redirecting requests and information about the\n redirect destination. In this case, the website configuration must provide an index\n document for the bucket, because some requests might not be redirected.

\n
    \n
  • \n

    \n WebsiteConfiguration\n

    \n
  • \n
  • \n

    \n IndexDocument\n

    \n
  • \n
  • \n

    \n Suffix\n

    \n
  • \n
  • \n

    \n ErrorDocument\n

    \n
  • \n
  • \n

    \n Key\n

    \n
  • \n
  • \n

    \n RoutingRules\n

    \n
  • \n
  • \n

    \n RoutingRule\n

    \n
  • \n
  • \n

    \n Condition\n

    \n
  • \n
  • \n

    \n HttpErrorCodeReturnedEquals\n

    \n
  • \n
  • \n

    \n KeyPrefixEquals\n

    \n
  • \n
  • \n

    \n Redirect\n

    \n
  • \n
  • \n

    \n Protocol\n

    \n
  • \n
  • \n

    \n HostName\n

    \n
  • \n
  • \n

    \n ReplaceKeyPrefixWith\n

    \n
  • \n
  • \n

    \n ReplaceKeyWith\n

    \n
  • \n
  • \n

    \n HttpRedirectCode\n

    \n
  • \n
\n

Amazon S3 has a limitation of 50 routing rules per website configuration. If you require more\n than 50 routing rules, you can use object redirect. For more information, see Configuring an\n Object Redirect in the Amazon S3 User Guide.

\n

The maximum request length is limited to 128 KB.

", "smithy.api#examples": [ { "title": "Set website configuration on a bucket", @@ -28105,6 +30306,11 @@ "method": "PUT", "uri": "/{Bucket}?website", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -28132,7 +30338,7 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, @@ -28148,7 +30354,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -28169,22 +30375,19 @@ "aws.protocols#httpChecksum": { "requestAlgorithmMember": "ChecksumAlgorithm" }, - "smithy.api#documentation": "

Adds an object to a bucket. You must have WRITE permissions on a bucket to add an object\n to it.

\n \n

Amazon S3 never adds partial objects; if you receive a success response, Amazon S3 added the\n entire object to the bucket. You cannot use PutObject to only update a\n single piece of metadata for an existing object. You must put the entire object with\n updated metadata if you want to update some values.

\n
\n

Amazon S3 is a distributed system. If it receives multiple write requests for the same object\n simultaneously, it overwrites all but the last object written. To prevent objects from\n being deleted or overwritten, you can use Amazon S3 Object\n Lock.

\n

To ensure that data is not corrupted traversing the network, use the\n Content-MD5 header. When you use this header, Amazon S3 checks the object\n against the provided MD5 value and, if they do not match, returns an error. Additionally,\n you can calculate the MD5 while putting an object to Amazon S3 and compare the returned ETag to\n the calculated MD5 value.

\n \n
    \n
  • \n

    To successfully complete the PutObject request, you must have the\n s3:PutObject in your IAM permissions.

    \n
  • \n
  • \n

    To successfully change the objects acl of your PutObject request,\n you must have the s3:PutObjectAcl in your IAM permissions.

    \n
  • \n
  • \n

    To successfully set the tag-set with your PutObject request, you\n must have the s3:PutObjectTagging in your IAM permissions.

    \n
  • \n
  • \n

    The Content-MD5 header is required for any request to upload an\n object with a retention period configured using Amazon S3 Object Lock. For more\n information about Amazon S3 Object Lock, see Amazon S3 Object Lock\n Overview in the Amazon S3 User Guide.

    \n
  • \n
\n
\n

You have four mutually exclusive options to protect data using server-side encryption in\n Amazon S3, depending on how you choose to manage the encryption keys. Specifically, the\n encryption key options are Amazon S3 managed keys (SSE-S3), Amazon Web Services KMS keys (SSE-KMS or\n DSSE-KMS), and customer-provided keys (SSE-C). Amazon S3 encrypts data with server-side\n encryption by using Amazon S3 managed keys (SSE-S3) by default. You can optionally tell Amazon S3 to\n encrypt data at rest by using server-side encryption with other key options. For more\n information, see Using Server-Side\n Encryption.

\n

When adding a new object, you can use headers to grant ACL-based permissions to\n individual Amazon Web Services accounts or to predefined groups defined by Amazon S3. These permissions are\n then added to the ACL on the object. By default, all objects are private. Only the owner\n has full access control. For more information, see Access Control List (ACL) Overview\n and Managing\n ACLs Using the REST API.

\n

If the bucket that you're uploading objects to uses the bucket owner enforced setting\n for S3 Object Ownership, ACLs are disabled and no longer affect permissions. Buckets that\n use this setting only accept PUT requests that don't specify an ACL or PUT requests that\n specify bucket owner full control ACLs, such as the bucket-owner-full-control\n canned ACL or an equivalent form of this ACL expressed in the XML format. PUT requests that\n contain other ACLs (for example, custom grants to certain Amazon Web Services accounts) fail and return a\n 400 error with the error code AccessControlListNotSupported.\n For more information, see Controlling ownership of\n objects and disabling ACLs in the Amazon S3 User Guide.

\n \n

If your bucket uses the bucket owner enforced setting for Object Ownership, all\n objects written to the bucket by any account will be owned by the bucket owner.

\n
\n

By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The\n STANDARD storage class provides high durability and high availability. Depending on\n performance needs, you can specify a different Storage Class. Amazon S3 on Outposts only uses\n the OUTPOSTS Storage Class. For more information, see Storage Classes in the\n Amazon S3 User Guide.

\n

If you enable versioning for a bucket, Amazon S3 automatically generates a unique version ID\n for the object being stored. Amazon S3 returns this ID in the response. When you enable\n versioning for a bucket, if Amazon S3 receives multiple write requests for the same object\n simultaneously, it stores all of the objects. For more information about versioning, see\n Adding Objects to\n Versioning-Enabled Buckets. For information about returning the versioning state\n of a bucket, see GetBucketVersioning.

\n

For more information about related Amazon S3 APIs, see the following:

\n ", + "smithy.api#documentation": "

Adds an object to a bucket.

\n \n
    \n
  • \n

    Amazon S3 never adds partial objects; if you receive a success response, Amazon S3 added the\n entire object to the bucket. You cannot use PutObject to only update a\n single piece of metadata for an existing object. You must put the entire object with\n updated metadata if you want to update some values.

    \n
  • \n
  • \n

    If your bucket uses the bucket owner enforced setting for Object Ownership, ACLs are disabled and no longer affect permissions. All\n objects written to the bucket by any account will be owned by the bucket owner.

    \n
  • \n
  • \n

    \n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

    \n
  • \n
\n
\n

Amazon S3 is a distributed system. If it receives multiple write requests for the same object\n simultaneously, it overwrites all but the last object written. However, Amazon S3 provides features that can modify this behavior:

\n
    \n
  • \n

    \n S3 Object Lock - To prevent objects from\n being deleted or overwritten, you can use Amazon S3 Object\n Lock in the Amazon S3 User Guide.

    \n \n

    This functionality is not supported for directory buckets.

    \n
    \n
  • \n
  • \n

    \n S3 Versioning - When you enable\n versioning for a bucket, if Amazon S3 receives multiple write requests for the same object\n simultaneously, it stores all versions of the objects. For each write request that is made to the same object, Amazon S3 automatically generates a unique version ID\n of that object being stored in Amazon S3. \n You can retrieve, replace, or delete any version of the object. For more information about versioning, see\n Adding Objects to\n Versioning-Enabled Buckets in the Amazon S3\n User Guide. For information about returning the versioning state\n of a bucket, see GetBucketVersioning.

    \n \n

    This functionality is not supported for directory buckets.

    \n
    \n
  • \n
\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - The following permissions are required in your policies when your \n PutObject request includes specific headers.

    \n
      \n
    • \n

      \n \n s3:PutObject\n - To successfully complete the PutObject request, you must always have the s3:PutObject permission on a bucket to add an object\n to it.

      \n
    • \n
    • \n

      \n \n s3:PutObjectAcl\n - To successfully change the objects ACL of your PutObject request, you must have the s3:PutObjectAcl.

      \n
    • \n
    • \n

      \n \n s3:PutObjectTagging\n - To successfully set the tag-set with your PutObject request, you\n must have the s3:PutObjectTagging.

      \n
    • \n
    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation on a directory bucket, we recommend that you use the \n CreateSession\n API operation for session-based authorization. Specifically, you grant the s3express:CreateSession permission to the directory bucket in a bucket policy or an IAM identity-based policy. Then, you make the CreateSession API call on the bucket to obtain a session token. With the session token in your request header, you can make API requests to this operation. After the session token expires, you make another CreateSession API call to generate a new session token for use. \nAmazon Web Services CLI or SDKs create session and refresh the session token automatically to avoid service interruptions when a session expires. For more information about authorization, see \n CreateSession\n .

    \n
  • \n
\n
\n
Data integrity with Content-MD5
\n
\n
    \n
  • \n

    \n General purpose bucket - To ensure that data is not corrupted traversing the network, use the\n Content-MD5 header. When you use this header, Amazon S3 checks the object\n against the provided MD5 value and, if they do not match, Amazon S3 returns an error. Alternatively, when the object's ETag is its MD5 digest, \n you can calculate the MD5 while putting the object to Amazon S3 and compare the returned ETag to\n the calculated MD5 value.

    \n
  • \n
  • \n

    \n Directory bucket - This functionality is not supported for directory buckets.

    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

For more information about related Amazon S3 APIs, see the following:

\n ", "smithy.api#examples": [ { - "title": "To upload an object and specify server-side encryption and object tags", - "documentation": "The following example uploads an object. The request specifies the optional server-side encryption option. The request also specifies optional object tags. If the bucket is versioning enabled, S3 returns version ID in response.", + "title": "To create an object.", + "documentation": "The following example creates an object. If the bucket is versioning enabled, S3 returns version ID in response.", "input": { "Body": "filetoupload", "Bucket": "examplebucket", - "Key": "exampleobject", - "ServerSideEncryption": "AES256", - "Tagging": "key1=value1&key2=value2" + "Key": "objectkey" }, "output": { - "VersionId": "Ri.vC6qVlA4dEnjgRV4ZHsHoFIjqEMNt", - "ETag": "\"6805f2cfc46c0f04559748bb039d69ae\"", - "ServerSideEncryption": "AES256" + "VersionId": "Bvq0EDKxOcXLJXNo_Lkz37eM3R4pfzyQ", + "ETag": "\"6805f2cfc46c0f04559748bb039d69ae\"" } } ], @@ -28213,7 +30416,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Uses the acl subresource to set the access control list (ACL) permissions\n for a new or existing object in an S3 bucket. You must have WRITE_ACP\n permission to set the ACL of an object. For more information, see What\n permissions can I grant? in the Amazon S3 User Guide.

\n

This action is not supported by Amazon S3 on Outposts.

\n

Depending on your application needs, you can choose to set the ACL on an object using\n either the request body or the headers. For example, if you have an existing application\n that updates a bucket ACL using the request body, you can continue to use that approach.\n For more information, see Access Control List (ACL) Overview\n in the Amazon S3 User Guide.

\n \n

If your bucket uses the bucket owner enforced setting for S3 Object Ownership, ACLs\n are disabled and no longer affect permissions. You must use policies to grant access to\n your bucket and the objects in it. Requests to set ACLs or update ACLs fail and return\n the AccessControlListNotSupported error code. Requests to read ACLs are\n still supported. For more information, see Controlling object\n ownership in the Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n

You can set access permissions using one of the following methods:

\n
    \n
  • \n

    Specify a canned ACL with the x-amz-acl request header. Amazon S3\n supports a set of predefined ACLs, known as canned ACLs. Each canned ACL has\n a predefined set of grantees and permissions. Specify the canned ACL name as\n the value of x-amz-acl. If you use this header, you cannot use\n other access control-specific headers in your request. For more information,\n see Canned\n ACL.

    \n
  • \n
  • \n

    Specify access permissions explicitly with the\n x-amz-grant-read, x-amz-grant-read-acp,\n x-amz-grant-write-acp, and\n x-amz-grant-full-control headers. When using these headers,\n you specify explicit access permissions and grantees (Amazon Web Services accounts or Amazon S3\n groups) who will receive the permission. If you use these ACL-specific\n headers, you cannot use x-amz-acl header to set a canned ACL.\n These parameters map to the set of permissions that Amazon S3 supports in an ACL.\n For more information, see Access Control List (ACL)\n Overview.

    \n

    You specify each grantee as a type=value pair, where the type is one of\n the following:

    \n
      \n
    • \n

      \n id – if the value specified is the canonical user ID\n of an Amazon Web Services account

      \n
    • \n
    • \n

      \n uri – if you are granting permissions to a predefined\n group

      \n
    • \n
    • \n

      \n emailAddress – if the value specified is the email\n address of an Amazon Web Services account

      \n \n

      Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

      \n
        \n
      • \n

        US East (N. Virginia)

        \n
      • \n
      • \n

        US West (N. California)

        \n
      • \n
      • \n

        US West (Oregon)

        \n
      • \n
      • \n

        Asia Pacific (Singapore)

        \n
      • \n
      • \n

        Asia Pacific (Sydney)

        \n
      • \n
      • \n

        Asia Pacific (Tokyo)

        \n
      • \n
      • \n

        Europe (Ireland)

        \n
      • \n
      • \n

        South America (São Paulo)

        \n
      • \n
      \n

      For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

      \n
      \n
    • \n
    \n

    For example, the following x-amz-grant-read header grants\n list objects permission to the two Amazon Web Services accounts identified by their email\n addresses.

    \n

    \n x-amz-grant-read: emailAddress=\"xyz@amazon.com\",\n emailAddress=\"abc@amazon.com\" \n

    \n
  • \n
\n

You can use either a canned ACL or specify access permissions explicitly. You\n cannot do both.

\n
\n
Grantee Values
\n
\n

You can specify the person (grantee) to whom you're assigning access rights\n (using request elements) in the following ways:

\n
    \n
  • \n

    By the person's ID:

    \n

    \n <>ID<><>GranteesEmail<>\n \n

    \n

    DisplayName is optional and ignored in the request.

    \n
  • \n
  • \n

    By URI:

    \n

    \n <>http://acs.amazonaws.com/groups/global/AuthenticatedUsers<>\n

    \n
  • \n
  • \n

    By Email address:

    \n

    \n <>Grantees@email.com<>lt;/Grantee>\n

    \n

    The grantee is resolved to the CanonicalUser and, in a response to a GET\n Object acl request, appears as the CanonicalUser.

    \n \n

    Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

    \n
      \n
    • \n

      US East (N. Virginia)

      \n
    • \n
    • \n

      US West (N. California)

      \n
    • \n
    • \n

      US West (Oregon)

      \n
    • \n
    • \n

      Asia Pacific (Singapore)

      \n
    • \n
    • \n

      Asia Pacific (Sydney)

      \n
    • \n
    • \n

      Asia Pacific (Tokyo)

      \n
    • \n
    • \n

      Europe (Ireland)

      \n
    • \n
    • \n

      South America (São Paulo)

      \n
    • \n
    \n

    For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

    \n
    \n
  • \n
\n
\n
Versioning
\n
\n

The ACL of an object is set at the object version level. By default, PUT sets\n the ACL of the current version of an object. To set the ACL of a different\n version, use the versionId subresource.

\n
\n
\n

The following operations are related to PutObjectAcl:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Uses the acl subresource to set the access control list (ACL) permissions\n for a new or existing object in an S3 bucket. You must have the WRITE_ACP\n permission to set the ACL of an object. For more information, see What\n permissions can I grant? in the Amazon S3 User Guide.

\n

This functionality is not supported for Amazon S3 on Outposts.

\n

Depending on your application needs, you can choose to set the ACL on an object using\n either the request body or the headers. For example, if you have an existing application\n that updates a bucket ACL using the request body, you can continue to use that approach.\n For more information, see Access Control List (ACL) Overview\n in the Amazon S3 User Guide.

\n \n

If your bucket uses the bucket owner enforced setting for S3 Object Ownership, ACLs\n are disabled and no longer affect permissions. You must use policies to grant access to\n your bucket and the objects in it. Requests to set ACLs or update ACLs fail and return\n the AccessControlListNotSupported error code. Requests to read ACLs are\n still supported. For more information, see Controlling object\n ownership in the Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n

You can set access permissions using one of the following methods:

\n
    \n
  • \n

    Specify a canned ACL with the x-amz-acl request header. Amazon S3\n supports a set of predefined ACLs, known as canned ACLs. Each canned ACL has\n a predefined set of grantees and permissions. Specify the canned ACL name as\n the value of x-amz-acl. If you use this header, you cannot use\n other access control-specific headers in your request. For more information,\n see Canned\n ACL.

    \n
  • \n
  • \n

    Specify access permissions explicitly with the\n x-amz-grant-read, x-amz-grant-read-acp,\n x-amz-grant-write-acp, and\n x-amz-grant-full-control headers. When using these headers,\n you specify explicit access permissions and grantees (Amazon Web Services accounts or Amazon S3\n groups) who will receive the permission. If you use these ACL-specific\n headers, you cannot use x-amz-acl header to set a canned ACL.\n These parameters map to the set of permissions that Amazon S3 supports in an ACL.\n For more information, see Access Control List (ACL)\n Overview.

    \n

    You specify each grantee as a type=value pair, where the type is one of\n the following:

    \n
      \n
    • \n

      \n id – if the value specified is the canonical user ID\n of an Amazon Web Services account

      \n
    • \n
    • \n

      \n uri – if you are granting permissions to a predefined\n group

      \n
    • \n
    • \n

      \n emailAddress – if the value specified is the email\n address of an Amazon Web Services account

      \n \n

      Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

      \n
        \n
      • \n

        US East (N. Virginia)

        \n
      • \n
      • \n

        US West (N. California)

        \n
      • \n
      • \n

        US West (Oregon)

        \n
      • \n
      • \n

        Asia Pacific (Singapore)

        \n
      • \n
      • \n

        Asia Pacific (Sydney)

        \n
      • \n
      • \n

        Asia Pacific (Tokyo)

        \n
      • \n
      • \n

        Europe (Ireland)

        \n
      • \n
      • \n

        South America (São Paulo)

        \n
      • \n
      \n

      For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

      \n
      \n
    • \n
    \n

    For example, the following x-amz-grant-read header grants\n list objects permission to the two Amazon Web Services accounts identified by their email\n addresses.

    \n

    \n x-amz-grant-read: emailAddress=\"xyz@amazon.com\",\n emailAddress=\"abc@amazon.com\" \n

    \n
  • \n
\n

You can use either a canned ACL or specify access permissions explicitly. You\n cannot do both.

\n
\n
Grantee Values
\n
\n

You can specify the person (grantee) to whom you're assigning access rights\n (using request elements) in the following ways:

\n
    \n
  • \n

    By the person's ID:

    \n

    \n <>ID<><>GranteesEmail<>\n \n

    \n

    DisplayName is optional and ignored in the request.

    \n
  • \n
  • \n

    By URI:

    \n

    \n <>http://acs.amazonaws.com/groups/global/AuthenticatedUsers<>\n

    \n
  • \n
  • \n

    By Email address:

    \n

    \n <>Grantees@email.com<>lt;/Grantee>\n

    \n

    The grantee is resolved to the CanonicalUser and, in a response to a GET\n Object acl request, appears as the CanonicalUser.

    \n \n

    Using email addresses to specify a grantee is only supported in the following Amazon Web Services Regions:

    \n
      \n
    • \n

      US East (N. Virginia)

      \n
    • \n
    • \n

      US West (N. California)

      \n
    • \n
    • \n

      US West (Oregon)

      \n
    • \n
    • \n

      Asia Pacific (Singapore)

      \n
    • \n
    • \n

      Asia Pacific (Sydney)

      \n
    • \n
    • \n

      Asia Pacific (Tokyo)

      \n
    • \n
    • \n

      Europe (Ireland)

      \n
    • \n
    • \n

      South America (São Paulo)

      \n
    • \n
    \n

    For a list of all the Amazon S3 supported Regions and endpoints, see Regions and Endpoints in the Amazon Web Services General Reference.

    \n
    \n
  • \n
\n
\n
Versioning
\n
\n

The ACL of an object is set at the object version level. By default, PUT sets\n the ACL of the current version of an object. To set the ACL of a different\n version, use the versionId subresource.

\n
\n
\n

The following operations are related to PutObjectAcl:

\n ", "smithy.api#examples": [ { "title": "To grant permissions using object ACL", @@ -28270,7 +30473,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name that contains the object to which you want to attach the ACL.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name that contains the object to which you want to attach the ACL.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -28288,28 +30491,28 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, "GrantFullControl": { "target": "com.amazonaws.s3#GrantFullControl", "traits": { - "smithy.api#documentation": "

Allows grantee the read, write, read ACP, and write ACP permissions on the\n bucket.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Allows grantee the read, write, read ACP, and write ACP permissions on the\n bucket.

\n

This functionality is not supported for Amazon S3 on Outposts.

", "smithy.api#httpHeader": "x-amz-grant-full-control" } }, "GrantRead": { "target": "com.amazonaws.s3#GrantRead", "traits": { - "smithy.api#documentation": "

Allows grantee to list the objects in the bucket.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Allows grantee to list the objects in the bucket.

\n

This functionality is not supported for Amazon S3 on Outposts.

", "smithy.api#httpHeader": "x-amz-grant-read" } }, "GrantReadACP": { "target": "com.amazonaws.s3#GrantReadACP", "traits": { - "smithy.api#documentation": "

Allows grantee to read the bucket ACL.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Allows grantee to read the bucket ACL.

\n

This functionality is not supported for Amazon S3 on Outposts.

", "smithy.api#httpHeader": "x-amz-grant-read-acp" } }, @@ -28323,16 +30526,19 @@ "GrantWriteACP": { "target": "com.amazonaws.s3#GrantWriteACP", "traits": { - "smithy.api#documentation": "

Allows grantee to write the ACL for the applicable bucket.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Allows grantee to write the ACL for the applicable bucket.

\n

This functionality is not supported for Amazon S3 on Outposts.

", "smithy.api#httpHeader": "x-amz-grant-write-acp" } }, "Key": { "target": "com.amazonaws.s3#ObjectKey", "traits": { - "smithy.api#documentation": "

Key for which the PUT action was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

Key for which the PUT action was initiated.

", "smithy.api#httpLabel": {}, - "smithy.api#required": {} + "smithy.api#required": {}, + "smithy.rules#contextParam": { + "name": "Key" + } } }, "RequestPayer": { @@ -28344,14 +30550,14 @@ "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

VersionId used to reference a specific version of the object.

", + "smithy.api#documentation": "

Version ID used to reference a specific version of the object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpQuery": "versionId" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -28373,7 +30579,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Applies a legal hold configuration to the specified object. For more information, see\n Locking\n Objects.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Applies a legal hold configuration to the specified object. For more information, see\n Locking\n Objects.

\n

This functionality is not supported for Amazon S3 on Outposts.

", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}/{Key+}?legal-hold", @@ -28401,7 +30607,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the object that you want to place a legal hold on.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the object that you want to place a legal hold on.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -28448,14 +30654,14 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -28477,7 +30683,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Places an Object Lock configuration on the specified bucket. The rule specified in the\n Object Lock configuration will be applied by default to every new object placed in the\n specified bucket. For more information, see Locking Objects.

\n \n
    \n
  • \n

    The DefaultRetention settings require both a mode and a\n period.

    \n
  • \n
  • \n

    The DefaultRetention period can be either Days or\n Years but you must select one. You cannot specify\n Days and Years at the same time.

    \n
  • \n
  • \n

    You can only enable Object Lock for new buckets. If you want to turn on Object\n Lock for an existing bucket, contact Amazon Web Services Support.

    \n
  • \n
\n
", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Places an Object Lock configuration on the specified bucket. The rule specified in the\n Object Lock configuration will be applied by default to every new object placed in the\n specified bucket. For more information, see Locking Objects.

\n \n
    \n
  • \n

    The DefaultRetention settings require both a mode and a\n period.

    \n
  • \n
  • \n

    The DefaultRetention period can be either Days or\n Years but you must select one. You cannot specify\n Days and Years at the same time.

    \n
  • \n
  • \n

    You can enable Object Lock for new or existing buckets. For more\n information, see Configuring Object\n Lock.

    \n
  • \n
\n
", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?object-lock", @@ -28544,14 +30750,14 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -28566,92 +30772,91 @@ "Expiration": { "target": "com.amazonaws.s3#Expiration", "traits": { - "smithy.api#documentation": "

If the expiration is configured for the object (see PutBucketLifecycleConfiguration), the response includes this header. It\n includes the expiry-date and rule-id key-value pairs that provide\n information about object expiration. The value of the rule-id is\n URL-encoded.

", + "smithy.api#documentation": "

If the expiration is configured for the object (see PutBucketLifecycleConfiguration) in the Amazon S3 User Guide, the response includes this header. It\n includes the expiry-date and rule-id key-value pairs that provide\n information about object expiration. The value of the rule-id is\n URL-encoded.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-expiration" } }, "ETag": { "target": "com.amazonaws.s3#ETag", "traits": { - "smithy.api#documentation": "

Entity tag for the uploaded object.

", + "smithy.api#documentation": "

Entity tag for the uploaded object.

\n

\n General purpose buckets - To ensure that data is not corrupted traversing the network, \n for objects where the \n ETag is the MD5 digest of the object, you can calculate the MD5 while putting an object to Amazon S3 and compare the returned ETag to\n the calculated MD5 value.

\n

\n Directory buckets - The ETag for the object in a directory bucket isn't the MD5 digest of the object.

", "smithy.api#httpHeader": "ETag" } }, "ChecksumCRC32": { "target": "com.amazonaws.s3#ChecksumCRC32", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-crc32" } }, "ChecksumCRC32C": { "target": "com.amazonaws.s3#ChecksumCRC32C", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-crc32c" } }, "ChecksumSHA1": { "target": "com.amazonaws.s3#ChecksumSHA1", "traits": { - "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. When you use the API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-sha1" } }, "ChecksumSHA256": { "target": "com.amazonaws.s3#ChecksumSHA256", "traits": { - "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-sha256" } }, "ServerSideEncryption": { "target": "com.amazonaws.s3#ServerSideEncryption", "traits": { - "smithy.api#documentation": "

The server-side encryption algorithm used when storing this object in Amazon S3 (for example,\n AES256, aws:kms, aws:kms:dsse).

", + "smithy.api#documentation": "

The server-side encryption algorithm used when you store this object in Amazon S3 (for example,\n AES256, aws:kms, aws:kms:dsse).

\n \n

For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption" } }, "VersionId": { "target": "com.amazonaws.s3#ObjectVersionId", "traits": { - "smithy.api#documentation": "

Version of the object.

", + "smithy.api#documentation": "

Version ID of the object.

\n

If you enable versioning for a bucket, Amazon S3 automatically generates a unique version ID\n for the object being stored. Amazon S3 returns this ID in the response. When you enable\n versioning for a bucket, if Amazon S3 receives multiple write requests for the same object\n simultaneously, it stores all of the objects. For more information about versioning, see\n Adding Objects to\n Versioning-Enabled Buckets in the Amazon S3\n User Guide. For information about returning the versioning state\n of a bucket, see GetBucketVersioning.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-version-id" } }, "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header confirming the encryption algorithm used.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to confirm the encryption algorithm that's used.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide round-trip message integrity verification of\n the customer-provided encryption key.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide the round-trip message integrity verification of\n the customer-provided encryption key.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, "SSEKMSKeyId": { "target": "com.amazonaws.s3#SSEKMSKeyId", "traits": { - "smithy.api#documentation": "

If x-amz-server-side-encryption has a valid value of aws:kms\n or aws:kms:dsse, this header specifies the ID of the Key Management Service (KMS)\n symmetric encryption customer managed key that was used for the object.

", + "smithy.api#documentation": "

If x-amz-server-side-encryption has a valid value of aws:kms\n or aws:kms:dsse, this header indicates the ID of the Key Management Service (KMS)\n symmetric encryption customer managed key that was used for the object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-aws-kms-key-id" } }, "SSEKMSEncryptionContext": { "target": "com.amazonaws.s3#SSEKMSEncryptionContext", "traits": { - "smithy.api#documentation": "

If present, specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The\n value of this header is a base64-encoded UTF-8 string holding JSON with the encryption\n context key-value pairs. This value is stored as object metadata and automatically gets\n passed on to Amazon Web Services KMS for future GetObject or CopyObject\n operations on this object.

", + "smithy.api#documentation": "

If present, indicates the Amazon Web Services KMS Encryption Context to use for object encryption. The\n value of this header is a base64-encoded UTF-8 string holding JSON with the encryption\n context key-value pairs. This value is stored as object metadata and automatically gets\n passed on to Amazon Web Services KMS for future GetObject or CopyObject\n operations on this object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-context" } }, "BucketKeyEnabled": { "target": "com.amazonaws.s3#BucketKeyEnabled", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Indicates whether the uploaded object uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

", + "smithy.api#documentation": "

Indicates whether the uploaded object uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-bucket-key-enabled" } }, @@ -28672,7 +30877,7 @@ "ACL": { "target": "com.amazonaws.s3#ObjectCannedACL", "traits": { - "smithy.api#documentation": "

The canned ACL to apply to the object. For more information, see Canned\n ACL.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

The canned ACL to apply to the object. For more information, see Canned\n ACL in the Amazon S3 User Guide.

\n

When adding a new object, you can use headers to grant ACL-based permissions to\n individual Amazon Web Services accounts or to predefined groups defined by Amazon S3. These permissions are\n then added to the ACL on the object. By default, all objects are private. Only the owner\n has full access control. For more information, see Access Control List (ACL) Overview\n and Managing\n ACLs Using the REST API in the Amazon S3 User Guide.

\n

If the bucket that you're uploading objects to uses the bucket owner enforced setting\n for S3 Object Ownership, ACLs are disabled and no longer affect permissions. Buckets that\n use this setting only accept PUT requests that don't specify an ACL or PUT requests that\n specify bucket owner full control ACLs, such as the bucket-owner-full-control\n canned ACL or an equivalent form of this ACL expressed in the XML format. PUT requests that\n contain other ACLs (for example, custom grants to certain Amazon Web Services accounts) fail and return a\n 400 error with the error code AccessControlListNotSupported.\n For more information, see Controlling ownership of\n objects and disabling ACLs in the Amazon S3 User Guide.

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-acl" } }, @@ -28687,7 +30892,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name to which the PUT action was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name to which the PUT action was initiated.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -28698,7 +30903,7 @@ "CacheControl": { "target": "com.amazonaws.s3#CacheControl", "traits": { - "smithy.api#documentation": "

Can be used to specify caching behavior along the request/reply chain. For more\n information, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.

", + "smithy.api#documentation": "

Can be used to specify caching behavior along the request/reply chain. For more\n information, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.

", "smithy.api#httpHeader": "Cache-Control" } }, @@ -28726,7 +30931,6 @@ "ContentLength": { "target": "com.amazonaws.s3#ContentLength", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Size of the body in bytes. This parameter is useful when the size of the body cannot be\n determined automatically. For more information, see https://www.rfc-editor.org/rfc/rfc9110.html#name-content-length.

", "smithy.api#httpHeader": "Content-Length" } @@ -28734,7 +30938,7 @@ "ContentMD5": { "target": "com.amazonaws.s3#ContentMD5", "traits": { - "smithy.api#documentation": "

The base64-encoded 128-bit MD5 digest of the message (without the headers) according to\n RFC 1864. This header can be used as a message integrity check to verify that the data is\n the same data that was originally sent. Although it is optional, we recommend using the\n Content-MD5 mechanism as an end-to-end integrity check. For more information about REST\n request authentication, see REST Authentication.

", + "smithy.api#documentation": "

The base64-encoded 128-bit MD5 digest of the message (without the headers) according to\n RFC 1864. This header can be used as a message integrity check to verify that the data is\n the same data that was originally sent. Although it is optional, we recommend using the\n Content-MD5 mechanism as an end-to-end integrity check. For more information about REST\n request authentication, see REST Authentication.

\n \n

The Content-MD5 header is required for any request to upload an\n object with a retention period configured using Amazon S3 Object Lock. For more\n information about Amazon S3 Object Lock, see Amazon S3 Object Lock\n Overview in the Amazon S3 User Guide.

\n
\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "Content-MD5" } }, @@ -28748,7 +30952,7 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum-algorithm\n or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request.

\n

For the x-amz-checksum-algorithm\n header, replace \n algorithm\n with the supported algorithm from the following list:

\n
    \n
  • \n

    CRC32

    \n
  • \n
  • \n

    CRC32C

    \n
  • \n
  • \n

    SHA1

    \n
  • \n
  • \n

    SHA256

    \n
  • \n
\n

For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If the individual checksum value you provide through x-amz-checksum-algorithm\n doesn't match the checksum algorithm you set through x-amz-sdk-checksum-algorithm, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter and uses the checksum algorithm that matches the provided value in x-amz-checksum-algorithm\n .

\n \n

For directory buckets, when you use Amazon Web Services SDKs, CRC32 is the default checksum algorithm that's used for performance.

\n
", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, @@ -28790,28 +30994,28 @@ "GrantFullControl": { "target": "com.amazonaws.s3#GrantFullControl", "traits": { - "smithy.api#documentation": "

Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Gives the grantee READ, READ_ACP, and WRITE_ACP permissions on the object.

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-grant-full-control" } }, "GrantRead": { "target": "com.amazonaws.s3#GrantRead", "traits": { - "smithy.api#documentation": "

Allows grantee to read the object data and its metadata.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Allows grantee to read the object data and its metadata.

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-grant-read" } }, "GrantReadACP": { "target": "com.amazonaws.s3#GrantReadACP", "traits": { - "smithy.api#documentation": "

Allows grantee to read the object ACL.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Allows grantee to read the object ACL.

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-grant-read-acp" } }, "GrantWriteACP": { "target": "com.amazonaws.s3#GrantWriteACP", "traits": { - "smithy.api#documentation": "

Allows grantee to write the ACL for the applicable object.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "

Allows grantee to write the ACL for the applicable object.

\n \n
    \n
  • \n

    This functionality is not supported for directory buckets.

    \n
  • \n
  • \n

    This functionality is not supported for Amazon S3 on Outposts.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-grant-write-acp" } }, @@ -28820,7 +31024,10 @@ "traits": { "smithy.api#documentation": "

Object key for which the PUT action was initiated.

", "smithy.api#httpLabel": {}, - "smithy.api#required": {} + "smithy.api#required": {}, + "smithy.rules#contextParam": { + "name": "Key" + } } }, "Metadata": { @@ -28833,64 +31040,63 @@ "ServerSideEncryption": { "target": "com.amazonaws.s3#ServerSideEncryption", "traits": { - "smithy.api#documentation": "

The server-side encryption algorithm used when storing this object in Amazon S3 (for example,\n AES256, aws:kms, aws:kms:dsse).

", + "smithy.api#documentation": "

The server-side encryption algorithm that was used when you store this object in Amazon S3 (for example,\n AES256, aws:kms, aws:kms:dsse).

\n

\n General purpose buckets - You have four mutually exclusive options to protect data using server-side encryption in\n Amazon S3, depending on how you choose to manage the encryption keys. Specifically, the\n encryption key options are Amazon S3 managed keys (SSE-S3), Amazon Web Services KMS keys (SSE-KMS or\n DSSE-KMS), and customer-provided keys (SSE-C). Amazon S3 encrypts data with server-side\n encryption by using Amazon S3 managed keys (SSE-S3) by default. You can optionally tell Amazon S3 to\n encrypt data at rest by using server-side encryption with other key options. For more\n information, see Using Server-Side\n Encryption in the Amazon S3 User Guide.

\n

\n Directory buckets - For directory buckets, only the server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) value is supported.

", "smithy.api#httpHeader": "x-amz-server-side-encryption" } }, "StorageClass": { "target": "com.amazonaws.s3#StorageClass", "traits": { - "smithy.api#documentation": "

By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The\n STANDARD storage class provides high durability and high availability. Depending on\n performance needs, you can specify a different Storage Class. Amazon S3 on Outposts only uses\n the OUTPOSTS Storage Class. For more information, see Storage Classes in the\n Amazon S3 User Guide.

", + "smithy.api#documentation": "

By default, Amazon S3 uses the STANDARD Storage Class to store newly created objects. The\n STANDARD storage class provides high durability and high availability. Depending on\n performance needs, you can specify a different Storage Class. For more information, see Storage Classes in the\n Amazon S3 User Guide.

\n \n
    \n
  • \n

    For directory buckets, only the S3 Express One Zone storage class is supported to store newly created objects.

    \n
  • \n
  • \n

    Amazon S3 on Outposts only uses\n the OUTPOSTS Storage Class.

    \n
  • \n
\n
", "smithy.api#httpHeader": "x-amz-storage-class" } }, "WebsiteRedirectLocation": { "target": "com.amazonaws.s3#WebsiteRedirectLocation", "traits": { - "smithy.api#documentation": "

If the bucket is configured as a website, redirects requests for this object to another\n object in the same bucket or to an external URL. Amazon S3 stores the value of this header in\n the object metadata. For information about object metadata, see Object Key and Metadata.

\n

In the following example, the request header sets the redirect to an object\n (anotherPage.html) in the same bucket:

\n

\n x-amz-website-redirect-location: /anotherPage.html\n

\n

In the following example, the request header sets the object redirect to another\n website:

\n

\n x-amz-website-redirect-location: http://www.example.com/\n

\n

For more information about website hosting in Amazon S3, see Hosting Websites on Amazon S3 and\n How to\n Configure Website Page Redirects.

", + "smithy.api#documentation": "

If the bucket is configured as a website, redirects requests for this object to another\n object in the same bucket or to an external URL. Amazon S3 stores the value of this header in\n the object metadata. For information about object metadata, see Object Key and Metadata in the Amazon S3\n User Guide.

\n

In the following example, the request header sets the redirect to an object\n (anotherPage.html) in the same bucket:

\n

\n x-amz-website-redirect-location: /anotherPage.html\n

\n

In the following example, the request header sets the object redirect to another\n website:

\n

\n x-amz-website-redirect-location: http://www.example.com/\n

\n

For more information about website hosting in Amazon S3, see Hosting Websites on Amazon S3 and\n How to\n Configure Website Page Redirects in the Amazon S3\n User Guide.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-website-redirect-location" } }, "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

Specifies the algorithm to use to when encrypting the object (for example,\n AES256).

", + "smithy.api#documentation": "

Specifies the algorithm to use when encrypting the object (for example,\n AES256).

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKey": { "target": "com.amazonaws.s3#SSECustomerKey", "traits": { - "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header.

", + "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

", + "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, "SSEKMSKeyId": { "target": "com.amazonaws.s3#SSEKMSKeyId", "traits": { - "smithy.api#documentation": "

If x-amz-server-side-encryption has a valid value of aws:kms\n or aws:kms:dsse, this header specifies the ID (Key ID, Key ARN, or Key Alias) of the Key Management Service (KMS)\n symmetric encryption customer managed key that was used for the object. If you specify\n x-amz-server-side-encryption:aws:kms or\n x-amz-server-side-encryption:aws:kms:dsse, but do not provide\n x-amz-server-side-encryption-aws-kms-key-id, Amazon S3 uses the Amazon Web Services managed key\n (aws/s3) to protect the data. If the KMS key does not exist in the same\n account that's issuing the command, you must use the full ARN and not just the ID.

", + "smithy.api#documentation": "

If x-amz-server-side-encryption has a valid value of aws:kms\n or aws:kms:dsse, this header specifies the ID (Key ID, Key ARN, or Key Alias) of the Key Management Service (KMS)\n symmetric encryption customer managed key that was used for the object. If you specify\n x-amz-server-side-encryption:aws:kms or\n x-amz-server-side-encryption:aws:kms:dsse, but do not provide\n x-amz-server-side-encryption-aws-kms-key-id, Amazon S3 uses the Amazon Web Services managed key\n (aws/s3) to protect the data. If the KMS key does not exist in the same\n account that's issuing the command, you must use the full ARN and not just the ID.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-aws-kms-key-id" } }, "SSEKMSEncryptionContext": { "target": "com.amazonaws.s3#SSEKMSEncryptionContext", "traits": { - "smithy.api#documentation": "

Specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The value of\n this header is a base64-encoded UTF-8 string holding JSON with the encryption context\n key-value pairs. This value is stored as object metadata and automatically gets passed on\n to Amazon Web Services KMS for future GetObject or CopyObject operations on\n this object.

", + "smithy.api#documentation": "

Specifies the Amazon Web Services KMS Encryption Context to use for object encryption. The value of\n this header is a base64-encoded UTF-8 string holding JSON with the encryption context\n key-value pairs. This value is stored as object metadata and automatically gets passed on\n to Amazon Web Services KMS for future GetObject or CopyObject operations on\n this object. This value must be explicitly added during CopyObject operations.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-context" } }, "BucketKeyEnabled": { "target": "com.amazonaws.s3#BucketKeyEnabled", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Specifies whether Amazon S3 should use an S3 Bucket Key for object encryption with\n server-side encryption using Key Management Service (KMS) keys (SSE-KMS). Setting this header to\n true causes Amazon S3 to use an S3 Bucket Key for object encryption with\n SSE-KMS.

\n

Specifying this header with a PUT action doesn’t affect bucket-level settings for S3\n Bucket Key.

", + "smithy.api#documentation": "

Specifies whether Amazon S3 should use an S3 Bucket Key for object encryption with\n server-side encryption using Key Management Service (KMS) keys (SSE-KMS). Setting this header to\n true causes Amazon S3 to use an S3 Bucket Key for object encryption with\n SSE-KMS.

\n

Specifying this header with a PUT action doesn’t affect bucket-level settings for S3\n Bucket Key.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-bucket-key-enabled" } }, @@ -28903,35 +31109,35 @@ "Tagging": { "target": "com.amazonaws.s3#TaggingHeader", "traits": { - "smithy.api#documentation": "

The tag-set for the object. The tag-set must be encoded as URL Query parameters. (For\n example, \"Key1=Value1\")

", + "smithy.api#documentation": "

The tag-set for the object. The tag-set must be encoded as URL Query parameters. (For\n example, \"Key1=Value1\")

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-tagging" } }, "ObjectLockMode": { "target": "com.amazonaws.s3#ObjectLockMode", "traits": { - "smithy.api#documentation": "

The Object Lock mode that you want to apply to this object.

", + "smithy.api#documentation": "

The Object Lock mode that you want to apply to this object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-mode" } }, "ObjectLockRetainUntilDate": { "target": "com.amazonaws.s3#ObjectLockRetainUntilDate", "traits": { - "smithy.api#documentation": "

The date and time when you want this object's Object Lock to expire. Must be formatted\n as a timestamp parameter.

", + "smithy.api#documentation": "

The date and time when you want this object's Object Lock to expire. Must be formatted\n as a timestamp parameter.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-retain-until-date" } }, "ObjectLockLegalHoldStatus": { "target": "com.amazonaws.s3#ObjectLockLegalHoldStatus", "traits": { - "smithy.api#documentation": "

Specifies whether a legal hold will be applied to this object. For more information\n about S3 Object Lock, see Object Lock.

", + "smithy.api#documentation": "

Specifies whether a legal hold will be applied to this object. For more information\n about S3 Object Lock, see Object Lock in the Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-object-lock-legal-hold" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -28953,7 +31159,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Places an Object Retention configuration on an object. For more information, see Locking Objects.\n Users or accounts require the s3:PutObjectRetention permission in order to\n place an Object Retention configuration on objects. Bypassing a Governance Retention\n configuration requires the s3:BypassGovernanceRetention permission.

\n

This action is not supported by Amazon S3 on Outposts.

", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Places an Object Retention configuration on an object. For more information, see Locking Objects.\n Users or accounts require the s3:PutObjectRetention permission in order to\n place an Object Retention configuration on objects. Bypassing a Governance Retention\n configuration requires the s3:BypassGovernanceRetention permission.

\n

This functionality is not supported for Amazon S3 on Outposts.

", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}/{Key+}?retention", @@ -28981,7 +31187,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name that contains the object you want to apply this Object Retention\n configuration to.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name that contains the object you want to apply this Object Retention\n configuration to.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -29021,7 +31227,6 @@ "BypassGovernanceRetention": { "target": "com.amazonaws.s3#BypassGovernanceRetention", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Indicates whether this action should bypass Governance-mode restrictions.

", "smithy.api#httpHeader": "x-amz-bypass-governance-retention" } @@ -29036,14 +31241,14 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -29065,7 +31270,7 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Sets the supplied tag-set to an object that already exists in a bucket. A tag is a\n key-value pair. For more information, see Object Tagging.

\n

You can associate tags with an object by sending a PUT request against the tagging\n subresource that is associated with the object. You can retrieve tags by sending a GET\n request. For more information, see GetObjectTagging.

\n

For tagging-related restrictions related to characters and encodings, see Tag\n Restrictions. Note that Amazon S3 limits the maximum number of tags to 10 tags per\n object.

\n

To use this operation, you must have permission to perform the\n s3:PutObjectTagging action. By default, the bucket owner has this\n permission and can grant this permission to others.

\n

To put tags of any other version, use the versionId query parameter. You\n also need permission for the s3:PutObjectVersionTagging action.

\n

\n PutObjectTagging has the following special errors. For more Amazon S3 errors\n see, Error\n Responses.

\n
    \n
  • \n

    \n InvalidTag - The tag provided was not a valid tag. This error\n can occur if the tag did not pass input validation. For more information, see Object\n Tagging.

    \n
  • \n
  • \n

    \n MalformedXML - The XML provided does not match the\n schema.

    \n
  • \n
  • \n

    \n OperationAborted - A conflicting conditional action is\n currently in progress against this resource. Please try again.

    \n
  • \n
  • \n

    \n InternalError - The service was unable to apply the provided\n tag to the object.

    \n
  • \n
\n

The following operations are related to PutObjectTagging:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Sets the supplied tag-set to an object that already exists in a bucket. A tag is a\n key-value pair. For more information, see Object Tagging.

\n

You can associate tags with an object by sending a PUT request against the tagging\n subresource that is associated with the object. You can retrieve tags by sending a GET\n request. For more information, see GetObjectTagging.

\n

For tagging-related restrictions related to characters and encodings, see Tag\n Restrictions. Note that Amazon S3 limits the maximum number of tags to 10 tags per\n object.

\n

To use this operation, you must have permission to perform the\n s3:PutObjectTagging action. By default, the bucket owner has this\n permission and can grant this permission to others.

\n

To put tags of any other version, use the versionId query parameter. You\n also need permission for the s3:PutObjectVersionTagging action.

\n

\n PutObjectTagging has the following special errors. For more Amazon S3 errors\n see, Error\n Responses.

\n
    \n
  • \n

    \n InvalidTag - The tag provided was not a valid tag. This error\n can occur if the tag did not pass input validation. For more information, see Object\n Tagging.

    \n
  • \n
  • \n

    \n MalformedXML - The XML provided does not match the\n schema.

    \n
  • \n
  • \n

    \n OperationAborted - A conflicting conditional action is\n currently in progress against this resource. Please try again.

    \n
  • \n
  • \n

    \n InternalError - The service was unable to apply the provided\n tag to the object.

    \n
  • \n
\n

The following operations are related to PutObjectTagging:

\n ", "smithy.api#examples": [ { "title": "To add tags to an existing object", @@ -29119,7 +31324,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the object.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the object.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -29152,7 +31357,7 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, @@ -29168,7 +31373,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, @@ -29196,11 +31401,16 @@ "requestAlgorithmMember": "ChecksumAlgorithm", "requestChecksumRequired": true }, - "smithy.api#documentation": "

Creates or modifies the PublicAccessBlock configuration for an Amazon S3 bucket.\n To use this operation, you must have the s3:PutBucketPublicAccessBlock\n permission. For more information about Amazon S3 permissions, see Specifying Permissions in a\n Policy.

\n \n

When Amazon S3 evaluates the PublicAccessBlock configuration for a bucket or\n an object, it checks the PublicAccessBlock configuration for both the\n bucket (or the bucket that contains the object) and the bucket owner's account. If the\n PublicAccessBlock configurations are different between the bucket and\n the account, S3 uses the most restrictive combination of the bucket-level and\n account-level settings.

\n
\n

For more information about when Amazon S3 considers a bucket or an object public, see The Meaning of \"Public\".

\n

The following operations are related to PutPublicAccessBlock:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Creates or modifies the PublicAccessBlock configuration for an Amazon S3 bucket.\n To use this operation, you must have the s3:PutBucketPublicAccessBlock\n permission. For more information about Amazon S3 permissions, see Specifying Permissions in a\n Policy.

\n \n

When Amazon S3 evaluates the PublicAccessBlock configuration for a bucket or\n an object, it checks the PublicAccessBlock configuration for both the\n bucket (or the bucket that contains the object) and the bucket owner's account. If the\n PublicAccessBlock configurations are different between the bucket and\n the account, Amazon S3 uses the most restrictive combination of the bucket-level and\n account-level settings.

\n
\n

For more information about when Amazon S3 considers a bucket or an object public, see The Meaning of \"Public\".

\n

The following operations are related to PutPublicAccessBlock:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}?publicAccessBlock", "code": 200 + }, + "smithy.rules#staticContextParams": { + "UseS3ExpressControlEndpoint": { + "value": true + } } } }, @@ -29228,7 +31438,7 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, @@ -29244,7 +31454,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -29294,10 +31504,7 @@ } }, "com.amazonaws.s3#Quiet": { - "type": "boolean", - "traits": { - "smithy.api#default": false - } + "type": "boolean" }, "com.amazonaws.s3#QuoteCharacter": { "type": "string" @@ -29402,6 +31609,15 @@ "smithy.api#documentation": "

Specifies the redirect behavior of all requests to a website endpoint of an Amazon S3\n bucket.

" } }, + "com.amazonaws.s3#Region": { + "type": "string", + "traits": { + "smithy.api#length": { + "min": 0, + "max": 20 + } + } + }, "com.amazonaws.s3#ReplaceKeyPrefixWith": { "type": "string" }, @@ -29479,7 +31695,6 @@ "Priority": { "target": "com.amazonaws.s3#Priority", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The priority indicates which rule has precedence whenever two or more replication rules\n conflict. Amazon S3 will attempt to replicate objects according to all replication rules.\n However, if there are two or more rules with the same destination bucket, then objects will\n be replicated according to the rule with the highest priority. The higher the number, the\n higher the priority.

\n

For more information, see Replication in the\n Amazon S3 User Guide.

" } }, @@ -29678,7 +31893,6 @@ "Minutes": { "target": "com.amazonaws.s3#Minutes", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Contains an integer specifying time in minutes.

\n

Valid value: 15

" } } @@ -29698,7 +31912,7 @@ } }, "traits": { - "smithy.api#documentation": "

If present, indicates that the requester was successfully charged for the\n request.

" + "smithy.api#documentation": "

If present, indicates that the requester was successfully charged for the\n request.

\n \n

This functionality is not supported for directory buckets.

\n
" } }, "com.amazonaws.s3#RequestPayer": { @@ -29712,7 +31926,7 @@ } }, "traits": { - "smithy.api#documentation": "

Confirms that the requester knows that they will be charged for the request. Bucket\n owners need not specify this parameter in their requests. If either the source or\n destination Amazon S3 bucket has Requester Pays enabled, the requester will pay for\n corresponding charges to copy the object. For information about downloading objects from\n Requester Pays buckets, see Downloading Objects in\n Requester Pays Buckets in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

Confirms that the requester knows that they will be charged for the request. Bucket\n owners need not specify this parameter in their requests. If either the source or\n destination S3 bucket has Requester Pays enabled, the requester will pay for\n corresponding charges to copy the object. For information about downloading objects from\n Requester Pays buckets, see Downloading Objects in\n Requester Pays Buckets in the Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets.

\n
" } }, "com.amazonaws.s3#RequestPaymentConfiguration": { @@ -29736,7 +31950,6 @@ "Enabled": { "target": "com.amazonaws.s3#EnableRequestProgress", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Specifies whether periodic QueryProgress frames should be sent. Valid values: TRUE,\n FALSE. Default value: FALSE.

" } } @@ -29795,7 +32008,7 @@ "aws.protocols#httpChecksum": { "requestAlgorithmMember": "ChecksumAlgorithm" }, - "smithy.api#documentation": "

Restores an archived copy of an object back into Amazon S3

\n

This action is not supported by Amazon S3 on Outposts.

\n

This action performs the following types of requests:

\n
    \n
  • \n

    \n select - Perform a select query on an archived object

    \n
  • \n
  • \n

    \n restore an archive - Restore an archived object

    \n
  • \n
\n

For more information about the S3 structure in the request body, see the\n following:

\n \n

Define the SQL expression for the SELECT type of restoration for your query\n in the request body's SelectParameters structure. You can use expressions like\n the following examples.

\n
    \n
  • \n

    The following expression returns all records from the specified object.

    \n

    \n SELECT * FROM Object\n

    \n
  • \n
  • \n

    Assuming that you are not using any headers for data stored in the object, you can\n specify columns with positional headers.

    \n

    \n SELECT s._1, s._2 FROM Object s WHERE s._3 > 100\n

    \n
  • \n
  • \n

    If you have headers and you set the fileHeaderInfo in the\n CSV structure in the request body to USE, you can\n specify headers in the query. (If you set the fileHeaderInfo field to\n IGNORE, the first row is skipped for the query.) You cannot mix\n ordinal positions with header column names.

    \n

    \n SELECT s.Id, s.FirstName, s.SSN FROM S3Object s\n

    \n
  • \n
\n

When making a select request, you can also do the following:

\n
    \n
  • \n

    To expedite your queries, specify the Expedited tier. For more\n information about tiers, see \"Restoring Archives,\" later in this topic.

    \n
  • \n
  • \n

    Specify details about the data serialization format of both the input object that\n is being queried and the serialization of the CSV-encoded query results.

    \n
  • \n
\n

The following are additional important facts about the select feature:

\n
    \n
  • \n

    The output results are new Amazon S3 objects. Unlike archive retrievals, they are\n stored until explicitly deleted-manually or through a lifecycle configuration.

    \n
  • \n
  • \n

    You can issue more than one select request on the same Amazon S3 object. Amazon S3 doesn't\n duplicate requests, so avoid issuing duplicate requests.

    \n
  • \n
  • \n

    Amazon S3 accepts a select request even if the object has already been restored. A\n select request doesn’t return error response 409.

    \n
  • \n
\n
\n
Permissions
\n
\n

To use this operation, you must have permissions to perform the\n s3:RestoreObject action. The bucket owner has this permission by\n default and can grant this permission to others. For more information about\n permissions, see Permissions Related to Bucket Subresource Operations and Managing Access Permissions to Your Amazon S3 Resources in the\n Amazon S3 User Guide.

\n
\n
Restoring objects
\n
\n

Objects that you archive to the S3 Glacier Flexible Retrieval Flexible Retrieval\n or S3 Glacier Deep Archive storage class, and S3 Intelligent-Tiering Archive or\n S3 Intelligent-Tiering Deep Archive tiers, are not accessible in real time. For objects in the\n S3 Glacier Flexible Retrieval Flexible Retrieval or S3 Glacier Deep Archive\n storage classes, you must first initiate a restore request, and then wait until a\n temporary copy of the object is available. If you want a permanent copy of the\n object, create a copy of it in the Amazon S3 Standard storage class in your S3 bucket.\n To access an archived object, you must restore the object for the duration (number\n of days) that you specify. For objects in the Archive Access or Deep Archive\n Access tiers of S3 Intelligent-Tiering, you must first initiate a restore request,\n and then wait until the object is moved into the Frequent Access tier.

\n

To restore a specific object version, you can provide a version ID. If you\n don't provide a version ID, Amazon S3 restores the current version.

\n

When restoring an archived object, you can specify one of the following data\n access tier options in the Tier element of the request body:

\n
    \n
  • \n

    \n Expedited - Expedited retrievals allow you to quickly access\n your data stored in the S3 Glacier Flexible Retrieval Flexible Retrieval\n storage class or S3 Intelligent-Tiering Archive tier when occasional urgent requests\n for restoring archives are required. For all but the largest archived\n objects (250 MB+), data accessed using Expedited retrievals is typically\n made available within 1–5 minutes. Provisioned capacity ensures that\n retrieval capacity for Expedited retrievals is available when you need it.\n Expedited retrievals and provisioned capacity are not available for objects\n stored in the S3 Glacier Deep Archive storage class or\n S3 Intelligent-Tiering Deep Archive tier.

    \n
  • \n
  • \n

    \n Standard - Standard retrievals allow you to access any of\n your archived objects within several hours. This is the default option for\n retrieval requests that do not specify the retrieval option. Standard\n retrievals typically finish within 3–5 hours for objects stored in the\n S3 Glacier Flexible Retrieval Flexible Retrieval storage class or\n S3 Intelligent-Tiering Archive tier. They typically finish within 12 hours for\n objects stored in the S3 Glacier Deep Archive storage class or\n S3 Intelligent-Tiering Deep Archive tier. Standard retrievals are free for objects stored\n in S3 Intelligent-Tiering.

    \n
  • \n
  • \n

    \n Bulk - Bulk retrievals free for objects stored in the\n S3 Glacier Flexible Retrieval and S3 Intelligent-Tiering storage classes,\n enabling you to retrieve large amounts, even petabytes, of data at no cost.\n Bulk retrievals typically finish within 5–12 hours for objects stored in the\n S3 Glacier Flexible Retrieval Flexible Retrieval storage class or\n S3 Intelligent-Tiering Archive tier. Bulk retrievals are also the lowest-cost\n retrieval option when restoring objects from\n S3 Glacier Deep Archive. They typically finish within 48 hours for\n objects stored in the S3 Glacier Deep Archive storage class or\n S3 Intelligent-Tiering Deep Archive tier.

    \n
  • \n
\n

For more information about archive retrieval options and provisioned capacity\n for Expedited data access, see Restoring Archived\n Objects in the Amazon S3 User Guide.

\n

You can use Amazon S3 restore speed upgrade to change the restore speed to a faster\n speed while it is in progress. For more information, see Upgrading the speed of an in-progress restore in the\n Amazon S3 User Guide.

\n

To get the status of object restoration, you can send a HEAD\n request. Operations return the x-amz-restore header, which provides\n information about the restoration status, in the response. You can use Amazon S3 event\n notifications to notify you when a restore is initiated or completed. For more\n information, see Configuring Amazon S3 Event\n Notifications in the Amazon S3 User Guide.

\n

After restoring an archived object, you can update the restoration period by\n reissuing the request with a new period. Amazon S3 updates the restoration period\n relative to the current time and charges only for the request-there are no\n data transfer charges. You cannot update the restoration period when Amazon S3 is\n actively processing your current restore request for the object.

\n

If your bucket has a lifecycle configuration with a rule that includes an\n expiration action, the object expiration overrides the life span that you specify\n in a restore request. For example, if you restore an object copy for 10 days, but\n the object is scheduled to expire in 3 days, Amazon S3 deletes the object in 3 days.\n For more information about lifecycle configuration, see PutBucketLifecycleConfiguration and Object Lifecycle\n Management in Amazon S3 User Guide.

\n
\n
Responses
\n
\n

A successful action returns either the 200 OK or 202\n Accepted status code.

\n
    \n
  • \n

    If the object is not previously restored, then Amazon S3 returns 202\n Accepted in the response.

    \n
  • \n
  • \n

    If the object is previously restored, Amazon S3 returns 200 OK in\n the response.

    \n
  • \n
\n
    \n
  • \n

    Special errors:

    \n
      \n
    • \n

      \n Code: RestoreAlreadyInProgress\n

      \n
    • \n
    • \n

      \n Cause: Object restore is already in progress. (This error\n does not apply to SELECT type requests.)\n

      \n
    • \n
    • \n

      \n HTTP Status Code: 409 Conflict\n

      \n
    • \n
    • \n

      \n SOAP Fault Code Prefix: Client\n

      \n
    • \n
    \n
  • \n
  • \n
      \n
    • \n

      \n Code: GlacierExpeditedRetrievalNotAvailable\n

      \n
    • \n
    • \n

      \n Cause: expedited retrievals are currently not available.\n Try again later. (Returned if there is insufficient capacity to\n process the Expedited request. This error applies only to Expedited\n retrievals and not to S3 Standard or Bulk retrievals.)\n

      \n
    • \n
    • \n

      \n HTTP Status Code: 503\n

      \n
    • \n
    • \n

      \n SOAP Fault Code Prefix: N/A\n

      \n
    • \n
    \n
  • \n
\n
\n
\n

The following operations are related to RestoreObject:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Restores an archived copy of an object back into Amazon S3

\n

This functionality is not supported for Amazon S3 on Outposts.

\n

This action performs the following types of requests:

\n
    \n
  • \n

    \n select - Perform a select query on an archived object

    \n
  • \n
  • \n

    \n restore an archive - Restore an archived object

    \n
  • \n
\n

For more information about the S3 structure in the request body, see the\n following:

\n \n

Define the SQL expression for the SELECT type of restoration for your query\n in the request body's SelectParameters structure. You can use expressions like\n the following examples.

\n
    \n
  • \n

    The following expression returns all records from the specified object.

    \n

    \n SELECT * FROM Object\n

    \n
  • \n
  • \n

    Assuming that you are not using any headers for data stored in the object, you can\n specify columns with positional headers.

    \n

    \n SELECT s._1, s._2 FROM Object s WHERE s._3 > 100\n

    \n
  • \n
  • \n

    If you have headers and you set the fileHeaderInfo in the\n CSV structure in the request body to USE, you can\n specify headers in the query. (If you set the fileHeaderInfo field to\n IGNORE, the first row is skipped for the query.) You cannot mix\n ordinal positions with header column names.

    \n

    \n SELECT s.Id, s.FirstName, s.SSN FROM S3Object s\n

    \n
  • \n
\n

When making a select request, you can also do the following:

\n
    \n
  • \n

    To expedite your queries, specify the Expedited tier. For more\n information about tiers, see \"Restoring Archives,\" later in this topic.

    \n
  • \n
  • \n

    Specify details about the data serialization format of both the input object that\n is being queried and the serialization of the CSV-encoded query results.

    \n
  • \n
\n

The following are additional important facts about the select feature:

\n
    \n
  • \n

    The output results are new Amazon S3 objects. Unlike archive retrievals, they are\n stored until explicitly deleted-manually or through a lifecycle configuration.

    \n
  • \n
  • \n

    You can issue more than one select request on the same Amazon S3 object. Amazon S3 doesn't\n duplicate requests, so avoid issuing duplicate requests.

    \n
  • \n
  • \n

    Amazon S3 accepts a select request even if the object has already been restored. A\n select request doesn’t return error response 409.

    \n
  • \n
\n
\n
Permissions
\n
\n

To use this operation, you must have permissions to perform the\n s3:RestoreObject action. The bucket owner has this permission by\n default and can grant this permission to others. For more information about\n permissions, see Permissions Related to Bucket Subresource Operations and Managing Access Permissions to Your Amazon S3 Resources in the\n Amazon S3 User Guide.

\n
\n
Restoring objects
\n
\n

Objects that you archive to the S3 Glacier Flexible Retrieval Flexible Retrieval\n or S3 Glacier Deep Archive storage class, and S3 Intelligent-Tiering Archive or\n S3 Intelligent-Tiering Deep Archive tiers, are not accessible in real time. For objects in the\n S3 Glacier Flexible Retrieval Flexible Retrieval or S3 Glacier Deep Archive\n storage classes, you must first initiate a restore request, and then wait until a\n temporary copy of the object is available. If you want a permanent copy of the\n object, create a copy of it in the Amazon S3 Standard storage class in your S3 bucket.\n To access an archived object, you must restore the object for the duration (number\n of days) that you specify. For objects in the Archive Access or Deep Archive\n Access tiers of S3 Intelligent-Tiering, you must first initiate a restore request,\n and then wait until the object is moved into the Frequent Access tier.

\n

To restore a specific object version, you can provide a version ID. If you\n don't provide a version ID, Amazon S3 restores the current version.

\n

When restoring an archived object, you can specify one of the following data\n access tier options in the Tier element of the request body:

\n
    \n
  • \n

    \n Expedited - Expedited retrievals allow you to quickly access\n your data stored in the S3 Glacier Flexible Retrieval Flexible Retrieval\n storage class or S3 Intelligent-Tiering Archive tier when occasional urgent requests\n for restoring archives are required. For all but the largest archived\n objects (250 MB+), data accessed using Expedited retrievals is typically\n made available within 1–5 minutes. Provisioned capacity ensures that\n retrieval capacity for Expedited retrievals is available when you need it.\n Expedited retrievals and provisioned capacity are not available for objects\n stored in the S3 Glacier Deep Archive storage class or\n S3 Intelligent-Tiering Deep Archive tier.

    \n
  • \n
  • \n

    \n Standard - Standard retrievals allow you to access any of\n your archived objects within several hours. This is the default option for\n retrieval requests that do not specify the retrieval option. Standard\n retrievals typically finish within 3–5 hours for objects stored in the\n S3 Glacier Flexible Retrieval Flexible Retrieval storage class or\n S3 Intelligent-Tiering Archive tier. They typically finish within 12 hours for\n objects stored in the S3 Glacier Deep Archive storage class or\n S3 Intelligent-Tiering Deep Archive tier. Standard retrievals are free for objects stored\n in S3 Intelligent-Tiering.

    \n
  • \n
  • \n

    \n Bulk - Bulk retrievals free for objects stored in the\n S3 Glacier Flexible Retrieval and S3 Intelligent-Tiering storage classes,\n enabling you to retrieve large amounts, even petabytes, of data at no cost.\n Bulk retrievals typically finish within 5–12 hours for objects stored in the\n S3 Glacier Flexible Retrieval Flexible Retrieval storage class or\n S3 Intelligent-Tiering Archive tier. Bulk retrievals are also the lowest-cost\n retrieval option when restoring objects from\n S3 Glacier Deep Archive. They typically finish within 48 hours for\n objects stored in the S3 Glacier Deep Archive storage class or\n S3 Intelligent-Tiering Deep Archive tier.

    \n
  • \n
\n

For more information about archive retrieval options and provisioned capacity\n for Expedited data access, see Restoring Archived\n Objects in the Amazon S3 User Guide.

\n

You can use Amazon S3 restore speed upgrade to change the restore speed to a faster\n speed while it is in progress. For more information, see Upgrading the speed of an in-progress restore in the\n Amazon S3 User Guide.

\n

To get the status of object restoration, you can send a HEAD\n request. Operations return the x-amz-restore header, which provides\n information about the restoration status, in the response. You can use Amazon S3 event\n notifications to notify you when a restore is initiated or completed. For more\n information, see Configuring Amazon S3 Event\n Notifications in the Amazon S3 User Guide.

\n

After restoring an archived object, you can update the restoration period by\n reissuing the request with a new period. Amazon S3 updates the restoration period\n relative to the current time and charges only for the request-there are no\n data transfer charges. You cannot update the restoration period when Amazon S3 is\n actively processing your current restore request for the object.

\n

If your bucket has a lifecycle configuration with a rule that includes an\n expiration action, the object expiration overrides the life span that you specify\n in a restore request. For example, if you restore an object copy for 10 days, but\n the object is scheduled to expire in 3 days, Amazon S3 deletes the object in 3 days.\n For more information about lifecycle configuration, see PutBucketLifecycleConfiguration and Object Lifecycle\n Management in Amazon S3 User Guide.

\n
\n
Responses
\n
\n

A successful action returns either the 200 OK or 202\n Accepted status code.

\n
    \n
  • \n

    If the object is not previously restored, then Amazon S3 returns 202\n Accepted in the response.

    \n
  • \n
  • \n

    If the object is previously restored, Amazon S3 returns 200 OK in\n the response.

    \n
  • \n
\n
    \n
  • \n

    Special errors:

    \n
      \n
    • \n

      \n Code: RestoreAlreadyInProgress\n

      \n
    • \n
    • \n

      \n Cause: Object restore is already in progress. (This error\n does not apply to SELECT type requests.)\n

      \n
    • \n
    • \n

      \n HTTP Status Code: 409 Conflict\n

      \n
    • \n
    • \n

      \n SOAP Fault Code Prefix: Client\n

      \n
    • \n
    \n
  • \n
  • \n
      \n
    • \n

      \n Code: GlacierExpeditedRetrievalNotAvailable\n

      \n
    • \n
    • \n

      \n Cause: expedited retrievals are currently not available.\n Try again later. (Returned if there is insufficient capacity to\n process the Expedited request. This error applies only to Expedited\n retrievals and not to S3 Standard or Bulk retrievals.)\n

      \n
    • \n
    • \n

      \n HTTP Status Code: 503\n

      \n
    • \n
    • \n

      \n SOAP Fault Code Prefix: N/A\n

      \n
    • \n
    \n
  • \n
\n
\n
\n

The following operations are related to RestoreObject:

\n ", "smithy.api#examples": [ { "title": "To restore an archived object", @@ -29847,7 +32060,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name containing the object to restore.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name containing the object to restore.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -29886,14 +32099,14 @@ "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -29911,7 +32124,6 @@ "Days": { "target": "com.amazonaws.s3#Days", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Lifetime of the active copy in days. Do not use with restores that specify\n OutputLocation.

\n

The Days element is required for regular restores, and must not be provided for select\n requests.

" } }, @@ -29973,7 +32185,6 @@ "IsRestoreInProgress": { "target": "com.amazonaws.s3#IsRestoreInProgress", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Specifies whether the object is currently being restored. If the object restoration is\n in progress, the header returns the value TRUE. For example:

\n

\n x-amz-optional-object-attributes: IsRestoreInProgress=\"true\"\n

\n

If the object restoration has completed, the header returns the value\n FALSE. For example:

\n

\n x-amz-optional-object-attributes: IsRestoreInProgress=\"false\",\n RestoreExpiryDate=\"2012-12-21T00:00:00.000Z\"\n

\n

If the object hasn't been restored, there is no header response.

" } }, @@ -29985,7 +32196,7 @@ } }, "traits": { - "smithy.api#documentation": "

Specifies the restoration status of an object. Objects in certain storage classes must\n be restored before they can be retrieved. For more information about these storage classes\n and how to work with archived objects, see Working with archived\n objects in the Amazon S3 User Guide.

" + "smithy.api#documentation": "

Specifies the restoration status of an object. Objects in certain storage classes must\n be restored before they can be retrieved. For more information about these storage classes\n and how to work with archived objects, see Working with archived\n objects in the Amazon S3 User Guide.

\n \n

This functionality is not supported for directory buckets. Only the S3 Express One Zone storage class is supported by directory buckets to store objects.

\n
" } }, "com.amazonaws.s3#Role": { @@ -30145,14 +32356,12 @@ "Start": { "target": "com.amazonaws.s3#Start", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Specifies the start of the byte range. This parameter is optional. Valid values:\n non-negative integers. The default value is 0. If only start is supplied, it\n means scan from that point to the end of the file. For example,\n 50 means scan\n from byte 50 until the end of the file.

" } }, "End": { "target": "com.amazonaws.s3#End", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Specifies the end of the byte range. This parameter is optional. Valid values:\n non-negative integers. The default value is one less than the size of the object being\n queried. If only the End parameter is supplied, it is interpreted to mean scan the last N\n bytes of the file. For example,\n 50 means scan the\n last 50 bytes.

" } } @@ -30170,7 +32379,7 @@ "target": "com.amazonaws.s3#SelectObjectContentOutput" }, "traits": { - "smithy.api#documentation": "

This action filters the contents of an Amazon S3 object based on a simple structured query\n language (SQL) statement. In the request, along with the SQL expression, you must also\n specify a data serialization format (JSON, CSV, or Apache Parquet) of the object. Amazon S3 uses\n this format to parse object data into records, and returns only records that match the\n specified SQL expression. You must also specify the data serialization format for the\n response.

\n

This action is not supported by Amazon S3 on Outposts.

\n

For more information about Amazon S3 Select, see Selecting Content from\n Objects and SELECT\n Command in the Amazon S3 User Guide.

\n

\n
\n
Permissions
\n
\n

You must have s3:GetObject permission for this operation. Amazon S3\n Select does not support anonymous access. For more information about permissions,\n see Specifying Permissions in\n a Policy in the Amazon S3 User Guide.

\n
\n
Object Data Formats
\n
\n

You can use Amazon S3 Select to query objects that have the following format\n properties:

\n
    \n
  • \n

    \n CSV, JSON, and Parquet - Objects must be in CSV,\n JSON, or Parquet format.

    \n
  • \n
  • \n

    \n UTF-8 - UTF-8 is the only encoding type Amazon S3 Select\n supports.

    \n
  • \n
  • \n

    \n GZIP or BZIP2 - CSV and JSON files can be compressed\n using GZIP or BZIP2. GZIP and BZIP2 are the only compression formats that\n Amazon S3 Select supports for CSV and JSON files. Amazon S3 Select supports columnar\n compression for Parquet using GZIP or Snappy. Amazon S3 Select does not support\n whole-object compression for Parquet objects.

    \n
  • \n
  • \n

    \n Server-side encryption - Amazon S3 Select supports\n querying objects that are protected with server-side encryption.

    \n

    For objects that are encrypted with customer-provided encryption keys\n (SSE-C), you must use HTTPS, and you must use the headers that are\n documented in the GetObject. For more\n information about SSE-C, see Server-Side Encryption (Using Customer-Provided Encryption Keys)\n in the Amazon S3 User Guide.

    \n

    For objects that are encrypted with Amazon S3 managed keys (SSE-S3) and\n Amazon Web Services KMS keys (SSE-KMS), server-side encryption is handled transparently,\n so you don't need to specify anything. For more information about\n server-side encryption, including SSE-S3 and SSE-KMS, see Protecting Data Using Server-Side Encryption in the\n Amazon S3 User Guide.

    \n
  • \n
\n
\n
Working with the Response Body
\n
\n

Given the response size is unknown, Amazon S3 Select streams the response as a\n series of messages and includes a Transfer-Encoding header with\n chunked as its value in the response. For more information, see\n Appendix:\n SelectObjectContent\n Response.

\n
\n
GetObject Support
\n
\n

The SelectObjectContent action does not support the following\n GetObject functionality. For more information, see GetObject.

\n
    \n
  • \n

    \n Range: Although you can specify a scan range for an Amazon S3 Select\n request (see SelectObjectContentRequest - ScanRange in the request\n parameters), you cannot specify the range of bytes of an object to return.\n

    \n
  • \n
  • \n

    The GLACIER, DEEP_ARCHIVE, and\n REDUCED_REDUNDANCY storage classes, or the\n ARCHIVE_ACCESS and DEEP_ARCHIVE_ACCESS access\n tiers of the INTELLIGENT_TIERING storage class: You cannot\n query objects in the GLACIER, DEEP_ARCHIVE, or\n REDUCED_REDUNDANCY storage classes, nor objects in the\n ARCHIVE_ACCESS or DEEP_ARCHIVE_ACCESS access\n tiers of the INTELLIGENT_TIERING storage class. For more\n information about storage classes, see Using Amazon S3\n storage classes in the\n Amazon S3 User Guide.

    \n
  • \n
\n
\n
Special Errors
\n
\n

For a list of special errors for this operation, see List of SELECT Object Content Error Codes\n

\n
\n
\n

The following operations are related to SelectObjectContent:

\n ", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

This action filters the contents of an Amazon S3 object based on a simple structured query\n language (SQL) statement. In the request, along with the SQL expression, you must also\n specify a data serialization format (JSON, CSV, or Apache Parquet) of the object. Amazon S3 uses\n this format to parse object data into records, and returns only records that match the\n specified SQL expression. You must also specify the data serialization format for the\n response.

\n

This functionality is not supported for Amazon S3 on Outposts.

\n

For more information about Amazon S3 Select, see Selecting Content from\n Objects and SELECT\n Command in the Amazon S3 User Guide.

\n

\n
\n
Permissions
\n
\n

You must have the s3:GetObject permission for this operation. Amazon S3\n Select does not support anonymous access. For more information about permissions,\n see Specifying Permissions in\n a Policy in the Amazon S3 User Guide.

\n
\n
Object Data Formats
\n
\n

You can use Amazon S3 Select to query objects that have the following format\n properties:

\n
    \n
  • \n

    \n CSV, JSON, and Parquet - Objects must be in CSV,\n JSON, or Parquet format.

    \n
  • \n
  • \n

    \n UTF-8 - UTF-8 is the only encoding type Amazon S3 Select\n supports.

    \n
  • \n
  • \n

    \n GZIP or BZIP2 - CSV and JSON files can be compressed\n using GZIP or BZIP2. GZIP and BZIP2 are the only compression formats that\n Amazon S3 Select supports for CSV and JSON files. Amazon S3 Select supports columnar\n compression for Parquet using GZIP or Snappy. Amazon S3 Select does not support\n whole-object compression for Parquet objects.

    \n
  • \n
  • \n

    \n Server-side encryption - Amazon S3 Select supports\n querying objects that are protected with server-side encryption.

    \n

    For objects that are encrypted with customer-provided encryption keys\n (SSE-C), you must use HTTPS, and you must use the headers that are\n documented in the GetObject. For more\n information about SSE-C, see Server-Side Encryption (Using Customer-Provided Encryption Keys)\n in the Amazon S3 User Guide.

    \n

    For objects that are encrypted with Amazon S3 managed keys (SSE-S3) and\n Amazon Web Services KMS keys (SSE-KMS), server-side encryption is handled transparently,\n so you don't need to specify anything. For more information about\n server-side encryption, including SSE-S3 and SSE-KMS, see Protecting Data Using Server-Side Encryption in the\n Amazon S3 User Guide.

    \n
  • \n
\n
\n
Working with the Response Body
\n
\n

Given the response size is unknown, Amazon S3 Select streams the response as a\n series of messages and includes a Transfer-Encoding header with\n chunked as its value in the response. For more information, see\n Appendix:\n SelectObjectContent\n Response.

\n
\n
GetObject Support
\n
\n

The SelectObjectContent action does not support the following\n GetObject functionality. For more information, see GetObject.

\n
    \n
  • \n

    \n Range: Although you can specify a scan range for an Amazon S3 Select\n request (see SelectObjectContentRequest - ScanRange in the request\n parameters), you cannot specify the range of bytes of an object to return.\n

    \n
  • \n
  • \n

    The GLACIER, DEEP_ARCHIVE, and\n REDUCED_REDUNDANCY storage classes, or the\n ARCHIVE_ACCESS and DEEP_ARCHIVE_ACCESS access\n tiers of the INTELLIGENT_TIERING storage class: You cannot\n query objects in the GLACIER, DEEP_ARCHIVE, or\n REDUCED_REDUNDANCY storage classes, nor objects in the\n ARCHIVE_ACCESS or DEEP_ARCHIVE_ACCESS access\n tiers of the INTELLIGENT_TIERING storage class. For more\n information about storage classes, see Using Amazon S3\n storage classes in the\n Amazon S3 User Guide.

    \n
  • \n
\n
\n
Special Errors
\n
\n

For a list of special errors for this operation, see List of SELECT Object Content Error Codes\n

\n
\n
\n

The following operations are related to SelectObjectContent:

\n ", "smithy.api#http": { "method": "POST", "uri": "/{Bucket}/{Key+}?select&select-type=2&x-id=SelectObjectContent", @@ -30318,7 +32527,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -30437,7 +32646,6 @@ "BucketKeyEnabled": { "target": "com.amazonaws.s3#BucketKeyEnabled", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Specifies whether Amazon S3 should use an S3 Bucket Key with server-side encryption using KMS\n (SSE-KMS) for new objects in the bucket. Existing objects are not affected. Setting the\n BucketKeyEnabled element to true causes Amazon S3 to use an S3\n Bucket Key. By default, S3 Bucket Key is not enabled.

\n

For more information, see Amazon S3 Bucket Keys in the\n Amazon S3 User Guide.

" } } @@ -30452,24 +32660,89 @@ "target": "com.amazonaws.s3#ServerSideEncryptionRule" } }, - "com.amazonaws.s3#Setting": { - "type": "boolean", + "com.amazonaws.s3#SessionCredentialValue": { + "type": "string", "traits": { - "smithy.api#default": false + "smithy.api#sensitive": {} } }, - "com.amazonaws.s3#Size": { - "type": "long", + "com.amazonaws.s3#SessionCredentials": { + "type": "structure", + "members": { + "AccessKeyId": { + "target": "com.amazonaws.s3#AccessKeyIdValue", + "traits": { + "smithy.api#documentation": "

A unique identifier that's associated with a secret access key. The access key ID and the secret access key are used together to sign programmatic Amazon Web Services requests cryptographically.

", + "smithy.api#required": {}, + "smithy.api#xmlName": "AccessKeyId" + } + }, + "SecretAccessKey": { + "target": "com.amazonaws.s3#SessionCredentialValue", + "traits": { + "smithy.api#documentation": "

A key that's used with the access key ID to cryptographically sign programmatic Amazon Web Services requests. Signing a request identifies the sender and prevents the request from being altered.

", + "smithy.api#required": {}, + "smithy.api#xmlName": "SecretAccessKey" + } + }, + "SessionToken": { + "target": "com.amazonaws.s3#SessionCredentialValue", + "traits": { + "smithy.api#documentation": "

A part of the temporary security credentials. The session token is used to validate the temporary security credentials. \n \n

", + "smithy.api#required": {}, + "smithy.api#xmlName": "SessionToken" + } + }, + "Expiration": { + "target": "com.amazonaws.s3#SessionExpiration", + "traits": { + "smithy.api#documentation": "

Temporary security credentials expire after a specified interval. After temporary credentials expire, any calls that you make with those credentials will fail. So you must generate a new set of temporary credentials. \n Temporary credentials cannot be extended or refreshed beyond the original specified interval.

", + "smithy.api#required": {}, + "smithy.api#xmlName": "Expiration" + } + } + }, "traits": { - "smithy.api#default": 0 + "smithy.api#documentation": "

The established temporary security credentials of the session.

\n \n

\n Directory buckets - These session credentials are only supported for the authentication and authorization of Zonal endpoint APIs on directory buckets.

\n
" } }, - "com.amazonaws.s3#SkipValidation": { - "type": "boolean", + "com.amazonaws.s3#SessionExpiration": { + "type": "timestamp" + }, + "com.amazonaws.s3#SessionMode": { + "type": "enum", + "members": { + "ReadOnly": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "ReadOnly" + } + }, + "ReadWrite": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "ReadWrite" + } + } + } + }, + "com.amazonaws.s3#Setting": { + "type": "boolean" + }, + "com.amazonaws.s3#SimplePrefix": { + "type": "structure", + "members": {}, "traits": { - "smithy.api#default": false + "smithy.api#documentation": "

To use simple format for S3 keys for log objects, set SimplePrefix to an empty object.

\n

\n [DestinationPrefix][YYYY]-[MM]-[DD]-[hh]-[mm]-[ss]-[UniqueString]\n

", + "smithy.api#xmlName": "SimplePrefix" } }, + "com.amazonaws.s3#Size": { + "type": "long" + }, + "com.amazonaws.s3#SkipValidation": { + "type": "boolean" + }, "com.amazonaws.s3#SourceSelectionCriteria": { "type": "structure", "members": { @@ -30523,10 +32796,7 @@ } }, "com.amazonaws.s3#Start": { - "type": "long", - "traits": { - "smithy.api#default": 0 - } + "type": "long" }, "com.amazonaws.s3#StartAfter": { "type": "string" @@ -30537,21 +32807,18 @@ "BytesScanned": { "target": "com.amazonaws.s3#BytesScanned", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The total number of object bytes scanned.

" } }, "BytesProcessed": { "target": "com.amazonaws.s3#BytesProcessed", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The total number of uncompressed object bytes processed.

" } }, "BytesReturned": { "target": "com.amazonaws.s3#BytesReturned", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The total number of bytes of records payload data returned.

" } } @@ -30637,6 +32904,12 @@ "traits": { "smithy.api#enumValue": "SNOW" } + }, + "EXPRESS_ONEZONE": { + "target": "smithy.api#Unit", + "traits": { + "smithy.api#enumValue": "EXPRESS_ONEZONE" + } } } }, @@ -30719,10 +32992,7 @@ } }, "com.amazonaws.s3#TagCount": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#TagSet": { "type": "list", @@ -30804,6 +33074,28 @@ } } }, + "com.amazonaws.s3#TargetObjectKeyFormat": { + "type": "structure", + "members": { + "SimplePrefix": { + "target": "com.amazonaws.s3#SimplePrefix", + "traits": { + "smithy.api#documentation": "

To use the simple format for S3 keys for log objects. To specify SimplePrefix format, set SimplePrefix to {}.

", + "smithy.api#xmlName": "SimplePrefix" + } + }, + "PartitionedPrefix": { + "target": "com.amazonaws.s3#PartitionedPrefix", + "traits": { + "smithy.api#documentation": "

Partitioned S3 key for log objects.

", + "smithy.api#xmlName": "PartitionedPrefix" + } + } + }, + "traits": { + "smithy.api#documentation": "

Amazon S3 key format for log objects. Only one format, PartitionedPrefix or SimplePrefix, is allowed.

" + } + }, "com.amazonaws.s3#TargetPrefix": { "type": "string" }, @@ -30836,7 +33128,6 @@ "Days": { "target": "com.amazonaws.s3#IntelligentTieringDays", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The number of consecutive days of no access after which an object will be eligible to be\n transitioned to the corresponding tier. The minimum number of days specified for\n Archive Access tier must be at least 90 days and Deep Archive Access tier must be at least\n 180 days. The maximum can be up to 2 years (730 days).

", "smithy.api#required": {} } @@ -30914,7 +33205,6 @@ "Days": { "target": "com.amazonaws.s3#Days", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Indicates the number of days after creation when objects are transitioned to the\n specified storage class. The value must be a positive integer.

" } }, @@ -31017,7 +33307,7 @@ "aws.protocols#httpChecksum": { "requestAlgorithmMember": "ChecksumAlgorithm" }, - "smithy.api#documentation": "

Uploads a part in a multipart upload.

\n \n

In this operation, you provide part data in your request. However, you have an option\n to specify your existing Amazon S3 object as a data source for the part you are uploading. To\n upload a part from an existing object, you use the UploadPartCopy operation.\n

\n
\n

You must initiate a multipart upload (see CreateMultipartUpload)\n before you can upload any part. In response to your initiate request, Amazon S3 returns an\n upload ID, a unique identifier, that you must include in your upload part request.

\n

Part numbers can be any number from 1 to 10,000, inclusive. A part number uniquely\n identifies a part and also defines its position within the object being created. If you\n upload a new part using the same part number that was used with a previous part, the\n previously uploaded part is overwritten.

\n

For information about maximum and minimum part sizes and other multipart upload\n specifications, see Multipart upload limits in the Amazon S3 User Guide.

\n

To ensure that data is not corrupted when traversing the network, specify the\n Content-MD5 header in the upload part request. Amazon S3 checks the part data\n against the provided MD5 value. If they do not match, Amazon S3 returns an error.

\n

If the upload request is signed with Signature Version 4, then Amazon Web Services S3 uses the\n x-amz-content-sha256 header as a checksum instead of\n Content-MD5. For more information see Authenticating\n Requests: Using the Authorization Header (Amazon Web Services Signature Version 4).

\n

\n Note: After you initiate multipart upload and upload\n one or more parts, you must either complete or abort multipart upload in order to stop\n getting charged for storage of the uploaded parts. Only after you either complete or abort\n multipart upload, Amazon S3 frees up the parts storage and stops charging you for the parts\n storage.

\n

For more information on multipart uploads, go to Multipart Upload Overview in the\n Amazon S3 User Guide .

\n

For information on the permissions required to use the multipart upload API, go to\n Multipart\n Upload and Permissions in the Amazon S3 User Guide.

\n

Server-side encryption is for data encryption at rest. Amazon S3 encrypts your data as it\n writes it to disks in its data centers and decrypts it when you access it. You have three\n mutually exclusive options to protect data using server-side encryption in Amazon S3, depending\n on how you choose to manage the encryption keys. Specifically, the encryption key options\n are Amazon S3 managed keys (SSE-S3), Amazon Web Services KMS keys (SSE-KMS), and Customer-Provided Keys\n (SSE-C). Amazon S3 encrypts data with server-side encryption using Amazon S3 managed keys (SSE-S3) by\n default. You can optionally tell Amazon S3 to encrypt data at rest using server-side encryption\n with other key options. The option you use depends on whether you want to use KMS keys\n (SSE-KMS) or provide your own encryption key (SSE-C). If you choose to provide your own\n encryption key, the request headers you provide in the request must match the headers you\n used in the request to initiate the upload by using CreateMultipartUpload.\n For more information, go to Using Server-Side\n Encryption in the Amazon S3 User Guide.

\n

Server-side encryption is supported by the S3 Multipart Upload actions. Unless you are\n using a customer-provided encryption key (SSE-C), you don't need to specify the encryption\n parameters in each UploadPart request. Instead, you only need to specify the server-side\n encryption parameters in the initial Initiate Multipart request. For more information, see\n CreateMultipartUpload.

\n

If you requested server-side encryption using a customer-provided encryption key (SSE-C)\n in your initiate multipart upload request, you must provide identical encryption\n information in each part upload using the following headers.

\n
    \n
  • \n

    x-amz-server-side-encryption-customer-algorithm

    \n
  • \n
  • \n

    x-amz-server-side-encryption-customer-key

    \n
  • \n
  • \n

    x-amz-server-side-encryption-customer-key-MD5

    \n
  • \n
\n

\n UploadPart has the following special errors:

\n
    \n
  • \n
      \n
    • \n

      \n Code: NoSuchUpload\n

      \n
    • \n
    • \n

      \n Cause: The specified multipart upload does not exist. The upload\n ID might be invalid, or the multipart upload might have been aborted or\n completed.\n

      \n
    • \n
    • \n

      \n HTTP Status Code: 404 Not Found \n

      \n
    • \n
    • \n

      \n SOAP Fault Code Prefix: Client\n

      \n
    • \n
    \n
  • \n
\n

The following operations are related to UploadPart:

\n ", + "smithy.api#documentation": "

Uploads a part in a multipart upload.

\n \n

In this operation, you provide new data as a part of an object in your request. However, you have an option\n to specify your existing Amazon S3 object as a data source for the part you are uploading. To\n upload a part from an existing object, you use the UploadPartCopy operation.\n

\n
\n

You must initiate a multipart upload (see CreateMultipartUpload)\n before you can upload any part. In response to your initiate request, Amazon S3 returns an\n upload ID, a unique identifier that you must include in your upload part request.

\n

Part numbers can be any number from 1 to 10,000, inclusive. A part number uniquely\n identifies a part and also defines its position within the object being created. If you\n upload a new part using the same part number that was used with a previous part, the\n previously uploaded part is overwritten.

\n

For information about maximum and minimum part sizes and other multipart upload\n specifications, see Multipart upload limits in the Amazon S3 User Guide.

\n \n

After you initiate multipart upload and upload\n one or more parts, you must either complete or abort multipart upload in order to stop\n getting charged for storage of the uploaded parts. Only after you either complete or abort\n multipart upload, Amazon S3 frees up the parts storage and stops charging you for the parts\n storage.

\n
\n

For more information on multipart uploads, go to Multipart Upload Overview in the\n Amazon S3 User Guide .

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Permissions
\n
\n
    \n
  • \n

    \n General purpose bucket permissions - For information on the permissions required to use the multipart upload API, see \n Multipart\n Upload and Permissions in the Amazon S3 User Guide.

    \n
  • \n
  • \n

    \n Directory bucket permissions - To grant access to this API operation on a directory bucket, we recommend that you use the \n CreateSession\n API operation for session-based authorization. Specifically, you grant the s3express:CreateSession permission to the directory bucket in a bucket policy or an IAM identity-based policy. Then, you make the CreateSession API call on the bucket to obtain a session token. With the session token in your request header, you can make API requests to this operation. After the session token expires, you make another CreateSession API call to generate a new session token for use. \nAmazon Web Services CLI or SDKs create session and refresh the session token automatically to avoid service interruptions when a session expires. For more information about authorization, see \n CreateSession\n .

    \n
  • \n
\n
\n
Data integrity
\n
\n

\n General purpose bucket - To ensure that data is not corrupted traversing the network, specify the\n Content-MD5 header in the upload part request. Amazon S3 checks the part data against the provided MD5 value. If they do not match, Amazon S3 returns an error. If the upload request is signed with Signature Version 4, then Amazon Web Services S3 uses the\n x-amz-content-sha256 header as a checksum instead of\n Content-MD5. For more information see Authenticating\n Requests: Using the Authorization Header (Amazon Web Services Signature Version 4).

\n \n

\n Directory buckets - MD5 is not supported by directory buckets. You can use checksum algorithms to check object integrity.

\n
\n
\n
Encryption
\n
\n
    \n
  • \n

    \n General purpose bucket - Server-side encryption is for data encryption at rest. Amazon S3 encrypts your data as it\n writes it to disks in its data centers and decrypts it when you access it. You have \n mutually exclusive options to protect data using server-side encryption in Amazon S3, depending\n on how you choose to manage the encryption keys. Specifically, the encryption key options\n are Amazon S3 managed keys (SSE-S3), Amazon Web Services KMS keys (SSE-KMS), and Customer-Provided Keys\n (SSE-C). Amazon S3 encrypts data with server-side encryption using Amazon S3 managed keys (SSE-S3) by\n default. You can optionally tell Amazon S3 to encrypt data at rest using server-side encryption\n with other key options. The option you use depends on whether you want to use KMS keys\n (SSE-KMS) or provide your own encryption key (SSE-C).

    \n

    Server-side encryption is supported by the S3 Multipart Upload operations. Unless you are\n using a customer-provided encryption key (SSE-C), you don't need to specify the encryption\n parameters in each UploadPart request. Instead, you only need to specify the server-side\n encryption parameters in the initial Initiate Multipart request. For more information, see\n CreateMultipartUpload.

    \n

    If you request server-side encryption using a customer-provided encryption key (SSE-C)\n in your initiate multipart upload request, you must provide identical encryption\n information in each part upload using the following request headers.

    \n
      \n
    • \n

      x-amz-server-side-encryption-customer-algorithm

      \n
    • \n
    • \n

      x-amz-server-side-encryption-customer-key

      \n
    • \n
    • \n

      x-amz-server-side-encryption-customer-key-MD5

      \n
    • \n
    \n
  • \n
  • \n

    \n Directory bucket - For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

    \n
  • \n
\n

\n For more information, see Using Server-Side\n Encryption in the Amazon S3 User Guide.

\n
\n
Special errors
\n
\n
    \n
  • \n

    Error Code: NoSuchUpload\n

    \n
      \n
    • \n

      Description: The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed.

      \n
    • \n
    • \n

      HTTP Status Code: 404 Not Found

      \n
    • \n
    • \n

      SOAP Fault Code Prefix: Client

      \n
    • \n
    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

The following operations are related to UploadPart:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}/{Key+}?x-id=UploadPart", @@ -31034,11 +33324,16 @@ "target": "com.amazonaws.s3#UploadPartCopyOutput" }, "traits": { - "smithy.api#documentation": "

Uploads a part by copying data from an existing object as data source. You specify the\n data source by adding the request header x-amz-copy-source in your request and\n a byte range by adding the request header x-amz-copy-source-range in your\n request.

\n

For information about maximum and minimum part sizes and other multipart upload\n specifications, see Multipart upload limits in the Amazon S3 User Guide.

\n \n

Instead of using an existing object as part data, you might use the UploadPart\n action and provide data in your request.

\n
\n

You must initiate a multipart upload before you can upload any part. In response to your\n initiate request. Amazon S3 returns a unique identifier, the upload ID, that you must include in\n your upload part request.

\n

For more information about using the UploadPartCopy operation, see the\n following:

\n
    \n
  • \n

    For conceptual information about multipart uploads, see Uploading\n Objects Using Multipart Upload in the\n Amazon S3 User Guide.

    \n
  • \n
  • \n

    For information about permissions required to use the multipart upload API, see\n Multipart Upload and Permissions in the\n Amazon S3 User Guide.

    \n
  • \n
  • \n

    For information about copying objects using a single atomic action vs. a multipart\n upload, see Operations on Objects in\n the Amazon S3 User Guide.

    \n
  • \n
  • \n

    For information about using server-side encryption with customer-provided\n encryption keys with the UploadPartCopy operation, see CopyObject and UploadPart.

    \n
  • \n
\n

Note the following additional considerations about the request headers\n x-amz-copy-source-if-match, x-amz-copy-source-if-none-match,\n x-amz-copy-source-if-unmodified-since, and\n x-amz-copy-source-if-modified-since:

\n

\n
    \n
  • \n

    \n Consideration 1 - If both of the\n x-amz-copy-source-if-match and\n x-amz-copy-source-if-unmodified-since headers are present in the\n request as follows:

    \n

    \n x-amz-copy-source-if-match condition evaluates to true,\n and;

    \n

    \n x-amz-copy-source-if-unmodified-since condition evaluates to\n false;

    \n

    Amazon S3 returns 200 OK and copies the data.\n

    \n
  • \n
  • \n

    \n Consideration 2 - If both of the\n x-amz-copy-source-if-none-match and\n x-amz-copy-source-if-modified-since headers are present in the\n request as follows:

    \n

    \n x-amz-copy-source-if-none-match condition evaluates to\n false, and;

    \n

    \n x-amz-copy-source-if-modified-since condition evaluates to\n true;

    \n

    Amazon S3 returns 412 Precondition Failed response code.\n

    \n
  • \n
\n
\n
Versioning
\n
\n

If your bucket has versioning enabled, you could have multiple versions of the\n same object. By default, x-amz-copy-source identifies the current\n version of the object to copy. If the current version is a delete marker and you\n don't specify a versionId in the x-amz-copy-source, Amazon S3 returns a\n 404 error, because the object does not exist. If you specify versionId in the\n x-amz-copy-source and the versionId is a delete marker, Amazon S3\n returns an HTTP 400 error, because you are not allowed to specify a delete marker\n as a version for the x-amz-copy-source.

\n

You can optionally specify a specific version of the source object to copy by\n adding the versionId subresource as shown in the following\n example:

\n

\n x-amz-copy-source: /bucket/object?versionId=version id\n

\n
\n
Special errors
\n
\n
    \n
  • \n
      \n
    • \n

      \n Code: NoSuchUpload\n

      \n
    • \n
    • \n

      \n Cause: The specified multipart upload does not exist. The\n upload ID might be invalid, or the multipart upload might have been\n aborted or completed.\n

      \n
    • \n
    • \n

      \n HTTP Status Code: 404 Not Found\n

      \n
    • \n
    \n
  • \n
  • \n
      \n
    • \n

      \n Code: InvalidRequest\n

      \n
    • \n
    • \n

      \n Cause: The specified copy source is not supported as a\n byte-range copy source.\n

      \n
    • \n
    • \n

      \n HTTP Status Code: 400 Bad Request\n

      \n
    • \n
    \n
  • \n
\n
\n
\n

The following operations are related to UploadPartCopy:

\n ", + "smithy.api#documentation": "

Uploads a part by copying data from an existing object as data source. To specify the\n data source, you add the request header x-amz-copy-source in your request. To specify \n a byte range, you add the request header x-amz-copy-source-range in your\n request.

\n

For information about maximum and minimum part sizes and other multipart upload\n specifications, see Multipart upload limits in the Amazon S3 User Guide.

\n \n

Instead of copying data from an existing object as part data, you might use the UploadPart\n action to upload new data as a part of an object in your request.

\n
\n

You must initiate a multipart upload before you can upload any part. In response to your\n initiate request, Amazon S3 returns the upload ID, a unique identifier that you must include in\n your upload part request.

\n

For conceptual information about multipart uploads, see Uploading\n Objects Using Multipart Upload in the\n Amazon S3 User Guide. For information about copying objects using a single atomic action vs. a multipart\n upload, see Operations on Objects in\n the Amazon S3 User Guide.

\n \n

\n Directory buckets - For directory buckets, you must make requests for this API operation to the Zonal endpoint. These endpoints support virtual-hosted-style requests in the format https://bucket_name.s3express-az_id.region.amazonaws.com/key-name\n . Path-style requests are not supported. For more information, see Regional and Zonal endpoints in the\n Amazon S3 User Guide.

\n
\n
\n
Authentication and authorization
\n
\n

All UploadPartCopy requests must be authenticated and signed by using IAM credentials (access key ID and secret access key for the IAM identities). All headers with the x-amz- prefix, including\n x-amz-copy-source, must be signed. For more information, see REST Authentication.

\n

\n Directory buckets - You must use IAM credentials to authenticate and authorize your access to the UploadPartCopy API operation, instead of using the \n temporary security credentials through the CreateSession API operation.

\n

Amazon Web Services CLI or SDKs handles authentication and authorization on your behalf.

\n
\n
Permissions
\n
\n

You must have READ access to the source object and WRITE\n access to the destination bucket.

\n
    \n
  • \n

    \n General purpose bucket permissions - You must have the permissions in a policy based on the bucket types of your source bucket and destination bucket in an UploadPartCopy operation.

    \n
      \n
    • \n

      If the source object is in a general purpose bucket, you must have the \n s3:GetObject\n permission to read the source object that is being copied.

      \n
    • \n
    • \n

      If the destination bucket is a general purpose bucket, you must have the \n s3:PubObject\n permission to write the object copy to the destination bucket.\n

      \n
    • \n
    \n

    For information about permissions required to use the multipart upload API, see\n Multipart Upload and Permissions in the\n Amazon S3 User Guide.

    \n
  • \n
  • \n

    \n Directory bucket permissions -\n You must have permissions in a bucket policy or an IAM identity-based policy based on the source and destination\n bucket types in an UploadPartCopy operation.

    \n
      \n
    • \n

      If the source object that you want to copy is in a\n directory bucket, you must have the \n s3express:CreateSession\n permission in\n the Action element of a policy to read the object\n . \n By default, the session is in the ReadWrite mode. If you want to restrict the access, you can explicitly set the s3express:SessionMode condition key to ReadOnly on the copy source bucket.

      \n
    • \n
    • \n

      If the copy destination is a directory bucket, you must have the \n \n s3express:CreateSession\n permission in the\n Action element of a policy to write the object\n to the destination. The s3express:SessionMode condition\n key cannot be set to ReadOnly on the copy destination.

      \n
    • \n
    \n

    For example policies, see Example bucket policies for S3 Express One Zone and Amazon Web Services Identity and Access Management (IAM) identity-based policies for S3 Express One Zone in the\n Amazon S3 User Guide.

    \n
  • \n
\n
\n
Encryption
\n
\n
    \n
  • \n

    \n General purpose buckets - \n \n For information about using server-side encryption with customer-provided\n encryption keys with the UploadPartCopy operation, see CopyObject and UploadPart.\n

    \n
  • \n
  • \n

    \n Directory buckets - For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

    \n
  • \n
\n
\n
Special errors
\n
\n
    \n
  • \n

    Error Code: NoSuchUpload\n

    \n
      \n
    • \n

      Description: The specified multipart upload does not exist. The\n upload ID might be invalid, or the multipart upload might have been\n aborted or completed.

      \n
    • \n
    • \n

      HTTP Status Code: 404 Not Found

      \n
    • \n
    \n
  • \n
  • \n

    Error Code: InvalidRequest\n

    \n
      \n
    • \n

      Description: The specified copy source is not supported as a\n byte-range copy source.

      \n
    • \n
    • \n

      HTTP Status Code: 400 Bad Request

      \n
    • \n
    \n
  • \n
\n
\n
HTTP Host header syntax
\n
\n

\n Directory buckets - The HTTP Host header syntax is \n Bucket_name.s3express-az_id.region.amazonaws.com.

\n
\n
\n

The following operations are related to UploadPartCopy:

\n ", "smithy.api#http": { "method": "PUT", "uri": "/{Bucket}/{Key+}?x-id=UploadPartCopy", "code": 200 + }, + "smithy.rules#staticContextParams": { + "DisableS3ExpressSessionAuth": { + "value": true + } } } }, @@ -31048,7 +33343,7 @@ "CopySourceVersionId": { "target": "com.amazonaws.s3#CopySourceVersionId", "traits": { - "smithy.api#documentation": "

The version of the source object that was copied, if you have enabled versioning on the\n source bucket.

", + "smithy.api#documentation": "

The version of the source object that was copied, if you have enabled versioning on the\n source bucket.

\n \n

This functionality is not supported when the source object is in a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-copy-source-version-id" } }, @@ -31062,36 +33357,35 @@ "ServerSideEncryption": { "target": "com.amazonaws.s3#ServerSideEncryption", "traits": { - "smithy.api#documentation": "

The server-side encryption algorithm used when storing this object in Amazon S3 (for example,\n AES256, aws:kms).

", + "smithy.api#documentation": "

The server-side encryption algorithm used when you store this object in Amazon S3 (for example,\n AES256, aws:kms).

\n \n

For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption" } }, "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header confirming the encryption algorithm used.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to confirm the encryption algorithm that's used.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide round-trip message integrity verification of\n the customer-provided encryption key.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide the round-trip message integrity verification of\n the customer-provided encryption key.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, "SSEKMSKeyId": { "target": "com.amazonaws.s3#SSEKMSKeyId", "traits": { - "smithy.api#documentation": "

If present, specifies the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n that was used for the object.

", + "smithy.api#documentation": "

If present, indicates the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n that was used for the object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-aws-kms-key-id" } }, "BucketKeyEnabled": { "target": "com.amazonaws.s3#BucketKeyEnabled", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

", + "smithy.api#documentation": "

Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-bucket-key-enabled" } }, @@ -31112,7 +33406,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The bucket name.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The bucket name.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -31123,7 +33417,7 @@ "CopySource": { "target": "com.amazonaws.s3#CopySource", "traits": { - "smithy.api#documentation": "

Specifies the source object for the copy operation. You specify the value in one of two\n formats, depending on whether you want to access the source object through an access point:

\n
    \n
  • \n

    For objects not accessed through an access point, specify the name of the source bucket\n and key of the source object, separated by a slash (/). For example, to copy the\n object reports/january.pdf from the bucket\n awsexamplebucket, use awsexamplebucket/reports/january.pdf.\n The value must be URL-encoded.

    \n
  • \n
  • \n

    For objects accessed through access points, specify the Amazon Resource Name (ARN) of the object as accessed through the access point, in the format arn:aws:s3:::accesspoint//object/. For example, to copy the object reports/january.pdf through access point my-access-point owned by account 123456789012 in Region us-west-2, use the URL encoding of arn:aws:s3:us-west-2:123456789012:accesspoint/my-access-point/object/reports/january.pdf. The value must be URL encoded.

    \n \n

    Amazon S3 supports copy operations using access points only when the source and destination buckets are in the same Amazon Web Services Region.

    \n
    \n

    Alternatively, for objects accessed through Amazon S3 on Outposts, specify the ARN of the object as accessed in the format arn:aws:s3-outposts:::outpost//object/. For example, to copy the object reports/january.pdf through outpost my-outpost owned by account 123456789012 in Region us-west-2, use the URL encoding of arn:aws:s3-outposts:us-west-2:123456789012:outpost/my-outpost/object/reports/january.pdf. The value must be URL-encoded.

    \n
  • \n
\n

To copy a specific version of an object, append ?versionId=\n to the value (for example,\n awsexamplebucket/reports/january.pdf?versionId=QUpfdndhfd8438MNFDN93jdnJFkdmqnh893).\n If you don't specify a version ID, Amazon S3 copies the latest version of the source\n object.

", + "smithy.api#documentation": "

Specifies the source object for the copy operation. You specify the value in one of two\n formats, depending on whether you want to access the source object through an access point:

\n
    \n
  • \n

    For objects not accessed through an access point, specify the name of the source bucket\n and key of the source object, separated by a slash (/). For example, to copy the\n object reports/january.pdf from the bucket\n awsexamplebucket, use awsexamplebucket/reports/january.pdf.\n The value must be URL-encoded.

    \n
  • \n
  • \n

    For objects accessed through access points, specify the Amazon Resource Name (ARN) of the object as accessed through the access point, in the format arn:aws:s3:::accesspoint//object/. For example, to copy the object reports/january.pdf through access point my-access-point owned by account 123456789012 in Region us-west-2, use the URL encoding of arn:aws:s3:us-west-2:123456789012:accesspoint/my-access-point/object/reports/january.pdf. The value must be URL encoded.

    \n \n
      \n
    • \n

      Amazon S3 supports copy operations using Access points only when the source and destination buckets are in the same Amazon Web Services Region.

      \n
    • \n
    • \n

      Access points are not supported by directory buckets.

      \n
    • \n
    \n
    \n

    Alternatively, for objects accessed through Amazon S3 on Outposts, specify the ARN of the object as accessed in the format arn:aws:s3-outposts:::outpost//object/. For example, to copy the object reports/january.pdf through outpost my-outpost owned by account 123456789012 in Region us-west-2, use the URL encoding of arn:aws:s3-outposts:us-west-2:123456789012:outpost/my-outpost/object/reports/january.pdf. The value must be URL-encoded.

    \n
  • \n
\n

If your bucket has versioning enabled, you could have multiple versions of the\n same object. By default, x-amz-copy-source identifies the current\n version of the source object to copy. \n To copy a specific version of the source object to copy, append ?versionId=\n to the x-amz-copy-source request header (for example, \n x-amz-copy-source: /awsexamplebucket/reports/january.pdf?versionId=QUpfdndhfd8438MNFDN93jdnJFkdmqnh893).\n

\n

If the current version is a delete marker and you\n don't specify a versionId in the x-amz-copy-source request header, Amazon S3 returns a\n 404 Not Found error, because the object does not exist. If you specify versionId in the\n x-amz-copy-source and the versionId is a delete marker, Amazon S3\n returns an HTTP 400 Bad Request error, because you are not allowed to specify a delete marker\n as a version for the x-amz-copy-source.

\n \n

\n Directory buckets - S3 Versioning isn't enabled and supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-copy-source", "smithy.api#required": {} } @@ -31131,28 +33425,28 @@ "CopySourceIfMatch": { "target": "com.amazonaws.s3#CopySourceIfMatch", "traits": { - "smithy.api#documentation": "

Copies the object if its entity tag (ETag) matches the specified tag.

", + "smithy.api#documentation": "

Copies the object if its entity tag (ETag) matches the specified tag.

\n

If both of the\n x-amz-copy-source-if-match and\n x-amz-copy-source-if-unmodified-since headers are present in the\n request as follows:

\n

\n x-amz-copy-source-if-match condition evaluates to true,\n and;

\n

\n x-amz-copy-source-if-unmodified-since condition evaluates to\n false;

\n

Amazon S3 returns 200 OK and copies the data.\n

", "smithy.api#httpHeader": "x-amz-copy-source-if-match" } }, "CopySourceIfModifiedSince": { "target": "com.amazonaws.s3#CopySourceIfModifiedSince", "traits": { - "smithy.api#documentation": "

Copies the object if it has been modified since the specified time.

", + "smithy.api#documentation": "

Copies the object if it has been modified since the specified time.

\n

If both of the\n x-amz-copy-source-if-none-match and\n x-amz-copy-source-if-modified-since headers are present in the\n request as follows:

\n

\n x-amz-copy-source-if-none-match condition evaluates to\n false, and;

\n

\n x-amz-copy-source-if-modified-since condition evaluates to\n true;

\n

Amazon S3 returns 412 Precondition Failed response code.\n

", "smithy.api#httpHeader": "x-amz-copy-source-if-modified-since" } }, "CopySourceIfNoneMatch": { "target": "com.amazonaws.s3#CopySourceIfNoneMatch", "traits": { - "smithy.api#documentation": "

Copies the object if its entity tag (ETag) is different than the specified ETag.

", + "smithy.api#documentation": "

Copies the object if its entity tag (ETag) is different than the specified ETag.

\n

If both of the\n x-amz-copy-source-if-none-match and\n x-amz-copy-source-if-modified-since headers are present in the\n request as follows:

\n

\n x-amz-copy-source-if-none-match condition evaluates to\n false, and;

\n

\n x-amz-copy-source-if-modified-since condition evaluates to\n true;

\n

Amazon S3 returns 412 Precondition Failed response code.\n

", "smithy.api#httpHeader": "x-amz-copy-source-if-none-match" } }, "CopySourceIfUnmodifiedSince": { "target": "com.amazonaws.s3#CopySourceIfUnmodifiedSince", "traits": { - "smithy.api#documentation": "

Copies the object if it hasn't been modified since the specified time.

", + "smithy.api#documentation": "

Copies the object if it hasn't been modified since the specified time.

\n

If both of the\n x-amz-copy-source-if-match and\n x-amz-copy-source-if-unmodified-since headers are present in the\n request as follows:

\n

\n x-amz-copy-source-if-match condition evaluates to true,\n and;

\n

\n x-amz-copy-source-if-unmodified-since condition evaluates to\n false;

\n

Amazon S3 returns 200 OK and copies the data.\n

", "smithy.api#httpHeader": "x-amz-copy-source-if-unmodified-since" } }, @@ -31174,7 +33468,6 @@ "PartNumber": { "target": "com.amazonaws.s3#PartNumber", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Part number of part being copied. This is a positive integer between 1 and\n 10,000.

", "smithy.api#httpQuery": "partNumber", "smithy.api#required": {} @@ -31191,42 +33484,42 @@ "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

Specifies the algorithm to use to when encrypting the object (for example,\n AES256).

", + "smithy.api#documentation": "

Specifies the algorithm to use when encrypting the object (for example,\n AES256).

\n \n

This functionality is not supported when the destination bucket is a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKey": { "target": "com.amazonaws.s3#SSECustomerKey", "traits": { - "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header. This must be the\n same encryption key specified in the initiate multipart upload request.

", + "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header. This must be the\n same encryption key specified in the initiate multipart upload request.

\n \n

This functionality is not supported when the destination bucket is a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

", + "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

\n \n

This functionality is not supported when the destination bucket is a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, "CopySourceSSECustomerAlgorithm": { "target": "com.amazonaws.s3#CopySourceSSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

Specifies the algorithm to use when decrypting the source object (for example,\n AES256).

", + "smithy.api#documentation": "

Specifies the algorithm to use when decrypting the source object (for example,\n AES256).

\n \n

This functionality is not supported when the source object is in a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-copy-source-server-side-encryption-customer-algorithm" } }, "CopySourceSSECustomerKey": { "target": "com.amazonaws.s3#CopySourceSSECustomerKey", "traits": { - "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use to decrypt the source\n object. The encryption key provided in this header must be one that was used when the\n source object was created.

", + "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use to decrypt the source\n object. The encryption key provided in this header must be one that was used when the\n source object was created.

\n \n

This functionality is not supported when the source object is in a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-copy-source-server-side-encryption-customer-key" } }, "CopySourceSSECustomerKeyMD5": { "target": "com.amazonaws.s3#CopySourceSSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

", + "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

\n \n

This functionality is not supported when the source object is in a directory bucket.

\n
", "smithy.api#httpHeader": "x-amz-copy-source-server-side-encryption-customer-key-MD5" } }, @@ -31239,14 +33532,14 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected destination bucket owner. If the destination bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected destination bucket owner. If the account ID that you provide does not match the actual owner of the destination bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } }, "ExpectedSourceBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected source bucket owner. If the source bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected source bucket owner. If the account ID that you provide does not match the actual owner of the source bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-source-expected-bucket-owner" } } @@ -31261,7 +33554,7 @@ "ServerSideEncryption": { "target": "com.amazonaws.s3#ServerSideEncryption", "traits": { - "smithy.api#documentation": "

The server-side encryption algorithm used when storing this object in Amazon S3 (for example,\n AES256, aws:kms).

", + "smithy.api#documentation": "

The server-side encryption algorithm used when you store this object in Amazon S3 (for example,\n AES256, aws:kms).

\n \n

For directory buckets, only server-side encryption with Amazon S3 managed keys (SSE-S3) (AES256) is supported.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption" } }, @@ -31275,57 +33568,56 @@ "ChecksumCRC32": { "target": "com.amazonaws.s3#ChecksumCRC32", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32 checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-crc32" } }, "ChecksumCRC32C": { "target": "com.amazonaws.s3#ChecksumCRC32C", "traits": { - "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 32-bit CRC32C checksum of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-crc32c" } }, "ChecksumSHA1": { "target": "com.amazonaws.s3#ChecksumSHA1", "traits": { - "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 160-bit SHA-1 digest of the object. This will only be present if it was uploaded\n with the object. When you use the API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-sha1" } }, "ChecksumSHA256": { "target": "com.amazonaws.s3#ChecksumSHA256", "traits": { - "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. With multipart uploads, this may not be a checksum value of the object. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The base64-encoded, 256-bit SHA-256 digest of the object. This will only be present if it was uploaded\n with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object. Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated\n with multipart uploads, see \n Checking object integrity in the Amazon S3 User Guide.

", "smithy.api#httpHeader": "x-amz-checksum-sha256" } }, "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header confirming the encryption algorithm used.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to confirm the encryption algorithm that's used.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide round-trip message integrity verification of\n the customer-provided encryption key.

", + "smithy.api#documentation": "

If server-side encryption with a customer-provided encryption key was requested, the\n response will include this header to provide the round-trip message integrity verification of\n the customer-provided encryption key.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, "SSEKMSKeyId": { "target": "com.amazonaws.s3#SSEKMSKeyId", "traits": { - "smithy.api#documentation": "

If present, specifies the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n was used for the object.

", + "smithy.api#documentation": "

If present, indicates the ID of the Key Management Service (KMS) symmetric encryption customer managed key\n that was used for the object.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-aws-kms-key-id" } }, "BucketKeyEnabled": { "target": "com.amazonaws.s3#BucketKeyEnabled", "traits": { - "smithy.api#default": false, - "smithy.api#documentation": "

Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

", + "smithy.api#documentation": "

Indicates whether the multipart upload uses an S3 Bucket Key for server-side encryption\n with Key Management Service (KMS) keys (SSE-KMS).

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-bucket-key-enabled" } }, @@ -31354,7 +33646,7 @@ "Bucket": { "target": "com.amazonaws.s3#BucketName", "traits": { - "smithy.api#documentation": "

The name of the bucket to which the multipart upload was initiated.

\n

When using this action with an access point, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n

When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", + "smithy.api#documentation": "

The name of the bucket to which the multipart upload was initiated.

\n

\n Directory buckets - When you use this operation with a directory bucket, you must use virtual-hosted-style requests in the format \n Bucket_name.s3express-az_id.region.amazonaws.com. Path-style requests are not supported. Directory bucket names must be unique in the chosen Availability Zone. Bucket names must follow the format \n bucket_base_name--az-id--x-s3 (for example, \n DOC-EXAMPLE-BUCKET--usw2-az2--x-s3). For information about bucket naming\n restrictions, see Directory bucket naming\n rules in the Amazon S3 User Guide.

\n

\n Access points - When you use this action with an access point, you must provide the alias of the access point in place of the bucket name or specify the access point ARN. When using the access point ARN, you must direct requests to the access point hostname. The access point hostname takes the form AccessPointName-AccountId.s3-accesspoint.Region.amazonaws.com. When using this action with an access point through the Amazon Web Services SDKs, you provide the access point ARN in place of the bucket name. For more information about access point ARNs, see Using access points in the Amazon S3 User Guide.

\n \n

Access points and Object Lambda access points are not supported by directory buckets.

\n
\n

\n S3 on Outposts - When you use this action with Amazon S3 on Outposts, you must direct requests to the S3 on Outposts hostname. The S3 on Outposts hostname takes the form \n AccessPointName-AccountId.outpostID.s3-outposts.Region.amazonaws.com. When you use this action with S3 on Outposts through the Amazon Web Services SDKs, you provide the Outposts access point ARN in place of the bucket name. For more information about S3 on Outposts ARNs, see What is S3 on Outposts? in the Amazon S3 User Guide.

", "smithy.api#httpLabel": {}, "smithy.api#required": {}, "smithy.rules#contextParam": { @@ -31365,7 +33657,6 @@ "ContentLength": { "target": "com.amazonaws.s3#ContentLength", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Size of the body in bytes. This parameter is useful when the size of the body cannot be\n determined automatically.

", "smithy.api#httpHeader": "Content-Length" } @@ -31373,14 +33664,14 @@ "ContentMD5": { "target": "com.amazonaws.s3#ContentMD5", "traits": { - "smithy.api#documentation": "

The base64-encoded 128-bit MD5 digest of the part data. This parameter is auto-populated\n when using the command from the CLI. This parameter is required if object lock parameters\n are specified.

", + "smithy.api#documentation": "

The base64-encoded 128-bit MD5 digest of the part data. This parameter is auto-populated\n when using the command from the CLI. This parameter is required if object lock parameters\n are specified.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "Content-MD5" } }, "ChecksumAlgorithm": { "target": "com.amazonaws.s3#ChecksumAlgorithm", "traits": { - "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when using the SDK. This header will not provide any\n additional functionality if not using the SDK. When sending this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

\n

This checksum algorithm must be the same for all parts and it match the checksum value\n supplied in the CreateMultipartUpload request.

", + "smithy.api#documentation": "

Indicates the algorithm used to create the checksum for the object when you use the SDK. This header will not provide any\n additional functionality if you don't use the SDK. When you send this header, there must be a corresponding x-amz-checksum or\n x-amz-trailer header sent. Otherwise, Amazon S3 fails the request with the HTTP status code 400 Bad Request. For more\n information, see Checking object integrity in\n the Amazon S3 User Guide.

\n

If you provide an individual checksum, Amazon S3 ignores any provided\n ChecksumAlgorithm parameter.

\n

This checksum algorithm must be the same for all parts and it match the checksum value\n supplied in the CreateMultipartUpload request.

", "smithy.api#httpHeader": "x-amz-sdk-checksum-algorithm" } }, @@ -31417,13 +33708,15 @@ "traits": { "smithy.api#documentation": "

Object key for which the multipart upload was initiated.

", "smithy.api#httpLabel": {}, - "smithy.api#required": {} + "smithy.api#required": {}, + "smithy.rules#contextParam": { + "name": "Key" + } } }, "PartNumber": { "target": "com.amazonaws.s3#PartNumber", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Part number of part being uploaded. This is a positive integer between 1 and\n 10,000.

", "smithy.api#httpQuery": "partNumber", "smithy.api#required": {} @@ -31440,21 +33733,21 @@ "SSECustomerAlgorithm": { "target": "com.amazonaws.s3#SSECustomerAlgorithm", "traits": { - "smithy.api#documentation": "

Specifies the algorithm to use to when encrypting the object (for example,\n AES256).

", + "smithy.api#documentation": "

Specifies the algorithm to use when encrypting the object (for example,\n AES256).

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-algorithm" } }, "SSECustomerKey": { "target": "com.amazonaws.s3#SSECustomerKey", "traits": { - "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header. This must be the\n same encryption key specified in the initiate multipart upload request.

", + "smithy.api#documentation": "

Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data. This\n value is used to store the object and then it is discarded; Amazon S3 does not store the\n encryption key. The key must be appropriate for use with the algorithm specified in the\n x-amz-server-side-encryption-customer-algorithm header. This must be the\n same encryption key specified in the initiate multipart upload request.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key" } }, "SSECustomerKeyMD5": { "target": "com.amazonaws.s3#SSECustomerKeyMD5", "traits": { - "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

", + "smithy.api#documentation": "

Specifies the 128-bit MD5 digest of the encryption key according to RFC 1321. Amazon S3 uses\n this header for a message integrity check to ensure that the encryption key was transmitted\n without error.

\n \n

This functionality is not supported for directory buckets.

\n
", "smithy.api#httpHeader": "x-amz-server-side-encryption-customer-key-MD5" } }, @@ -31467,7 +33760,7 @@ "ExpectedBucketOwner": { "target": "com.amazonaws.s3#AccountId", "traits": { - "smithy.api#documentation": "

The account ID of the expected bucket owner. If the bucket is owned by a different account, the request fails with the HTTP status code 403 Forbidden (access denied).

", + "smithy.api#documentation": "

The account ID of the expected bucket owner. If the account ID that you provide does not match the actual owner of the bucket, the request fails with the HTTP status code 403 Forbidden (access denied).

", "smithy.api#httpHeader": "x-amz-expected-bucket-owner" } } @@ -31489,10 +33782,7 @@ "type": "string" }, "com.amazonaws.s3#VersionCount": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" }, "com.amazonaws.s3#VersionIdMarker": { "type": "string" @@ -31566,7 +33856,7 @@ "smithy.api#auth": [ "aws.auth#sigv4" ], - "smithy.api#documentation": "

Passes transformed objects to a GetObject operation when using Object Lambda access points. For\n information about Object Lambda access points, see Transforming objects with\n Object Lambda access points in the Amazon S3 User Guide.

\n

This operation supports metadata that can be returned by GetObject, in addition to\n RequestRoute, RequestToken, StatusCode,\n ErrorCode, and ErrorMessage. The GetObject\n response metadata is supported so that the WriteGetObjectResponse caller,\n typically an Lambda function, can provide the same metadata when it internally invokes\n GetObject. When WriteGetObjectResponse is called by a\n customer-owned Lambda function, the metadata returned to the end user\n GetObject call might differ from what Amazon S3 would normally return.

\n

You can include any number of metadata headers. When including a metadata header, it\n should be prefaced with x-amz-meta. For example,\n x-amz-meta-my-custom-header: MyCustomValue. The primary use case for this\n is to forward GetObject metadata.

\n

Amazon Web Services provides some prebuilt Lambda functions that you can use with S3 Object Lambda to\n detect and redact personally identifiable information (PII) and decompress S3 objects.\n These Lambda functions are available in the Amazon Web Services Serverless Application Repository, and\n can be selected through the Amazon Web Services Management Console when you create your Object Lambda access point.

\n

Example 1: PII Access Control - This Lambda function uses Amazon Comprehend, a\n natural language processing (NLP) service using machine learning to find insights and\n relationships in text. It automatically detects personally identifiable information (PII)\n such as names, addresses, dates, credit card numbers, and social security numbers from\n documents in your Amazon S3 bucket.

\n

Example 2: PII Redaction - This Lambda function uses Amazon Comprehend, a natural\n language processing (NLP) service using machine learning to find insights and relationships\n in text. It automatically redacts personally identifiable information (PII) such as names,\n addresses, dates, credit card numbers, and social security numbers from documents in your\n Amazon S3 bucket.

\n

Example 3: Decompression - The Lambda function S3ObjectLambdaDecompression, is\n equipped to decompress objects stored in S3 in one of six compressed file formats including\n bzip2, gzip, snappy, zlib, zstandard and ZIP.

\n

For information on how to view and use these functions, see Using Amazon Web Services built Lambda\n functions in the Amazon S3 User Guide.

", + "smithy.api#documentation": "\n

This operation is not supported by directory buckets.

\n
\n

Passes transformed objects to a GetObject operation when using Object Lambda access points. For\n information about Object Lambda access points, see Transforming objects with\n Object Lambda access points in the Amazon S3 User Guide.

\n

This operation supports metadata that can be returned by GetObject, in addition to\n RequestRoute, RequestToken, StatusCode,\n ErrorCode, and ErrorMessage. The GetObject\n response metadata is supported so that the WriteGetObjectResponse caller,\n typically an Lambda function, can provide the same metadata when it internally invokes\n GetObject. When WriteGetObjectResponse is called by a\n customer-owned Lambda function, the metadata returned to the end user\n GetObject call might differ from what Amazon S3 would normally return.

\n

You can include any number of metadata headers. When including a metadata header, it\n should be prefaced with x-amz-meta. For example,\n x-amz-meta-my-custom-header: MyCustomValue. The primary use case for this\n is to forward GetObject metadata.

\n

Amazon Web Services provides some prebuilt Lambda functions that you can use with S3 Object Lambda to\n detect and redact personally identifiable information (PII) and decompress S3 objects.\n These Lambda functions are available in the Amazon Web Services Serverless Application Repository, and\n can be selected through the Amazon Web Services Management Console when you create your Object Lambda access point.

\n

Example 1: PII Access Control - This Lambda function uses Amazon Comprehend, a\n natural language processing (NLP) service using machine learning to find insights and\n relationships in text. It automatically detects personally identifiable information (PII)\n such as names, addresses, dates, credit card numbers, and social security numbers from\n documents in your Amazon S3 bucket.

\n

Example 2: PII Redaction - This Lambda function uses Amazon Comprehend, a natural\n language processing (NLP) service using machine learning to find insights and relationships\n in text. It automatically redacts personally identifiable information (PII) such as names,\n addresses, dates, credit card numbers, and social security numbers from documents in your\n Amazon S3 bucket.

\n

Example 3: Decompression - The Lambda function S3ObjectLambdaDecompression, is\n equipped to decompress objects stored in S3 in one of six compressed file formats including\n bzip2, gzip, snappy, zlib, zstandard and ZIP.

\n

For information on how to view and use these functions, see Using Amazon Web Services built Lambda\n functions in the Amazon S3 User Guide.

", "smithy.api#endpoint": { "hostPrefix": "{RequestRoute}." }, @@ -31613,7 +33903,6 @@ "StatusCode": { "target": "com.amazonaws.s3#GetObjectResponseStatusCode", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The integer status code for an HTTP response of a corresponding GetObject\n request. The following is a list of status codes.

\n
    \n
  • \n

    \n 200 - OK\n

    \n
  • \n
  • \n

    \n 206 - Partial Content\n

    \n
  • \n
  • \n

    \n 304 - Not Modified\n

    \n
  • \n
  • \n

    \n 400 - Bad Request\n

    \n
  • \n
  • \n

    \n 401 - Unauthorized\n

    \n
  • \n
  • \n

    \n 403 - Forbidden\n

    \n
  • \n
  • \n

    \n 404 - Not Found\n

    \n
  • \n
  • \n

    \n 405 - Method Not Allowed\n

    \n
  • \n
  • \n

    \n 409 - Conflict\n

    \n
  • \n
  • \n

    \n 411 - Length Required\n

    \n
  • \n
  • \n

    \n 412 - Precondition Failed\n

    \n
  • \n
  • \n

    \n 416 - Range Not Satisfiable\n

    \n
  • \n
  • \n

    \n 500 - Internal Server Error\n

    \n
  • \n
  • \n

    \n 503 - Service Unavailable\n

    \n
  • \n
", "smithy.api#httpHeader": "x-amz-fwd-status" } @@ -31670,7 +33959,6 @@ "ContentLength": { "target": "com.amazonaws.s3#ContentLength", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The size of the content body in bytes.

", "smithy.api#httpHeader": "Content-Length" } @@ -31720,7 +34008,6 @@ "DeleteMarker": { "target": "com.amazonaws.s3#DeleteMarker", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Specifies whether an object stored in Amazon S3 is (true) or is not\n (false) a delete marker.

", "smithy.api#httpHeader": "x-amz-fwd-header-x-amz-delete-marker" } @@ -31756,7 +34043,6 @@ "MissingMeta": { "target": "com.amazonaws.s3#MissingMeta", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

Set to the number of metadata entries not returned in x-amz-meta headers.\n This can happen if you create metadata using an API like SOAP that supports more flexible\n metadata than the REST API. For example, using SOAP, you can create metadata whose values\n are not legal HTTP headers.

", "smithy.api#httpHeader": "x-amz-fwd-header-x-amz-missing-meta" } @@ -31792,7 +34078,6 @@ "PartsCount": { "target": "com.amazonaws.s3#PartsCount", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The count of parts this object has.

", "smithy.api#httpHeader": "x-amz-fwd-header-x-amz-mp-parts-count" } @@ -31855,7 +34140,6 @@ "TagCount": { "target": "com.amazonaws.s3#TagCount", "traits": { - "smithy.api#default": 0, "smithy.api#documentation": "

The number of tags, if any, on the object.

", "smithy.api#httpHeader": "x-amz-fwd-header-x-amz-tagging-count" } @@ -31870,7 +34154,6 @@ "BucketKeyEnabled": { "target": "com.amazonaws.s3#BucketKeyEnabled", "traits": { - "smithy.api#default": false, "smithy.api#documentation": "

Indicates whether the object stored in Amazon S3 uses an S3 bucket key for server-side\n encryption with Amazon Web Services KMS (SSE-KMS).

", "smithy.api#httpHeader": "x-amz-fwd-header-x-amz-server-side-encryption-bucket-key-enabled" } @@ -31881,10 +34164,7 @@ } }, "com.amazonaws.s3#Years": { - "type": "integer", - "traits": { - "smithy.api#default": 0 - } + "type": "integer" } } } diff --git a/aws/sdk/aws-models/sdk-endpoints.json b/aws/sdk/aws-models/sdk-endpoints.json index 0ab97122237..1886a2f05c6 100644 --- a/aws/sdk/aws-models/sdk-endpoints.json +++ b/aws/sdk/aws-models/sdk-endpoints.json @@ -405,6 +405,11 @@ } } }, + "agreement-marketplace" : { + "endpoints" : { + "us-east-1" : { } + } + }, "airflow" : { "endpoints" : { "ap-northeast-1" : { }, @@ -515,13 +520,26 @@ "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, - "ca-central-1" : { }, + "ca-central-1" : { + "variants" : [ { + "hostname" : "api.detective-fips.ca-central-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "ca-central-1-fips" : { + "credentialScope" : { + "region" : "ca-central-1" + }, + "deprecated" : true, + "hostname" : "api.detective-fips.ca-central-1.amazonaws.com" + }, "eu-central-1" : { }, "eu-north-1" : { }, "eu-south-1" : { }, "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, + "il-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { @@ -1049,11 +1067,18 @@ "endpoints" : { "af-south-1" : { }, "ap-northeast-1" : { }, + "ap-northeast-2" : { }, + "ap-northeast-3" : { }, "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, + "ap-southeast-4" : { }, + "ca-central-1" : { }, "eu-central-1" : { }, + "eu-north-1" : { }, "eu-west-1" : { }, + "eu-west-3" : { }, + "sa-east-1" : { }, "us-east-1" : { }, "us-east-2" : { }, "us-west-2" : { } @@ -1429,11 +1454,59 @@ "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, + "fips-us-east-1" : { + "credentialScope" : { + "region" : "us-east-1" + }, + "deprecated" : true, + "hostname" : "appflow-fips.us-east-1.amazonaws.com" + }, + "fips-us-east-2" : { + "credentialScope" : { + "region" : "us-east-2" + }, + "deprecated" : true, + "hostname" : "appflow-fips.us-east-2.amazonaws.com" + }, + "fips-us-west-1" : { + "credentialScope" : { + "region" : "us-west-1" + }, + "deprecated" : true, + "hostname" : "appflow-fips.us-west-1.amazonaws.com" + }, + "fips-us-west-2" : { + "credentialScope" : { + "region" : "us-west-2" + }, + "deprecated" : true, + "hostname" : "appflow-fips.us-west-2.amazonaws.com" + }, "sa-east-1" : { }, - "us-east-1" : { }, - "us-east-2" : { }, - "us-west-1" : { }, - "us-west-2" : { } + "us-east-1" : { + "variants" : [ { + "hostname" : "appflow-fips.us-east-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-east-2" : { + "variants" : [ { + "hostname" : "appflow-fips.us-east-2.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-west-1" : { + "variants" : [ { + "hostname" : "appflow-fips.us-west-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-west-2" : { + "variants" : [ { + "hostname" : "appflow-fips.us-west-2.amazonaws.com", + "tags" : [ "fips" ] + } ] + } } }, "application-autoscaling" : { @@ -1612,6 +1685,12 @@ "tags" : [ "dualstack" ] } ] }, + "il-central-1" : { + "variants" : [ { + "hostname" : "appmesh.il-central-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, "me-south-1" : { "variants" : [ { "hostname" : "appmesh.me-south-1.api.aws", @@ -1705,10 +1784,13 @@ "apprunner" : { "endpoints" : { "ap-northeast-1" : { }, + "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, "eu-central-1" : { }, "eu-west-1" : { }, + "eu-west-2" : { }, + "eu-west-3" : { }, "fips-us-east-1" : { "credentialScope" : { "region" : "us-east-1" @@ -2037,6 +2119,12 @@ "deprecated" : true, "hostname" : "athena-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { + "variants" : [ { + "hostname" : "athena.il-central-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, "me-central-1" : { "variants" : [ { "hostname" : "athena.me-central-1.api.aws", @@ -2137,7 +2225,12 @@ "ap-southeast-2" : { }, "ap-southeast-3" : { }, "ap-southeast-4" : { }, - "ca-central-1" : { }, + "ca-central-1" : { + "variants" : [ { + "hostname" : "autoscaling-fips.ca-central-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, "eu-central-1" : { }, "eu-central-2" : { }, "eu-north-1" : { }, @@ -2146,14 +2239,69 @@ "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, + "fips-ca-central-1" : { + "credentialScope" : { + "region" : "ca-central-1" + }, + "deprecated" : true, + "hostname" : "autoscaling-fips.ca-central-1.amazonaws.com" + }, + "fips-us-east-1" : { + "credentialScope" : { + "region" : "us-east-1" + }, + "deprecated" : true, + "hostname" : "autoscaling-fips.us-east-1.amazonaws.com" + }, + "fips-us-east-2" : { + "credentialScope" : { + "region" : "us-east-2" + }, + "deprecated" : true, + "hostname" : "autoscaling-fips.us-east-2.amazonaws.com" + }, + "fips-us-west-1" : { + "credentialScope" : { + "region" : "us-west-1" + }, + "deprecated" : true, + "hostname" : "autoscaling-fips.us-west-1.amazonaws.com" + }, + "fips-us-west-2" : { + "credentialScope" : { + "region" : "us-west-2" + }, + "deprecated" : true, + "hostname" : "autoscaling-fips.us-west-2.amazonaws.com" + }, "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, - "us-east-1" : { }, - "us-east-2" : { }, - "us-west-1" : { }, - "us-west-2" : { } + "us-east-1" : { + "variants" : [ { + "hostname" : "autoscaling-fips.us-east-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-east-2" : { + "variants" : [ { + "hostname" : "autoscaling-fips.us-east-2.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-west-1" : { + "variants" : [ { + "hostname" : "autoscaling-fips.us-west-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-west-2" : { + "variants" : [ { + "hostname" : "autoscaling-fips.us-west-2.amazonaws.com", + "tags" : [ "fips" ] + } ] + } } }, "autoscaling-plans" : { @@ -2207,6 +2355,7 @@ "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, @@ -2328,6 +2477,7 @@ "deprecated" : true, "hostname" : "fips.batch.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, @@ -2357,6 +2507,99 @@ } } }, + "bedrock" : { + "endpoints" : { + "ap-northeast-1" : { }, + "ap-southeast-1" : { }, + "bedrock-ap-northeast-1" : { + "credentialScope" : { + "region" : "ap-northeast-1" + }, + "hostname" : "bedrock.ap-northeast-1.amazonaws.com" + }, + "bedrock-ap-southeast-1" : { + "credentialScope" : { + "region" : "ap-southeast-1" + }, + "hostname" : "bedrock.ap-southeast-1.amazonaws.com" + }, + "bedrock-eu-central-1" : { + "credentialScope" : { + "region" : "eu-central-1" + }, + "hostname" : "bedrock.eu-central-1.amazonaws.com" + }, + "bedrock-fips-us-east-1" : { + "credentialScope" : { + "region" : "us-east-1" + }, + "hostname" : "bedrock-fips.us-east-1.amazonaws.com" + }, + "bedrock-fips-us-west-2" : { + "credentialScope" : { + "region" : "us-west-2" + }, + "hostname" : "bedrock-fips.us-west-2.amazonaws.com" + }, + "bedrock-runtime-ap-northeast-1" : { + "credentialScope" : { + "region" : "ap-northeast-1" + }, + "hostname" : "bedrock-runtime.ap-northeast-1.amazonaws.com" + }, + "bedrock-runtime-ap-southeast-1" : { + "credentialScope" : { + "region" : "ap-southeast-1" + }, + "hostname" : "bedrock-runtime.ap-southeast-1.amazonaws.com" + }, + "bedrock-runtime-eu-central-1" : { + "credentialScope" : { + "region" : "eu-central-1" + }, + "hostname" : "bedrock-runtime.eu-central-1.amazonaws.com" + }, + "bedrock-runtime-fips-us-east-1" : { + "credentialScope" : { + "region" : "us-east-1" + }, + "hostname" : "bedrock-runtime-fips.us-east-1.amazonaws.com" + }, + "bedrock-runtime-fips-us-west-2" : { + "credentialScope" : { + "region" : "us-west-2" + }, + "hostname" : "bedrock-runtime-fips.us-west-2.amazonaws.com" + }, + "bedrock-runtime-us-east-1" : { + "credentialScope" : { + "region" : "us-east-1" + }, + "hostname" : "bedrock-runtime.us-east-1.amazonaws.com" + }, + "bedrock-runtime-us-west-2" : { + "credentialScope" : { + "region" : "us-west-2" + }, + "hostname" : "bedrock-runtime.us-west-2.amazonaws.com" + }, + "bedrock-us-east-1" : { + "credentialScope" : { + "region" : "us-east-1" + }, + "hostname" : "bedrock.us-east-1.amazonaws.com" + }, + "bedrock-us-west-2" : { + "credentialScope" : { + "region" : "us-west-2" + }, + "hostname" : "bedrock.us-west-2.amazonaws.com" + }, + "eu-central-1" : { }, + "us-east-1" : { }, + "us-west-2" : { } + } + }, "billingconductor" : { "endpoints" : { "aws-global" : { @@ -3034,6 +3277,7 @@ "deprecated" : true, "hostname" : "codecommit-fips.ca-central-1.amazonaws.com" }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, @@ -3191,9 +3435,13 @@ "ap-east-1" : { }, "ap-northeast-1" : { }, "ap-northeast-2" : { }, + "ap-northeast-3" : { }, "ap-south-1" : { }, + "ap-south-2" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, + "ap-southeast-3" : { }, + "ap-southeast-4" : { }, "ca-central-1" : { "variants" : [ { "hostname" : "codepipeline-fips.ca-central-1.amazonaws.com", @@ -3204,6 +3452,7 @@ "eu-central-2" : { }, "eu-north-1" : { }, "eu-south-1" : { }, + "eu-south-2" : { }, "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, @@ -3242,6 +3491,8 @@ "deprecated" : true, "hostname" : "codepipeline-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, + "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { @@ -3334,6 +3585,7 @@ "endpoints" : { "ap-northeast-1" : { }, "ap-northeast-2" : { }, + "ap-northeast-3" : { }, "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, @@ -3372,6 +3624,7 @@ "deprecated" : true, "hostname" : "cognito-identity-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { @@ -3404,6 +3657,7 @@ "endpoints" : { "ap-northeast-1" : { }, "ap-northeast-2" : { }, + "ap-northeast-3" : { }, "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, @@ -3442,6 +3696,7 @@ "deprecated" : true, "hostname" : "cognito-idp-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { @@ -3625,6 +3880,12 @@ }, "hostname" : "compute-optimizer.ap-south-1.amazonaws.com" }, + "ap-south-2" : { + "credentialScope" : { + "region" : "ap-south-2" + }, + "hostname" : "compute-optimizer.ap-south-2.amazonaws.com" + }, "ap-southeast-1" : { "credentialScope" : { "region" : "ap-southeast-1" @@ -3637,6 +3898,18 @@ }, "hostname" : "compute-optimizer.ap-southeast-2.amazonaws.com" }, + "ap-southeast-3" : { + "credentialScope" : { + "region" : "ap-southeast-3" + }, + "hostname" : "compute-optimizer.ap-southeast-3.amazonaws.com" + }, + "ap-southeast-4" : { + "credentialScope" : { + "region" : "ap-southeast-4" + }, + "hostname" : "compute-optimizer.ap-southeast-4.amazonaws.com" + }, "ca-central-1" : { "credentialScope" : { "region" : "ca-central-1" @@ -3649,6 +3922,12 @@ }, "hostname" : "compute-optimizer.eu-central-1.amazonaws.com" }, + "eu-central-2" : { + "credentialScope" : { + "region" : "eu-central-2" + }, + "hostname" : "compute-optimizer.eu-central-2.amazonaws.com" + }, "eu-north-1" : { "credentialScope" : { "region" : "eu-north-1" @@ -3661,6 +3940,12 @@ }, "hostname" : "compute-optimizer.eu-south-1.amazonaws.com" }, + "eu-south-2" : { + "credentialScope" : { + "region" : "eu-south-2" + }, + "hostname" : "compute-optimizer.eu-south-2.amazonaws.com" + }, "eu-west-1" : { "credentialScope" : { "region" : "eu-west-1" @@ -3679,15 +3964,27 @@ }, "hostname" : "compute-optimizer.eu-west-3.amazonaws.com" }, - "me-south-1" : { + "il-central-1" : { "credentialScope" : { - "region" : "me-south-1" + "region" : "il-central-1" }, - "hostname" : "compute-optimizer.me-south-1.amazonaws.com" + "hostname" : "compute-optimizer.il-central-1.amazonaws.com" }, - "sa-east-1" : { + "me-central-1" : { "credentialScope" : { - "region" : "sa-east-1" + "region" : "me-central-1" + }, + "hostname" : "compute-optimizer.me-central-1.amazonaws.com" + }, + "me-south-1" : { + "credentialScope" : { + "region" : "me-south-1" + }, + "hostname" : "compute-optimizer.me-south-1.amazonaws.com" + }, + "sa-east-1" : { + "credentialScope" : { + "region" : "sa-east-1" }, "hostname" : "compute-optimizer.sa-east-1.amazonaws.com" }, @@ -3839,6 +4136,7 @@ "endpoints" : { "ap-southeast-2" : { }, "ca-central-1" : { }, + "eu-central-1" : { }, "eu-west-2" : { }, "fips-us-east-1" : { "credentialScope" : { @@ -3890,9 +4188,11 @@ "ap-northeast-2" : { }, "ap-northeast-3" : { }, "ap-south-1" : { }, + "ap-south-2" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, "ap-southeast-3" : { }, + "ap-southeast-4" : { }, "ca-central-1" : { "variants" : [ { "hostname" : "controltower-fips.ca-central-1.amazonaws.com", @@ -3907,11 +4207,15 @@ "hostname" : "controltower-fips.ca-central-1.amazonaws.com" }, "eu-central-1" : { }, + "eu-central-2" : { }, "eu-north-1" : { }, "eu-south-1" : { }, + "eu-south-2" : { }, "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, + "il-central-1" : { }, + "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { @@ -3968,6 +4272,16 @@ } } }, + "cost-optimization-hub" : { + "endpoints" : { + "us-east-1" : { + "credentialScope" : { + "region" : "us-east-1" + }, + "hostname" : "cost-optimization-hub.us-east-1.amazonaws.com" + } + } + }, "cur" : { "endpoints" : { "us-east-1" : { } @@ -4402,6 +4716,7 @@ "deprecated" : true, "hostname" : "datasync-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, @@ -4431,6 +4746,118 @@ } } }, + "datazone" : { + "defaults" : { + "dnsSuffix" : "api.aws", + "variants" : [ { + "dnsSuffix" : "api.aws", + "hostname" : "{service}-fips.{region}.{dnsSuffix}", + "tags" : [ "fips" ] + } ] + }, + "endpoints" : { + "af-south-1" : { + "hostname" : "datazone.af-south-1.api.aws" + }, + "ap-east-1" : { + "hostname" : "datazone.ap-east-1.api.aws" + }, + "ap-northeast-1" : { + "hostname" : "datazone.ap-northeast-1.api.aws" + }, + "ap-northeast-2" : { + "hostname" : "datazone.ap-northeast-2.api.aws" + }, + "ap-northeast-3" : { + "hostname" : "datazone.ap-northeast-3.api.aws" + }, + "ap-south-1" : { + "hostname" : "datazone.ap-south-1.api.aws" + }, + "ap-south-2" : { + "hostname" : "datazone.ap-south-2.api.aws" + }, + "ap-southeast-1" : { + "hostname" : "datazone.ap-southeast-1.api.aws" + }, + "ap-southeast-2" : { + "hostname" : "datazone.ap-southeast-2.api.aws" + }, + "ap-southeast-3" : { + "hostname" : "datazone.ap-southeast-3.api.aws" + }, + "ap-southeast-4" : { + "hostname" : "datazone.ap-southeast-4.api.aws" + }, + "ca-central-1" : { + "hostname" : "datazone.ca-central-1.api.aws", + "variants" : [ { + "hostname" : "datazone-fips.ca-central-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "eu-central-1" : { + "hostname" : "datazone.eu-central-1.api.aws" + }, + "eu-central-2" : { + "hostname" : "datazone.eu-central-2.api.aws" + }, + "eu-north-1" : { + "hostname" : "datazone.eu-north-1.api.aws" + }, + "eu-south-1" : { + "hostname" : "datazone.eu-south-1.api.aws" + }, + "eu-south-2" : { + "hostname" : "datazone.eu-south-2.api.aws" + }, + "eu-west-1" : { + "hostname" : "datazone.eu-west-1.api.aws" + }, + "eu-west-2" : { + "hostname" : "datazone.eu-west-2.api.aws" + }, + "eu-west-3" : { + "hostname" : "datazone.eu-west-3.api.aws" + }, + "il-central-1" : { + "hostname" : "datazone.il-central-1.api.aws" + }, + "me-central-1" : { + "hostname" : "datazone.me-central-1.api.aws" + }, + "me-south-1" : { + "hostname" : "datazone.me-south-1.api.aws" + }, + "sa-east-1" : { + "hostname" : "datazone.sa-east-1.api.aws" + }, + "us-east-1" : { + "hostname" : "datazone.us-east-1.api.aws", + "variants" : [ { + "hostname" : "datazone-fips.us-east-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-east-2" : { + "hostname" : "datazone.us-east-2.api.aws", + "variants" : [ { + "hostname" : "datazone-fips.us-east-2.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-west-1" : { + "hostname" : "datazone.us-west-1.api.aws" + }, + "us-west-2" : { + "hostname" : "datazone.us-west-2.api.aws", + "variants" : [ { + "hostname" : "datazone-fips.us-west-2.amazonaws.com", + "tags" : [ "fips" ] + } ] + } + } + }, "dax" : { "endpoints" : { "ap-northeast-1" : { }, @@ -4865,6 +5292,7 @@ "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, @@ -6152,6 +6580,9 @@ "variants" : [ { "hostname" : "elasticmapreduce-fips.us-east-2.amazonaws.com", "tags" : [ "fips" ] + }, { + "hostname" : "elasticmapreduce.us-east-2.api.aws", + "tags" : [ "dualstack" ] } ] }, "us-west-1" : { @@ -6190,13 +6621,25 @@ "ap-southeast-1" : { }, "ap-southeast-2" : { }, "ap-southeast-3" : { }, - "ca-central-1" : { }, + "ca-central-1" : { + "variants" : [ { + "hostname" : "email-fips.ca-central-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, "eu-central-1" : { }, "eu-north-1" : { }, "eu-south-1" : { }, "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, + "fips-ca-central-1" : { + "credentialScope" : { + "region" : "ca-central-1" + }, + "deprecated" : true, + "hostname" : "email-fips.ca-central-1.amazonaws.com" + }, "fips-us-east-1" : { "credentialScope" : { "region" : "us-east-1" @@ -6204,6 +6647,20 @@ "deprecated" : true, "hostname" : "email-fips.us-east-1.amazonaws.com" }, + "fips-us-east-2" : { + "credentialScope" : { + "region" : "us-east-2" + }, + "deprecated" : true, + "hostname" : "email-fips.us-east-2.amazonaws.com" + }, + "fips-us-west-1" : { + "credentialScope" : { + "region" : "us-west-1" + }, + "deprecated" : true, + "hostname" : "email-fips.us-west-1.amazonaws.com" + }, "fips-us-west-2" : { "credentialScope" : { "region" : "us-west-2" @@ -6211,6 +6668,7 @@ "deprecated" : true, "hostname" : "email-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { @@ -6219,8 +6677,18 @@ "tags" : [ "fips" ] } ] }, - "us-east-2" : { }, - "us-west-1" : { }, + "us-east-2" : { + "variants" : [ { + "hostname" : "email-fips.us-east-2.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-west-1" : { + "variants" : [ { + "hostname" : "email-fips.us-west-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, "us-west-2" : { "variants" : [ { "hostname" : "email-fips.us-west-2.amazonaws.com", @@ -6235,9 +6703,11 @@ "ap-east-1" : { }, "ap-northeast-1" : { }, "ap-northeast-2" : { }, + "ap-northeast-3" : { }, "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, + "ap-southeast-3" : { }, "ca-central-1" : { "variants" : [ { "hostname" : "emr-containers-fips.ca-central-1.amazonaws.com", @@ -6285,6 +6755,7 @@ "deprecated" : true, "hostname" : "emr-containers-fips.us-west-2.amazonaws.com" }, + "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { @@ -6315,12 +6786,15 @@ }, "emr-serverless" : { "endpoints" : { + "af-south-1" : { }, "ap-east-1" : { }, "ap-northeast-1" : { }, "ap-northeast-2" : { }, + "ap-northeast-3" : { }, "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, + "ap-southeast-3" : { }, "ca-central-1" : { "variants" : [ { "hostname" : "emr-serverless-fips.ca-central-1.amazonaws.com", @@ -6329,6 +6803,7 @@ }, "eu-central-1" : { }, "eu-north-1" : { }, + "eu-south-1" : { }, "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, @@ -6407,26 +6882,126 @@ }, "es" : { "endpoints" : { - "af-south-1" : { }, - "ap-east-1" : { }, - "ap-northeast-1" : { }, - "ap-northeast-2" : { }, - "ap-northeast-3" : { }, - "ap-south-1" : { }, - "ap-south-2" : { }, - "ap-southeast-1" : { }, - "ap-southeast-2" : { }, - "ap-southeast-3" : { }, - "ap-southeast-4" : { }, - "ca-central-1" : { }, - "eu-central-1" : { }, - "eu-central-2" : { }, - "eu-north-1" : { }, - "eu-south-1" : { }, - "eu-south-2" : { }, - "eu-west-1" : { }, - "eu-west-2" : { }, - "eu-west-3" : { }, + "af-south-1" : { + "variants" : [ { + "hostname" : "aos.af-south-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "ap-east-1" : { + "variants" : [ { + "hostname" : "aos.ap-east-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "ap-northeast-1" : { + "variants" : [ { + "hostname" : "aos.ap-northeast-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "ap-northeast-2" : { + "variants" : [ { + "hostname" : "aos.ap-northeast-2.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "ap-northeast-3" : { + "variants" : [ { + "hostname" : "aos.ap-northeast-3.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "ap-south-1" : { + "variants" : [ { + "hostname" : "aos.ap-south-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "ap-south-2" : { + "variants" : [ { + "hostname" : "aos.ap-south-2.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "ap-southeast-1" : { + "variants" : [ { + "hostname" : "aos.ap-southeast-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "ap-southeast-2" : { + "variants" : [ { + "hostname" : "aos.ap-southeast-2.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "ap-southeast-3" : { + "variants" : [ { + "hostname" : "aos.ap-southeast-3.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "ap-southeast-4" : { + "variants" : [ { + "hostname" : "aos.ap-southeast-4.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "ca-central-1" : { + "variants" : [ { + "hostname" : "aos.ca-central-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "eu-central-1" : { + "variants" : [ { + "hostname" : "aos.eu-central-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "eu-central-2" : { + "variants" : [ { + "hostname" : "aos.eu-central-2.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "eu-north-1" : { + "variants" : [ { + "hostname" : "aos.eu-north-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "eu-south-1" : { + "variants" : [ { + "hostname" : "aos.eu-south-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "eu-south-2" : { + "variants" : [ { + "hostname" : "aos.eu-south-2.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "eu-west-1" : { + "variants" : [ { + "hostname" : "aos.eu-west-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "eu-west-2" : { + "variants" : [ { + "hostname" : "aos.eu-west-2.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "eu-west-3" : { + "variants" : [ { + "hostname" : "aos.eu-west-3.api.aws", + "tags" : [ "dualstack" ] + } ] + }, "fips" : { "credentialScope" : { "region" : "us-west-1" @@ -6434,12 +7009,35 @@ "deprecated" : true, "hostname" : "es-fips.us-west-1.amazonaws.com" }, - "il-central-1" : { }, - "me-central-1" : { }, - "me-south-1" : { }, - "sa-east-1" : { }, + "il-central-1" : { + "variants" : [ { + "hostname" : "aos.il-central-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "me-central-1" : { + "variants" : [ { + "hostname" : "aos.me-central-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "me-south-1" : { + "variants" : [ { + "hostname" : "aos.me-south-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, + "sa-east-1" : { + "variants" : [ { + "hostname" : "aos.sa-east-1.api.aws", + "tags" : [ "dualstack" ] + } ] + }, "us-east-1" : { "variants" : [ { + "hostname" : "aos.us-east-1.api.aws", + "tags" : [ "dualstack" ] + }, { "hostname" : "es-fips.us-east-1.amazonaws.com", "tags" : [ "fips" ] } ] @@ -6453,6 +7051,9 @@ }, "us-east-2" : { "variants" : [ { + "hostname" : "aos.us-east-2.api.aws", + "tags" : [ "dualstack" ] + }, { "hostname" : "es-fips.us-east-2.amazonaws.com", "tags" : [ "fips" ] } ] @@ -6466,6 +7067,9 @@ }, "us-west-1" : { "variants" : [ { + "hostname" : "aos.us-west-1.api.aws", + "tags" : [ "dualstack" ] + }, { "hostname" : "es-fips.us-west-1.amazonaws.com", "tags" : [ "fips" ] } ] @@ -6479,6 +7083,9 @@ }, "us-west-2" : { "variants" : [ { + "hostname" : "aos.us-west-2.api.aws", + "tags" : [ "dualstack" ] + }, { "hostname" : "es-fips.us-west-2.amazonaws.com", "tags" : [ "fips" ] } ] @@ -6605,8 +7212,13 @@ }, "finspace" : { "endpoints" : { + "ap-northeast-1" : { }, + "ap-southeast-1" : { }, + "ap-southeast-2" : { }, "ca-central-1" : { }, + "eu-central-1" : { }, "eu-west-1" : { }, + "eu-west-2" : { }, "us-east-1" : { }, "us-east-2" : { }, "us-west-2" : { } @@ -6924,6 +7536,7 @@ "deprecated" : true, "hostname" : "fms-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { "variants" : [ { @@ -7170,6 +7783,7 @@ "deprecated" : true, "hostname" : "fsx-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "prod-ca-central-1" : { @@ -7274,12 +7888,6 @@ "us-west-2" : { } } }, - "gamesparks" : { - "endpoints" : { - "ap-northeast-1" : { }, - "us-east-1" : { } - } - }, "geo" : { "endpoints" : { "ap-northeast-1" : { }, @@ -7675,6 +8283,7 @@ "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, @@ -7853,11 +8462,13 @@ "ap-southeast-3" : { }, "ca-central-1" : { }, "eu-central-1" : { }, + "eu-central-2" : { }, "eu-north-1" : { }, "eu-south-1" : { }, "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, + "il-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { }, @@ -8008,14 +8619,18 @@ }, "inspector2" : { "endpoints" : { + "af-south-1" : { }, "ap-east-1" : { }, "ap-northeast-1" : { }, "ap-northeast-2" : { }, + "ap-northeast-3" : { }, "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, + "ap-southeast-3" : { }, "ca-central-1" : { }, "eu-central-1" : { }, + "eu-central-2" : { }, "eu-north-1" : { }, "eu-south-1" : { }, "eu-west-1" : { }, @@ -8123,7 +8738,7 @@ "ca-central-1" : { "hostname" : "internetmonitor.ca-central-1.api.aws", "variants" : [ { - "hostname" : "internetmonitor-fips.ca-central-1.api.aws", + "hostname" : "internetmonitor-fips.ca-central-1.amazonaws.com", "tags" : [ "fips" ] } ] }, @@ -8166,28 +8781,28 @@ "us-east-1" : { "hostname" : "internetmonitor.us-east-1.api.aws", "variants" : [ { - "hostname" : "internetmonitor-fips.us-east-1.api.aws", + "hostname" : "internetmonitor-fips.us-east-1.amazonaws.com", "tags" : [ "fips" ] } ] }, "us-east-2" : { "hostname" : "internetmonitor.us-east-2.api.aws", "variants" : [ { - "hostname" : "internetmonitor-fips.us-east-2.api.aws", + "hostname" : "internetmonitor-fips.us-east-2.amazonaws.com", "tags" : [ "fips" ] } ] }, "us-west-1" : { "hostname" : "internetmonitor.us-west-1.api.aws", "variants" : [ { - "hostname" : "internetmonitor-fips.us-west-1.api.aws", + "hostname" : "internetmonitor-fips.us-west-1.amazonaws.com", "tags" : [ "fips" ] } ] }, "us-west-2" : { "hostname" : "internetmonitor.us-west-2.api.aws", "variants" : [ { - "hostname" : "internetmonitor-fips.us-west-2.api.aws", + "hostname" : "internetmonitor-fips.us-west-2.amazonaws.com", "tags" : [ "fips" ] } ] } @@ -8637,8 +9252,29 @@ }, "iottwinmaker" : { "endpoints" : { + "ap-northeast-1" : { }, + "ap-northeast-2" : { }, + "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, + "api-ap-northeast-1" : { + "credentialScope" : { + "region" : "ap-northeast-1" + }, + "hostname" : "api.iottwinmaker.ap-northeast-1.amazonaws.com" + }, + "api-ap-northeast-2" : { + "credentialScope" : { + "region" : "ap-northeast-2" + }, + "hostname" : "api.iottwinmaker.ap-northeast-2.amazonaws.com" + }, + "api-ap-south-1" : { + "credentialScope" : { + "region" : "ap-south-1" + }, + "hostname" : "api.iottwinmaker.ap-south-1.amazonaws.com" + }, "api-ap-southeast-1" : { "credentialScope" : { "region" : "ap-southeast-1" @@ -8675,6 +9311,24 @@ }, "hostname" : "api.iottwinmaker.us-west-2.amazonaws.com" }, + "data-ap-northeast-1" : { + "credentialScope" : { + "region" : "ap-northeast-1" + }, + "hostname" : "data.iottwinmaker.ap-northeast-1.amazonaws.com" + }, + "data-ap-northeast-2" : { + "credentialScope" : { + "region" : "ap-northeast-2" + }, + "hostname" : "data.iottwinmaker.ap-northeast-2.amazonaws.com" + }, + "data-ap-south-1" : { + "credentialScope" : { + "region" : "ap-south-1" + }, + "hostname" : "data.iottwinmaker.ap-south-1.amazonaws.com" + }, "data-ap-southeast-1" : { "credentialScope" : { "region" : "ap-southeast-1" @@ -8894,6 +9548,7 @@ "deprecated" : true, "hostname" : "kafka-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, @@ -9906,13 +10561,17 @@ "ap-northeast-2" : { }, "ap-northeast-3" : { }, "ap-south-1" : { }, + "ap-south-2" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, "ap-southeast-3" : { }, + "ap-southeast-4" : { }, "ca-central-1" : { }, "eu-central-1" : { }, + "eu-central-2" : { }, "eu-north-1" : { }, "eu-south-1" : { }, + "eu-south-2" : { }, "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, @@ -9944,6 +10603,8 @@ "deprecated" : true, "hostname" : "license-manager-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, + "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { @@ -10060,12 +10721,17 @@ "ap-northeast-2" : { }, "ap-northeast-3" : { }, "ap-south-1" : { }, + "ap-south-2" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, + "ap-southeast-3" : { }, + "ap-southeast-4" : { }, "ca-central-1" : { }, "eu-central-1" : { }, + "eu-central-2" : { }, "eu-north-1" : { }, "eu-south-1" : { }, + "eu-south-2" : { }, "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, @@ -10097,6 +10763,8 @@ "deprecated" : true, "hostname" : "license-manager-user-subscriptions-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, + "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { @@ -10314,36 +10982,6 @@ "us-east-1" : { } } }, - "macie" : { - "endpoints" : { - "fips-us-east-1" : { - "credentialScope" : { - "region" : "us-east-1" - }, - "deprecated" : true, - "hostname" : "macie-fips.us-east-1.amazonaws.com" - }, - "fips-us-west-2" : { - "credentialScope" : { - "region" : "us-west-2" - }, - "deprecated" : true, - "hostname" : "macie-fips.us-west-2.amazonaws.com" - }, - "us-east-1" : { - "variants" : [ { - "hostname" : "macie-fips.us-east-1.amazonaws.com", - "tags" : [ "fips" ] - } ] - }, - "us-west-2" : { - "variants" : [ { - "hostname" : "macie-fips.us-west-2.amazonaws.com", - "tags" : [ "fips" ] - } ] - } - } - }, "macie2" : { "endpoints" : { "af-south-1" : { }, @@ -10389,6 +11027,7 @@ "deprecated" : true, "hostname" : "macie2-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { @@ -10427,6 +11066,11 @@ "us-east-1" : { } } }, + "managedblockchain-query" : { + "endpoints" : { + "us-east-1" : { } + } + }, "marketplacecommerceanalytics" : { "endpoints" : { "us-east-1" : { } @@ -10492,9 +11136,11 @@ "af-south-1" : { }, "ap-northeast-1" : { }, "ap-northeast-2" : { }, + "ap-northeast-3" : { }, "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, + "ap-southeast-4" : { }, "ca-central-1" : { "variants" : [ { "hostname" : "mediaconvert-fips.ca-central-1.amazonaws.com", @@ -10626,6 +11272,7 @@ "endpoints" : { "ap-northeast-1" : { }, "ap-northeast-2" : { }, + "ap-northeast-3" : { }, "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, @@ -10646,6 +11293,7 @@ "endpoints" : { "ap-northeast-1" : { }, "ap-northeast-2" : { }, + "ap-northeast-3" : { }, "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, @@ -10666,6 +11314,7 @@ "endpoints" : { "ap-northeast-1" : { }, "ap-northeast-2" : { }, + "ap-northeast-3" : { }, "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, @@ -10697,8 +11346,15 @@ }, "meetings-chime" : { "endpoints" : { + "ap-northeast-1" : { }, + "ap-northeast-2" : { }, + "ap-south-1" : { }, "ap-southeast-1" : { }, + "ap-southeast-2" : { }, + "ca-central-1" : { }, "eu-central-1" : { }, + "eu-west-2" : { }, + "il-central-1" : { }, "us-east-1" : { "variants" : [ { "hostname" : "meetings-chime-fips.us-east-1.amazonaws.com", @@ -10903,6 +11559,7 @@ "deprecated" : true, "hostname" : "mgn-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, @@ -11364,6 +12021,7 @@ "deprecated" : true, "hostname" : "network-firewall-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, @@ -11531,6 +12189,12 @@ }, "hostname" : "oidc.eu-central-1.amazonaws.com" }, + "eu-central-2" : { + "credentialScope" : { + "region" : "eu-central-2" + }, + "hostname" : "oidc.eu-central-2.amazonaws.com" + }, "eu-north-1" : { "credentialScope" : { "region" : "eu-north-1" @@ -11561,6 +12225,12 @@ }, "hostname" : "oidc.eu-west-3.amazonaws.com" }, + "il-central-1" : { + "credentialScope" : { + "region" : "il-central-1" + }, + "hostname" : "oidc.il-central-1.amazonaws.com" + }, "me-south-1" : { "credentialScope" : { "region" : "me-south-1" @@ -11639,6 +12309,12 @@ "deprecated" : true, "hostname" : "omics-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { + "credentialScope" : { + "region" : "il-central-1" + }, + "hostname" : "omics.il-central-1.amazonaws.com" + }, "us-east-1" : { "credentialScope" : { "region" : "us-east-1" @@ -11719,8 +12395,11 @@ "osis" : { "endpoints" : { "ap-northeast-1" : { }, + "ap-northeast-2" : { }, + "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, + "ca-central-1" : { }, "eu-central-1" : { }, "eu-west-1" : { }, "eu-west-2" : { }, @@ -11788,6 +12467,8 @@ "deprecated" : true, "hostname" : "outposts-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, + "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { @@ -11994,13 +12675,16 @@ "ap-northeast-2" : { }, "ap-northeast-3" : { }, "ap-south-1" : { }, + "ap-south-2" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, "ap-southeast-3" : { }, "ca-central-1" : { }, "eu-central-1" : { }, + "eu-central-2" : { }, "eu-north-1" : { }, "eu-south-1" : { }, + "eu-south-2" : { }, "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, @@ -12153,6 +12837,12 @@ }, "hostname" : "portal.sso.eu-central-1.amazonaws.com" }, + "eu-central-2" : { + "credentialScope" : { + "region" : "eu-central-2" + }, + "hostname" : "portal.sso.eu-central-2.amazonaws.com" + }, "eu-north-1" : { "credentialScope" : { "region" : "eu-north-1" @@ -12183,6 +12873,12 @@ }, "hostname" : "portal.sso.eu-west-3.amazonaws.com" }, + "il-central-1" : { + "credentialScope" : { + "region" : "il-central-1" + }, + "hostname" : "portal.sso.il-central-1.amazonaws.com" + }, "me-south-1" : { "credentialScope" : { "region" : "me-south-1" @@ -12297,6 +12993,102 @@ "us-west-2" : { } } }, + "qbusiness" : { + "defaults" : { + "dnsSuffix" : "api.aws", + "variants" : [ { + "dnsSuffix" : "api.aws", + "hostname" : "{service}-fips.{region}.{dnsSuffix}", + "tags" : [ "fips" ] + } ] + }, + "endpoints" : { + "af-south-1" : { + "hostname" : "qbusiness.af-south-1.api.aws" + }, + "ap-east-1" : { + "hostname" : "qbusiness.ap-east-1.api.aws" + }, + "ap-northeast-1" : { + "hostname" : "qbusiness.ap-northeast-1.api.aws" + }, + "ap-northeast-2" : { + "hostname" : "qbusiness.ap-northeast-2.api.aws" + }, + "ap-northeast-3" : { + "hostname" : "qbusiness.ap-northeast-3.api.aws" + }, + "ap-south-1" : { + "hostname" : "qbusiness.ap-south-1.api.aws" + }, + "ap-south-2" : { + "hostname" : "qbusiness.ap-south-2.api.aws" + }, + "ap-southeast-1" : { + "hostname" : "qbusiness.ap-southeast-1.api.aws" + }, + "ap-southeast-2" : { + "hostname" : "qbusiness.ap-southeast-2.api.aws" + }, + "ap-southeast-3" : { + "hostname" : "qbusiness.ap-southeast-3.api.aws" + }, + "ap-southeast-4" : { + "hostname" : "qbusiness.ap-southeast-4.api.aws" + }, + "ca-central-1" : { + "hostname" : "qbusiness.ca-central-1.api.aws" + }, + "eu-central-1" : { + "hostname" : "qbusiness.eu-central-1.api.aws" + }, + "eu-central-2" : { + "hostname" : "qbusiness.eu-central-2.api.aws" + }, + "eu-north-1" : { + "hostname" : "qbusiness.eu-north-1.api.aws" + }, + "eu-south-1" : { + "hostname" : "qbusiness.eu-south-1.api.aws" + }, + "eu-south-2" : { + "hostname" : "qbusiness.eu-south-2.api.aws" + }, + "eu-west-1" : { + "hostname" : "qbusiness.eu-west-1.api.aws" + }, + "eu-west-2" : { + "hostname" : "qbusiness.eu-west-2.api.aws" + }, + "eu-west-3" : { + "hostname" : "qbusiness.eu-west-3.api.aws" + }, + "il-central-1" : { + "hostname" : "qbusiness.il-central-1.api.aws" + }, + "me-central-1" : { + "hostname" : "qbusiness.me-central-1.api.aws" + }, + "me-south-1" : { + "hostname" : "qbusiness.me-south-1.api.aws" + }, + "sa-east-1" : { + "hostname" : "qbusiness.sa-east-1.api.aws" + }, + "us-east-1" : { + "hostname" : "qbusiness.us-east-1.api.aws" + }, + "us-east-2" : { + "hostname" : "qbusiness.us-east-2.api.aws" + }, + "us-west-1" : { + "hostname" : "qbusiness.us-west-1.api.aws" + }, + "us-west-2" : { + "hostname" : "qbusiness.us-west-2.api.aws" + } + } + }, "qldb" : { "endpoints" : { "ap-northeast-1" : { }, @@ -12941,6 +13733,7 @@ "eu-central-1" : { }, "eu-west-1" : { }, "eu-west-2" : { }, + "il-central-1" : { }, "rekognition-fips.ca-central-1" : { "credentialScope" : { "region" : "ca-central-1" @@ -13114,6 +13907,12 @@ } ] }, "endpoints" : { + "af-south-1" : { + "hostname" : "resource-explorer-2.af-south-1.api.aws" + }, + "ap-east-1" : { + "hostname" : "resource-explorer-2.ap-east-1.api.aws" + }, "ap-northeast-1" : { "hostname" : "resource-explorer-2.ap-northeast-1.api.aws" }, @@ -13135,6 +13934,9 @@ "ap-southeast-2" : { "hostname" : "resource-explorer-2.ap-southeast-2.api.aws" }, + "ap-southeast-3" : { + "hostname" : "resource-explorer-2.ap-southeast-3.api.aws" + }, "ap-southeast-4" : { "hostname" : "resource-explorer-2.ap-southeast-4.api.aws" }, @@ -13150,6 +13952,9 @@ "eu-north-1" : { "hostname" : "resource-explorer-2.eu-north-1.api.aws" }, + "eu-south-1" : { + "hostname" : "resource-explorer-2.eu-south-1.api.aws" + }, "eu-west-1" : { "hostname" : "resource-explorer-2.eu-west-1.api.aws" }, @@ -13162,6 +13967,12 @@ "il-central-1" : { "hostname" : "resource-explorer-2.il-central-1.api.aws" }, + "me-central-1" : { + "hostname" : "resource-explorer-2.me-central-1.api.aws" + }, + "me-south-1" : { + "hostname" : "resource-explorer-2.me-south-1.api.aws" + }, "sa-east-1" : { "hostname" : "resource-explorer-2.sa-east-1.api.aws" }, @@ -14122,6 +14933,7 @@ "fips-us-west-2" : { "deprecated" : true }, + "il-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { @@ -14417,12 +15229,16 @@ "endpoints" : { "ap-northeast-1" : { }, "ap-northeast-2" : { }, + "ap-northeast-3" : { }, "ap-south-1" : { }, "ap-southeast-1" : { }, "ap-southeast-2" : { }, + "ca-central-1" : { }, "eu-central-1" : { }, + "eu-north-1" : { }, "eu-west-1" : { }, "eu-west-2" : { }, + "eu-west-3" : { }, "sa-east-1" : { }, "us-east-1" : { }, "us-east-2" : { }, @@ -14633,6 +15449,7 @@ "deprecated" : true, "hostname" : "servicecatalog-appregistry-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, @@ -14924,6 +15741,7 @@ "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, @@ -15887,11 +16705,13 @@ "ap-southeast-3" : { }, "ca-central-1" : { }, "eu-central-1" : { }, + "eu-central-2" : { }, "eu-north-1" : { }, "eu-south-1" : { }, "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, + "il-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, "us-east-1" : { }, @@ -16014,6 +16834,7 @@ "eu-west-1" : { }, "eu-west-2" : { }, "eu-west-3" : { }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, @@ -16490,11 +17311,27 @@ } } }, + "thinclient" : { + "endpoints" : { + "ap-south-1" : { }, + "ca-central-1" : { }, + "eu-central-1" : { }, + "eu-west-1" : { }, + "eu-west-2" : { }, + "us-east-1" : { }, + "us-west-2" : { } + } + }, "tnb" : { "endpoints" : { + "ap-northeast-2" : { }, "ap-southeast-2" : { }, + "ca-central-1" : { }, "eu-central-1" : { }, + "eu-north-1" : { }, + "eu-south-2" : { }, "eu-west-3" : { }, + "sa-east-1" : { }, "us-east-1" : { }, "us-west-2" : { } } @@ -16737,6 +17574,7 @@ "deprecated" : true, "hostname" : "transfer-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "me-central-1" : { }, "me-south-1" : { }, "sa-east-1" : { }, @@ -16861,6 +17699,7 @@ "ap-northeast-1" : { }, "ap-northeast-2" : { }, "ap-southeast-1" : { }, + "ap-southeast-2" : { }, "ca-central-1" : { "variants" : [ { "hostname" : "voice-chime-fips.ca-central-1.amazonaws.com", @@ -18090,6 +18929,7 @@ "deprecated" : true, "hostname" : "workspaces-fips.us-west-2.amazonaws.com" }, + "il-central-1" : { }, "sa-east-1" : { }, "us-east-1" : { "variants" : [ { @@ -18278,6 +19118,16 @@ } } }, + "api.pricing" : { + "defaults" : { + "credentialScope" : { + "service" : "pricing" + } + }, + "endpoints" : { + "cn-northwest-1" : { } + } + }, "api.sagemaker" : { "endpoints" : { "cn-north-1" : { }, @@ -18565,6 +19415,24 @@ "cn-northwest-1" : { } } }, + "datazone" : { + "defaults" : { + "dnsSuffix" : "api.amazonwebservices.com.cn", + "variants" : [ { + "dnsSuffix" : "api.amazonwebservices.com.cn", + "hostname" : "{service}-fips.{region}.{dnsSuffix}", + "tags" : [ "fips" ] + } ] + }, + "endpoints" : { + "cn-north-1" : { + "hostname" : "datazone.cn-north-1.api.amazonwebservices.com.cn" + }, + "cn-northwest-1" : { + "hostname" : "datazone.cn-northwest-1.api.amazonwebservices.com.cn" + } + } + }, "dax" : { "endpoints" : { "cn-north-1" : { }, @@ -18700,8 +19568,18 @@ "protocols" : [ "https" ] }, "endpoints" : { - "cn-north-1" : { }, - "cn-northwest-1" : { } + "cn-north-1" : { + "variants" : [ { + "hostname" : "elasticmapreduce.cn-north-1.api.amazonwebservices.com.cn", + "tags" : [ "dualstack" ] + } ] + }, + "cn-northwest-1" : { + "variants" : [ { + "hostname" : "elasticmapreduce.cn-northwest-1.api.amazonwebservices.com.cn", + "tags" : [ "dualstack" ] + } ] + } } }, "emr-containers" : { @@ -18718,8 +19596,18 @@ }, "es" : { "endpoints" : { - "cn-north-1" : { }, - "cn-northwest-1" : { } + "cn-north-1" : { + "variants" : [ { + "hostname" : "aos.cn-north-1.api.amazonwebservices.com.cn", + "tags" : [ "dualstack" ] + } ] + }, + "cn-northwest-1" : { + "variants" : [ { + "hostname" : "aos.cn-northwest-1.api.amazonwebservices.com.cn", + "tags" : [ "dualstack" ] + } ] + } } }, "events" : { @@ -18827,6 +19715,12 @@ "isRegionalized" : false, "partitionEndpoint" : "aws-cn-global" }, + "identitystore" : { + "endpoints" : { + "cn-north-1" : { }, + "cn-northwest-1" : { } + } + }, "internetmonitor" : { "defaults" : { "dnsSuffix" : "api.amazonwebservices.com.cn", @@ -19028,6 +19922,22 @@ "cn-northwest-1" : { } } }, + "oidc" : { + "endpoints" : { + "cn-north-1" : { + "credentialScope" : { + "region" : "cn-north-1" + }, + "hostname" : "oidc.cn-north-1.amazonaws.com.cn" + }, + "cn-northwest-1" : { + "credentialScope" : { + "region" : "cn-northwest-1" + }, + "hostname" : "oidc.cn-northwest-1.amazonaws.com.cn" + } + } + }, "organizations" : { "endpoints" : { "aws-cn-global" : { @@ -19056,6 +19966,40 @@ "cn-northwest-1" : { } } }, + "portal.sso" : { + "endpoints" : { + "cn-north-1" : { + "credentialScope" : { + "region" : "cn-north-1" + }, + "hostname" : "portal.sso.cn-north-1.amazonaws.com.cn" + }, + "cn-northwest-1" : { + "credentialScope" : { + "region" : "cn-northwest-1" + }, + "hostname" : "portal.sso.cn-northwest-1.amazonaws.com.cn" + } + } + }, + "qbusiness" : { + "defaults" : { + "dnsSuffix" : "api.amazonwebservices.com.cn", + "variants" : [ { + "dnsSuffix" : "api.amazonwebservices.com.cn", + "hostname" : "{service}-fips.{region}.{dnsSuffix}", + "tags" : [ "fips" ] + } ] + }, + "endpoints" : { + "cn-north-1" : { + "hostname" : "qbusiness.cn-north-1.api.amazonwebservices.com.cn" + }, + "cn-northwest-1" : { + "hostname" : "qbusiness.cn-northwest-1.api.amazonwebservices.com.cn" + } + } + }, "ram" : { "endpoints" : { "cn-north-1" : { }, @@ -19080,6 +20024,11 @@ "cn-northwest-1" : { } } }, + "redshift-serverless" : { + "endpoints" : { + "cn-north-1" : { } + } + }, "resource-explorer-2" : { "defaults" : { "dnsSuffix" : "api.amazonwebservices.com.cn", @@ -19342,12 +20291,28 @@ "cn-northwest-1" : { } } }, - "states" : { + "sso" : { "endpoints" : { "cn-north-1" : { }, "cn-northwest-1" : { } } }, + "states" : { + "endpoints" : { + "cn-north-1" : { + "variants" : [ { + "hostname" : "states.cn-north-1.api.amazonwebservices.com.cn", + "tags" : [ "dualstack" ] + } ] + }, + "cn-northwest-1" : { + "variants" : [ { + "hostname" : "states.cn-northwest-1.api.amazonwebservices.com.cn", + "tags" : [ "dualstack" ] + } ] + } + } + }, "storagegateway" : { "endpoints" : { "cn-north-1" : { }, @@ -19875,8 +20840,32 @@ }, "appconfigdata" : { "endpoints" : { - "us-gov-east-1" : { }, - "us-gov-west-1" : { } + "fips-us-gov-east-1" : { + "credentialScope" : { + "region" : "us-gov-east-1" + }, + "deprecated" : true, + "hostname" : "appconfigdata.us-gov-east-1.amazonaws.com" + }, + "fips-us-gov-west-1" : { + "credentialScope" : { + "region" : "us-gov-west-1" + }, + "deprecated" : true, + "hostname" : "appconfigdata.us-gov-west-1.amazonaws.com" + }, + "us-gov-east-1" : { + "variants" : [ { + "hostname" : "appconfigdata.us-gov-east-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-gov-west-1" : { + "variants" : [ { + "hostname" : "appconfigdata.us-gov-west-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + } } }, "application-autoscaling" : { @@ -19971,6 +20960,12 @@ } } }, + "arc-zonal-shift" : { + "endpoints" : { + "us-gov-east-1" : { }, + "us-gov-west-1" : { } + } + }, "athena" : { "endpoints" : { "fips-us-gov-east-1" : { @@ -20398,6 +21393,11 @@ } } }, + "codestar-connections" : { + "endpoints" : { + "us-gov-east-1" : { } + } + }, "cognito-identity" : { "endpoints" : { "fips-us-gov-west-1" : { @@ -20693,6 +21693,24 @@ } } }, + "datazone" : { + "defaults" : { + "dnsSuffix" : "api.aws", + "variants" : [ { + "dnsSuffix" : "api.aws", + "hostname" : "{service}-fips.{region}.{dnsSuffix}", + "tags" : [ "fips" ] + } ] + }, + "endpoints" : { + "us-gov-east-1" : { + "hostname" : "datazone.us-gov-east-1.api.aws" + }, + "us-gov-west-1" : { + "hostname" : "datazone.us-gov-west-1.api.aws" + } + } + }, "directconnect" : { "endpoints" : { "us-gov-east-1" : { @@ -20802,6 +21820,36 @@ } } }, + "drs" : { + "endpoints" : { + "fips-us-gov-east-1" : { + "credentialScope" : { + "region" : "us-gov-east-1" + }, + "deprecated" : true, + "hostname" : "drs-fips.us-gov-east-1.amazonaws.com" + }, + "fips-us-gov-west-1" : { + "credentialScope" : { + "region" : "us-gov-west-1" + }, + "deprecated" : true, + "hostname" : "drs-fips.us-gov-west-1.amazonaws.com" + }, + "us-gov-east-1" : { + "variants" : [ { + "hostname" : "drs-fips.us-gov-east-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-gov-west-1" : { + "variants" : [ { + "hostname" : "drs-fips.us-gov-west-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + } + } + }, "ds" : { "endpoints" : { "fips-us-gov-east-1" : { @@ -21133,6 +22181,9 @@ "variants" : [ { "hostname" : "elasticmapreduce.us-gov-east-1.amazonaws.com", "tags" : [ "fips" ] + }, { + "hostname" : "elasticmapreduce.us-gov-east-1.api.aws", + "tags" : [ "dualstack" ] } ] }, "us-gov-west-1" : { @@ -21140,6 +22191,9 @@ "variants" : [ { "hostname" : "elasticmapreduce.us-gov-west-1.amazonaws.com", "tags" : [ "fips" ] + }, { + "hostname" : "elasticmapreduce.us-gov-west-1.api.aws", + "tags" : [ "dualstack" ] } ] } } @@ -21178,6 +22232,9 @@ }, "us-gov-east-1" : { "variants" : [ { + "hostname" : "aos.us-gov-east-1.api.aws", + "tags" : [ "dualstack" ] + }, { "hostname" : "es-fips.us-gov-east-1.amazonaws.com", "tags" : [ "fips" ] } ] @@ -21191,6 +22248,9 @@ }, "us-gov-west-1" : { "variants" : [ { + "hostname" : "aos.us-gov-west-1.api.aws", + "tags" : [ "dualstack" ] + }, { "hostname" : "es-fips.us-gov-west-1.amazonaws.com", "tags" : [ "fips" ] } ] @@ -21361,6 +22421,23 @@ } } }, + "geo" : { + "endpoints" : { + "fips-us-gov-west-1" : { + "credentialScope" : { + "region" : "us-gov-west-1" + }, + "deprecated" : true, + "hostname" : "geo-fips.us-gov-west-1.amazonaws.com" + }, + "us-gov-west-1" : { + "variants" : [ { + "hostname" : "geo-fips.us-gov-west-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + } + } + }, "glacier" : { "endpoints" : { "fips-us-gov-east-1" : { @@ -21412,12 +22489,24 @@ "variants" : [ { "hostname" : "glue-fips.us-gov-east-1.amazonaws.com", "tags" : [ "fips" ] + }, { + "hostname" : "glue-fips.us-gov-east-1.api.aws", + "tags" : [ "dualstack", "fips" ] + }, { + "hostname" : "glue.us-gov-east-1.api.aws", + "tags" : [ "dualstack" ] } ] }, "us-gov-west-1" : { "variants" : [ { "hostname" : "glue-fips.us-gov-west-1.amazonaws.com", "tags" : [ "fips" ] + }, { + "hostname" : "glue-fips.us-gov-west-1.api.aws", + "tags" : [ "dualstack", "fips" ] + }, { + "hostname" : "glue.us-gov-west-1.api.aws", + "tags" : [ "dualstack" ] } ] } } @@ -22028,12 +23117,24 @@ "variants" : [ { "hostname" : "lakeformation-fips.us-gov-east-1.amazonaws.com", "tags" : [ "fips" ] + }, { + "hostname" : "lakeformation-fips.us-gov-east-1.api.aws", + "tags" : [ "dualstack", "fips" ] + }, { + "hostname" : "lakeformation.us-gov-east-1.api.aws", + "tags" : [ "dualstack" ] } ] }, "us-gov-west-1" : { "variants" : [ { "hostname" : "lakeformation-fips.us-gov-west-1.amazonaws.com", "tags" : [ "fips" ] + }, { + "hostname" : "lakeformation-fips.us-gov-west-1.api.aws", + "tags" : [ "dualstack", "fips" ] + }, { + "hostname" : "lakeformation.us-gov-west-1.api.aws", + "tags" : [ "dualstack" ] } ] } } @@ -22128,13 +23229,33 @@ }, "us-gov-east-1" : { "variants" : [ { - "hostname" : "logs.us-gov-east-1.amazonaws.com", + "hostname" : "logs.us-gov-east-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-gov-west-1" : { + "variants" : [ { + "hostname" : "logs.us-gov-west-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + } + } + }, + "m2" : { + "endpoints" : { + "fips-us-gov-east-1" : { + "deprecated" : true + }, + "fips-us-gov-west-1" : { + "deprecated" : true + }, + "us-gov-east-1" : { + "variants" : [ { "tags" : [ "fips" ] } ] }, "us-gov-west-1" : { "variants" : [ { - "hostname" : "logs.us-gov-west-1.amazonaws.com", "tags" : [ "fips" ] } ] } @@ -22551,6 +23672,24 @@ } } }, + "qbusiness" : { + "defaults" : { + "dnsSuffix" : "api.aws", + "variants" : [ { + "dnsSuffix" : "api.aws", + "hostname" : "{service}-fips.{region}.{dnsSuffix}", + "tags" : [ "fips" ] + } ] + }, + "endpoints" : { + "us-gov-east-1" : { + "hostname" : "qbusiness.us-gov-east-1.api.aws" + }, + "us-gov-west-1" : { + "hostname" : "qbusiness.us-gov-west-1.api.aws" + } + } + }, "quicksight" : { "endpoints" : { "api" : { }, @@ -22725,6 +23864,36 @@ } } }, + "resiliencehub" : { + "endpoints" : { + "fips-us-gov-east-1" : { + "credentialScope" : { + "region" : "us-gov-east-1" + }, + "deprecated" : true, + "hostname" : "resiliencehub-fips.us-gov-east-1.amazonaws.com" + }, + "fips-us-gov-west-1" : { + "credentialScope" : { + "region" : "us-gov-west-1" + }, + "deprecated" : true, + "hostname" : "resiliencehub-fips.us-gov-west-1.amazonaws.com" + }, + "us-gov-east-1" : { + "variants" : [ { + "hostname" : "resiliencehub-fips.us-gov-east-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-gov-west-1" : { + "variants" : [ { + "hostname" : "resiliencehub-fips.us-gov-west-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + } + } + }, "resource-explorer-2" : { "defaults" : { "dnsSuffix" : "api.aws", @@ -22784,6 +23953,12 @@ "us-gov-west-1" : { } } }, + "rolesanywhere" : { + "endpoints" : { + "us-gov-east-1" : { }, + "us-gov-west-1" : { } + } + }, "route53" : { "endpoints" : { "aws-us-gov-global" : { @@ -23178,13 +24353,13 @@ }, "us-gov-east-1" : { "variants" : [ { - "hostname" : "servicediscovery-fips.us-gov-east-1.amazonaws.com", - "tags" : [ "dualstack", "fips" ] - }, { "hostname" : "servicediscovery-fips.us-gov-east-1.amazonaws.com", "tags" : [ "fips" ] }, { - "hostname" : "servicediscovery.us-gov-east-1.amazonaws.com", + "hostname" : "servicediscovery-fips.us-gov-east-1.api.aws", + "tags" : [ "dualstack", "fips" ] + }, { + "hostname" : "servicediscovery.us-gov-east-1.api.aws", "tags" : [ "dualstack" ] } ] }, @@ -23197,13 +24372,13 @@ }, "us-gov-west-1" : { "variants" : [ { - "hostname" : "servicediscovery-fips.us-gov-west-1.amazonaws.com", - "tags" : [ "dualstack", "fips" ] - }, { "hostname" : "servicediscovery-fips.us-gov-west-1.amazonaws.com", "tags" : [ "fips" ] }, { - "hostname" : "servicediscovery.us-gov-west-1.amazonaws.com", + "hostname" : "servicediscovery-fips.us-gov-west-1.api.aws", + "tags" : [ "dualstack", "fips" ] + }, { + "hostname" : "servicediscovery.us-gov-west-1.api.aws", "tags" : [ "dualstack" ] } ] }, @@ -23255,8 +24430,32 @@ }, "simspaceweaver" : { "endpoints" : { - "us-gov-east-1" : { }, - "us-gov-west-1" : { } + "fips-us-gov-east-1" : { + "credentialScope" : { + "region" : "us-gov-east-1" + }, + "deprecated" : true, + "hostname" : "simspaceweaver.us-gov-east-1.amazonaws.com" + }, + "fips-us-gov-west-1" : { + "credentialScope" : { + "region" : "us-gov-west-1" + }, + "deprecated" : true, + "hostname" : "simspaceweaver.us-gov-west-1.amazonaws.com" + }, + "us-gov-east-1" : { + "variants" : [ { + "hostname" : "simspaceweaver.us-gov-east-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-gov-west-1" : { + "variants" : [ { + "hostname" : "simspaceweaver.us-gov-west-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + } } }, "sms" : { @@ -23420,12 +24619,34 @@ "credentialScope" : { "region" : "us-gov-east-1" }, + "hostname" : "sso.us-gov-east-1.amazonaws.com", + "variants" : [ { + "hostname" : "sso.us-gov-east-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-gov-east-1-fips" : { + "credentialScope" : { + "region" : "us-gov-east-1" + }, + "deprecated" : true, "hostname" : "sso.us-gov-east-1.amazonaws.com" }, "us-gov-west-1" : { "credentialScope" : { "region" : "us-gov-west-1" }, + "hostname" : "sso.us-gov-west-1.amazonaws.com", + "variants" : [ { + "hostname" : "sso.us-gov-west-1.amazonaws.com", + "tags" : [ "fips" ] + } ] + }, + "us-gov-west-1-fips" : { + "credentialScope" : { + "region" : "us-gov-west-1" + }, + "deprecated" : true, "hostname" : "sso.us-gov-west-1.amazonaws.com" } } @@ -24067,6 +25288,23 @@ "us-iso-east-1" : { } } }, + "datasync" : { + "endpoints" : { + "fips-us-iso-west-1" : { + "credentialScope" : { + "region" : "us-iso-west-1" + }, + "deprecated" : true, + "hostname" : "datasync-fips.us-iso-west-1.c2s.ic.gov" + }, + "us-iso-west-1" : { + "variants" : [ { + "hostname" : "datasync-fips.us-iso-west-1.c2s.ic.gov", + "tags" : [ "fips" ] + } ] + } + } + }, "directconnect" : { "endpoints" : { "us-iso-east-1" : { }, @@ -24148,7 +25386,8 @@ }, "ebs" : { "endpoints" : { - "us-iso-east-1" : { } + "us-iso-east-1" : { }, + "us-iso-west-1" : { } } }, "ec2" : { @@ -24168,7 +25407,8 @@ "protocols" : [ "http", "https" ] }, "endpoints" : { - "us-iso-east-1" : { } + "us-iso-east-1" : { }, + "us-iso-west-1" : { } } }, "elasticache" : { @@ -24217,10 +25457,33 @@ }, "elasticmapreduce" : { "endpoints" : { + "fips-us-iso-east-1" : { + "credentialScope" : { + "region" : "us-iso-east-1" + }, + "deprecated" : true, + "hostname" : "elasticmapreduce.us-iso-east-1.c2s.ic.gov" + }, + "fips-us-iso-west-1" : { + "credentialScope" : { + "region" : "us-iso-west-1" + }, + "deprecated" : true, + "hostname" : "elasticmapreduce.us-iso-west-1.c2s.ic.gov" + }, "us-iso-east-1" : { - "protocols" : [ "https" ] + "protocols" : [ "https" ], + "variants" : [ { + "hostname" : "elasticmapreduce.us-iso-east-1.c2s.ic.gov", + "tags" : [ "fips" ] + } ] }, - "us-iso-west-1" : { } + "us-iso-west-1" : { + "variants" : [ { + "hostname" : "elasticmapreduce.us-iso-west-1.c2s.ic.gov", + "tags" : [ "fips" ] + } ] + } } }, "es" : { @@ -24395,12 +25658,76 @@ } }, "rds" : { + "endpoints" : { + "rds-fips.us-iso-east-1" : { + "credentialScope" : { + "region" : "us-iso-east-1" + }, + "deprecated" : true, + "hostname" : "rds-fips.us-iso-east-1.c2s.ic.gov" + }, + "rds-fips.us-iso-west-1" : { + "credentialScope" : { + "region" : "us-iso-west-1" + }, + "deprecated" : true, + "hostname" : "rds-fips.us-iso-west-1.c2s.ic.gov" + }, + "rds.us-iso-east-1" : { + "credentialScope" : { + "region" : "us-iso-east-1" + }, + "deprecated" : true, + "variants" : [ { + "hostname" : "rds-fips.us-iso-east-1.c2s.ic.gov", + "tags" : [ "fips" ] + } ] + }, + "rds.us-iso-west-1" : { + "credentialScope" : { + "region" : "us-iso-west-1" + }, + "deprecated" : true, + "variants" : [ { + "hostname" : "rds-fips.us-iso-west-1.c2s.ic.gov", + "tags" : [ "fips" ] + } ] + }, + "us-iso-east-1" : { + "variants" : [ { + "hostname" : "rds-fips.us-iso-east-1.c2s.ic.gov", + "tags" : [ "fips" ] + } ] + }, + "us-iso-east-1-fips" : { + "credentialScope" : { + "region" : "us-iso-east-1" + }, + "deprecated" : true, + "hostname" : "rds-fips.us-iso-east-1.c2s.ic.gov" + }, + "us-iso-west-1" : { + "variants" : [ { + "hostname" : "rds-fips.us-iso-west-1.c2s.ic.gov", + "tags" : [ "fips" ] + } ] + }, + "us-iso-west-1-fips" : { + "credentialScope" : { + "region" : "us-iso-west-1" + }, + "deprecated" : true, + "hostname" : "rds-fips.us-iso-west-1.c2s.ic.gov" + } + } + }, + "redshift" : { "endpoints" : { "us-iso-east-1" : { }, "us-iso-west-1" : { } } }, - "redshift" : { + "resource-groups" : { "endpoints" : { "us-iso-east-1" : { }, "us-iso-west-1" : { } @@ -24585,6 +25912,11 @@ } } }, + "api.sagemaker" : { + "endpoints" : { + "us-isob-east-1" : { } + } + }, "appconfig" : { "endpoints" : { "us-isob-east-1" : { } @@ -24611,6 +25943,11 @@ "us-isob-east-1" : { } } }, + "cloudcontrolapi" : { + "endpoints" : { + "us-isob-east-1" : { } + } + }, "cloudformation" : { "endpoints" : { "us-isob-east-1" : { } @@ -24751,7 +26088,19 @@ }, "elasticmapreduce" : { "endpoints" : { - "us-isob-east-1" : { } + "fips-us-isob-east-1" : { + "credentialScope" : { + "region" : "us-isob-east-1" + }, + "deprecated" : true, + "hostname" : "elasticmapreduce.us-isob-east-1.sc2s.sgov.gov" + }, + "us-isob-east-1" : { + "variants" : [ { + "hostname" : "elasticmapreduce.us-isob-east-1.sc2s.sgov.gov", + "tags" : [ "fips" ] + } ] + } } }, "es" : { @@ -24850,6 +26199,11 @@ "us-isob-east-1" : { } } }, + "outposts" : { + "endpoints" : { + "us-isob-east-1" : { } + } + }, "ram" : { "endpoints" : { "us-isob-east-1" : { } @@ -24874,7 +26228,36 @@ }, "rds" : { "endpoints" : { - "us-isob-east-1" : { } + "rds-fips.us-isob-east-1" : { + "credentialScope" : { + "region" : "us-isob-east-1" + }, + "deprecated" : true, + "hostname" : "rds-fips.us-isob-east-1.sc2s.sgov.gov" + }, + "rds.us-isob-east-1" : { + "credentialScope" : { + "region" : "us-isob-east-1" + }, + "deprecated" : true, + "variants" : [ { + "hostname" : "rds-fips.us-isob-east-1.sc2s.sgov.gov", + "tags" : [ "fips" ] + } ] + }, + "us-isob-east-1" : { + "variants" : [ { + "hostname" : "rds-fips.us-isob-east-1.sc2s.sgov.gov", + "tags" : [ "fips" ] + } ] + }, + "us-isob-east-1-fips" : { + "credentialScope" : { + "region" : "us-isob-east-1" + }, + "deprecated" : true, + "hostname" : "rds-fips.us-isob-east-1.sc2s.sgov.gov" + } } }, "redshift" : { @@ -24904,6 +26287,11 @@ "us-isob-east-1" : { } } }, + "runtime.sagemaker" : { + "endpoints" : { + "us-isob-east-1" : { } + } + }, "s3" : { "defaults" : { "protocols" : [ "http", "https" ], diff --git a/aws/sdk/aws-models/sdk-partitions.json b/aws/sdk/aws-models/sdk-partitions.json new file mode 100644 index 00000000000..b3e964aac2a --- /dev/null +++ b/aws/sdk/aws-models/sdk-partitions.json @@ -0,0 +1,213 @@ +{ + "partitions" : [ { + "id" : "aws", + "outputs" : { + "dnsSuffix" : "amazonaws.com", + "dualStackDnsSuffix" : "api.aws", + "implicitGlobalRegion" : "us-east-1", + "name" : "aws", + "supportsDualStack" : true, + "supportsFIPS" : true + }, + "regionRegex" : "^(us|eu|ap|sa|ca|me|af|il)\\-\\w+\\-\\d+$", + "regions" : { + "af-south-1" : { + "description" : "Africa (Cape Town)" + }, + "ap-east-1" : { + "description" : "Asia Pacific (Hong Kong)" + }, + "ap-northeast-1" : { + "description" : "Asia Pacific (Tokyo)" + }, + "ap-northeast-2" : { + "description" : "Asia Pacific (Seoul)" + }, + "ap-northeast-3" : { + "description" : "Asia Pacific (Osaka)" + }, + "ap-south-1" : { + "description" : "Asia Pacific (Mumbai)" + }, + "ap-south-2" : { + "description" : "Asia Pacific (Hyderabad)" + }, + "ap-southeast-1" : { + "description" : "Asia Pacific (Singapore)" + }, + "ap-southeast-2" : { + "description" : "Asia Pacific (Sydney)" + }, + "ap-southeast-3" : { + "description" : "Asia Pacific (Jakarta)" + }, + "ap-southeast-4" : { + "description" : "Asia Pacific (Melbourne)" + }, + "aws-global" : { + "description" : "AWS Standard global region" + }, + "ca-central-1" : { + "description" : "Canada (Central)" + }, + "eu-central-1" : { + "description" : "Europe (Frankfurt)" + }, + "eu-central-2" : { + "description" : "Europe (Zurich)" + }, + "eu-north-1" : { + "description" : "Europe (Stockholm)" + }, + "eu-south-1" : { + "description" : "Europe (Milan)" + }, + "eu-south-2" : { + "description" : "Europe (Spain)" + }, + "eu-west-1" : { + "description" : "Europe (Ireland)" + }, + "eu-west-2" : { + "description" : "Europe (London)" + }, + "eu-west-3" : { + "description" : "Europe (Paris)" + }, + "il-central-1" : { + "description" : "Israel (Tel Aviv)" + }, + "me-central-1" : { + "description" : "Middle East (UAE)" + }, + "me-south-1" : { + "description" : "Middle East (Bahrain)" + }, + "sa-east-1" : { + "description" : "South America (Sao Paulo)" + }, + "us-east-1" : { + "description" : "US East (N. Virginia)" + }, + "us-east-2" : { + "description" : "US East (Ohio)" + }, + "us-west-1" : { + "description" : "US West (N. California)" + }, + "us-west-2" : { + "description" : "US West (Oregon)" + } + } + }, { + "id" : "aws-cn", + "outputs" : { + "dnsSuffix" : "amazonaws.com.cn", + "dualStackDnsSuffix" : "api.amazonwebservices.com.cn", + "implicitGlobalRegion" : "cn-northwest-1", + "name" : "aws-cn", + "supportsDualStack" : true, + "supportsFIPS" : true + }, + "regionRegex" : "^cn\\-\\w+\\-\\d+$", + "regions" : { + "aws-cn-global" : { + "description" : "AWS China global region" + }, + "cn-north-1" : { + "description" : "China (Beijing)" + }, + "cn-northwest-1" : { + "description" : "China (Ningxia)" + } + } + }, { + "id" : "aws-us-gov", + "outputs" : { + "dnsSuffix" : "amazonaws.com", + "dualStackDnsSuffix" : "api.aws", + "implicitGlobalRegion" : "us-gov-west-1", + "name" : "aws-us-gov", + "supportsDualStack" : true, + "supportsFIPS" : true + }, + "regionRegex" : "^us\\-gov\\-\\w+\\-\\d+$", + "regions" : { + "aws-us-gov-global" : { + "description" : "AWS GovCloud (US) global region" + }, + "us-gov-east-1" : { + "description" : "AWS GovCloud (US-East)" + }, + "us-gov-west-1" : { + "description" : "AWS GovCloud (US-West)" + } + } + }, { + "id" : "aws-iso", + "outputs" : { + "dnsSuffix" : "c2s.ic.gov", + "dualStackDnsSuffix" : "c2s.ic.gov", + "implicitGlobalRegion" : "us-iso-east-1", + "name" : "aws-iso", + "supportsDualStack" : false, + "supportsFIPS" : true + }, + "regionRegex" : "^us\\-iso\\-\\w+\\-\\d+$", + "regions" : { + "aws-iso-global" : { + "description" : "AWS ISO (US) global region" + }, + "us-iso-east-1" : { + "description" : "US ISO East" + }, + "us-iso-west-1" : { + "description" : "US ISO WEST" + } + } + }, { + "id" : "aws-iso-b", + "outputs" : { + "dnsSuffix" : "sc2s.sgov.gov", + "dualStackDnsSuffix" : "sc2s.sgov.gov", + "implicitGlobalRegion" : "us-isob-east-1", + "name" : "aws-iso-b", + "supportsDualStack" : false, + "supportsFIPS" : true + }, + "regionRegex" : "^us\\-isob\\-\\w+\\-\\d+$", + "regions" : { + "aws-iso-b-global" : { + "description" : "AWS ISOB (US) global region" + }, + "us-isob-east-1" : { + "description" : "US ISOB East (Ohio)" + } + } + }, { + "id" : "aws-iso-e", + "outputs" : { + "dnsSuffix" : "cloud.adc-e.uk", + "dualStackDnsSuffix" : "cloud.adc-e.uk", + "implicitGlobalRegion" : "eu-isoe-west-1", + "name" : "aws-iso-e", + "supportsDualStack" : false, + "supportsFIPS" : true + }, + "regionRegex" : "^eu\\-isoe\\-\\w+\\-\\d+$", + "regions" : { } + }, { + "id" : "aws-iso-f", + "outputs" : { + "dnsSuffix" : "csp.hci.ic.gov", + "dualStackDnsSuffix" : "csp.hci.ic.gov", + "implicitGlobalRegion" : "us-isof-south-1", + "name" : "aws-iso-f", + "supportsDualStack" : false, + "supportsFIPS" : true + }, + "regionRegex" : "^us\\-isof\\-\\w+\\-\\d+$", + "regions" : { } + } ], + "version" : "1.1" +} diff --git a/aws/sdk/aws-models/sso-oidc.json b/aws/sdk/aws-models/sso-oidc.json index 83a497aca3b..2974461fc06 100644 --- a/aws/sdk/aws-models/sso-oidc.json +++ b/aws/sdk/aws-models/sso-oidc.json @@ -36,6 +36,9 @@ { "target": "com.amazonaws.ssooidc#CreateToken" }, + { + "target": "com.amazonaws.ssooidc#CreateTokenWithIAM" + }, { "target": "com.amazonaws.ssooidc#RegisterClient" }, @@ -46,16 +49,16 @@ "traits": { "aws.api#service": { "sdkId": "SSO OIDC", - "arnNamespace": "awsssooidc", + "arnNamespace": "sso-oauth", "cloudFormationName": "SSOOIDC", "cloudTrailEventSource": "ssooidc.amazonaws.com", "endpointPrefix": "oidc" }, "aws.auth#sigv4": { - "name": "awsssooidc" + "name": "sso-oauth" }, "aws.protocols#restJson1": {}, - "smithy.api#documentation": "

AWS IAM Identity Center (successor to AWS Single Sign-On) OpenID Connect (OIDC) is a web service that enables a client (such as AWS CLI\n or a native application) to register with IAM Identity Center. The service also enables the client to\n fetch the user’s access token upon successful authentication and authorization with\n IAM Identity Center.

\n \n

Although AWS Single Sign-On was renamed, the sso and\n identitystore API namespaces will continue to retain their original name for\n backward compatibility purposes. For more information, see IAM Identity Center rename.

\n
\n

\n Considerations for Using This Guide\n

\n

Before you begin using this guide, we recommend that you first review the following\n important information about how the IAM Identity Center OIDC service works.

\n
    \n
  • \n

    The IAM Identity Center OIDC service currently implements only the portions of the OAuth 2.0\n Device Authorization Grant standard (https://tools.ietf.org/html/rfc8628) that are necessary to enable single\n sign-on authentication with the AWS CLI. Support for other OIDC flows frequently needed\n for native applications, such as Authorization Code Flow (+ PKCE), will be addressed in\n future releases.

    \n
  • \n
  • \n

    The service emits only OIDC access tokens, such that obtaining a new token (For\n example, token refresh) requires explicit user re-authentication.

    \n
  • \n
  • \n

    The access tokens provided by this service grant access to all AWS account\n entitlements assigned to an IAM Identity Center user, not just a particular application.

    \n
  • \n
  • \n

    The documentation in this guide does not describe the mechanism to convert the access\n token into AWS Auth (“sigv4”) credentials for use with IAM-protected AWS service\n endpoints. For more information, see GetRoleCredentials in the IAM Identity Center Portal API Reference\n Guide.

    \n
  • \n
\n

For general information about IAM Identity Center, see What is\n IAM Identity Center? in the IAM Identity Center User Guide.

", + "smithy.api#documentation": "

IAM Identity Center OpenID Connect (OIDC) is a web service that enables a client (such as CLI\n or a native application) to register with IAM Identity Center. The service also enables the client to\n fetch the user’s access token upon successful authentication and authorization with\n IAM Identity Center.

\n \n

IAM Identity Center uses the sso and identitystore API namespaces.

\n
\n

\n Considerations for Using This Guide\n

\n

Before you begin using this guide, we recommend that you first review the following\n important information about how the IAM Identity Center OIDC service works.

\n
    \n
  • \n

    The IAM Identity Center OIDC service currently implements only the portions of the OAuth 2.0 Device\n Authorization Grant standard (https://tools.ietf.org/html/rfc8628) that are necessary to enable single\n sign-on authentication with the CLI.

    \n
  • \n
  • \n

    With older versions of the CLI, the service only emits OIDC access tokens, so to\n obtain a new token, users must explicitly re-authenticate. To access the OIDC flow that\n supports token refresh and doesn’t require re-authentication, update to the latest CLI\n version (1.27.10 for CLI V1 and 2.9.0 for CLI V2) with support for OIDC token refresh and\n configurable IAM Identity Center session durations. For more information, see Configure Amazon Web Services access portal session duration .

    \n
  • \n
  • \n

    The access tokens provided by this service grant access to all Amazon Web Services account\n entitlements assigned to an IAM Identity Center user, not just a particular application.

    \n
  • \n
  • \n

    The documentation in this guide does not describe the mechanism to convert the access\n token into Amazon Web Services Auth (“sigv4”) credentials for use with IAM-protected Amazon Web Services service\n endpoints. For more information, see GetRoleCredentials in the IAM Identity Center Portal API Reference\n Guide.

    \n
  • \n
\n

For general information about IAM Identity Center, see What is\n IAM Identity Center? in the IAM Identity Center User Guide.

", "smithy.api#title": "AWS SSO OIDC", "smithy.rules#endpointRuleSet": { "version": "1.0", @@ -963,10 +966,16 @@ "type": "structure", "members": { "error": { - "target": "com.amazonaws.ssooidc#Error" + "target": "com.amazonaws.ssooidc#Error", + "traits": { + "smithy.api#documentation": "

Single error code.\n For this exception the value will be access_denied.

" + } }, "error_description": { - "target": "com.amazonaws.ssooidc#ErrorDescription" + "target": "com.amazonaws.ssooidc#ErrorDescription", + "traits": { + "smithy.api#documentation": "

Human-readable text providing additional information, used to assist the\n client developer in understanding the error that occurred.

" + } } }, "traits": { @@ -976,7 +985,16 @@ } }, "com.amazonaws.ssooidc#AccessToken": { - "type": "string" + "type": "string", + "traits": { + "smithy.api#sensitive": {} + } + }, + "com.amazonaws.ssooidc#Assertion": { + "type": "string", + "traits": { + "smithy.api#sensitive": {} + } }, "com.amazonaws.ssooidc#AuthCode": { "type": "string" @@ -985,10 +1003,16 @@ "type": "structure", "members": { "error": { - "target": "com.amazonaws.ssooidc#Error" + "target": "com.amazonaws.ssooidc#Error", + "traits": { + "smithy.api#documentation": "

Single error code.\n For this exception the value will be authorization_pending.

" + } }, "error_description": { - "target": "com.amazonaws.ssooidc#ErrorDescription" + "target": "com.amazonaws.ssooidc#ErrorDescription", + "traits": { + "smithy.api#documentation": "

Human-readable text providing additional information, used to assist the\n client developer in understanding the error that occurred.

" + } } }, "traits": { @@ -1004,7 +1028,10 @@ "type": "string" }, "com.amazonaws.ssooidc#ClientSecret": { - "type": "string" + "type": "string", + "traits": { + "smithy.api#sensitive": {} + } }, "com.amazonaws.ssooidc#ClientType": { "type": "string" @@ -1054,7 +1081,25 @@ ], "traits": { "smithy.api#auth": [], - "smithy.api#documentation": "

Creates and returns an access token for the authorized client. The access token issued\n will be used to fetch short-term credentials for the assigned roles in the AWS\n account.

", + "smithy.api#documentation": "

Creates and returns access and refresh tokens for clients that are authenticated using\n client secrets. The access token can be used to fetch short-term credentials for the assigned\n AWS accounts or to access application APIs using bearer authentication.

", + "smithy.api#examples": [ + { + "title": "Call OAuth/OIDC /token endpoint for Device Code grant with Secret authentication", + "documentation": "", + "input": { + "clientId": "_yzkThXVzLWVhc3QtMQEXAMPLECLIENTID", + "clientSecret": "VERYLONGSECRETeyJraWQiOiJrZXktMTU2NDAyODA5OSIsImFsZyI6IkhTMzg0In0", + "grantType": "urn:ietf:params:oauth:grant-type:device-code", + "deviceCode": "yJraWQiOiJrZXktMTU2Njk2ODA4OCIsImFsZyI6IkhTMzIn0EXAMPLEDEVICECODE" + }, + "output": { + "accessToken": "aoal-YigITUDiNX1xZwOMXM5MxOWDL0E0jg9P6_C_jKQPxS_SKCP6f0kh1Up4g7TtvQqkMnD-GJiU_S1gvug6SrggAkc0:MGYCMQD3IatVjV7jAJU91kK3PkS/SfA2wtgWzOgZWDOR7sDGN9t0phCZz5It/aes/3C1Zj0CMQCKWOgRaiz6AIhza3DSXQNMLjRKXC8F8ceCsHlgYLMZ7hZidEXAMPLEACCESSTOKEN", + "tokenType": "Bearer", + "expiresIn": 1579729529, + "refreshToken": "aorvJYubGpU6i91YnH7Mfo-AT2fIVa1zCfA_Rvq9yjVKIP3onFmmykuQ7E93y2I-9Nyj-A_sVvMufaLNL0bqnDRtgAkc0:MGUCMFrRsktMRVlWaOR70XGMFGLL0SlcCw4DiYveIiOVx1uK9BbD0gvAddsW3UTLozXKMgIxAJ3qxUvjpnlLIOaaKOoa/FuNgqJVvr9GMwDtnAtlh9iZzAkEXAMPLEREFRESHTOKEN" + } + } + ], "smithy.api#http": { "method": "POST", "uri": "/token", @@ -1069,7 +1114,7 @@ "clientId": { "target": "com.amazonaws.ssooidc#ClientId", "traits": { - "smithy.api#documentation": "

The unique identifier string for each client. This value should come from the persisted\n result of the RegisterClient API.

", + "smithy.api#documentation": "

The unique identifier string for the client or application. This value comes from the\n result of the RegisterClient API.

", "smithy.api#required": {} } }, @@ -1083,38 +1128,38 @@ "grantType": { "target": "com.amazonaws.ssooidc#GrantType", "traits": { - "smithy.api#documentation": "

Supports grant types for the authorization code, refresh token, and device code request.\n For device code requests, specify the following value:

\n

\n urn:ietf:params:oauth:grant-type:device_code\n \n

\n

For information about how to obtain the device code, see the StartDeviceAuthorization topic.

", + "smithy.api#documentation": "

Supports the following OAuth grant types: Device Code and Refresh Token.\n Specify either of the following values, depending on the grant type that you want:

\n

* Device Code - urn:ietf:params:oauth:grant-type:device_code\n

\n

* Refresh Token - refresh_token\n

\n

For information about how to obtain the device code, see the StartDeviceAuthorization topic.

", "smithy.api#required": {} } }, "deviceCode": { "target": "com.amazonaws.ssooidc#DeviceCode", "traits": { - "smithy.api#documentation": "

Used only when calling this API for the device code grant type. This short-term code is\n used to identify this authentication attempt. This should come from an in-memory reference to\n the result of the StartDeviceAuthorization API.

" + "smithy.api#documentation": "

Used only when calling this API for the Device Code grant type. This short-term code is\n used to identify this authorization request. This comes from the result of the\n StartDeviceAuthorization API.

" } }, "code": { "target": "com.amazonaws.ssooidc#AuthCode", "traits": { - "smithy.api#documentation": "

The authorization code received from the authorization service. This parameter is required\n to perform an authorization grant request to get access to a token.

" + "smithy.api#documentation": "

Used only when calling this API for the Authorization Code grant type. The short-term code is\n used to identify this authorization request. This grant type is currently unsupported for the\n CreateToken API.

" } }, "refreshToken": { "target": "com.amazonaws.ssooidc#RefreshToken", "traits": { - "smithy.api#documentation": "

Currently, refreshToken is not yet implemented and is not supported. For more\n information about the features and limitations of the current IAM Identity Center OIDC implementation,\n see Considerations for Using this Guide in the IAM Identity Center\n OIDC API Reference.

\n

The token used to obtain an access token in the event that the access token is invalid or\n expired.

" + "smithy.api#documentation": "

Used only when calling this API for the Refresh Token grant type. This token is used to\n refresh short-term tokens, such as the access token, that might expire.

\n

For more information about the features and limitations of the current IAM Identity Center OIDC\n implementation, see Considerations for Using this Guide in the IAM Identity Center\n OIDC API Reference.

" } }, "scope": { "target": "com.amazonaws.ssooidc#Scopes", "traits": { - "smithy.api#documentation": "

The list of scopes that is defined by the client. Upon authorization, this list is used to\n restrict permissions when granting an access token.

" + "smithy.api#documentation": "

The list of scopes for which authorization is requested. The access token that is issued\n is limited to the scopes that are granted. If this value is not specified, IAM Identity Center authorizes\n all scopes that are configured for the client during the call to\n RegisterClient.

" } }, "redirectUri": { "target": "com.amazonaws.ssooidc#URI", "traits": { - "smithy.api#documentation": "

The location of the application that will receive the authorization code. Users authorize\n the service to send the request to this location.

" + "smithy.api#documentation": "

Used only when calling this API for the Authorization Code grant type. This value specifies\n the location of the client or application that has registered to receive the authorization\n code.

" } } }, @@ -1128,13 +1173,207 @@ "accessToken": { "target": "com.amazonaws.ssooidc#AccessToken", "traits": { - "smithy.api#documentation": "

An opaque token to access IAM Identity Center resources assigned to a user.

" + "smithy.api#documentation": "

A bearer token to access AWS accounts and applications assigned to a user.

" + } + }, + "tokenType": { + "target": "com.amazonaws.ssooidc#TokenType", + "traits": { + "smithy.api#documentation": "

Used to notify the client that the returned token is an access token. The supported token\n type is Bearer.

" + } + }, + "expiresIn": { + "target": "com.amazonaws.ssooidc#ExpirationInSeconds", + "traits": { + "smithy.api#default": 0, + "smithy.api#documentation": "

Indicates the time in seconds when an access token will expire.

" + } + }, + "refreshToken": { + "target": "com.amazonaws.ssooidc#RefreshToken", + "traits": { + "smithy.api#documentation": "

A token that, if present, can be used to refresh a previously issued access token that\n might have expired.

\n

For more\n information about the features and limitations of the current IAM Identity Center OIDC implementation,\n see Considerations for Using this Guide in the IAM Identity Center\n OIDC API Reference.

" + } + }, + "idToken": { + "target": "com.amazonaws.ssooidc#IdToken", + "traits": { + "smithy.api#documentation": "

The idToken is not implemented or supported. For more information about the\n features and limitations of the current IAM Identity Center OIDC implementation, see Considerations\n for Using this Guide in the IAM Identity Center\n OIDC API Reference.

\n

A JSON Web Token (JWT) that identifies who is associated with the issued access token.\n

" + } + } + }, + "traits": { + "smithy.api#output": {} + } + }, + "com.amazonaws.ssooidc#CreateTokenWithIAM": { + "type": "operation", + "input": { + "target": "com.amazonaws.ssooidc#CreateTokenWithIAMRequest" + }, + "output": { + "target": "com.amazonaws.ssooidc#CreateTokenWithIAMResponse" + }, + "errors": [ + { + "target": "com.amazonaws.ssooidc#AccessDeniedException" + }, + { + "target": "com.amazonaws.ssooidc#AuthorizationPendingException" + }, + { + "target": "com.amazonaws.ssooidc#ExpiredTokenException" + }, + { + "target": "com.amazonaws.ssooidc#InternalServerException" + }, + { + "target": "com.amazonaws.ssooidc#InvalidClientException" + }, + { + "target": "com.amazonaws.ssooidc#InvalidGrantException" + }, + { + "target": "com.amazonaws.ssooidc#InvalidRequestException" + }, + { + "target": "com.amazonaws.ssooidc#InvalidRequestRegionException" + }, + { + "target": "com.amazonaws.ssooidc#InvalidScopeException" + }, + { + "target": "com.amazonaws.ssooidc#SlowDownException" + }, + { + "target": "com.amazonaws.ssooidc#UnauthorizedClientException" + }, + { + "target": "com.amazonaws.ssooidc#UnsupportedGrantTypeException" + } + ], + "traits": { + "smithy.api#documentation": "

Creates and returns access and refresh tokens for clients and applications that are\n authenticated using IAM entities. The access token can be used to fetch short-term credentials\n for the assigned AWS accounts or to access application APIs using bearer\n authentication.

", + "smithy.api#examples": [ + { + "title": "Call OAuth/OIDC /token endpoint for Authorization Code grant with IAM authentication", + "documentation": "", + "input": { + "clientId": "arn:aws:sso::123456789012:application/ssoins-111111111111/apl-222222222222", + "grantType": "authorization_code", + "code": "yJraWQiOiJrZXktMTU2Njk2ODA4OCIsImFsZyI6IkhTMzg0In0EXAMPLEAUTHCODE", + "redirectUri": "https://mywebapp.example/redirect", + "scope": [ + "openid", + "aws", + "sts:identity_context" + ] + }, + "output": { + "accessToken": "aoal-YigITUDiNX1xZwOMXM5MxOWDL0E0jg9P6_C_jKQPxS_SKCP6f0kh1Up4g7TtvQqkMnD-GJiU_S1gvug6SrggAkc0:MGYCMQD3IatVjV7jAJU91kK3PkS/SfA2wtgWzOgZWDOR7sDGN9t0phCZz5It/aes/3C1Zj0CMQCKWOgRaiz6AIhza3DSXQNMLjRKXC8F8ceCsHlgYLMZ7hZidEXAMPLEACCESSTOKEN", + "tokenType": "Bearer", + "expiresIn": 1579729529, + "refreshToken": "aorvJYubGpU6i91YnH7Mfo-AT2fIVa1zCfA_Rvq9yjVKIP3onFmmykuQ7E93y2I-9Nyj-A_sVvMufaLNL0bqnDRtgAkc0:MGUCMFrRsktMRVlWaOR70XGMFGLL0SlcCw4DiYveIiOVx1uK9BbD0gvAddsW3UTLozXKMgIxAJ3qxUvjpnlLIOaaKOoa/FuNgqJVvr9GMwDtnAtlh9iZzAkEXAMPLEREFRESHTOKEN", + "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhd3M6aWRlbnRpdHlfc3RvcmVfaWQiOiJkLTMzMzMzMzMzMzMiLCJzdWIiOiI3MzA0NDhmMi1lMGExLTcwYTctYzk1NC0wMDAwMDAwMDAwMDAiLCJhd3M6aW5zdGFuY2VfYWNjb3VudCI6IjExMTExMTExMTExMSIsInN0czppZGVudGl0eV9jb250ZXh0IjoiRVhBTVBMRUlERU5USVRZQ09OVEVYVCIsInN0czphdWRpdF9jb250ZXh0IjoiRVhBTVBMRUFVRElUQ09OVEVYVCIsImlzcyI6Imh0dHBzOi8vaWRlbnRpdHljZW50ZXIuYW1hem9uYXdzLmNvbS9zc29pbnMtMTExMTExMTExMTExIiwiYXdzOmlkZW50aXR5X3N0b3JlX2FybiI6ImFybjphd3M6aWRlbnRpdHlzdG9yZTo6MTExMTExMTExMTExOmlkZW50aXR5c3RvcmUvZC0zMzMzMzMzMzMzIiwiYXVkIjoiYXJuOmF3czpzc286OjEyMzQ1Njc4OTAxMjphcHBsaWNhdGlvbi9zc29pbnMtMTExMTExMTExMTExL2FwbC0yMjIyMjIyMjIyMjIiLCJhd3M6aW5zdGFuY2VfYXJuIjoiYXJuOmF3czpzc286OjppbnN0YW5jZS9zc29pbnMtMTExMTExMTExMTExIiwiYXdzOmNyZWRlbnRpYWxfaWQiOiJfWlIyTjZhVkJqMjdGUEtheWpfcEtwVjc3QVBERl80MXB4ZXRfWWpJdUpONlVJR2RBdkpFWEFNUExFQ1JFRElEIiwiYXV0aF90aW1lIjoiMjAyMC0wMS0yMlQxMjo0NToyOVoiLCJleHAiOjE1Nzk3Mjk1MjksImlhdCI6MTU3OTcyNTkyOX0.Xyah6qbk78qThzJ41iFU2yfGuRqqtKXHrJYwQ8L9Ip0", + "issuedTokenType": "urn:ietf:params:oauth:token-type:refresh_token", + "scope": [ + "openid", + "aws", + "sts:identity_context" + ] + } + } + ], + "smithy.api#http": { + "method": "POST", + "uri": "/token?aws_iam=t", + "code": 200 + } + } + }, + "com.amazonaws.ssooidc#CreateTokenWithIAMRequest": { + "type": "structure", + "members": { + "clientId": { + "target": "com.amazonaws.ssooidc#ClientId", + "traits": { + "smithy.api#documentation": "

The unique identifier string for the client or application. This value is an application\n ARN that has OAuth grants configured.

", + "smithy.api#required": {} + } + }, + "grantType": { + "target": "com.amazonaws.ssooidc#GrantType", + "traits": { + "smithy.api#documentation": "

Supports the following OAuth grant types: Authorization Code, Refresh Token, JWT Bearer,\n and Token Exchange. Specify one of the following values, depending on the grant type that you\n want:

\n

* Authorization Code - authorization_code\n

\n

* Refresh Token - refresh_token\n

\n

* JWT Bearer - urn:ietf:params:oauth:grant-type:jwt-bearer\n

\n

* Token Exchange - urn:ietf:params:oauth:grant-type:token-exchange\n

", + "smithy.api#required": {} + } + }, + "code": { + "target": "com.amazonaws.ssooidc#AuthCode", + "traits": { + "smithy.api#documentation": "

Used only when calling this API for the Authorization Code grant type. This short-term\n code is used to identify this authorization request. The code is obtained through a redirect\n from IAM Identity Center to a redirect URI persisted in the Authorization Code GrantOptions for the\n application.

" + } + }, + "refreshToken": { + "target": "com.amazonaws.ssooidc#RefreshToken", + "traits": { + "smithy.api#documentation": "

Used only when calling this API for the Refresh Token grant type. This token is used to\n refresh short-term tokens, such as the access token, that might expire.

\n

For more information about the features and limitations of the current IAM Identity Center OIDC\n implementation, see Considerations for Using this Guide in the IAM Identity Center\n OIDC API Reference.

" + } + }, + "assertion": { + "target": "com.amazonaws.ssooidc#Assertion", + "traits": { + "smithy.api#documentation": "

Used only when calling this API for the JWT Bearer grant type. This value specifies the JSON\n Web Token (JWT) issued by a trusted token issuer. To authorize a trusted token issuer,\n configure the JWT Bearer GrantOptions for the application.

" + } + }, + "scope": { + "target": "com.amazonaws.ssooidc#Scopes", + "traits": { + "smithy.api#documentation": "

The list of scopes for which authorization is requested. The access token that is issued\n is limited to the scopes that are granted. If the value is not specified, IAM Identity Center authorizes all\n scopes configured for the application, including the following default scopes:\n openid, aws, sts:identity_context.

" + } + }, + "redirectUri": { + "target": "com.amazonaws.ssooidc#URI", + "traits": { + "smithy.api#documentation": "

Used only when calling this API for the Authorization Code grant type. This value specifies\n the location of the client or application that has registered to receive the authorization code.\n

" + } + }, + "subjectToken": { + "target": "com.amazonaws.ssooidc#SubjectToken", + "traits": { + "smithy.api#documentation": "

Used only when calling this API for the Token Exchange grant type. This value specifies\n the subject of the exchange. The value of the subject token must be an access token issued by\n IAM Identity Center to a different client or application. The access token must have authorized scopes\n that indicate the requested application as a target audience.

" + } + }, + "subjectTokenType": { + "target": "com.amazonaws.ssooidc#TokenTypeURI", + "traits": { + "smithy.api#documentation": "

Used only when calling this API for the Token Exchange grant type. This value specifies\n the type of token that is passed as the subject of the exchange. The following value is\n supported:

\n

* Access Token - urn:ietf:params:oauth:token-type:access_token\n

" + } + }, + "requestedTokenType": { + "target": "com.amazonaws.ssooidc#TokenTypeURI", + "traits": { + "smithy.api#documentation": "

Used only when calling this API for the Token Exchange grant type. This value specifies\n the type of token that the requester can receive. The following values are supported:

\n

* Access Token - urn:ietf:params:oauth:token-type:access_token\n

\n

* Refresh Token - urn:ietf:params:oauth:token-type:refresh_token\n

" + } + } + }, + "traits": { + "smithy.api#input": {} + } + }, + "com.amazonaws.ssooidc#CreateTokenWithIAMResponse": { + "type": "structure", + "members": { + "accessToken": { + "target": "com.amazonaws.ssooidc#AccessToken", + "traits": { + "smithy.api#documentation": "

A bearer token to access AWS accounts and applications assigned to a user.

" } }, "tokenType": { "target": "com.amazonaws.ssooidc#TokenType", "traits": { - "smithy.api#documentation": "

Used to notify the client that the returned token is an access token. The supported type\n is BearerToken.

" + "smithy.api#documentation": "

Used to notify the requester that the returned token is an access token. The supported\n token type is Bearer.

" } }, "expiresIn": { @@ -1147,13 +1386,25 @@ "refreshToken": { "target": "com.amazonaws.ssooidc#RefreshToken", "traits": { - "smithy.api#documentation": "

Currently, refreshToken is not yet implemented and is not supported. For more\n information about the features and limitations of the current IAM Identity Center OIDC implementation,\n see Considerations for Using this Guide in the IAM Identity Center\n OIDC API Reference.

\n

A token that, if present, can be used to refresh a previously issued access token that\n might have expired.

" + "smithy.api#documentation": "

A token that, if present, can be used to refresh a previously issued access token that\n might have expired.

\n

For more\n information about the features and limitations of the current IAM Identity Center OIDC implementation,\n see Considerations for Using this Guide in the IAM Identity Center\n OIDC API Reference.

" } }, "idToken": { "target": "com.amazonaws.ssooidc#IdToken", "traits": { - "smithy.api#documentation": "

Currently, idToken is not yet implemented and is not supported. For more\n information about the features and limitations of the current IAM Identity Center OIDC implementation,\n see Considerations for Using this Guide in the IAM Identity Center\n OIDC API Reference.

\n

The identifier of the user that associated with the access token, if present.

" + "smithy.api#documentation": "

A JSON Web Token (JWT) that identifies the user associated with the issued access token.\n

" + } + }, + "issuedTokenType": { + "target": "com.amazonaws.ssooidc#TokenTypeURI", + "traits": { + "smithy.api#documentation": "

Indicates the type of tokens that are issued by IAM Identity Center. The following values are supported:\n

\n

* Access Token - urn:ietf:params:oauth:token-type:access_token\n

\n

* Refresh Token - urn:ietf:params:oauth:token-type:refresh_token\n

" + } + }, + "scope": { + "target": "com.amazonaws.ssooidc#Scopes", + "traits": { + "smithy.api#documentation": "

The list of scopes for which authorization is granted. The access token that is issued\n is limited to the scopes that are granted.

" } } }, @@ -1180,10 +1431,16 @@ "type": "structure", "members": { "error": { - "target": "com.amazonaws.ssooidc#Error" + "target": "com.amazonaws.ssooidc#Error", + "traits": { + "smithy.api#documentation": "

Single error code.\n For this exception the value will be expired_token.

" + } }, "error_description": { - "target": "com.amazonaws.ssooidc#ErrorDescription" + "target": "com.amazonaws.ssooidc#ErrorDescription", + "traits": { + "smithy.api#documentation": "

Human-readable text providing additional information, used to assist the\n client developer in understanding the error that occurred.

" + } } }, "traits": { @@ -1196,16 +1453,25 @@ "type": "string" }, "com.amazonaws.ssooidc#IdToken": { - "type": "string" + "type": "string", + "traits": { + "smithy.api#sensitive": {} + } }, "com.amazonaws.ssooidc#InternalServerException": { "type": "structure", "members": { "error": { - "target": "com.amazonaws.ssooidc#Error" + "target": "com.amazonaws.ssooidc#Error", + "traits": { + "smithy.api#documentation": "

Single error code.\n For this exception the value will be server_error.

" + } }, "error_description": { - "target": "com.amazonaws.ssooidc#ErrorDescription" + "target": "com.amazonaws.ssooidc#ErrorDescription", + "traits": { + "smithy.api#documentation": "

Human-readable text providing additional information, used to assist the\n client developer in understanding the error that occurred.

" + } } }, "traits": { @@ -1224,10 +1490,16 @@ "type": "structure", "members": { "error": { - "target": "com.amazonaws.ssooidc#Error" + "target": "com.amazonaws.ssooidc#Error", + "traits": { + "smithy.api#documentation": "

Single error code.\n For this exception the value will be invalid_client.

" + } }, "error_description": { - "target": "com.amazonaws.ssooidc#ErrorDescription" + "target": "com.amazonaws.ssooidc#ErrorDescription", + "traits": { + "smithy.api#documentation": "

Human-readable text providing additional information, used to assist the\n client developer in understanding the error that occurred.

" + } } }, "traits": { @@ -1240,10 +1512,16 @@ "type": "structure", "members": { "error": { - "target": "com.amazonaws.ssooidc#Error" + "target": "com.amazonaws.ssooidc#Error", + "traits": { + "smithy.api#documentation": "

Single error code.\n For this exception the value will be invalid_client_metadata.

" + } }, "error_description": { - "target": "com.amazonaws.ssooidc#ErrorDescription" + "target": "com.amazonaws.ssooidc#ErrorDescription", + "traits": { + "smithy.api#documentation": "

Human-readable text providing additional information, used to assist the\n client developer in understanding the error that occurred.

" + } } }, "traits": { @@ -1256,10 +1534,16 @@ "type": "structure", "members": { "error": { - "target": "com.amazonaws.ssooidc#Error" + "target": "com.amazonaws.ssooidc#Error", + "traits": { + "smithy.api#documentation": "

Single error code.\n For this exception the value will be invalid_grant.

" + } }, "error_description": { - "target": "com.amazonaws.ssooidc#ErrorDescription" + "target": "com.amazonaws.ssooidc#ErrorDescription", + "traits": { + "smithy.api#documentation": "

Human-readable text providing additional information, used to assist the\n client developer in understanding the error that occurred.

" + } } }, "traits": { @@ -1272,10 +1556,16 @@ "type": "structure", "members": { "error": { - "target": "com.amazonaws.ssooidc#Error" + "target": "com.amazonaws.ssooidc#Error", + "traits": { + "smithy.api#documentation": "

Single error code.\n For this exception the value will be invalid_request.

" + } }, "error_description": { - "target": "com.amazonaws.ssooidc#ErrorDescription" + "target": "com.amazonaws.ssooidc#ErrorDescription", + "traits": { + "smithy.api#documentation": "

Human-readable text providing additional information, used to assist the\n client developer in understanding the error that occurred.

" + } } }, "traits": { @@ -1284,14 +1574,54 @@ "smithy.api#httpError": 400 } }, + "com.amazonaws.ssooidc#InvalidRequestRegionException": { + "type": "structure", + "members": { + "error": { + "target": "com.amazonaws.ssooidc#Error", + "traits": { + "smithy.api#documentation": "

Single error code.\n For this exception the value will be invalid_request.

" + } + }, + "error_description": { + "target": "com.amazonaws.ssooidc#ErrorDescription", + "traits": { + "smithy.api#documentation": "

Human-readable text providing additional information, used to assist the\n client developer in understanding the error that occurred.

" + } + }, + "endpoint": { + "target": "com.amazonaws.ssooidc#Location", + "traits": { + "smithy.api#documentation": "

Indicates the IAM Identity Center endpoint which the requester may call with this token.

" + } + }, + "region": { + "target": "com.amazonaws.ssooidc#Region", + "traits": { + "smithy.api#documentation": "

Indicates the region which the requester may call with this token.

" + } + } + }, + "traits": { + "smithy.api#documentation": "

Indicates that a token provided as input to the request was issued by and is only usable\n by calling IAM Identity Center endpoints in another region.

", + "smithy.api#error": "client", + "smithy.api#httpError": 400 + } + }, "com.amazonaws.ssooidc#InvalidScopeException": { "type": "structure", "members": { "error": { - "target": "com.amazonaws.ssooidc#Error" + "target": "com.amazonaws.ssooidc#Error", + "traits": { + "smithy.api#documentation": "

Single error code.\n For this exception the value will be invalid_scope.

" + } }, "error_description": { - "target": "com.amazonaws.ssooidc#ErrorDescription" + "target": "com.amazonaws.ssooidc#ErrorDescription", + "traits": { + "smithy.api#documentation": "

Human-readable text providing additional information, used to assist the\n client developer in understanding the error that occurred.

" + } } }, "traits": { @@ -1300,6 +1630,9 @@ "smithy.api#httpError": 400 } }, + "com.amazonaws.ssooidc#Location": { + "type": "string" + }, "com.amazonaws.ssooidc#LongTimeStampType": { "type": "long", "traits": { @@ -1307,6 +1640,12 @@ } }, "com.amazonaws.ssooidc#RefreshToken": { + "type": "string", + "traits": { + "smithy.api#sensitive": {} + } + }, + "com.amazonaws.ssooidc#Region": { "type": "string" }, "com.amazonaws.ssooidc#RegisterClient": { @@ -1334,6 +1673,26 @@ "traits": { "smithy.api#auth": [], "smithy.api#documentation": "

Registers a client with IAM Identity Center. This allows clients to initiate device authorization.\n The output should be persisted for reuse through many authentication requests.

", + "smithy.api#examples": [ + { + "title": "Call OAuth/OIDC /register-client endpoint", + "documentation": "", + "input": { + "clientName": "My IDE Plugin", + "clientType": "public", + "scopes": [ + "sso:account:access", + "codewhisperer:completions" + ] + }, + "output": { + "clientId": "_yzkThXVzLWVhc3QtMQEXAMPLECLIENTID", + "clientSecret": "VERYLONGSECRETeyJraWQiOiJrZXktMTU2NDAyODA5OSIsImFsZyI6IkhTMzg0In0", + "clientIdIssuedAt": 1579725929, + "clientSecretExpiresAt": 1587584729 + } + } + ], "smithy.api#http": { "method": "POST", "uri": "/client/register", @@ -1402,13 +1761,13 @@ "authorizationEndpoint": { "target": "com.amazonaws.ssooidc#URI", "traits": { - "smithy.api#documentation": "

The endpoint where the client can request authorization.

" + "smithy.api#documentation": "

An endpoint that the client can use to request authorization.

" } }, "tokenEndpoint": { "target": "com.amazonaws.ssooidc#URI", "traits": { - "smithy.api#documentation": "

The endpoint where the client can get an access token.

" + "smithy.api#documentation": "

An endpoint that the client can use to create tokens.

" } } }, @@ -1429,10 +1788,16 @@ "type": "structure", "members": { "error": { - "target": "com.amazonaws.ssooidc#Error" + "target": "com.amazonaws.ssooidc#Error", + "traits": { + "smithy.api#documentation": "

Single error code.\n For this exception the value will be slow_down.

" + } }, "error_description": { - "target": "com.amazonaws.ssooidc#ErrorDescription" + "target": "com.amazonaws.ssooidc#ErrorDescription", + "traits": { + "smithy.api#documentation": "

Human-readable text providing additional information, used to assist the\n client developer in understanding the error that occurred.

" + } } }, "traits": { @@ -1469,6 +1834,25 @@ "traits": { "smithy.api#auth": [], "smithy.api#documentation": "

Initiates device authorization by requesting a pair of verification codes from the\n authorization service.

", + "smithy.api#examples": [ + { + "title": "Call OAuth/OIDC /start-device-authorization endpoint", + "documentation": "", + "input": { + "clientId": "_yzkThXVzLWVhc3QtMQEXAMPLECLIENTID", + "clientSecret": "VERYLONGSECRETeyJraWQiOiJrZXktMTU2NDAyODA5OSIsImFsZyI6IkhTMzg0In0", + "startUrl": "https://identitycenter.amazonaws.com/ssoins-111111111111" + }, + "output": { + "deviceCode": "yJraWQiOiJrZXktMTU2Njk2ODA4OCIsImFsZyI6IkhTMzIn0EXAMPLEDEVICECODE", + "userCode": "makdfsk83yJraWQiOiJrZXktMTU2Njk2sImFsZyI6IkhTMzIn0EXAMPLEUSERCODE", + "verificationUri": "https://device.sso.us-west-2.amazonaws.com", + "verificationUriComplete": "https://device.sso.us-west-2.amazonaws.com?user_code=makdfsk83yJraWQiOiJrZXktMTU2Njk2sImFsZyI6IkhTMzIn0EXAMPLEUSERCODE", + "expiresIn": 1579729529, + "interval": 1 + } + } + ], "smithy.api#http": { "method": "POST", "uri": "/device_authorization", @@ -1497,7 +1881,7 @@ "startUrl": { "target": "com.amazonaws.ssooidc#URI", "traits": { - "smithy.api#documentation": "

The URL for the AWS access portal. For more information, see Using\n the AWS access portal in the IAM Identity Center User Guide.

", + "smithy.api#documentation": "

The URL for the Amazon Web Services access portal. For more information, see Using\n the Amazon Web Services access portal in the IAM Identity Center User Guide.

", "smithy.api#required": {} } } @@ -1552,9 +1936,18 @@ "smithy.api#output": {} } }, + "com.amazonaws.ssooidc#SubjectToken": { + "type": "string", + "traits": { + "smithy.api#sensitive": {} + } + }, "com.amazonaws.ssooidc#TokenType": { "type": "string" }, + "com.amazonaws.ssooidc#TokenTypeURI": { + "type": "string" + }, "com.amazonaws.ssooidc#URI": { "type": "string" }, @@ -1562,10 +1955,16 @@ "type": "structure", "members": { "error": { - "target": "com.amazonaws.ssooidc#Error" + "target": "com.amazonaws.ssooidc#Error", + "traits": { + "smithy.api#documentation": "

Single error code.\n For this exception the value will be unauthorized_client.

" + } }, "error_description": { - "target": "com.amazonaws.ssooidc#ErrorDescription" + "target": "com.amazonaws.ssooidc#ErrorDescription", + "traits": { + "smithy.api#documentation": "

Human-readable text providing additional information, used to assist the\n client developer in understanding the error that occurred.

" + } } }, "traits": { @@ -1578,10 +1977,16 @@ "type": "structure", "members": { "error": { - "target": "com.amazonaws.ssooidc#Error" + "target": "com.amazonaws.ssooidc#Error", + "traits": { + "smithy.api#documentation": "

Single error code.\n For this exception the value will be unsupported_grant_type.

" + } }, "error_description": { - "target": "com.amazonaws.ssooidc#ErrorDescription" + "target": "com.amazonaws.ssooidc#ErrorDescription", + "traits": { + "smithy.api#documentation": "

Human-readable text providing additional information, used to assist the\n client developer in understanding the error that occurred.

" + } } }, "traits": { diff --git a/aws/sdk/aws-models/sts.json b/aws/sdk/aws-models/sts.json index c9648e8cb23..eabc44ceb77 100644 --- a/aws/sdk/aws-models/sts.json +++ b/aws/sdk/aws-models/sts.json @@ -2389,7 +2389,7 @@ "ProvidedContexts": { "target": "com.amazonaws.sts#ProvidedContextsListType", "traits": { - "smithy.api#documentation": "

Reserved for future use.

" + "smithy.api#documentation": "

A list of previously acquired trusted context assertions in the format of a JSON array.\n The trusted context assertion is signed and encrypted by Amazon Web Services STS.

\n

The following is an example of a ProvidedContext value that includes a\n single trusted context assertion and the ARN of the context provider from which the trusted\n context assertion was generated.

\n

\n [{\"ProviderArn\":\"arn:aws:iam::aws:contextProvider/IdentityCenter\",\"ContextAssertion\":\"trusted-context-assertion\"}]\n

" } } }, @@ -3356,18 +3356,18 @@ "ProviderArn": { "target": "com.amazonaws.sts#arnType", "traits": { - "smithy.api#documentation": "

Reserved for future use.

" + "smithy.api#documentation": "

The context provider ARN from which the trusted context assertion was generated.

" } }, "ContextAssertion": { "target": "com.amazonaws.sts#contextAssertionType", "traits": { - "smithy.api#documentation": "

Reserved for future use.

" + "smithy.api#documentation": "

The signed and encrypted trusted context assertion generated by the context provider.\n The trusted context assertion is signed and encrypted by Amazon Web Services STS.

" } } }, "traits": { - "smithy.api#documentation": "

Reserved for future use.

" + "smithy.api#documentation": "

Contains information about the provided context. This includes the signed and encrypted\n trusted context assertion and the context provider ARN from which the trusted context\n assertion was generated.

" } }, "com.amazonaws.sts#ProvidedContextsListType": { diff --git a/aws/sdk/aws-models/transcribe-streaming.json b/aws/sdk/aws-models/transcribe-streaming.json index d8b9be6cf8c..aba0f389cca 100644 --- a/aws/sdk/aws-models/transcribe-streaming.json +++ b/aws/sdk/aws-models/transcribe-streaming.json @@ -1890,7 +1890,7 @@ } ], "traits": { - "smithy.api#documentation": "

Starts a bidirectional HTTP/2 or WebSocket stream where audio is streamed to \n Amazon Transcribe and the transcription results are streamed to your application.

\n

The following parameters are required:

\n
    \n
  • \n

    \n language-code or identify-language\n

    \n
  • \n
  • \n

    \n media-encoding\n

    \n
  • \n
  • \n

    \n sample-rate\n

    \n
  • \n
\n

For more information on streaming with Amazon Transcribe, see Transcribing streaming audio.

", + "smithy.api#documentation": "

Starts a bidirectional HTTP/2 or WebSocket stream where audio is streamed to \n Amazon Transcribe and the transcription results are streamed to your application.

\n

The following parameters are required:

\n
    \n
  • \n

    \n language-code or identify-language or identify-multiple-language\n

    \n
  • \n
  • \n

    \n media-encoding\n

    \n
  • \n
  • \n

    \n sample-rate\n

    \n
  • \n
\n

For more information on streaming with Amazon Transcribe, see Transcribing streaming audio.

", "smithy.api#http": { "method": "POST", "uri": "/stream-transcription", @@ -2030,7 +2030,7 @@ "target": "com.amazonaws.transcribestreaming#Boolean", "traits": { "smithy.api#default": false, - "smithy.api#documentation": "

Enables automatic language identification for your transcription.

\n

If you include IdentifyLanguage, you can optionally include a list of \n language codes, using LanguageOptions, that you think may be present in \n your audio stream. Including language options can improve transcription accuracy.

\n

You can also include a preferred language using PreferredLanguage. Adding a \n preferred language can help Amazon Transcribe identify the language faster than if you omit this \n parameter.

\n

If you have multi-channel audio that contains different languages on each channel, and you've \n enabled channel identification, automatic language identification identifies the dominant language on \n each audio channel.

\n

Note that you must include either LanguageCode or \n IdentifyLanguage in your request. If you include both parameters, your request\n fails.

\n

Streaming language identification can't be combined with custom language models or \n redaction.

", + "smithy.api#documentation": "

Enables automatic language identification for your transcription.

\n

If you include IdentifyLanguage, you can optionally include a list of \n language codes, using LanguageOptions, that you think may be present in \n your audio stream. Including language options can improve transcription accuracy.

\n

You can also include a preferred language using PreferredLanguage. Adding a \n preferred language can help Amazon Transcribe identify the language faster than if you omit this \n parameter.

\n

If you have multi-channel audio that contains different languages on each channel, and you've \n enabled channel identification, automatic language identification identifies the dominant language on \n each audio channel.

\n

Note that you must include either LanguageCode or \n IdentifyLanguage or IdentifyMultipleLanguages in your request. If you include more than one of these parameters, your transcription job\n fails.

\n

Streaming language identification can't be combined with custom language models or \n redaction.

", "smithy.api#httpHeader": "x-amzn-transcribe-identify-language" } }, @@ -2048,6 +2048,14 @@ "smithy.api#httpHeader": "x-amzn-transcribe-preferred-language" } }, + "IdentifyMultipleLanguages": { + "target": "com.amazonaws.transcribestreaming#Boolean", + "traits": { + "smithy.api#default": false, + "smithy.api#documentation": "

Enables automatic multi-language identification in your transcription job request. Use this parameter if your stream contains more than one language. If your stream contains only one language, use IdentifyLanguage instead.

\n

If you include IdentifyMultipleLanguages, you can optionally include a list of language codes, using LanguageOptions, that you think may be present in your stream. Including LanguageOptions restricts IdentifyMultipleLanguages to only the language options that you specify, which can improve transcription accuracy.

\n

If you want to apply a custom vocabulary or a custom vocabulary filter to your automatic multiple language identification request, include VocabularyNames or VocabularyFilterNames.

\n

Note that you must include one of LanguageCode, IdentifyLanguage, or IdentifyMultipleLanguages in your request. If you include more than one of these parameters, your transcription job fails.

", + "smithy.api#httpHeader": "x-amzn-transcribe-identify-multiple-languages" + } + }, "VocabularyNames": { "target": "com.amazonaws.transcribestreaming#VocabularyNames", "traits": { @@ -2221,6 +2229,14 @@ "smithy.api#httpHeader": "x-amzn-transcribe-preferred-language" } }, + "IdentifyMultipleLanguages": { + "target": "com.amazonaws.transcribestreaming#Boolean", + "traits": { + "smithy.api#default": false, + "smithy.api#documentation": "

Shows whether automatic multi-language identification was enabled for your transcription.

", + "smithy.api#httpHeader": "x-amzn-transcribe-identify-multiple-languages" + } + }, "VocabularyNames": { "target": "com.amazonaws.transcribestreaming#VocabularyNames", "traits": { diff --git a/aws/sdk/benchmarks/s3-throughput/benchmark/Cargo.toml b/aws/sdk/benchmarks/s3-throughput/benchmark/Cargo.toml index eeee431cec4..d15d7823ef1 100644 --- a/aws/sdk/benchmarks/s3-throughput/benchmark/Cargo.toml +++ b/aws/sdk/benchmarks/s3-throughput/benchmark/Cargo.toml @@ -17,5 +17,5 @@ clap = { version = "4.3.2", default-features = false, features = ["derive", "std tokio = { version = "1.28.2", features = ["full"] } tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } tracing = "0.1" -async-trait = "0.1.68" +async-trait = "0.1.74" hyper = { version = "0.14.27", features = ["client"] } diff --git a/aws/sdk/build.gradle.kts b/aws/sdk/build.gradle.kts index e4eee8fd524..7b263e0b518 100644 --- a/aws/sdk/build.gradle.kts +++ b/aws/sdk/build.gradle.kts @@ -18,6 +18,11 @@ plugins { id("software.amazon.smithy") } +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + configure { smithyBuildConfigs = files(layout.buildDirectory.file("smithy-build.json")) allowUnknownTraits = true @@ -95,8 +100,7 @@ fun generateSmithyBuild(services: AwsServices): String { "plugins": { "rust-client-codegen": { "runtimeConfig": { - "relativePath": "../", - "version": "DEFAULT" + "relativePath": "../" }, "codegen": { "includeFluentClient": false, @@ -117,10 +121,10 @@ fun generateSmithyBuild(services: AwsServices): String { "license": "Apache-2.0", "customizationConfig": { "awsSdk": { - "generateReadme": true, + "awsSdkBuild": true, "awsConfigVersion": "$awsConfigVersion", "defaultConfigPath": "${services.defaultConfigPath}", - "endpointsConfigPath": "${services.endpointsConfigPath}", + "partitionsConfigPath": "${services.partitionsConfigPath}", "integrationTestPath": "${project.projectDir.resolve("integration-tests")}" } } @@ -354,11 +358,7 @@ tasks.register("fixManifests") { toolPath = publisherToolPath binaryName = "publisher" - arguments = mutableListOf("fix-manifests", "--location", outputDir.asFile.absolutePath).apply { - if (crateVersioner.independentVersioningEnabled()) { - add("--disable-version-number-validation") - } - } + arguments = mutableListOf("fix-manifests", "--location", outputDir.asFile.absolutePath) } tasks.register("hydrateReadme") { diff --git a/aws/sdk/integration-tests/dynamodb/Cargo.toml b/aws/sdk/integration-tests/dynamodb/Cargo.toml index 3283676a42c..57eadecc005 100644 --- a/aws/sdk/integration-tests/dynamodb/Cargo.toml +++ b/aws/sdk/integration-tests/dynamodb/Cargo.toml @@ -19,13 +19,13 @@ aws-sdk-dynamodb = { path = "../../build/aws-sdk/sdk/dynamodb", features = ["beh aws-smithy-async = { path = "../../build/aws-sdk/sdk/aws-smithy-async", features = ["test-util"] } aws-smithy-http = { path = "../../build/aws-sdk/sdk/aws-smithy-http" } aws-smithy-protocol-test = { path = "../../build/aws-sdk/sdk/aws-smithy-protocol-test" } -aws-smithy-runtime = { path = "../../build/aws-sdk/sdk/aws-smithy-runtime", features = ["test-util"]} +aws-smithy-runtime = { path = "../../build/aws-sdk/sdk/aws-smithy-runtime", features = ["test-util", "wire-mock"]} aws-smithy-runtime-api = { path = "../../build/aws-sdk/sdk/aws-smithy-runtime-api", features = ["test-util"]} aws-smithy-types = { path = "../../build/aws-sdk/sdk/aws-smithy-types", features = ["test-util"]} aws-types = { path = "../../build/aws-sdk/sdk/aws-types" } bytes = "1.0.0" criterion = { version = "0.5.0" } -futures-util = { version = "0.3.16", default-features = false } +futures-util = { version = "0.3.29", default-features = false } http = "0.2.0" serde_json = "1.0.0" tokio = { version = "1.23.1", features = ["full", "test-util"] } diff --git a/aws/sdk/integration-tests/dynamodb/tests/test-error-classification.rs b/aws/sdk/integration-tests/dynamodb/tests/test-error-classification.rs new file mode 100644 index 00000000000..244f20c8718 --- /dev/null +++ b/aws/sdk/integration-tests/dynamodb/tests/test-error-classification.rs @@ -0,0 +1,70 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use std::time::Duration; + +use aws_credential_types::Credentials; +use aws_sdk_dynamodb::types::AttributeValue; +use aws_sdk_dynamodb::Client; +use aws_smithy_async::rt::sleep::{SharedAsyncSleep, TokioSleep}; +use aws_smithy_runtime::client::http::test_util::wire::{ReplayedEvent, WireMockServer}; +use aws_smithy_runtime::{ev, match_events}; +use aws_smithy_types::retry::RetryConfig; +use aws_smithy_types::timeout::TimeoutConfig; +use aws_types::region::Region; +use bytes::Bytes; + +const DYNAMO_THROTTLING_RESPONSE: &str = r#"{"__type":"com.amazonaws.dynamodb.v20120810#ThrottlingException", +"message":"enhance your calm"}"#; + +const DYNAMODB_DB_SUCCESS_RESPONSE: &str = r#"{"Count":0,"Items":[],"ScannedCount":2}"#; + +#[tokio::test] +async fn test_no_reconnect_500_throttling() { + assert_error_not_transient(ReplayedEvent::HttpResponse { + status: 500, + body: Bytes::from(DYNAMO_THROTTLING_RESPONSE), + }) + .await +} + +#[tokio::test] +async fn test_no_reconnect_429_throttling() { + assert_error_not_transient(ReplayedEvent::HttpResponse { + status: 429, + body: Bytes::from(DYNAMO_THROTTLING_RESPONSE), + }) + .await +} + +async fn assert_error_not_transient(error: ReplayedEvent) { + let mock = WireMockServer::start(vec![ + error, + ReplayedEvent::with_body(DYNAMODB_DB_SUCCESS_RESPONSE), + ]) + .await; + + let config = aws_sdk_dynamodb::Config::builder() + .region(Region::from_static("us-east-2")) + .credentials_provider(Credentials::for_tests()) + .sleep_impl(SharedAsyncSleep::new(TokioSleep::new())) + .endpoint_url(mock.endpoint_url()) + .http_client(mock.http_client()) + .timeout_config( + TimeoutConfig::builder() + .operation_attempt_timeout(Duration::from_millis(100)) + .build(), + ) + .retry_config(RetryConfig::standard()) + .build(); + let client = Client::from_conf(config); + let _item = client + .get_item() + .key("foo", AttributeValue::Bool(true)) + .send() + .await + .expect("should succeed"); + match_events!(ev!(dns), ev!(connect), _, ev!(http(200)))(&mock.events()); +} diff --git a/aws/sdk/integration-tests/lambda/Cargo.toml b/aws/sdk/integration-tests/lambda/Cargo.toml index 7e53411d4c9..ec891d0100a 100644 --- a/aws/sdk/integration-tests/lambda/Cargo.toml +++ b/aws/sdk/integration-tests/lambda/Cargo.toml @@ -17,7 +17,7 @@ aws-smithy-http = { path = "../../build/aws-sdk/sdk/aws-smithy-http" } aws-smithy-runtime = { path = "../../build/aws-sdk/sdk/aws-smithy-runtime", features = ["client", "test-util"] } base64 = "0.13.0" bytes = "1.0.0" -futures-core = "0.3.14" +futures-core = "0.3.29" http = "0.2.0" serde_json = "1.0.0" tokio = { version = "1.23.1", features = ["full", "test-util"] } diff --git a/aws/sdk/integration-tests/s3/Cargo.toml b/aws/sdk/integration-tests/s3/Cargo.toml index 80ba48df858..cdb22592ba8 100644 --- a/aws/sdk/integration-tests/s3/Cargo.toml +++ b/aws/sdk/integration-tests/s3/Cargo.toml @@ -31,7 +31,7 @@ aws-types = { path = "../../build/aws-sdk/sdk/aws-types" } bytes = "1" bytes-utils = "0.1.2" fastrand = "2.0.1" -futures-util = { version = "0.3.16", default-features = false, features = ["alloc"] } +futures-util = { version = "0.3.29", default-features = false, features = ["alloc"] } hdrhistogram = "7.5.2" http = "0.2.3" http-body = "0.4.5" diff --git a/aws/sdk/integration-tests/s3/tests/status-200-errors.rs b/aws/sdk/integration-tests/s3/tests/status-200-errors.rs index 20217b2db20..131c6d274fc 100644 --- a/aws/sdk/integration-tests/s3/tests/status-200-errors.rs +++ b/aws/sdk/integration-tests/s3/tests/status-200-errors.rs @@ -6,6 +6,7 @@ use aws_credential_types::provider::SharedCredentialsProvider; use aws_credential_types::Credentials; use aws_sdk_s3::Client; +use aws_smithy_runtime::assert_str_contains; use aws_smithy_runtime::client::http::test_util::infallible_client_fn; use aws_smithy_types::body::SdkBody; use aws_smithy_types::error::metadata::ProvideErrorMetadata; @@ -37,5 +38,6 @@ async fn status_200_errors() { .send() .await .expect_err("should fail"); - assert_eq!(error.into_service_error().code(), Some("SlowDown")); + assert_eq!(error.as_service_error().unwrap().code(), Some("SlowDown")); + assert_str_contains!(format!("{:?}", error), "Please reduce your request rate"); } diff --git a/aws/sdk/integration-tests/transcribestreaming/Cargo.toml b/aws/sdk/integration-tests/transcribestreaming/Cargo.toml index 54138bf894f..0624ef56785 100644 --- a/aws/sdk/integration-tests/transcribestreaming/Cargo.toml +++ b/aws/sdk/integration-tests/transcribestreaming/Cargo.toml @@ -17,7 +17,7 @@ aws-smithy-eventstream = { path = "../../build/aws-sdk/sdk/aws-smithy-eventstrea aws-smithy-http = { path = "../../build/aws-sdk/sdk/aws-smithy-http" } aws-smithy-runtime = { path = "../../build/aws-sdk/sdk/aws-smithy-runtime", features = ["client", "test-util"] } bytes = "1.0.0" -futures-core = "0.3.14" +futures-core = "0.3.29" hound = "3.4.0" http = "0.2.0" serde_json = "1.0.0" diff --git a/aws/sdk/integration-tests/transcribestreaming/tests/test.rs b/aws/sdk/integration-tests/transcribestreaming/tests/test.rs index 5178bd2ae95..5b761eba2c5 100644 --- a/aws/sdk/integration-tests/transcribestreaming/tests/test.rs +++ b/aws/sdk/integration-tests/transcribestreaming/tests/test.rs @@ -7,6 +7,8 @@ use async_stream::stream; use aws_sdk_transcribestreaming::config::{Credentials, Region}; use aws_sdk_transcribestreaming::error::SdkError; use aws_sdk_transcribestreaming::operation::start_stream_transcription::StartStreamTranscriptionOutput; +#[allow(unused)] // making sure `EventReceiver` is re-exported +use aws_sdk_transcribestreaming::primitives::event_stream::EventReceiver; use aws_sdk_transcribestreaming::primitives::event_stream::{HeaderValue, Message}; use aws_sdk_transcribestreaming::primitives::Blob; use aws_sdk_transcribestreaming::types::error::{AudioStreamError, TranscriptResultStreamError}; diff --git a/aws/sdk/sync-models.py b/aws/sdk/sync-models.py index 9b622993dbd..68abc54d27e 100755 --- a/aws/sdk/sync-models.py +++ b/aws/sdk/sync-models.py @@ -11,24 +11,17 @@ # Ensure working directory is the script path script_path = path.dirname(path.realpath(__file__)) -# Looks for aws-models in the parent directory of smithy-rs +# Looks for aws-sdk-rust in the parent directory of smithy-rs def discover_aws_models(): - repo_path = path.abspath(path.join(script_path, "../../../aws-models")) + repo_path = path.abspath(path.join(script_path, "../../../aws-sdk-rust")) git_path = repo_path + "/.git" if path.exists(repo_path) and path.exists(git_path): print(f"Discovered aws-models at {repo_path}") - return repo_path + return Path(repo_path) / 'aws-models' else: return None -def discover_new_models(aws_models_repo, known_models): - new_models = [] - for model in os.listdir(aws_models_repo): - if model not in known_models and path.exists(Path(aws_models_repo) / model / "smithy" / "model.json"): - new_models.append(model) - return new_models - -def copy_model(source_path, model_path, model_name): +def copy_model(source_path, model_path): dest_path = Path("aws-models") / model_path source = source_path.read_text() # Add a newline at the end when copying the model over @@ -39,18 +32,22 @@ def copy_model(source_path, model_path, model_name): def copy_known_models(aws_models_repo): known_models = set() - for model in os.listdir("aws-models"): - if not model.endswith('.json'): + for model_file in os.listdir("aws-models"): + if not model_file.endswith('.json'): continue - model_name = model[:-len('.json')] - known_models.add(model_name) - source_path = Path(aws_models_repo) / model_name / "smithy" / "model.json" + known_models.add(model_file) + source_path = Path(aws_models_repo) / model_file if not source_path.exists(): - print(f" Warning: cannot find model for '{model_name}' in aws-models, but it exists in smithy-rs") + print(f" Warning: cannot find model for '{model_file}' in aws-models, but it exists in smithy-rs") continue - copy_model(source_path, model, model_name) + copy_model(source_path, model_file) return known_models +def copy_sdk_configs(aws_models_repo): + for model_file in os.listdir(aws_models_repo): + if model_file.startswith('sdk-'): + print('copying SDK configuration file', model_file) + copy_model(aws_models_repo / model_file, model_file) def main(): # Acquire model location aws_models_repo = discover_aws_models() @@ -62,16 +59,8 @@ def main(): aws_models_repo = sys.argv[1] print("Copying over known models...") - known_models = copy_known_models(aws_models_repo) - - print("Looking for new models...") - new_models = discover_new_models(aws_models_repo, known_models) - if len(new_models) > 0: - print(f" Warning: found models for {new_models} in aws-models that aren't in smithy-rs") - print(f" Run the following commands to bring these in:\n") - for model in new_models: - print(f" touch aws-models/{model}.json") - print(f" ./sync-models.py\n") + copy_known_models(aws_models_repo) + copy_sdk_configs(aws_models_repo) print("Models synced.") diff --git a/build.gradle.kts b/build.gradle.kts index 7439d73b146..d62cca61da4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,7 +18,7 @@ plugins { } allprojects { repositories { - /* mavenLocal() */ + // mavenLocal() mavenCentral() google() } @@ -33,31 +33,30 @@ allprojects.forEach { } } -val ktlint by configurations.creating { - // https://github.com/pinterest/ktlint/issues/1114#issuecomment-805793163 - attributes { - attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL)) - } -} +val ktlint by configurations.creating val ktlintVersion: String by project dependencies { - ktlint("com.pinterest:ktlint:$ktlintVersion") - ktlint("com.pinterest.ktlint:ktlint-ruleset-standard:$ktlintVersion") + ktlint("com.pinterest.ktlint:ktlint-cli:$ktlintVersion") { + attributes { + attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL)) + } + } } -val lintPaths = listOf( - "**/*.kt", - // Exclude build output directories - "!**/build/**", - "!**/node_modules/**", - "!**/target/**", -) +val lintPaths = + listOf( + "**/*.kt", + // Exclude build output directories + "!**/build/**", + "!**/node_modules/**", + "!**/target/**", + ) tasks.register("ktlint") { description = "Check Kotlin code style." - group = "Verification" - classpath = configurations.getByName("ktlint") + group = LifecycleBasePlugin.VERIFICATION_GROUP + classpath = ktlint mainClass.set("com.pinterest.ktlint.Main") args = listOf("--log-level=info", "--relative", "--") + lintPaths // https://github.com/pinterest/ktlint/issues/1195#issuecomment-1009027802 @@ -66,10 +65,24 @@ tasks.register("ktlint") { tasks.register("ktlintFormat") { description = "Auto fix Kotlin code style violations" - group = "formatting" - classpath = configurations.getByName("ktlint") + group = LifecycleBasePlugin.VERIFICATION_GROUP + classpath = ktlint mainClass.set("com.pinterest.ktlint.Main") args = listOf("--log-level=info", "--relative", "--format", "--") + lintPaths // https://github.com/pinterest/ktlint/issues/1195#issuecomment-1009027802 jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED") } + +tasks.register("ktlintPreCommit") { + description = "Check Kotlin code style (for the pre-commit hooks)." + group = LifecycleBasePlugin.VERIFICATION_GROUP + classpath = ktlint + mainClass.set("com.pinterest.ktlint.Main") + args = listOf("--log-level=warn", "--color", "--relative", "--format", "--") + + System.getProperty("ktlintPreCommitArgs").let { args -> + check(args.isNotBlank()) { "need to pass in -DktlintPreCommitArgs=" } + args.split(" ") + } + // https://github.com/pinterest/ktlint/issues/1195#issuecomment-1009027802 + jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED") +} diff --git a/buildSrc/src/main/kotlin/CodegenTestCommon.kt b/buildSrc/src/main/kotlin/CodegenTestCommon.kt index 042f3c633d3..d6dea95060f 100644 --- a/buildSrc/src/main/kotlin/CodegenTestCommon.kt +++ b/buildSrc/src/main/kotlin/CodegenTestCommon.kt @@ -22,44 +22,52 @@ data class CodegenTest( val imports: List = emptyList(), ) -fun generateImports(imports: List): String = if (imports.isEmpty()) { - "" -} else { - "\"imports\": [${imports.map { "\"$it\"" }.joinToString(", ")}]," -} +fun generateImports(imports: List): String = + if (imports.isEmpty()) { + "" + } else { + "\"imports\": [${imports.map { "\"$it\"" }.joinToString(", ")}]," + } -private fun generateSmithyBuild(projectDir: String, pluginName: String, tests: List): String { - val projections = tests.joinToString(",\n") { - """ - "${it.module}": { - ${generateImports(it.imports)} - "plugins": { - "$pluginName": { - "runtimeConfig": { - "relativePath": "$projectDir/rust-runtime" - }, - "codegen": { - ${it.extraCodegenConfig ?: ""} - }, - "service": "${it.service}", - "module": "${it.module}", - "moduleVersion": "0.0.1", - "moduleDescription": "test", - "moduleAuthors": ["protocoltest@example.com"] - ${it.extraConfig ?: ""} +private fun generateSmithyBuild( + projectDir: String, + pluginName: String, + tests: List, +): String { + val projections = + tests.joinToString(",\n") { + """ + "${it.module}": { + ${generateImports(it.imports)} + "plugins": { + "$pluginName": { + "runtimeConfig": { + "relativePath": "$projectDir/rust-runtime" + }, + "codegen": { + ${it.extraCodegenConfig ?: ""} + }, + "service": "${it.service}", + "module": "${it.module}", + "moduleVersion": "0.0.1", + "moduleDescription": "test", + "moduleAuthors": ["protocoltest@example.com"] + ${it.extraConfig ?: ""} + } } } + """.trimIndent() } - """.trimIndent() - } - return """ + return ( + """ { "version": "1.0", "projections": { $projections } } - """.trimIndent() + """.trimIndent() + ) } enum class Cargo(val toString: String) { @@ -69,26 +77,34 @@ enum class Cargo(val toString: String) { CLIPPY("cargoClippy"), } -private fun generateCargoWorkspace(pluginName: String, tests: List) = +private fun generateCargoWorkspace( + pluginName: String, + tests: List, +) = ( """ [workspace] members = [ ${tests.joinToString(",") { "\"${it.module}/$pluginName\"" }} ] """.trimIndent() +) /** * Filter the service integration tests for which to generate Rust crates in [allTests] using the given [properties]. */ -private fun codegenTests(properties: PropertyRetriever, allTests: List): List { +private fun codegenTests( + properties: PropertyRetriever, + allTests: List, +): List { val modulesOverride = properties.get("modules")?.split(",")?.map { it.trim() } - val ret = if (modulesOverride != null) { - println("modulesOverride: $modulesOverride") - allTests.filter { modulesOverride.contains(it.module) } - } else { - allTests - } + val ret = + if (modulesOverride != null) { + println("modulesOverride: $modulesOverride") + allTests.filter { modulesOverride.contains(it.module) } + } else { + allTests + } require(ret.isNotEmpty()) { "None of the provided module overrides (`$modulesOverride`) are valid test services (`${ allTests.map { @@ -106,22 +122,24 @@ val AllCargoCommands = listOf(Cargo.CHECK, Cargo.TEST, Cargo.CLIPPY, Cargo.DOCS) * The list of Cargo commands that is run by default is defined in [AllCargoCommands]. */ fun cargoCommands(properties: PropertyRetriever): List { - val cargoCommandsOverride = properties.get("cargoCommands")?.split(",")?.map { it.trim() }?.map { - when (it) { - "check" -> Cargo.CHECK - "test" -> Cargo.TEST - "doc" -> Cargo.DOCS - "clippy" -> Cargo.CLIPPY - else -> throw IllegalArgumentException("Unexpected Cargo command `$it` (valid commands are `check`, `test`, `doc`, `clippy`)") + val cargoCommandsOverride = + properties.get("cargoCommands")?.split(",")?.map { it.trim() }?.map { + when (it) { + "check" -> Cargo.CHECK + "test" -> Cargo.TEST + "doc" -> Cargo.DOCS + "clippy" -> Cargo.CLIPPY + else -> throw IllegalArgumentException("Unexpected Cargo command `$it` (valid commands are `check`, `test`, `doc`, `clippy`)") + } } - } - val ret = if (cargoCommandsOverride != null) { - println("cargoCommandsOverride: $cargoCommandsOverride") - AllCargoCommands.filter { cargoCommandsOverride.contains(it) } - } else { - AllCargoCommands - } + val ret = + if (cargoCommandsOverride != null) { + println("cargoCommandsOverride: $cargoCommandsOverride") + AllCargoCommands.filter { cargoCommandsOverride.contains(it) } + } else { + AllCargoCommands + } require(ret.isNotEmpty()) { "None of the provided cargo commands (`$cargoCommandsOverride`) are valid cargo commands (`${ AllCargoCommands.map { @@ -156,12 +174,13 @@ fun Project.registerGenerateSmithyBuildTask( // If this is a rebuild, cache all the hashes of the generated Rust files. These are later used by the // `modifyMtime` task. - project.extra[previousBuildHashesKey] = project.buildDir.walk() - .filter { it.isFile } - .map { - getChecksumForFile(it) to it.lastModified() - } - .toMap() + project.extra[previousBuildHashesKey] = + project.buildDir.walk() + .filter { it.isFile } + .map { + getChecksumForFile(it) to it.lastModified() + } + .toMap() } } } @@ -182,9 +201,7 @@ fun Project.registerGenerateCargoWorkspaceTask( } } -fun Project.registerGenerateCargoConfigTomlTask( - outputDir: File, -) { +fun Project.registerGenerateCargoConfigTomlTask(outputDir: File) { this.tasks.register("generateCargoConfigToml") { description = "generate `.cargo/config.toml`" doFirst { diff --git a/buildSrc/src/main/kotlin/CrateSet.kt b/buildSrc/src/main/kotlin/CrateSet.kt index 765503e5a16..e3ad6e49ee9 100644 --- a/buildSrc/src/main/kotlin/CrateSet.kt +++ b/buildSrc/src/main/kotlin/CrateSet.kt @@ -16,21 +16,21 @@ object CrateSet { * stable = true */ - val StableCrates = setOf( - // AWS crates - "aws-config", - "aws-credential-types", - "aws-runtime", - "aws-runtime-api", - "aws-sigv4", - "aws-types", - - // smithy crates - "aws-smithy-async", - "aws-smithy-runtime-api", - "aws-smithy-runtime", - "aws-smithy-types", - ) + val StableCrates = + setOf( + // AWS crates + "aws-config", + "aws-credential-types", + "aws-runtime", + "aws-runtime-api", + "aws-sigv4", + "aws-types", + // smithy crates + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-runtime", + "aws-smithy-types", + ) val version = { name: String -> when { @@ -39,44 +39,49 @@ object CrateSet { } } - val AWS_SDK_RUNTIME = listOf( - "aws-config", - "aws-credential-types", - "aws-endpoint", - "aws-http", - "aws-hyper", - "aws-runtime", - "aws-runtime-api", - "aws-sig-auth", - "aws-sigv4", - "aws-types", - ).map { Crate(it, version(it)) } + val AWS_SDK_RUNTIME = + listOf( + "aws-config", + "aws-credential-types", + "aws-endpoint", + "aws-http", + "aws-hyper", + "aws-runtime", + "aws-runtime-api", + "aws-sig-auth", + "aws-sigv4", + "aws-types", + ).map { Crate(it, version(it)) } - val SMITHY_RUNTIME_COMMON = listOf( - "aws-smithy-async", - "aws-smithy-checksums", - "aws-smithy-client", - "aws-smithy-eventstream", - "aws-smithy-http", - "aws-smithy-http-auth", - "aws-smithy-http-tower", - "aws-smithy-json", - "aws-smithy-protocol-test", - "aws-smithy-query", - "aws-smithy-runtime", - "aws-smithy-runtime-api", - "aws-smithy-types", - "aws-smithy-types-convert", - "aws-smithy-xml", - ).map { Crate(it, version(it)) } + val SMITHY_RUNTIME_COMMON = + listOf( + "aws-smithy-async", + "aws-smithy-checksums", + "aws-smithy-client", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-http-auth", + "aws-smithy-http-tower", + "aws-smithy-json", + "aws-smithy-mocks-experimental", + "aws-smithy-protocol-test", + "aws-smithy-query", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-types-convert", + "aws-smithy-xml", + ).map { Crate(it, version(it)) } val AWS_SDK_SMITHY_RUNTIME = SMITHY_RUNTIME_COMMON - val SERVER_SMITHY_RUNTIME = SMITHY_RUNTIME_COMMON + listOf( - Crate("aws-smithy-http-server", UNSTABLE_VERSION_PROP_NAME), - Crate("aws-smithy-http-server-python", UNSTABLE_VERSION_PROP_NAME), - Crate("aws-smithy-http-server-typescript", UNSTABLE_VERSION_PROP_NAME), - ) + val SERVER_SMITHY_RUNTIME = + SMITHY_RUNTIME_COMMON + + listOf( + Crate("aws-smithy-http-server", UNSTABLE_VERSION_PROP_NAME), + Crate("aws-smithy-http-server-python", UNSTABLE_VERSION_PROP_NAME), + Crate("aws-smithy-http-server-typescript", UNSTABLE_VERSION_PROP_NAME), + ) val ENTIRE_SMITHY_RUNTIME = (AWS_SDK_SMITHY_RUNTIME + SERVER_SMITHY_RUNTIME).toSortedSet(compareBy { it.name }) diff --git a/buildSrc/src/main/kotlin/HashUtils.kt b/buildSrc/src/main/kotlin/HashUtils.kt index fb093c15712..d92f328b9c1 100644 --- a/buildSrc/src/main/kotlin/HashUtils.kt +++ b/buildSrc/src/main/kotlin/HashUtils.kt @@ -8,5 +8,7 @@ import java.security.MessageDigest fun ByteArray.toHex() = joinToString(separator = "") { byte -> "%02x".format(byte) } -fun getChecksumForFile(file: File, digest: MessageDigest = MessageDigest.getInstance("SHA-256")): String = - digest.digest(file.readText().toByteArray()).toHex() +fun getChecksumForFile( + file: File, + digest: MessageDigest = MessageDigest.getInstance("SHA-256"), +): String = digest.digest(file.readText().toByteArray()).toHex() diff --git a/buildSrc/src/main/kotlin/ManifestPatcher.kt b/buildSrc/src/main/kotlin/ManifestPatcher.kt index aabe25a3db8..b55581d575a 100644 --- a/buildSrc/src/main/kotlin/ManifestPatcher.kt +++ b/buildSrc/src/main/kotlin/ManifestPatcher.kt @@ -5,20 +5,32 @@ import java.io.File -fun rewriteCrateVersion(line: String, version: String): String = line.replace( - """^\s*version\s*=\s*"0.0.0-smithy-rs-head"$""".toRegex(), - "version = \"$version\"", -) +fun rewriteCrateVersion( + line: String, + version: String, +): String = + line.replace( + """^\s*version\s*=\s*"0.0.0-smithy-rs-head"$""".toRegex(), + "version = \"$version\"", + ) /** - * Smithy runtime crate versions in smithy-rs are all `0.0.0-smithy-rs-head`. When copying over to the AWS SDK, - * these should be changed to the smithy-rs version. + * Dependently versioned Smithy runtime crate versions in smithy-rs are all `0.0.0-smithy-rs-head`. + * When copying over to the AWS SDK, these should be changed to the corresponding + * stable/unstable runtime crate version from gradle.properties. + * + * In the future when all the runtime crates are independently versioned, this can be removed. */ -fun rewriteRuntimeCrateVersion(version: String, line: String): String = - rewriteCrateVersion(line, version) +fun rewriteRuntimeCrateVersion( + version: String, + line: String, +): String = rewriteCrateVersion(line, version) /** Patches a file with the result of the given `operation` being run on each line */ -fun patchFile(path: File, operation: (String) -> String) { +fun patchFile( + path: File, + operation: (String) -> String, +) { val patchedContents = path.readLines().joinToString("\n", transform = operation) path.writeText(patchedContents) } diff --git a/buildSrc/src/main/kotlin/aws/sdk/CrateVersioner.kt b/buildSrc/src/main/kotlin/aws/sdk/CrateVersioner.kt index 08145202032..fbd768a2faf 100644 --- a/buildSrc/src/main/kotlin/aws/sdk/CrateVersioner.kt +++ b/buildSrc/src/main/kotlin/aws/sdk/CrateVersioner.kt @@ -14,13 +14,17 @@ import java.security.MessageDigest const val LOCAL_DEV_VERSION: String = "0.0.0-local" object CrateVersioner { - fun defaultFor(rootProject: Project, properties: PropertyRetriever): VersionCrate = + fun defaultFor( + rootProject: Project, + properties: PropertyRetriever, + ): VersionCrate = when (val versionsManifestPath = properties.get("aws.sdk.previous.release.versions.manifest")) { // In local dev, use special `0.0.0-local` version number for all SDK crates null -> SynchronizedCrateVersioner(properties, sdkVersion = LOCAL_DEV_VERSION) else -> { - val modelMetadataPath = properties.get("aws.sdk.model.metadata") - ?: throw IllegalArgumentException("Property `aws.sdk.model.metadata` required for independent crate version builds") + val modelMetadataPath = + properties.get("aws.sdk.model.metadata") + ?: throw IllegalArgumentException("Property `aws.sdk.model.metadata` required for independent crate version builds") IndependentCrateVersioner( VersionsManifest.fromFile(versionsManifestPath), ModelMetadata.fromFile(modelMetadataPath), @@ -32,23 +36,26 @@ object CrateVersioner { } interface VersionCrate { - fun decideCrateVersion(moduleName: String, service: AwsService): String - - fun independentVersioningEnabled(): Boolean + fun decideCrateVersion( + moduleName: String, + service: AwsService, + ): String } class SynchronizedCrateVersioner( properties: PropertyRetriever, - private val sdkVersion: String = properties.get(CrateSet.STABLE_VERSION_PROP_NAME) - ?: throw Exception("SDK runtime crate version missing"), + private val sdkVersion: String = + properties.get(CrateSet.STABLE_VERSION_PROP_NAME) + ?: throw Exception("SDK runtime crate version missing"), ) : VersionCrate { init { LoggerFactory.getLogger(javaClass).info("Using synchronized SDK crate versioning with version `$sdkVersion`") } - override fun decideCrateVersion(moduleName: String, service: AwsService): String = sdkVersion - - override fun independentVersioningEnabled(): Boolean = sdkVersion == LOCAL_DEV_VERSION + override fun decideCrateVersion( + moduleName: String, + service: AwsService, + ): String = sdkVersion } private data class SemVer( @@ -73,7 +80,9 @@ private data class SemVer( } fun bumpMajor(): SemVer = copy(major = major + 1, minor = 0, patch = 0) + fun bumpMinor(): SemVer = copy(minor = minor + 1, patch = 0) + fun bumpPatch(): SemVer = copy(patch = patch + 1) override fun toString(): String { @@ -117,34 +126,36 @@ class IndependentCrateVersioner( ) } - override fun independentVersioningEnabled(): Boolean = true - - override fun decideCrateVersion(moduleName: String, service: AwsService): String { + override fun decideCrateVersion( + moduleName: String, + service: AwsService, + ): String { var previousVersion: SemVer? = null - val (reason, newVersion) = when (val existingCrate = versionsManifest.crates.get(moduleName)) { - // The crate didn't exist before, so create a new major version - null -> "new service" to newMajorVersion() - else -> { - previousVersion = SemVer.parse(existingCrate.version) - if (smithyRsChanged) { - "smithy-rs changed" to previousVersion.bumpCodegenChanged() - } else { - when (modelMetadata.changeType(moduleName)) { - ChangeType.FEATURE -> "its API changed" to previousVersion.bumpModelChanged() - ChangeType.DOCUMENTATION -> "it has new docs" to previousVersion.bumpDocsChanged() - ChangeType.UNCHANGED -> { - val currentModelsHash = hashModelsFn(service) - val previousModelsHash = existingCrate.modelHash - if (currentModelsHash != previousModelsHash) { - "its model(s) changed" to previousVersion.bumpModelChanged() - } else { - "no change" to previousVersion + val (reason, newVersion) = + when (val existingCrate = versionsManifest.crates.get(moduleName)) { + // The crate didn't exist before, so create a new major version + null -> "new service" to newMajorVersion() + else -> { + previousVersion = SemVer.parse(existingCrate.version) + if (smithyRsChanged) { + "smithy-rs changed" to previousVersion.bumpCodegenChanged() + } else { + when (modelMetadata.changeType(moduleName)) { + ChangeType.FEATURE -> "its API changed" to previousVersion.bumpModelChanged() + ChangeType.DOCUMENTATION -> "it has new docs" to previousVersion.bumpDocsChanged() + ChangeType.UNCHANGED -> { + val currentModelsHash = hashModelsFn(service) + val previousModelsHash = existingCrate.modelHash + if (currentModelsHash != previousModelsHash) { + "its model(s) changed" to previousVersion.bumpModelChanged() + } else { + "no change" to previousVersion + } } } } } } - } if (previousVersion == null) { logger.info("`$moduleName` is a new service. Starting it at `$newVersion`") } else if (previousVersion != newVersion) { @@ -155,28 +166,35 @@ class IndependentCrateVersioner( return newVersion.toString() } - private fun newMajorVersion(): SemVer = when (devPreview) { - true -> SemVer.parse("0.1.0") - else -> SemVer.parse("1.0.0") - } + private fun newMajorVersion(): SemVer = + when (devPreview) { + true -> SemVer.parse("0.1.0") + else -> SemVer.parse("1.0.0") + } private fun SemVer.bumpCodegenChanged(): SemVer = bumpMinor() - private fun SemVer.bumpModelChanged(): SemVer = when (devPreview) { - true -> bumpPatch() - else -> bumpMinor() - } + + private fun SemVer.bumpModelChanged(): SemVer = + when (devPreview) { + true -> bumpPatch() + else -> bumpMinor() + } private fun SemVer.bumpDocsChanged(): SemVer = bumpPatch() } private fun ByteArray.toLowerHex(): String = joinToString("") { byte -> "%02x".format(byte) } -fun hashModels(awsService: AwsService, loadFile: (File) -> ByteArray = File::readBytes): String { +fun hashModels( + awsService: AwsService, + loadFile: (File) -> ByteArray = File::readBytes, +): String { // Needs to match hashing done in the `generate-version-manifest` tool: val sha256 = MessageDigest.getInstance("SHA-256") - val hashes = awsService.modelFiles().fold("") { hashes, file -> - val fileHash = sha256.digest(loadFile(file)).toLowerHex() - hashes + fileHash + "\n" - } + val hashes = + awsService.modelFiles().fold("") { hashes, file -> + val fileHash = sha256.digest(loadFile(file)).toLowerHex() + hashes + fileHash + "\n" + } return sha256.digest(hashes.toByteArray(Charsets.UTF_8)).toLowerHex() } diff --git a/buildSrc/src/main/kotlin/aws/sdk/DocsLandingPage.kt b/buildSrc/src/main/kotlin/aws/sdk/DocsLandingPage.kt index 715917c4db2..097c47f8e07 100644 --- a/buildSrc/src/main/kotlin/aws/sdk/DocsLandingPage.kt +++ b/buildSrc/src/main/kotlin/aws/sdk/DocsLandingPage.kt @@ -15,7 +15,10 @@ import java.io.File * The generated docs will include links to crates.io, docs.rs and GitHub examples for all generated services. The generated docs will * be written to `docs.md` in the provided [outputDir]. */ -fun Project.docsLandingPage(awsServices: AwsServices, outputPath: File) { +fun Project.docsLandingPage( + awsServices: AwsServices, + outputPath: File, +) { val project = this val writer = SimpleCodeWriter() with(writer) { @@ -28,7 +31,7 @@ fun Project.docsLandingPage(awsServices: AwsServices, outputPath: File) { writer.write("## AWS Services") writer.write("") // empty line between header and table - /* generate a basic markdown table */ + // generate a basic markdown table writer.write("| Service | Package |") writer.write("| ------- | ------- |") awsServices.services.sortedBy { it.humanName }.forEach { @@ -44,7 +47,10 @@ fun Project.docsLandingPage(awsServices: AwsServices, outputPath: File) { /** * Generate a link to the examples for a given service */ -private fun examplesLink(service: AwsService, project: Project) = service.examplesUri(project)?.let { +private fun examplesLink( + service: AwsService, + project: Project, +) = service.examplesUri(project)?.let { "([examples]($it))" } @@ -52,6 +58,9 @@ private fun examplesLink(service: AwsService, project: Project) = service.exampl * Generate a link to the docs */ private fun docsRs(service: AwsService) = docsRs(service.crate()) + private fun docsRs(crate: String) = "([docs](https://docs.rs/$crate))" + private fun cratesIo(service: AwsService) = cratesIo(service.crate()) + private fun cratesIo(crate: String) = "[$crate](https://crates.io/crates/$crate)" diff --git a/buildSrc/src/main/kotlin/aws/sdk/ModelMetadata.kt b/buildSrc/src/main/kotlin/aws/sdk/ModelMetadata.kt index 95d65fd106d..90a6337bfcb 100644 --- a/buildSrc/src/main/kotlin/aws/sdk/ModelMetadata.kt +++ b/buildSrc/src/main/kotlin/aws/sdk/ModelMetadata.kt @@ -27,17 +27,20 @@ data class ModelMetadata( fun fromString(value: String): ModelMetadata { val toml = Toml().read(value) return ModelMetadata( - crates = toml.getTable("crates")?.entrySet()?.map { entry -> - entry.key to when (val kind = (entry.value as Toml).getString("kind")) { - "Feature" -> ChangeType.FEATURE - "Documentation" -> ChangeType.DOCUMENTATION - else -> throw IllegalArgumentException("Unrecognized change type: $kind") - } - }?.toMap() ?: emptyMap(), + crates = + toml.getTable("crates")?.entrySet()?.map { entry -> + entry.key to + when (val kind = (entry.value as Toml).getString("kind")) { + "Feature" -> ChangeType.FEATURE + "Documentation" -> ChangeType.DOCUMENTATION + else -> throw IllegalArgumentException("Unrecognized change type: $kind") + } + }?.toMap() ?: emptyMap(), ) } } fun hasCrates(): Boolean = crates.isNotEmpty() + fun changeType(moduleName: String): ChangeType = crates[moduleName] ?: ChangeType.UNCHANGED } diff --git a/buildSrc/src/main/kotlin/aws/sdk/ServiceLoader.kt b/buildSrc/src/main/kotlin/aws/sdk/ServiceLoader.kt index f31211f4db0..b863022ccd8 100644 --- a/buildSrc/src/main/kotlin/aws/sdk/ServiceLoader.kt +++ b/buildSrc/src/main/kotlin/aws/sdk/ServiceLoader.kt @@ -22,7 +22,7 @@ data class RootTest( class AwsServices( private val project: Project, services: List, - val endpointsConfigPath: File, + val partitionsConfigPath: File, val defaultConfigPath: File, ) { val services: List @@ -40,7 +40,7 @@ class AwsServices( // Root tests should not be included since they can't be part of the root Cargo workspace // in order to test differences in Cargo features. Examples should not be included either // because each example itself is a workspace. - ).toSortedSet() + ).toSortedSet() } val examples: List by lazy { @@ -68,11 +68,12 @@ class AwsServices( private fun manifestCompatibleWithGeneratedServices(path: File) = File(path, "Cargo.toml").let { cargoToml -> if (cargoToml.exists()) { - val usedModules = cargoToml.readLines() - .map { line -> line.substringBefore('=').trim() } - .filter { line -> line.startsWith("aws-sdk-") } - .map { line -> line.substringAfter("aws-sdk-") } - .toSet() + val usedModules = + cargoToml.readLines() + .map { line -> line.substringBefore('=').trim() } + .filter { line -> line.startsWith("aws-sdk-") } + .map { line -> line.substringAfter("aws-sdk-") } + .toSet() moduleNames.containsAll(usedModules) } else { false @@ -96,47 +97,53 @@ class AwsServices( * Since this function parses all models, it is relatively expensive to call. The result should be cached in a property * during build. */ -fun Project.discoverServices(awsModelsPath: String?, serviceMembership: Membership): AwsServices { +fun Project.discoverServices( + awsModelsPath: String?, + serviceMembership: Membership, +): AwsServices { val models = awsModelsPath?.let { File(it) } ?: project.file("aws-models") logger.info("Using model path: $models") - val baseServices = fileTree(models) - .sortedBy { file -> file.name } - .mapNotNull { file -> - val model = Model.assembler().addImport(file.absolutePath).assemble().result.get() - val services: List = model.shapes(ServiceShape::class.java).sorted().toList() - if (services.size > 1) { - throw Exception("There must be exactly one service in each aws model file") - } - if (services.isEmpty()) { - logger.info("${file.name} has no services") - null - } else { - val service = services[0] - val title = service.expectTrait(TitleTrait::class.java).value - val sdkId = service.expectTrait(ServiceTrait::class.java).sdkId - .toLowerCase() - .replace(" ", "") - // The smithy models should not include the suffix "service" but currently they do - .removeSuffix("service") - .removeSuffix("api") - val testFile = file.parentFile.resolve("$sdkId-tests.smithy") - val extras = if (testFile.exists()) { - logger.warn("Discovered protocol tests for ${file.name}") - listOf(testFile) + val baseServices = + fileTree(models) + .sortedBy { file -> file.name } + .mapNotNull { file -> + val model = Model.assembler().addImport(file.absolutePath).assemble().result.get() + val services: List = model.shapes(ServiceShape::class.java).sorted().toList() + if (services.size > 1) { + throw Exception("There must be exactly one service in each aws model file") + } + if (services.isEmpty()) { + logger.info("${file.name} has no services") + null } else { - listOf() + val service = services[0] + val title = service.expectTrait(TitleTrait::class.java).value + val sdkId = + service.expectTrait(ServiceTrait::class.java).sdkId + .toLowerCase() + .replace(" ", "") + // The smithy models should not include the suffix "service" but currently they do + .removeSuffix("service") + .removeSuffix("api") + val testFile = file.parentFile.resolve("$sdkId-tests.smithy") + val extras = + if (testFile.exists()) { + logger.warn("Discovered protocol tests for ${file.name}") + listOf(testFile) + } else { + listOf() + } + AwsService( + service = service.id.toString(), + module = sdkId, + moduleDescription = "AWS SDK for $title", + modelFile = file, + // Order is important for the versions.toml model hash calculation + extraFiles = extras.sorted(), + humanName = title, + ) } - AwsService( - service = service.id.toString(), - module = sdkId, - moduleDescription = "AWS SDK for $title", - modelFile = file, - // Order is important for the versions.toml model hash calculation - extraFiles = extras.sorted(), - humanName = title, - ) } - } val baseModules = baseServices.map { it.module }.toSet() logger.info("Discovered base service modules to generate: $baseModules") @@ -165,7 +172,7 @@ fun Project.discoverServices(awsModelsPath: String?, serviceMembership: Membersh val moduleNames = services.map { it.module } logger.info("Final service module list: $moduleNames") }, - models.resolve("sdk-endpoints.json"), + models.resolve("sdk-partitions.json"), models.resolve("sdk-default-configuration.json"), ) } @@ -182,26 +189,29 @@ data class AwsService( val humanName: String, ) { fun modelFiles(): List = listOf(modelFile) + extraFiles + fun Project.examples(): File = projectDir.resolve("examples").resolve(module) /** * Generate a link to the examples for a given service */ - fun examplesUri(project: Project) = if (project.examples().exists()) { - "https://github.com/awslabs/aws-sdk-rust/tree/main/examples/$module" - } else { - null - } + fun examplesUri(project: Project) = + if (project.examples().exists()) { + "https://github.com/awslabs/aws-sdk-rust/tree/main/examples/$module" + } else { + null + } } fun AwsService.crate(): String = "aws-sdk-$module" -private fun Membership.isMember(member: String): Boolean = when { - exclusions.contains(member) -> false - inclusions.contains(member) -> true - inclusions.isEmpty() -> true - else -> false -} +private fun Membership.isMember(member: String): Boolean = + when { + exclusions.contains(member) -> false + inclusions.contains(member) -> true + inclusions.isEmpty() -> true + else -> false + } fun parseMembership(rawList: String): Membership { val inclusions = mutableSetOf() diff --git a/buildSrc/src/main/kotlin/aws/sdk/VersionsManifest.kt b/buildSrc/src/main/kotlin/aws/sdk/VersionsManifest.kt index 4ff726ab98d..01f97867c1d 100644 --- a/buildSrc/src/main/kotlin/aws/sdk/VersionsManifest.kt +++ b/buildSrc/src/main/kotlin/aws/sdk/VersionsManifest.kt @@ -32,15 +32,17 @@ data class VersionsManifest( return VersionsManifest( smithyRsRevision = toml.getString("smithy_rs_revision"), awsDocSdkExamplesRevision = toml.getString("aws_doc_sdk_examples_revision"), - crates = toml.getTable("crates").entrySet().map { entry -> - val crate = (entry.value as Toml) - entry.key to CrateVersion( - category = crate.getString("category"), - version = crate.getString("version"), - sourceHash = crate.getString("source_hash"), - modelHash = crate.getString("model_hash"), - ) - }.toMap(), + crates = + toml.getTable("crates").entrySet().map { entry -> + val crate = (entry.value as Toml) + entry.key to + CrateVersion( + category = crate.getString("category"), + version = crate.getString("version"), + sourceHash = crate.getString("source_hash"), + modelHash = crate.getString("model_hash"), + ) + }.toMap(), ) } } diff --git a/buildSrc/src/test/kotlin/CrateSetTest.kt b/buildSrc/src/test/kotlin/CrateSetTest.kt index dacc75cc329..53b1340db2f 100644 --- a/buildSrc/src/test/kotlin/CrateSetTest.kt +++ b/buildSrc/src/test/kotlin/CrateSetTest.kt @@ -22,7 +22,11 @@ class CrateSetTest { * matches what `package.metadata.smithy-rs-release-tooling` says in the `Cargo.toml` * for the corresponding crate. */ - private fun sutStabilityMatchesManifestStability(versionPropertyName: String, stabilityInManifest: Boolean, crate: String) { + private fun sutStabilityMatchesManifestStability( + versionPropertyName: String, + stabilityInManifest: Boolean, + crate: String, + ) { when (stabilityInManifest) { true -> assertEquals(STABLE_VERSION_PROP_NAME, versionPropertyName, "Crate: $crate") false -> assertEquals(UNSTABLE_VERSION_PROP_NAME, versionPropertyName, "Crate: $crate") @@ -37,16 +41,20 @@ class CrateSetTest { * If `package.metadata.smithy-rs-release-tooling` does not exist in a `Cargo.toml`, the implementation * will treat that crate as unstable. */ - private fun crateSetStabilitiesMatchManifestStabilities(crateSet: List, relativePathToRustRuntime: String) { + private fun crateSetStabilitiesMatchManifestStabilities( + crateSet: List, + relativePathToRustRuntime: String, + ) { crateSet.forEach { val path = "$relativePathToRustRuntime/${it.name}/Cargo.toml" val contents = File(path).readText() - val isStable = try { - Toml().read(contents).getTable("package.metadata.smithy-rs-release-tooling")?.getBoolean("stable") ?: false - } catch (e: java.lang.IllegalStateException) { - // sigv4 doesn't parse but it's stable now, hax hax hax - contents.trim().endsWith("[package.metadata.smithy-rs-release-tooling]\nstable = true") - } + val isStable = + try { + Toml().read(contents).getTable("package.metadata.smithy-rs-release-tooling")?.getBoolean("stable") ?: false + } catch (e: java.lang.IllegalStateException) { + // sigv4 doesn't parse but it's stable now, hax hax hax + contents.trim().endsWith("[package.metadata.smithy-rs-release-tooling]\nstable = true") + } sutStabilityMatchesManifestStability(it.versionPropertyName, isStable, it.name) } } diff --git a/buildSrc/src/test/kotlin/aws/sdk/IndependentCrateVersionerTest.kt b/buildSrc/src/test/kotlin/aws/sdk/IndependentCrateVersionerTest.kt index f4057c63144..0ec9f8051ae 100644 --- a/buildSrc/src/test/kotlin/aws/sdk/IndependentCrateVersionerTest.kt +++ b/buildSrc/src/test/kotlin/aws/sdk/IndependentCrateVersionerTest.kt @@ -9,15 +9,16 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import java.io.File -private fun service(name: String): AwsService = AwsService( - name, - "test", - "test", - File("testmodel"), - null, - emptyList(), - name, -) +private fun service(name: String): AwsService = + AwsService( + name, + "test", + "test", + File("testmodel"), + null, + emptyList(), + name, + ) class IndependentCrateVersionerTest { @Test @@ -27,45 +28,51 @@ class IndependentCrateVersionerTest { val s3 = service("s3") val someNewService = service("somenewservice") - val versioner = IndependentCrateVersioner( - VersionsManifest( - smithyRsRevision = "smithy-rs-1", - awsDocSdkExamplesRevision = "dontcare", - crates = mapOf( - "aws-sdk-dynamodb" to CrateVersion( - category = "AwsSdk", - version = "0.11.3", - modelHash = "dynamodb-hash", - ), - "aws-sdk-ec2" to CrateVersion( - category = "AwsSdk", - version = "0.10.1", - modelHash = "ec2-hash", - ), - "aws-sdk-s3" to CrateVersion( - category = "AwsSdk", - version = "0.12.0", - modelHash = "s3-hash", - ), + val versioner = + IndependentCrateVersioner( + VersionsManifest( + smithyRsRevision = "smithy-rs-1", + awsDocSdkExamplesRevision = "dontcare", + crates = + mapOf( + "aws-sdk-dynamodb" to + CrateVersion( + category = "AwsSdk", + version = "0.11.3", + modelHash = "dynamodb-hash", + ), + "aws-sdk-ec2" to + CrateVersion( + category = "AwsSdk", + version = "0.10.1", + modelHash = "ec2-hash", + ), + "aws-sdk-s3" to + CrateVersion( + category = "AwsSdk", + version = "0.12.0", + modelHash = "s3-hash", + ), + ), ), - ), - ModelMetadata( - crates = mapOf( - "aws-sdk-dynamodb" to ChangeType.FEATURE, - "aws-sdk-ec2" to ChangeType.DOCUMENTATION, + ModelMetadata( + crates = + mapOf( + "aws-sdk-dynamodb" to ChangeType.FEATURE, + "aws-sdk-ec2" to ChangeType.DOCUMENTATION, + ), ), - ), - devPreview = true, - smithyRsVersion = "smithy-rs-2", - hashModelsFn = { service -> - when (service) { - dynamoDb -> "dynamodb-hash" - ec2 -> "ec2-hash" - s3 -> "s3-hash" - else -> throw IllegalStateException("unreachable") - } - }, - ) + devPreview = true, + smithyRsVersion = "smithy-rs-2", + hashModelsFn = { service -> + when (service) { + dynamoDb -> "dynamodb-hash" + ec2 -> "ec2-hash" + s3 -> "s3-hash" + else -> throw IllegalStateException("unreachable") + } + }, + ) // The code generator changed, so all minor versions should bump assertEquals("0.12.0", versioner.decideCrateVersion("aws-sdk-dynamodb", dynamoDb)) @@ -82,52 +89,59 @@ class IndependentCrateVersionerTest { val s3 = service("s3") val someNewService = service("somenewservice") - val versioner = IndependentCrateVersioner( - VersionsManifest( - smithyRsRevision = "smithy-rs-1", - awsDocSdkExamplesRevision = "dontcare", - crates = mapOf( - "aws-sdk-dynamodb" to CrateVersion( - category = "AwsSdk", - version = "0.11.3", - modelHash = "dynamodb-hash", - ), - "aws-sdk-ec2" to CrateVersion( - category = "AwsSdk", - version = "0.10.1", - modelHash = "ec2-hash", - ), - "aws-sdk-polly" to CrateVersion( - category = "AwsSdk", - version = "0.9.0", - modelHash = "old-polly-hash", - ), - "aws-sdk-s3" to CrateVersion( - category = "AwsSdk", - version = "0.12.0", - modelHash = "s3-hash", - ), + val versioner = + IndependentCrateVersioner( + VersionsManifest( + smithyRsRevision = "smithy-rs-1", + awsDocSdkExamplesRevision = "dontcare", + crates = + mapOf( + "aws-sdk-dynamodb" to + CrateVersion( + category = "AwsSdk", + version = "0.11.3", + modelHash = "dynamodb-hash", + ), + "aws-sdk-ec2" to + CrateVersion( + category = "AwsSdk", + version = "0.10.1", + modelHash = "ec2-hash", + ), + "aws-sdk-polly" to + CrateVersion( + category = "AwsSdk", + version = "0.9.0", + modelHash = "old-polly-hash", + ), + "aws-sdk-s3" to + CrateVersion( + category = "AwsSdk", + version = "0.12.0", + modelHash = "s3-hash", + ), + ), ), - ), - ModelMetadata( - crates = mapOf( - "aws-sdk-dynamodb" to ChangeType.FEATURE, - "aws-sdk-ec2" to ChangeType.DOCUMENTATION, - // polly has a model change, but is absent from the model metadata file + ModelMetadata( + crates = + mapOf( + "aws-sdk-dynamodb" to ChangeType.FEATURE, + "aws-sdk-ec2" to ChangeType.DOCUMENTATION, + // polly has a model change, but is absent from the model metadata file + ), ), - ), - devPreview = true, - smithyRsVersion = "smithy-rs-1", - hashModelsFn = { service -> - when (service) { - dynamoDb -> "dynamodb-hash" - ec2 -> "ec2-hash" - polly -> "NEW-polly-hash" - s3 -> "s3-hash" - else -> throw IllegalStateException("unreachable") - } - }, - ) + devPreview = true, + smithyRsVersion = "smithy-rs-1", + hashModelsFn = { service -> + when (service) { + dynamoDb -> "dynamodb-hash" + ec2 -> "ec2-hash" + polly -> "NEW-polly-hash" + s3 -> "s3-hash" + else -> throw IllegalStateException("unreachable") + } + }, + ) assertEquals("0.11.4", versioner.decideCrateVersion("aws-sdk-dynamodb", dynamoDb)) assertEquals("0.10.2", versioner.decideCrateVersion("aws-sdk-ec2", ec2)) @@ -143,34 +157,40 @@ class IndependentCrateVersionerTest { val s3 = service("s3") val someNewService = service("somenewservice") - val versioner = IndependentCrateVersioner( - VersionsManifest( - smithyRsRevision = "smithy-rs-1", - awsDocSdkExamplesRevision = "dontcare", - crates = mapOf( - "aws-sdk-dynamodb" to CrateVersion( - category = "AwsSdk", - version = "1.11.3", - ), - "aws-sdk-ec2" to CrateVersion( - category = "AwsSdk", - version = "1.10.1", - ), - "aws-sdk-s3" to CrateVersion( - category = "AwsSdk", - version = "1.12.0", - ), + val versioner = + IndependentCrateVersioner( + VersionsManifest( + smithyRsRevision = "smithy-rs-1", + awsDocSdkExamplesRevision = "dontcare", + crates = + mapOf( + "aws-sdk-dynamodb" to + CrateVersion( + category = "AwsSdk", + version = "1.11.3", + ), + "aws-sdk-ec2" to + CrateVersion( + category = "AwsSdk", + version = "1.10.1", + ), + "aws-sdk-s3" to + CrateVersion( + category = "AwsSdk", + version = "1.12.0", + ), + ), ), - ), - ModelMetadata( - crates = mapOf( - "aws-sdk-dynamodb" to ChangeType.FEATURE, - "aws-sdk-ec2" to ChangeType.DOCUMENTATION, + ModelMetadata( + crates = + mapOf( + "aws-sdk-dynamodb" to ChangeType.FEATURE, + "aws-sdk-ec2" to ChangeType.DOCUMENTATION, + ), ), - ), - devPreview = false, - smithyRsVersion = "smithy-rs-2", - ) + devPreview = false, + smithyRsVersion = "smithy-rs-2", + ) // The code generator changed, so all minor versions should bump assertEquals("1.12.0", versioner.decideCrateVersion("aws-sdk-dynamodb", dynamoDb)) @@ -187,52 +207,59 @@ class IndependentCrateVersionerTest { val s3 = service("s3") val someNewService = service("somenewservice") - val versioner = IndependentCrateVersioner( - VersionsManifest( - smithyRsRevision = "smithy-rs-1", - awsDocSdkExamplesRevision = "dontcare", - crates = mapOf( - "aws-sdk-dynamodb" to CrateVersion( - category = "AwsSdk", - version = "1.11.3", - modelHash = "dynamodb-hash", - ), - "aws-sdk-ec2" to CrateVersion( - category = "AwsSdk", - version = "1.10.1", - modelHash = "ec2-hash", - ), - "aws-sdk-polly" to CrateVersion( - category = "AwsSdk", - version = "1.9.0", - modelHash = "old-polly-hash", - ), - "aws-sdk-s3" to CrateVersion( - category = "AwsSdk", - version = "1.12.0", - modelHash = "s3-hash", - ), + val versioner = + IndependentCrateVersioner( + VersionsManifest( + smithyRsRevision = "smithy-rs-1", + awsDocSdkExamplesRevision = "dontcare", + crates = + mapOf( + "aws-sdk-dynamodb" to + CrateVersion( + category = "AwsSdk", + version = "1.11.3", + modelHash = "dynamodb-hash", + ), + "aws-sdk-ec2" to + CrateVersion( + category = "AwsSdk", + version = "1.10.1", + modelHash = "ec2-hash", + ), + "aws-sdk-polly" to + CrateVersion( + category = "AwsSdk", + version = "1.9.0", + modelHash = "old-polly-hash", + ), + "aws-sdk-s3" to + CrateVersion( + category = "AwsSdk", + version = "1.12.0", + modelHash = "s3-hash", + ), + ), ), - ), - ModelMetadata( - crates = mapOf( - "aws-sdk-dynamodb" to ChangeType.FEATURE, - "aws-sdk-ec2" to ChangeType.DOCUMENTATION, - // polly has a model change, but is absent from the model metadata file + ModelMetadata( + crates = + mapOf( + "aws-sdk-dynamodb" to ChangeType.FEATURE, + "aws-sdk-ec2" to ChangeType.DOCUMENTATION, + // polly has a model change, but is absent from the model metadata file + ), ), - ), - devPreview = false, - smithyRsVersion = "smithy-rs-1", - hashModelsFn = { service -> - when (service) { - dynamoDb -> "dynamodb-hash" - ec2 -> "ec2-hash" - polly -> "NEW-polly-hash" - s3 -> "s3-hash" - else -> throw IllegalStateException("unreachable") - } - }, - ) + devPreview = false, + smithyRsVersion = "smithy-rs-1", + hashModelsFn = { service -> + when (service) { + dynamoDb -> "dynamodb-hash" + ec2 -> "ec2-hash" + polly -> "NEW-polly-hash" + s3 -> "s3-hash" + else -> throw IllegalStateException("unreachable") + } + }, + ) assertEquals("1.12.0", versioner.decideCrateVersion("aws-sdk-dynamodb", dynamoDb)) assertEquals("1.10.2", versioner.decideCrateVersion("aws-sdk-ec2", ec2)) @@ -245,17 +272,19 @@ class IndependentCrateVersionerTest { class HashModelsTest { @Test fun testHashModels() { - val service = service("test").copy( - modelFile = File("model1a"), - extraFiles = listOf(File("model1b")), - ) - val hash = hashModels(service) { file -> - when (file.toString()) { - "model1a" -> "foo".toByteArray(Charsets.UTF_8) - "model1b" -> "bar".toByteArray(Charsets.UTF_8) - else -> throw IllegalStateException("unreachable") + val service = + service("test").copy( + modelFile = File("model1a"), + extraFiles = listOf(File("model1b")), + ) + val hash = + hashModels(service) { file -> + when (file.toString()) { + "model1a" -> "foo".toByteArray(Charsets.UTF_8) + "model1b" -> "bar".toByteArray(Charsets.UTF_8) + else -> throw IllegalStateException("unreachable") + } } - } assertEquals("964021077fb6c3d42ae162ab2e2255be64c6d96a6d77bca089569774d54ef69b", hash) } } diff --git a/buildSrc/src/test/kotlin/aws/sdk/ModelMetadataTest.kt b/buildSrc/src/test/kotlin/aws/sdk/ModelMetadataTest.kt index d157ed0adc2..dba74d5a90e 100644 --- a/buildSrc/src/test/kotlin/aws/sdk/ModelMetadataTest.kt +++ b/buildSrc/src/test/kotlin/aws/sdk/ModelMetadataTest.kt @@ -18,13 +18,14 @@ class ModelMetadataTest { @Test fun `it should parse`() { - val contents = """ + val contents = + """ [crates.aws-sdk-someservice] kind = "Feature" [crates.aws-sdk-s3] kind = "Documentation" - """.trimIndent() + """.trimIndent() val result = ModelMetadata.fromString(contents) assertEquals(ChangeType.FEATURE, result.changeType("aws-sdk-someservice")) diff --git a/buildSrc/src/test/kotlin/aws/sdk/VersionsManifestTest.kt b/buildSrc/src/test/kotlin/aws/sdk/VersionsManifestTest.kt index 9ca9c954366..1aad2e53554 100644 --- a/buildSrc/src/test/kotlin/aws/sdk/VersionsManifestTest.kt +++ b/buildSrc/src/test/kotlin/aws/sdk/VersionsManifestTest.kt @@ -11,39 +11,42 @@ import org.junit.jupiter.api.Test class VersionsManifestTest { @Test fun `it should parse versions toml`() { - val manifest = VersionsManifest.fromString( - """ - smithy_rs_revision = 'some-smithy-rs-revision' - aws_doc_sdk_examples_revision = 'some-doc-revision' + val manifest = + VersionsManifest.fromString( + """ + smithy_rs_revision = 'some-smithy-rs-revision' + aws_doc_sdk_examples_revision = 'some-doc-revision' - [crates.aws-config] - category = 'AwsRuntime' - version = '0.12.0' - source_hash = '12d172094a2576e6f4d00a8ba58276c0d4abc4e241bb75f0d3de8ac3412e8e47' + [crates.aws-config] + category = 'AwsRuntime' + version = '0.12.0' + source_hash = '12d172094a2576e6f4d00a8ba58276c0d4abc4e241bb75f0d3de8ac3412e8e47' - [crates.aws-sdk-account] - category = 'AwsSdk' - version = '0.12.0' - source_hash = 'a0dfc080638b1d803745f0bd66b610131783cf40ab88fd710dce906fc69b983e' - model_hash = '179bbfd915093dc3bec5444771da2b20d99a37d104ba25f0acac9aa0d5bb758a' - """.trimIndent(), - ) + [crates.aws-sdk-account] + category = 'AwsSdk' + version = '0.12.0' + source_hash = 'a0dfc080638b1d803745f0bd66b610131783cf40ab88fd710dce906fc69b983e' + model_hash = '179bbfd915093dc3bec5444771da2b20d99a37d104ba25f0acac9aa0d5bb758a' + """.trimIndent(), + ) assertEquals("some-smithy-rs-revision", manifest.smithyRsRevision) assertEquals("some-doc-revision", manifest.awsDocSdkExamplesRevision) assertEquals( mapOf( - "aws-config" to CrateVersion( - category = "AwsRuntime", - version = "0.12.0", - sourceHash = "12d172094a2576e6f4d00a8ba58276c0d4abc4e241bb75f0d3de8ac3412e8e47", - ), - "aws-sdk-account" to CrateVersion( - category = "AwsSdk", - version = "0.12.0", - sourceHash = "a0dfc080638b1d803745f0bd66b610131783cf40ab88fd710dce906fc69b983e", - modelHash = "179bbfd915093dc3bec5444771da2b20d99a37d104ba25f0acac9aa0d5bb758a", - ), + "aws-config" to + CrateVersion( + category = "AwsRuntime", + version = "0.12.0", + sourceHash = "12d172094a2576e6f4d00a8ba58276c0d4abc4e241bb75f0d3de8ac3412e8e47", + ), + "aws-sdk-account" to + CrateVersion( + category = "AwsSdk", + version = "0.12.0", + sourceHash = "a0dfc080638b1d803745f0bd66b610131783cf40ab88fd710dce906fc69b983e", + modelHash = "179bbfd915093dc3bec5444771da2b20d99a37d104ba25f0acac9aa0d5bb758a", + ), ), manifest.crates, ) diff --git a/codegen-client-test/model/rest-xml-extras.smithy b/codegen-client-test/model/rest-xml-extras.smithy index b518ad09c69..2c18a35e920 100644 --- a/codegen-client-test/model/rest-xml-extras.smithy +++ b/codegen-client-test/model/rest-xml-extras.smithy @@ -21,6 +21,8 @@ service RestXmlExtras { StringHeader, CreateFoo, RequiredMember, + // TODO(https://github.com/smithy-lang/smithy-rs/issues/3315) + ZeroAndFalseQueryParams, ] } @@ -254,3 +256,32 @@ structure RequiredMemberInputOutput { @required requiredString: String } + +@httpRequestTests([ + { + id: "RestXmlZeroAndFalseQueryParamsAreSerialized" + protocol: restXml + code: 200 + method: "GET" + uri: "/ZeroAndFalseQueryParams" + body: "" + queryParams: [ + "Zero=0", + "False=false" + ] + params: { + zeroValue: 0 + falseValue: false + } + } +]) +@http(uri: "/ZeroAndFalseQueryParams", method: "GET") +operation ZeroAndFalseQueryParams { + input := { + @httpQuery("Zero") + zeroValue: Integer + + @httpQuery("False") + falseValue: Boolean + } +} diff --git a/codegen-client/build.gradle.kts b/codegen-client/build.gradle.kts index baed9a9b914..e274ed611dc 100644 --- a/codegen-client/build.gradle.kts +++ b/codegen-client/build.gradle.kts @@ -34,8 +34,13 @@ dependencies { testImplementation("software.amazon.smithy:smithy-validation-model:$smithyVersion") } +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + tasks.compileKotlin { - kotlinOptions.jvmTarget = "1.8" + kotlinOptions.jvmTarget = "11" } // Reusable license copySpec @@ -71,7 +76,7 @@ if (isTestingEnabled.toBoolean()) { } tasks.compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" + kotlinOptions.jvmTarget = "11" } tasks.test { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenContext.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenContext.kt index 64b3a2b2b36..60e6847be37 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenContext.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenContext.kt @@ -35,9 +35,10 @@ data class ClientCodegenContext( val rootDecorator: ClientCodegenDecorator, val protocolImpl: Protocol? = null, ) : CodegenContext( - model, symbolProvider, moduleDocProvider, serviceShape, protocol, settings, CodegenTarget.CLIENT, -) { + model, symbolProvider, moduleDocProvider, serviceShape, protocol, settings, CodegenTarget.CLIENT, + ) { val enableUserConfigurableRuntimePlugins: Boolean get() = settings.codegenConfig.enableUserConfigurableRuntimePlugins + override fun builderInstantiator(): BuilderInstantiator { return ClientBuilderInstantiator(this) } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenVisitor.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenVisitor.kt index ab26c7ae9ec..d057b7e6f56 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenVisitor.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenVisitor.kt @@ -73,49 +73,55 @@ class ClientCodegenVisitor( private val operationGenerator: OperationGenerator init { - val rustSymbolProviderConfig = RustSymbolProviderConfig( - runtimeConfig = settings.runtimeConfig, - renameExceptions = settings.codegenConfig.renameExceptions, - nullabilityCheckMode = settings.codegenConfig.nullabilityCheckMode, - moduleProvider = ClientModuleProvider, - nameBuilderFor = { symbol -> "${symbol.name}Builder" }, - ) + val rustSymbolProviderConfig = + RustSymbolProviderConfig( + runtimeConfig = settings.runtimeConfig, + renameExceptions = settings.codegenConfig.renameExceptions, + nullabilityCheckMode = settings.codegenConfig.nullabilityCheckMode, + moduleProvider = ClientModuleProvider, + nameBuilderFor = { symbol -> "${symbol.name}Builder" }, + ) val baseModel = baselineTransform(context.model) val untransformedService = settings.getService(baseModel) - val (protocol, generator) = ClientProtocolLoader( - codegenDecorator.protocols(untransformedService.id, ClientProtocolLoader.DefaultProtocols), - ).protocolFor(context.model, untransformedService) + val (protocol, generator) = + ClientProtocolLoader( + codegenDecorator.protocols(untransformedService.id, ClientProtocolLoader.DefaultProtocols), + ).protocolFor(context.model, untransformedService) protocolGeneratorFactory = generator model = codegenDecorator.transformModel(untransformedService, baseModel, settings) // the model transformer _might_ change the service shape val service = settings.getService(model) symbolProvider = RustClientCodegenPlugin.baseSymbolProvider(settings, model, service, rustSymbolProviderConfig, codegenDecorator) - codegenContext = ClientCodegenContext( - model, - symbolProvider, - null, - service, - protocol, - settings, - codegenDecorator, - ) + codegenContext = + ClientCodegenContext( + model, + symbolProvider, + null, + service, + protocol, + settings, + codegenDecorator, + ) - codegenContext = codegenContext.copy( - moduleDocProvider = codegenDecorator.moduleDocumentationCustomization( - codegenContext, - ClientModuleDocProvider(codegenContext, service.serviceNameOrDefault("the service")), - ), - protocolImpl = protocolGeneratorFactory.protocol(codegenContext), - ) + codegenContext = + codegenContext.copy( + moduleDocProvider = + codegenDecorator.moduleDocumentationCustomization( + codegenContext, + ClientModuleDocProvider(codegenContext, service.serviceNameOrDefault("the service")), + ), + protocolImpl = protocolGeneratorFactory.protocol(codegenContext), + ) - rustCrate = RustCrate( - context.fileManifest, - symbolProvider, - codegenContext.settings.codegenConfig, - codegenContext.expectModuleDocProvider(), - ) + rustCrate = + RustCrate( + context.fileManifest, + symbolProvider, + codegenContext.settings.codegenConfig, + codegenContext.expectModuleDocProvider(), + ) operationGenerator = protocolGeneratorFactory.buildProtocolGenerator(codegenContext) } @@ -214,44 +220,46 @@ class ClientCodegenVisitor( * This function _does not_ generate any serializers */ override fun structureShape(shape: StructureShape) { - val (renderStruct, renderBuilder) = when (val errorTrait = shape.getTrait()) { - null -> { - val struct: Writable = { - StructureGenerator( - model, - symbolProvider, - this, - shape, - codegenDecorator.structureCustomizations(codegenContext, emptyList()), - structSettings = codegenContext.structSettings(), - ).render() + val (renderStruct, renderBuilder) = + when (val errorTrait = shape.getTrait()) { + null -> { + val struct: Writable = { + StructureGenerator( + model, + symbolProvider, + this, + shape, + codegenDecorator.structureCustomizations(codegenContext, emptyList()), + structSettings = codegenContext.structSettings(), + ).render() - implBlock(symbolProvider.toSymbol(shape)) { - BuilderGenerator.renderConvenienceMethod(this, symbolProvider, shape) + implBlock(symbolProvider.toSymbol(shape)) { + BuilderGenerator.renderConvenienceMethod(this, symbolProvider, shape) + } } + val builder: Writable = { + BuilderGenerator( + codegenContext.model, + codegenContext.symbolProvider, + shape, + codegenDecorator.builderCustomizations(codegenContext, emptyList()), + ).render(this) + } + struct to builder } - val builder: Writable = { - BuilderGenerator( - codegenContext.model, - codegenContext.symbolProvider, - shape, - codegenDecorator.builderCustomizations(codegenContext, emptyList()), - ).render(this) + else -> { + val errorGenerator = + ErrorGenerator( + model, + symbolProvider, + shape, + errorTrait, + codegenDecorator.errorImplCustomizations(codegenContext, emptyList()), + codegenContext.structSettings(), + ) + errorGenerator::renderStruct to errorGenerator::renderBuilder } - struct to builder } - else -> { - val errorGenerator = ErrorGenerator( - model, - symbolProvider, - shape, - errorTrait, - codegenDecorator.errorImplCustomizations(codegenContext, emptyList()), - codegenContext.structSettings(), - ) - errorGenerator::renderStruct to errorGenerator::renderBuilder - } - } val privateModule = privateModule(shape) rustCrate.inPrivateModuleWithReexport(privateModule, symbolProvider.toSymbol(shape)) { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReExports.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReExports.kt index 6aaf638680c..e9154df9ff1 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReExports.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReExports.kt @@ -12,6 +12,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType * Although it is not always possible to use this, this is the preferred method for using types in config customizations * and ensures that your type will be re-exported if it is used. */ -fun configReexport(type: RuntimeType): RuntimeType = RuntimeType.forInlineFun(type.name, module = ClientRustModule.config) { - rustTemplate("pub use #{type};", "type" to type) -} +fun configReexport(type: RuntimeType): RuntimeType = + RuntimeType.forInlineFun(type.name, module = ClientRustModule.config) { + rustTemplate("pub use #{type};", "type" to type) + } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReservedWords.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReservedWords.kt index add9f53f6df..e2ff13dd4f4 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReservedWords.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientReservedWords.kt @@ -9,27 +9,31 @@ import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordConfig import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureGenerator import software.amazon.smithy.rust.codegen.core.smithy.generators.UnionGenerator -val ClientReservedWords = RustReservedWordConfig( - structureMemberMap = StructureGenerator.structureMemberNameMap + - mapOf( - "send" to "send_value", - // To avoid conflicts with the `make_operation` and `presigned` functions on generated inputs - "make_operation" to "make_operation_value", - "presigned" to "presigned_value", - "customize" to "customize_value", - // To avoid conflicts with the error metadata `meta` field - "meta" to "meta_value", - ), - unionMemberMap = mapOf( - // Unions contain an `Unknown` variant. This exists to support parsing data returned from the server - // that represent union variants that have been added since this SDK was generated. - UnionGenerator.UnknownVariantName to "${UnionGenerator.UnknownVariantName}Value", - "${UnionGenerator.UnknownVariantName}Value" to "${UnionGenerator.UnknownVariantName}Value_", - ), - enumMemberMap = mapOf( - // Unknown is used as the name of the variant containing unexpected values - "Unknown" to "UnknownValue", - // Real models won't end in `_` so it's safe to stop here - "UnknownValue" to "UnknownValue_", - ), -) +val ClientReservedWords = + RustReservedWordConfig( + structureMemberMap = + StructureGenerator.structureMemberNameMap + + mapOf( + "send" to "send_value", + // To avoid conflicts with the `make_operation` and `presigned` functions on generated inputs + "make_operation" to "make_operation_value", + "presigned" to "presigned_value", + "customize" to "customize_value", + // To avoid conflicts with the error metadata `meta` field + "meta" to "meta_value", + ), + unionMemberMap = + mapOf( + // Unions contain an `Unknown` variant. This exists to support parsing data returned from the server + // that represent union variants that have been added since this SDK was generated. + UnionGenerator.UnknownVariantName to "${UnionGenerator.UnknownVariantName}Value", + "${UnionGenerator.UnknownVariantName}Value" to "${UnionGenerator.UnknownVariantName}Value_", + ), + enumMemberMap = + mapOf( + // Unknown is used as the name of the variant containing unexpected values + "Unknown" to "UnknownValue", + // Real models won't end in `_` so it's safe to stop here + "UnknownValue" to "UnknownValue_", + ), + ) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustModule.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustModule.kt index 0216b2618cc..9d33c1b1c58 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustModule.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustModule.kt @@ -46,6 +46,7 @@ object ClientRustModule { /** crate::client */ val client = Client.self + object Client { /** crate::client */ val self = RustModule.public("client") @@ -56,6 +57,7 @@ object ClientRustModule { /** crate::config */ val config = Config.self + object Config { /** crate::client */ val self = RustModule.public("config") @@ -81,6 +83,7 @@ object ClientRustModule { /** crate::primitives */ val primitives = Primitives.self + object Primitives { /** crate::primitives */ val self = RustModule.public("primitives") @@ -91,6 +94,7 @@ object ClientRustModule { /** crate::types */ val types = Types.self + object Types { /** crate::types */ val self = RustModule.public("types") @@ -127,71 +131,80 @@ class ClientModuleDocProvider( } } - private fun clientModuleDoc(): Writable = writable { - val genericClientConstructionDocs = FluentClientDocs.clientConstructionDocs(codegenContext) - val writeClientConstructionDocs = codegenContext.rootDecorator - .clientConstructionDocs(codegenContext, genericClientConstructionDocs) + private fun clientModuleDoc(): Writable = + writable { + val genericClientConstructionDocs = FluentClientDocs.clientConstructionDocs(codegenContext) + val writeClientConstructionDocs = + codegenContext.rootDecorator + .clientConstructionDocs(codegenContext, genericClientConstructionDocs) - writeClientConstructionDocs(this) - FluentClientDocs.clientUsageDocs(codegenContext)(this) - } + writeClientConstructionDocs(this) + FluentClientDocs.clientUsageDocs(codegenContext)(this) + } - private fun customizeModuleDoc(): Writable = writable { - val model = codegenContext.model - docs("Operation customization and supporting types.\n") - if (codegenContext.serviceShape.operations.isNotEmpty()) { - val opFnName = FluentClientGenerator.clientOperationFnName( - codegenContext.serviceShape.operations.minOf { it } - .let { model.expectShape(it, OperationShape::class.java) }, - codegenContext.symbolProvider, - ) - val moduleUseName = codegenContext.moduleUseName() - docsTemplate( - """ - The underlying HTTP requests made during an operation can be customized - by calling the `customize()` method on the builder returned from a client - operation call. For example, this can be used to add an additional HTTP header: - - ```ignore - ## async fn wrapper() -> #{Result}<(), $moduleUseName::Error> { - ## let client: $moduleUseName::Client = unimplemented!(); - use #{http}::header::{HeaderName, HeaderValue}; - - let result = client.$opFnName() - .customize() - .mutate_request(|req| { - // Add `x-example-header` with value - req.headers_mut() - .insert( - HeaderName::from_static("x-example-header"), - HeaderValue::from_static("1"), - ); - }) - .send() - .await; - ## } - ``` - """.trimIndent(), - *RuntimeType.preludeScope, - "http" to CargoDependency.Http.toDevDependency().toType(), - ) + private fun customizeModuleDoc(): Writable = + writable { + val model = codegenContext.model + docs("Operation customization and supporting types.\n") + if (codegenContext.serviceShape.operations.isNotEmpty()) { + val opFnName = + FluentClientGenerator.clientOperationFnName( + codegenContext.serviceShape.operations.minOf { it } + .let { model.expectShape(it, OperationShape::class.java) }, + codegenContext.symbolProvider, + ) + val moduleUseName = codegenContext.moduleUseName() + docsTemplate( + """ + The underlying HTTP requests made during an operation can be customized + by calling the `customize()` method on the builder returned from a client + operation call. For example, this can be used to add an additional HTTP header: + + ```ignore + ## async fn wrapper() -> #{Result}<(), $moduleUseName::Error> { + ## let client: $moduleUseName::Client = unimplemented!(); + use #{http}::header::{HeaderName, HeaderValue}; + + let result = client.$opFnName() + .customize() + .mutate_request(|req| { + // Add `x-example-header` with value + req.headers_mut() + .insert( + HeaderName::from_static("x-example-header"), + HeaderValue::from_static("1"), + ); + }) + .send() + .await; + ## } + ``` + """.trimIndent(), + *RuntimeType.preludeScope, + "http" to CargoDependency.Http.toDevDependency().toType(), + ) + } } - } } object ClientModuleProvider : ModuleProvider { - override fun moduleForShape(context: ModuleProviderContext, shape: Shape): RustModule.LeafModule = when (shape) { - is OperationShape -> perOperationModule(context, shape) - is StructureShape -> when { - shape.hasTrait() -> ClientRustModule.Types.Error - shape.hasTrait() -> perOperationModule(context, shape) - shape.hasTrait() -> perOperationModule(context, shape) + override fun moduleForShape( + context: ModuleProviderContext, + shape: Shape, + ): RustModule.LeafModule = + when (shape) { + is OperationShape -> perOperationModule(context, shape) + is StructureShape -> + when { + shape.hasTrait() -> ClientRustModule.Types.Error + shape.hasTrait() -> perOperationModule(context, shape) + shape.hasTrait() -> perOperationModule(context, shape) + else -> ClientRustModule.types + } + else -> ClientRustModule.types } - else -> ClientRustModule.types - } - override fun moduleForOperationError( context: ModuleProviderContext, operation: OperationShape, @@ -202,7 +215,11 @@ object ClientModuleProvider : ModuleProvider { eventStream: UnionShape, ): RustModule.LeafModule = ClientRustModule.Types.Error - override fun moduleForBuilder(context: ModuleProviderContext, shape: Shape, symbol: Symbol): RustModule.LeafModule = + override fun moduleForBuilder( + context: ModuleProviderContext, + shape: Shape, + symbol: Symbol, + ): RustModule.LeafModule = RustModule.public("builders", parent = symbol.module(), documentationOverride = "Builders") private fun Shape.findOperation(model: Model): OperationShape { @@ -216,7 +233,10 @@ object ClientModuleProvider : ModuleProvider { } } - private fun perOperationModule(context: ModuleProviderContext, shape: Shape): RustModule.LeafModule { + private fun perOperationModule( + context: ModuleProviderContext, + shape: Shape, + ): RustModule.LeafModule { val operationShape = shape.findOperation(context.model) val contextName = operationShape.contextName(context.serviceShape) val operationModuleName = diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustSettings.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustSettings.kt index 67b76f0862b..ebb5db6a0a2 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustSettings.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientRustSettings.kt @@ -16,7 +16,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.core.util.orNull import java.util.Optional -/** +/* * [ClientRustSettings] and [ClientCodegenConfig] classes. * * These are specializations of [CoreRustSettings] and [CodegenConfig] for the `rust-client-codegen` @@ -39,20 +39,23 @@ data class ClientRustSettings( override val examplesUri: String?, override val customizationConfig: ObjectNode?, ) : CoreRustSettings( - service, - moduleName, - moduleVersion, - moduleAuthors, - moduleDescription, - moduleRepository, - runtimeConfig, - codegenConfig, - license, - examplesUri, - customizationConfig, -) { + service, + moduleName, + moduleVersion, + moduleAuthors, + moduleDescription, + moduleRepository, + runtimeConfig, + codegenConfig, + license, + examplesUri, + customizationConfig, + ) { companion object { - fun from(model: Model, config: ObjectNode): ClientRustSettings { + fun from( + model: Model, + config: ObjectNode, + ): ClientRustSettings { val coreRustSettings = CoreRustSettings.from(model, config) val codegenSettingsNode = config.getObjectMember(CODEGEN_SETTINGS) val coreCodegenConfig = CoreCodegenConfig.fromNode(codegenSettingsNode) @@ -93,8 +96,8 @@ data class ClientCodegenConfig( val includeEndpointUrlConfig: Boolean = defaultIncludeEndpointUrlConfig, val enableUserConfigurableRuntimePlugins: Boolean = defaultEnableUserConfigurableRuntimePlugins, ) : CoreCodegenConfig( - formatTimeoutSeconds, debugMode, defaultFlattenAccessors, -) { + formatTimeoutSeconds, debugMode, defaultFlattenAccessors, + ) { companion object { private const val defaultRenameExceptions = true private const val defaultIncludeFluentClient = true @@ -107,30 +110,33 @@ data class ClientCodegenConfig( // Note: only clients default to true, servers default to false private const val defaultFlattenAccessors = true - fun fromCodegenConfigAndNode(coreCodegenConfig: CoreCodegenConfig, node: Optional) = - if (node.isPresent) { - ClientCodegenConfig( - formatTimeoutSeconds = coreCodegenConfig.formatTimeoutSeconds, - flattenCollectionAccessors = node.get().getBooleanMemberOrDefault("flattenCollectionAccessors", defaultFlattenAccessors), - debugMode = coreCodegenConfig.debugMode, - eventStreamAllowList = node.get().getArrayMember("eventStreamAllowList").map { array -> + fun fromCodegenConfigAndNode( + coreCodegenConfig: CoreCodegenConfig, + node: Optional, + ) = if (node.isPresent) { + ClientCodegenConfig( + formatTimeoutSeconds = coreCodegenConfig.formatTimeoutSeconds, + flattenCollectionAccessors = node.get().getBooleanMemberOrDefault("flattenCollectionAccessors", defaultFlattenAccessors), + debugMode = coreCodegenConfig.debugMode, + eventStreamAllowList = + node.get().getArrayMember("eventStreamAllowList").map { array -> array.toList().mapNotNull { node -> node.asStringNode().orNull()?.value } }.orNull()?.toSet() ?: defaultEventStreamAllowList, - renameExceptions = node.get().getBooleanMemberOrDefault("renameErrors", defaultRenameExceptions), - includeFluentClient = node.get().getBooleanMemberOrDefault("includeFluentClient", defaultIncludeFluentClient), - addMessageToErrors = node.get().getBooleanMemberOrDefault("addMessageToErrors", defaultAddMessageToErrors), - includeEndpointUrlConfig = node.get().getBooleanMemberOrDefault("includeEndpointUrlConfig", defaultIncludeEndpointUrlConfig), - enableUserConfigurableRuntimePlugins = node.get().getBooleanMemberOrDefault("enableUserConfigurableRuntimePlugins", defaultEnableUserConfigurableRuntimePlugins), - nullabilityCheckMode = NullableIndex.CheckMode.valueOf(node.get().getStringMemberOrDefault("nullabilityCheckMode", defaultNullabilityCheckMode)), - ) - } else { - ClientCodegenConfig( - formatTimeoutSeconds = coreCodegenConfig.formatTimeoutSeconds, - debugMode = coreCodegenConfig.debugMode, - nullabilityCheckMode = NullableIndex.CheckMode.valueOf(defaultNullabilityCheckMode), - ) - } + renameExceptions = node.get().getBooleanMemberOrDefault("renameErrors", defaultRenameExceptions), + includeFluentClient = node.get().getBooleanMemberOrDefault("includeFluentClient", defaultIncludeFluentClient), + addMessageToErrors = node.get().getBooleanMemberOrDefault("addMessageToErrors", defaultAddMessageToErrors), + includeEndpointUrlConfig = node.get().getBooleanMemberOrDefault("includeEndpointUrlConfig", defaultIncludeEndpointUrlConfig), + enableUserConfigurableRuntimePlugins = node.get().getBooleanMemberOrDefault("enableUserConfigurableRuntimePlugins", defaultEnableUserConfigurableRuntimePlugins), + nullabilityCheckMode = NullableIndex.CheckMode.valueOf(node.get().getStringMemberOrDefault("nullabilityCheckMode", defaultNullabilityCheckMode)), + ) + } else { + ClientCodegenConfig( + formatTimeoutSeconds = coreCodegenConfig.formatTimeoutSeconds, + debugMode = coreCodegenConfig.debugMode, + nullabilityCheckMode = NullableIndex.CheckMode.valueOf(defaultNullabilityCheckMode), + ) + } } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt index ecfe3e0092c..1087a63feb5 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/RustClientCodegenPlugin.kt @@ -92,20 +92,19 @@ class RustClientCodegenPlugin : ClientDecoratableBuildPlugin() { serviceShape: ServiceShape, rustSymbolProviderConfig: RustSymbolProviderConfig, codegenDecorator: ClientCodegenDecorator, - ) = - SymbolVisitor(settings, model, serviceShape = serviceShape, config = rustSymbolProviderConfig) - // Generate different types for EventStream shapes (e.g. transcribe streaming) - .let { EventStreamSymbolProvider(rustSymbolProviderConfig.runtimeConfig, it, CodegenTarget.CLIENT) } - // Generate `ByteStream` instead of `Blob` for streaming binary shapes (e.g. S3 GetObject) - .let { StreamingShapeSymbolProvider(it) } - // Add Rust attributes (like `#[derive(PartialEq)]`) to generated shapes - .let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf(NonExhaustive)) } - // Streaming shapes need different derives (e.g. they cannot derive `PartialEq`) - .let { StreamingShapeMetadataProvider(it) } - // Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot - // be the name of an operation input - .let { RustReservedWordSymbolProvider(it, ClientReservedWords) } - // Allows decorators to inject a custom symbol provider - .let { codegenDecorator.symbolProvider(it) } + ) = SymbolVisitor(settings, model, serviceShape = serviceShape, config = rustSymbolProviderConfig) + // Generate different types for EventStream shapes (e.g. transcribe streaming) + .let { EventStreamSymbolProvider(rustSymbolProviderConfig.runtimeConfig, it, CodegenTarget.CLIENT) } + // Generate `ByteStream` instead of `Blob` for streaming binary shapes (e.g. S3 GetObject) + .let { StreamingShapeSymbolProvider(it) } + // Add Rust attributes (like `#[derive(PartialEq)]`) to generated shapes + .let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf(NonExhaustive)) } + // Streaming shapes need different derives (e.g. they cannot derive `PartialEq`) + .let { StreamingShapeMetadataProvider(it) } + // Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot + // be the name of an operation input + .let { RustReservedWordSymbolProvider(it, ClientReservedWords) } + // Allows decorators to inject a custom symbol provider + .let { codegenDecorator.symbolProvider(it) } } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ClientDocsGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ClientDocsGenerator.kt index 6c55a4e682d..fb709ac61ef 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ClientDocsGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ClientDocsGenerator.kt @@ -18,11 +18,12 @@ import software.amazon.smithy.rust.codegen.core.util.getTrait class ClientDocsGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { override fun section(section: LibRsSection): Writable { return when (section) { - is LibRsSection.ModuleDoc -> if (section.subsection is ModuleDocSection.CrateOrganization) { - crateLayout() - } else { - emptySection - } + is LibRsSection.ModuleDoc -> + if (section.subsection is ModuleDocSection.CrateOrganization) { + crateLayout() + } else { + emptySection + } else -> emptySection } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ConnectionPoisoningConfigCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ConnectionPoisoningConfigCustomization.kt index 5f1688037e2..e611e4832f6 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ConnectionPoisoningConfigCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ConnectionPoisoningConfigCustomization.kt @@ -18,20 +18,21 @@ class ConnectionPoisoningRuntimePluginCustomization( ) : ServiceRuntimePluginCustomization() { private val runtimeConfig = codegenContext.runtimeConfig - override fun section(section: ServiceRuntimePluginSection): Writable = writable { - when (section) { - is ServiceRuntimePluginSection.RegisterRuntimeComponents -> { - // This interceptor assumes that a compatible Connector is set. Otherwise, connection poisoning - // won't work and an error message will be logged. - section.registerInterceptor(this) { - rust( - "#T::new()", - smithyRuntime(runtimeConfig).resolve("client::http::connection_poisoning::ConnectionPoisoningInterceptor"), - ) + override fun section(section: ServiceRuntimePluginSection): Writable = + writable { + when (section) { + is ServiceRuntimePluginSection.RegisterRuntimeComponents -> { + // This interceptor assumes that a compatible Connector is set. Otherwise, connection poisoning + // won't work and an error message will be logged. + section.registerInterceptor(this) { + rust( + "#T::new()", + smithyRuntime(runtimeConfig).resolve("client::http::connection_poisoning::ConnectionPoisoningInterceptor"), + ) + } } - } - else -> emptySection + else -> emptySection + } } - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/DocsRsMetadataDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/DocsRsMetadataDecorator.kt index 442cedcf23d..b6f5517d758 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/DocsRsMetadataDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/DocsRsMetadataDecorator.kt @@ -26,16 +26,17 @@ data class DocsRsMetadataSettings( ) fun DocsRsMetadataSettings.asMap(): Map { - val inner = listOfNotNull( - features?.let { "features" to it }, - allFeatures?.let { "all-features" to it }, - noDefaultFeatures?.let { "no-default-features" to it }, - defaultTarget?.let { "no-default-target" to it }, - targets?.let { "targets" to it }, - rustcArgs?.let { "rustc-args" to it }, - rustdocArgs?.let { "rustdoc-args" to it }, - cargoArgs?.let { "cargo-args" to it }, - ).toMap() + custom + val inner = + listOfNotNull( + features?.let { "features" to it }, + allFeatures?.let { "all-features" to it }, + noDefaultFeatures?.let { "no-default-features" to it }, + defaultTarget?.let { "no-default-target" to it }, + targets?.let { "targets" to it }, + rustcArgs?.let { "rustc-args" to it }, + rustdocArgs?.let { "rustdoc-args" to it }, + cargoArgs?.let { "cargo-args" to it }, + ).toMap() + custom return mapOf("package" to mapOf("metadata" to mapOf("docs" to mapOf("rs" to inner)))) } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecorator.kt index 1f11f991643..676700e6d68 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecorator.kt @@ -40,7 +40,6 @@ private fun codegenScope(runtimeConfig: RuntimeConfig): Array> "Token" to configReexport(smithyRuntimeApi.resolve("client::identity::http::Token")), "Login" to configReexport(smithyRuntimeApi.resolve("client::identity::http::Login")), "ResolveIdentity" to configReexport(smithyRuntimeApi.resolve("client::identity::ResolveIdentity")), - "AuthSchemeId" to smithyRuntimeApi.resolve("client::auth::AuthSchemeId"), "ApiKeyAuthScheme" to authHttp.resolve("ApiKeyAuthScheme"), "ApiKeyLocation" to authHttp.resolve("ApiKeyLocation"), @@ -75,7 +74,9 @@ private data class HttpAuthSchemes( } fun anyEnabled(): Boolean = isTokenBased() || isLoginBased() + fun isTokenBased(): Boolean = apiKey || bearer + fun isLoginBased(): Boolean = basic || digest } @@ -93,7 +94,10 @@ class HttpAuthDecorator : ClientCodegenDecorator { val codegenScope = codegenScope(codegenContext.runtimeConfig) val options = ArrayList() for (authScheme in authSchemes.keys) { - fun addOption(schemeShapeId: ShapeId, name: String) { + fun addOption( + schemeShapeId: ShapeId, + name: String, + ) { options.add( StaticAuthSchemeOption( schemeShapeId, @@ -144,61 +148,63 @@ private class HttpAuthServiceRuntimePluginCustomization( private val serviceShape = codegenContext.serviceShape private val codegenScope = codegenScope(codegenContext.runtimeConfig) - override fun section(section: ServiceRuntimePluginSection): Writable = writable { - when (section) { - is ServiceRuntimePluginSection.RegisterRuntimeComponents -> { - fun registerAuthScheme(scheme: Writable) { - section.registerAuthScheme(this) { - rustTemplate("#{SharedAuthScheme}::new(#{Scheme})", *codegenScope, "Scheme" to scheme) + override fun section(section: ServiceRuntimePluginSection): Writable = + writable { + when (section) { + is ServiceRuntimePluginSection.RegisterRuntimeComponents -> { + fun registerAuthScheme(scheme: Writable) { + section.registerAuthScheme(this) { + rustTemplate("#{SharedAuthScheme}::new(#{Scheme})", *codegenScope, "Scheme" to scheme) + } } - } - fun registerNamedAuthScheme(name: String) { - registerAuthScheme { - rustTemplate("#{$name}::new()", *codegenScope) + fun registerNamedAuthScheme(name: String) { + registerAuthScheme { + rustTemplate("#{$name}::new()", *codegenScope) + } } - } - if (authSchemes.apiKey) { - val trait = serviceShape.getTrait()!! - val location = when (trait.`in`!!) { - HttpApiKeyAuthTrait.Location.HEADER -> { - check(trait.scheme.isPresent) { - "A scheme is required for `@httpApiKey` when `in` is set to `header`" - } - "Header" - } + if (authSchemes.apiKey) { + val trait = serviceShape.getTrait()!! + val location = + when (trait.`in`!!) { + HttpApiKeyAuthTrait.Location.HEADER -> { + check(trait.scheme.isPresent) { + "A scheme is required for `@httpApiKey` when `in` is set to `header`" + } + "Header" + } - HttpApiKeyAuthTrait.Location.QUERY -> "Query" - } + HttpApiKeyAuthTrait.Location.QUERY -> "Query" + } - registerAuthScheme { - rustTemplate( - """ - #{ApiKeyAuthScheme}::new( - ${trait.scheme.orElse("").dq()}, - #{ApiKeyLocation}::$location, - ${trait.name.dq()}, + registerAuthScheme { + rustTemplate( + """ + #{ApiKeyAuthScheme}::new( + ${trait.scheme.orElse("").dq()}, + #{ApiKeyLocation}::$location, + ${trait.name.dq()}, + ) + """, + *codegenScope, ) - """, - *codegenScope, - ) + } + } + if (authSchemes.basic) { + registerNamedAuthScheme("BasicAuthScheme") + } + if (authSchemes.bearer) { + registerNamedAuthScheme("BearerAuthScheme") + } + if (authSchemes.digest) { + registerNamedAuthScheme("DigestAuthScheme") } } - if (authSchemes.basic) { - registerNamedAuthScheme("BasicAuthScheme") - } - if (authSchemes.bearer) { - registerNamedAuthScheme("BearerAuthScheme") - } - if (authSchemes.digest) { - registerNamedAuthScheme("DigestAuthScheme") - } - } - else -> emptySection + else -> emptySection + } } - } } private class HttpAuthConfigCustomization( @@ -207,92 +213,93 @@ private class HttpAuthConfigCustomization( ) : ConfigCustomization() { private val codegenScope = codegenScope(codegenContext.runtimeConfig) - override fun section(section: ServiceConfig): Writable = writable { - when (section) { - is ServiceConfig.BuilderImpl -> { - if (authSchemes.apiKey) { - rustTemplate( - """ - /// Sets the API key that will be used for authentication. - pub fn api_key(self, api_key: #{Token}) -> Self { - self.api_key_resolver(api_key) - } + override fun section(section: ServiceConfig): Writable = + writable { + when (section) { + is ServiceConfig.BuilderImpl -> { + if (authSchemes.apiKey) { + rustTemplate( + """ + /// Sets the API key that will be used for authentication. + pub fn api_key(self, api_key: #{Token}) -> Self { + self.api_key_resolver(api_key) + } - /// Sets an API key resolver will be used for authentication. - pub fn api_key_resolver(mut self, api_key_resolver: impl #{ResolveIdentity} + 'static) -> Self { - self.runtime_components.set_identity_resolver( - #{HTTP_API_KEY_AUTH_SCHEME_ID}, - #{SharedIdentityResolver}::new(api_key_resolver) - ); - self - } - """, - *codegenScope, - ) - } - if (authSchemes.bearer) { - rustTemplate( - """ - /// Sets the bearer token that will be used for HTTP bearer auth. - pub fn bearer_token(self, bearer_token: #{Token}) -> Self { - self.bearer_token_resolver(bearer_token) - } + /// Sets an API key resolver will be used for authentication. + pub fn api_key_resolver(mut self, api_key_resolver: impl #{ResolveIdentity} + 'static) -> Self { + self.runtime_components.set_identity_resolver( + #{HTTP_API_KEY_AUTH_SCHEME_ID}, + #{SharedIdentityResolver}::new(api_key_resolver) + ); + self + } + """, + *codegenScope, + ) + } + if (authSchemes.bearer) { + rustTemplate( + """ + /// Sets the bearer token that will be used for HTTP bearer auth. + pub fn bearer_token(self, bearer_token: #{Token}) -> Self { + self.bearer_token_resolver(bearer_token) + } - /// Sets a bearer token provider that will be used for HTTP bearer auth. - pub fn bearer_token_resolver(mut self, bearer_token_resolver: impl #{ResolveIdentity} + 'static) -> Self { - self.runtime_components.set_identity_resolver( - #{HTTP_BEARER_AUTH_SCHEME_ID}, - #{SharedIdentityResolver}::new(bearer_token_resolver) - ); - self - } - """, - *codegenScope, - ) - } - if (authSchemes.basic) { - rustTemplate( - """ - /// Sets the login that will be used for HTTP basic auth. - pub fn basic_auth_login(self, basic_auth_login: #{Login}) -> Self { - self.basic_auth_login_resolver(basic_auth_login) - } + /// Sets a bearer token provider that will be used for HTTP bearer auth. + pub fn bearer_token_resolver(mut self, bearer_token_resolver: impl #{ResolveIdentity} + 'static) -> Self { + self.runtime_components.set_identity_resolver( + #{HTTP_BEARER_AUTH_SCHEME_ID}, + #{SharedIdentityResolver}::new(bearer_token_resolver) + ); + self + } + """, + *codegenScope, + ) + } + if (authSchemes.basic) { + rustTemplate( + """ + /// Sets the login that will be used for HTTP basic auth. + pub fn basic_auth_login(self, basic_auth_login: #{Login}) -> Self { + self.basic_auth_login_resolver(basic_auth_login) + } - /// Sets a login resolver that will be used for HTTP basic auth. - pub fn basic_auth_login_resolver(mut self, basic_auth_resolver: impl #{ResolveIdentity} + 'static) -> Self { - self.runtime_components.set_identity_resolver( - #{HTTP_BASIC_AUTH_SCHEME_ID}, - #{SharedIdentityResolver}::new(basic_auth_resolver) - ); - self - } - """, - *codegenScope, - ) - } - if (authSchemes.digest) { - rustTemplate( - """ - /// Sets the login that will be used for HTTP digest auth. - pub fn digest_auth_login(self, digest_auth_login: #{Login}) -> Self { - self.digest_auth_login_resolver(digest_auth_login) - } + /// Sets a login resolver that will be used for HTTP basic auth. + pub fn basic_auth_login_resolver(mut self, basic_auth_resolver: impl #{ResolveIdentity} + 'static) -> Self { + self.runtime_components.set_identity_resolver( + #{HTTP_BASIC_AUTH_SCHEME_ID}, + #{SharedIdentityResolver}::new(basic_auth_resolver) + ); + self + } + """, + *codegenScope, + ) + } + if (authSchemes.digest) { + rustTemplate( + """ + /// Sets the login that will be used for HTTP digest auth. + pub fn digest_auth_login(self, digest_auth_login: #{Login}) -> Self { + self.digest_auth_login_resolver(digest_auth_login) + } - /// Sets a login resolver that will be used for HTTP digest auth. - pub fn digest_auth_login_resolver(mut self, digest_auth_resolver: impl #{ResolveIdentity} + 'static) -> Self { - self.runtime_components.set_identity_resolver( - #{HTTP_DIGEST_AUTH_SCHEME_ID}, - #{SharedIdentityResolver}::new(digest_auth_resolver) - ); - self - } - """, - *codegenScope, - ) + /// Sets a login resolver that will be used for HTTP digest auth. + pub fn digest_auth_login_resolver(mut self, digest_auth_resolver: impl #{ResolveIdentity} + 'static) -> Self { + self.runtime_components.set_identity_resolver( + #{HTTP_DIGEST_AUTH_SCHEME_ID}, + #{SharedIdentityResolver}::new(digest_auth_resolver) + ); + self + } + """, + *codegenScope, + ) + } } - } - else -> {} + else -> {} + } } - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpChecksumRequiredGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpChecksumRequiredGenerator.kt index aba470973da..c4826763e55 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpChecksumRequiredGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpChecksumRequiredGenerator.kt @@ -35,22 +35,23 @@ class HttpChecksumRequiredGenerator( throw CodegenException("HttpChecksum required cannot be applied to a streaming shape") } return when (section) { - is OperationSection.AdditionalRuntimePlugins -> writable { - section.addOperationRuntimePlugin(this) { - rustTemplate( - "#{HttpChecksumRequiredRuntimePlugin}::new()", - "HttpChecksumRequiredRuntimePlugin" to - InlineDependency.forRustFile( - RustModule.pubCrate("client_http_checksum_required", parent = ClientRustModule.root), - "/inlineable/src/client_http_checksum_required.rs", - CargoDependency.smithyRuntimeApiClient(codegenContext.runtimeConfig), - CargoDependency.smithyTypes(codegenContext.runtimeConfig), - CargoDependency.Http, - CargoDependency.Md5, - ).toType().resolve("HttpChecksumRequiredRuntimePlugin"), - ) + is OperationSection.AdditionalRuntimePlugins -> + writable { + section.addOperationRuntimePlugin(this) { + rustTemplate( + "#{HttpChecksumRequiredRuntimePlugin}::new()", + "HttpChecksumRequiredRuntimePlugin" to + InlineDependency.forRustFile( + RustModule.pubCrate("client_http_checksum_required", parent = ClientRustModule.root), + "/inlineable/src/client_http_checksum_required.rs", + CargoDependency.smithyRuntimeApiClient(codegenContext.runtimeConfig), + CargoDependency.smithyTypes(codegenContext.runtimeConfig), + CargoDependency.Http, + CargoDependency.Md5, + ).toType().resolve("HttpChecksumRequiredRuntimePlugin"), + ) + } } - } else -> emptySection } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpConnectorConfigDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpConnectorConfigDecorator.kt index 343292055f3..c8a7a7e211e 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpConnectorConfigDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpConnectorConfigDecorator.kt @@ -31,105 +31,110 @@ private class HttpConnectorConfigCustomization( ) : ConfigCustomization() { private val runtimeConfig = codegenContext.runtimeConfig private val moduleUseName = codegenContext.moduleUseName() - private val codegenScope = arrayOf( - *preludeScope, - "HttpClient" to configReexport( - RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::http::HttpClient"), - ), - "IntoShared" to configReexport(RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("shared::IntoShared")), - "SharedHttpClient" to configReexport( - RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::http::SharedHttpClient"), - ), - ) + private val codegenScope = + arrayOf( + *preludeScope, + "HttpClient" to + configReexport( + RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::http::HttpClient"), + ), + "IntoShared" to configReexport(RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("shared::IntoShared")), + "SharedHttpClient" to + configReexport( + RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::http::SharedHttpClient"), + ), + ) override fun section(section: ServiceConfig): Writable { return when (section) { - is ServiceConfig.ConfigImpl -> writable { - rustTemplate( - """ - /// Return the [`SharedHttpClient`](#{SharedHttpClient}) to use when making requests, if any. - pub fn http_client(&self) -> Option<#{SharedHttpClient}> { - self.runtime_components.http_client() - } - """, - *codegenScope, - ) - } + is ServiceConfig.ConfigImpl -> + writable { + rustTemplate( + """ + /// Return the [`SharedHttpClient`](#{SharedHttpClient}) to use when making requests, if any. + pub fn http_client(&self) -> Option<#{SharedHttpClient}> { + self.runtime_components.http_client() + } + """, + *codegenScope, + ) + } - ServiceConfig.BuilderImpl -> writable { - rustTemplate( - """ - /// Sets the HTTP client to use when making requests. - /// - /// ## Examples - /// ```no_run - /// ## ##[cfg(test)] - /// ## mod tests { - /// ## ##[test] - /// ## fn example() { - /// use std::time::Duration; - /// use $moduleUseName::config::Config; - /// use aws_smithy_runtime::client::http::hyper_014::HyperClientBuilder; - /// - /// let https_connector = hyper_rustls::HttpsConnectorBuilder::new() - /// .with_webpki_roots() - /// .https_only() - /// .enable_http1() - /// .enable_http2() - /// .build(); - /// let hyper_client = HyperClientBuilder::new().build(https_connector); - /// - /// // This connector can then be given to a generated service Config - /// let config = my_service_client::Config::builder() - /// .endpoint_url("https://example.com") - /// .http_client(hyper_client) - /// .build(); - /// let client = my_service_client::Client::from_conf(config); - /// ## } - /// ## } - /// ``` - pub fn http_client(mut self, http_client: impl #{HttpClient} + 'static) -> Self { - self.set_http_client(#{Some}(#{IntoShared}::into_shared(http_client))); - self - } + ServiceConfig.BuilderImpl -> + writable { + rustTemplate( + """ + /// Sets the HTTP client to use when making requests. + /// + /// ## Examples + /// ```no_run + /// ## ##[cfg(test)] + /// ## mod tests { + /// ## ##[test] + /// ## fn example() { + /// use std::time::Duration; + /// use $moduleUseName::config::Config; + /// use aws_smithy_runtime::client::http::hyper_014::HyperClientBuilder; + /// + /// let https_connector = hyper_rustls::HttpsConnectorBuilder::new() + /// .with_webpki_roots() + /// .https_only() + /// .enable_http1() + /// .enable_http2() + /// .build(); + /// let hyper_client = HyperClientBuilder::new().build(https_connector); + /// + /// // This connector can then be given to a generated service Config + /// let config = my_service_client::Config::builder() + /// .endpoint_url("https://example.com") + /// .http_client(hyper_client) + /// .build(); + /// let client = my_service_client::Client::from_conf(config); + /// ## } + /// ## } + /// ``` + pub fn http_client(mut self, http_client: impl #{HttpClient} + 'static) -> Self { + self.set_http_client(#{Some}(#{IntoShared}::into_shared(http_client))); + self + } - /// Sets the HTTP client to use when making requests. - /// - /// ## Examples - /// ```no_run - /// ## ##[cfg(test)] - /// ## mod tests { - /// ## ##[test] - /// ## fn example() { - /// use std::time::Duration; - /// use $moduleUseName::config::{Builder, Config}; - /// use aws_smithy_runtime::client::http::hyper_014::HyperClientBuilder; - /// - /// fn override_http_client(builder: &mut Builder) { - /// let https_connector = hyper_rustls::HttpsConnectorBuilder::new() - /// .with_webpki_roots() - /// .https_only() - /// .enable_http1() - /// .enable_http2() - /// .build(); - /// let hyper_client = HyperClientBuilder::new().build(https_connector); - /// builder.set_http_client(Some(hyper_client)); - /// } - /// - /// let mut builder = $moduleUseName::Config::builder(); - /// override_http_client(&mut builder); - /// let config = builder.build(); - /// ## } - /// ## } - /// ``` - pub fn set_http_client(&mut self, http_client: Option<#{SharedHttpClient}>) -> &mut Self { - self.runtime_components.set_http_client(http_client); - self - } - """, - *codegenScope, - ) - } + /// Sets the HTTP client to use when making requests. + /// + /// ## Examples + /// ```no_run + /// ## ##[cfg(test)] + /// ## mod tests { + /// ## ##[test] + /// ## fn example() { + /// use std::time::Duration; + /// use $moduleUseName::config::{Builder, Config}; + /// use aws_smithy_runtime::client::http::hyper_014::HyperClientBuilder; + /// + /// fn override_http_client(builder: &mut Builder) { + /// let https_connector = hyper_rustls::HttpsConnectorBuilder::new() + /// .with_webpki_roots() + /// .https_only() + /// .enable_http1() + /// .enable_http2() + /// .build(); + /// let hyper_client = HyperClientBuilder::new().build(https_connector); + /// builder.set_http_client(Some(hyper_client)); + /// } + /// + /// let mut builder = $moduleUseName::Config::builder(); + /// override_http_client(&mut builder); + /// let config = builder.build(); + /// ## } + /// ## } + /// ``` + pub fn set_http_client(&mut self, http_client: Option<#{SharedHttpClient}>) -> &mut Self { + self.runtime_components.set_http_client(http_client); + self + } + """, + *codegenScope, + ) + } else -> emptySection } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenDecorator.kt index b33ee8fbbc2..cd40269b1c8 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenDecorator.kt @@ -25,12 +25,14 @@ class IdempotencyTokenDecorator : ClientCodegenDecorator { override val order: Byte = 0 private fun enabled(ctx: ClientCodegenContext) = ctx.serviceShape.needsIdempotencyToken(ctx.model) + override fun configCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = baseCustomizations.extendIf(enabled(codegenContext)) { - IdempotencyTokenProviderCustomization(codegenContext) - } + ): List = + baseCustomizations.extendIf(enabled(codegenContext)) { + IdempotencyTokenProviderCustomization(codegenContext) + } override fun operationCustomizations( codegenContext: ClientCodegenContext, @@ -46,11 +48,12 @@ class IdempotencyTokenDecorator : ClientCodegenDecorator { ): List { return baseCustomizations.extendIf(enabled(codegenContext)) { object : ServiceRuntimePluginCustomization() { - override fun section(section: ServiceRuntimePluginSection) = writable { - if (section is ServiceRuntimePluginSection.AdditionalConfig) { - section.putConfigValue(this, defaultTokenProvider((codegenContext.runtimeConfig))) + override fun section(section: ServiceRuntimePluginSection) = + writable { + if (section is ServiceRuntimePluginSection.AdditionalConfig) { + section.putConfigValue(this, defaultTokenProvider((codegenContext.runtimeConfig))) + } } - } } } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenGenerator.kt index af2e21294ca..dddaa45514c 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdempotencyTokenGenerator.kt @@ -39,40 +39,42 @@ class IdempotencyTokenGenerator( return emptySection } val memberName = symbolProvider.toMemberName(idempotencyTokenMember) - val codegenScope = arrayOf( - *preludeScope, - "Input" to symbolProvider.toSymbol(inputShape), - "IdempotencyTokenRuntimePlugin" to - InlineDependency.forRustFile( - RustModule.pubCrate("client_idempotency_token", parent = ClientRustModule.root), - "/inlineable/src/client_idempotency_token.rs", - CargoDependency.smithyRuntimeApiClient(runtimeConfig), - CargoDependency.smithyTypes(runtimeConfig), - InlineDependency.idempotencyToken(runtimeConfig), - ).toType().resolve("IdempotencyTokenRuntimePlugin"), - ) + val codegenScope = + arrayOf( + *preludeScope, + "Input" to symbolProvider.toSymbol(inputShape), + "IdempotencyTokenRuntimePlugin" to + InlineDependency.forRustFile( + RustModule.pubCrate("client_idempotency_token", parent = ClientRustModule.root), + "/inlineable/src/client_idempotency_token.rs", + CargoDependency.smithyRuntimeApiClient(runtimeConfig), + CargoDependency.smithyTypes(runtimeConfig), + InlineDependency.idempotencyToken(runtimeConfig), + ).toType().resolve("IdempotencyTokenRuntimePlugin"), + ) return when (section) { - is OperationSection.AdditionalRuntimePlugins -> writable { - section.addOperationRuntimePlugin(this) { - if (!symbolProvider.toSymbol(idempotencyTokenMember).isOptional()) { - UNREACHABLE("top level input members are always optional. $operationShape") + is OperationSection.AdditionalRuntimePlugins -> + writable { + section.addOperationRuntimePlugin(this) { + if (!symbolProvider.toSymbol(idempotencyTokenMember).isOptional()) { + UNREACHABLE("top level input members are always optional. $operationShape") + } + // An idempotency token is optional. If the user didn't specify a token + // then we'll generate one and set it. + rustTemplate( + """ + #{IdempotencyTokenRuntimePlugin}::new(|token_provider, input| { + let input: &mut #{Input} = input.downcast_mut().expect("correct type"); + if input.$memberName.is_none() { + input.$memberName = #{Some}(token_provider.make_idempotency_token()); + } + }) + """, + *codegenScope, + ) } - // An idempotency token is optional. If the user didn't specify a token - // then we'll generate one and set it. - rustTemplate( - """ - #{IdempotencyTokenRuntimePlugin}::new(|token_provider, input| { - let input: &mut #{Input} = input.downcast_mut().expect("correct type"); - if input.$memberName.is_none() { - input.$memberName = #{Some}(token_provider.make_idempotency_token()); - } - }) - """, - *codegenScope, - ) } - } else -> emptySection } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdentityCacheDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdentityCacheDecorator.kt index bdd3e267f6a..b5a31e402c6 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdentityCacheDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/IdentityCacheDecorator.kt @@ -18,91 +18,93 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.pre class IdentityCacheConfigCustomization(codegenContext: ClientCodegenContext) : ConfigCustomization() { private val moduleUseName = codegenContext.moduleUseName() - private val codegenScope = codegenContext.runtimeConfig.let { rc -> - val api = RuntimeType.smithyRuntimeApiClient(rc) - arrayOf( - *preludeScope, - "ResolveCachedIdentity" to configReexport(api.resolve("client::identity::ResolveCachedIdentity")), - "SharedIdentityCache" to configReexport(api.resolve("client::identity::SharedIdentityCache")), - ) - } + private val codegenScope = + codegenContext.runtimeConfig.let { rc -> + val api = RuntimeType.smithyRuntimeApiClient(rc) + arrayOf( + *preludeScope, + "ResolveCachedIdentity" to configReexport(api.resolve("client::identity::ResolveCachedIdentity")), + "SharedIdentityCache" to configReexport(api.resolve("client::identity::SharedIdentityCache")), + ) + } - override fun section(section: ServiceConfig): Writable = writable { - when (section) { - is ServiceConfig.BuilderImpl -> { - val docs = """ - /// Set the identity cache for auth. - /// - /// The identity cache defaults to a lazy caching implementation that will resolve - /// an identity when it is requested, and place it in the cache thereafter. Subsequent - /// requests will take the value from the cache while it is still valid. Once it expires, - /// the next request will result in refreshing the identity. - /// - /// This configuration allows you to disable or change the default caching mechanism. - /// To use a custom caching mechanism, implement the [`ResolveCachedIdentity`](#{ResolveCachedIdentity}) - /// trait and pass that implementation into this function. - /// - /// ## Examples - /// - /// Disabling identity caching: - /// ```no_run - /// use $moduleUseName::config::IdentityCache; - /// - /// let config = $moduleUseName::Config::builder() - /// .identity_cache(IdentityCache::no_cache()) - /// // ... - /// .build(); - /// let client = $moduleUseName::Client::from_conf(config); - /// ``` - /// - /// Customizing lazy caching: - /// ```no_run - /// use $moduleUseName::config::IdentityCache; - /// use std::time::Duration; - /// - /// let config = $moduleUseName::Config::builder() - /// .identity_cache( - /// IdentityCache::lazy() - /// // change the load timeout to 10 seconds - /// .load_timeout(Duration::from_secs(10)) - /// .build() - /// ) - /// // ... - /// .build(); - /// let client = $moduleUseName::Client::from_conf(config); - /// ``` - """ - rustTemplate( + override fun section(section: ServiceConfig): Writable = + writable { + when (section) { + is ServiceConfig.BuilderImpl -> { + val docs = """ + /// Set the identity cache for auth. + /// + /// The identity cache defaults to a lazy caching implementation that will resolve + /// an identity when it is requested, and place it in the cache thereafter. Subsequent + /// requests will take the value from the cache while it is still valid. Once it expires, + /// the next request will result in refreshing the identity. + /// + /// This configuration allows you to disable or change the default caching mechanism. + /// To use a custom caching mechanism, implement the [`ResolveCachedIdentity`](#{ResolveCachedIdentity}) + /// trait and pass that implementation into this function. + /// + /// ## Examples + /// + /// Disabling identity caching: + /// ```no_run + /// use $moduleUseName::config::IdentityCache; + /// + /// let config = $moduleUseName::Config::builder() + /// .identity_cache(IdentityCache::no_cache()) + /// // ... + /// .build(); + /// let client = $moduleUseName::Client::from_conf(config); + /// ``` + /// + /// Customizing lazy caching: + /// ```no_run + /// use $moduleUseName::config::IdentityCache; + /// use std::time::Duration; + /// + /// let config = $moduleUseName::Config::builder() + /// .identity_cache( + /// IdentityCache::lazy() + /// // change the load timeout to 10 seconds + /// .load_timeout(Duration::from_secs(10)) + /// .build() + /// ) + /// // ... + /// .build(); + /// let client = $moduleUseName::Client::from_conf(config); + /// ``` """ - $docs - pub fn identity_cache(mut self, identity_cache: impl #{ResolveCachedIdentity} + 'static) -> Self { - self.set_identity_cache(identity_cache); - self - } + rustTemplate( + """ + $docs + pub fn identity_cache(mut self, identity_cache: impl #{ResolveCachedIdentity} + 'static) -> Self { + self.set_identity_cache(identity_cache); + self + } - $docs - pub fn set_identity_cache(&mut self, identity_cache: impl #{ResolveCachedIdentity} + 'static) -> &mut Self { - self.runtime_components.set_identity_cache(#{Some}(identity_cache)); - self - } - """, - *codegenScope, - ) - } + $docs + pub fn set_identity_cache(&mut self, identity_cache: impl #{ResolveCachedIdentity} + 'static) -> &mut Self { + self.runtime_components.set_identity_cache(#{Some}(identity_cache)); + self + } + """, + *codegenScope, + ) + } - is ServiceConfig.ConfigImpl -> { - rustTemplate( - """ - /// Returns the configured identity cache for auth. - pub fn identity_cache(&self) -> #{Option}<#{SharedIdentityCache}> { - self.runtime_components.identity_cache() - } - """, - *codegenScope, - ) - } + is ServiceConfig.ConfigImpl -> { + rustTemplate( + """ + /// Returns the configured identity cache for auth. + pub fn identity_cache(&self) -> #{Option}<#{SharedIdentityCache}> { + self.runtime_components.identity_cache() + } + """, + *codegenScope, + ) + } - else -> {} + else -> {} + } } - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/InterceptorConfigCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/InterceptorConfigCustomization.kt index eecd7bb4a6b..0afdb500774 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/InterceptorConfigCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/InterceptorConfigCustomization.kt @@ -17,23 +17,25 @@ class InterceptorConfigCustomization(codegenContext: ClientCodegenContext) : Con private val moduleUseName = codegenContext.moduleUseName() private val runtimeConfig = codegenContext.runtimeConfig - private val codegenScope = arrayOf( - "Intercept" to configReexport(RuntimeType.intercept(runtimeConfig)), - "SharedInterceptor" to configReexport(RuntimeType.sharedInterceptor(runtimeConfig)), - ) + private val codegenScope = + arrayOf( + "Intercept" to configReexport(RuntimeType.intercept(runtimeConfig)), + "SharedInterceptor" to configReexport(RuntimeType.sharedInterceptor(runtimeConfig)), + ) override fun section(section: ServiceConfig) = writable { when (section) { - ServiceConfig.ConfigImpl -> rustTemplate( - """ - /// Returns interceptors currently registered by the user. - pub fn interceptors(&self) -> impl Iterator + '_ { - self.runtime_components.interceptors() - } - """, - *codegenScope, - ) + ServiceConfig.ConfigImpl -> + rustTemplate( + """ + /// Returns interceptors currently registered by the user. + pub fn interceptors(&self) -> impl Iterator + '_ { + self.runtime_components.interceptors() + } + """, + *codegenScope, + ) ServiceConfig.BuilderImpl -> rustTemplate( diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/MetadataCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/MetadataCustomization.kt index 03c62fb0493..df5a0e6aece 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/MetadataCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/MetadataCustomization.kt @@ -24,25 +24,26 @@ class MetadataCustomization( private val runtimeConfig = codegenContext.runtimeConfig private val codegenScope by lazy { arrayOf( - "Metadata" to RuntimeType.operationModule(runtimeConfig).resolve("Metadata"), + "Metadata" to RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::orchestrator::Metadata"), ) } - override fun section(section: OperationSection): Writable = writable { - when (section) { - is OperationSection.AdditionalRuntimePluginConfig -> { - rustTemplate( - """ - ${section.newLayerName}.store_put(#{Metadata}::new( - ${operationName.dq()}, - ${codegenContext.serviceShape.sdkId().dq()}, - )); - """, - *codegenScope, - ) - } + override fun section(section: OperationSection): Writable = + writable { + when (section) { + is OperationSection.AdditionalRuntimePluginConfig -> { + rustTemplate( + """ + ${section.newLayerName}.store_put(#{Metadata}::new( + ${operationName.dq()}, + ${codegenContext.serviceShape.sdkId().dq()}, + )); + """, + *codegenScope, + ) + } - else -> {} + else -> {} + } } - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/NoAuthDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/NoAuthDecorator.kt index bc68c958c88..4390f762588 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/NoAuthDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/NoAuthDecorator.kt @@ -30,16 +30,17 @@ class NoAuthDecorator : ClientCodegenDecorator { codegenContext: ClientCodegenContext, operationShape: OperationShape, baseAuthSchemeOptions: List, - ): List = baseAuthSchemeOptions + - AuthSchemeOption.StaticAuthSchemeOption( - noAuthSchemeShapeId, - listOf( - writable { - rustTemplate( - "#{NO_AUTH_SCHEME_ID}", - "NO_AUTH_SCHEME_ID" to noAuthModule(codegenContext).resolve("NO_AUTH_SCHEME_ID"), - ) - }, - ), - ) + ): List = + baseAuthSchemeOptions + + AuthSchemeOption.StaticAuthSchemeOption( + noAuthSchemeShapeId, + listOf( + writable { + rustTemplate( + "#{NO_AUTH_SCHEME_ID}", + "NO_AUTH_SCHEME_ID" to noAuthModule(codegenContext).resolve("NO_AUTH_SCHEME_ID"), + ) + }, + ), + ) } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ResiliencyConfigCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ResiliencyConfigCustomization.kt index 0f64fa0ccf7..8b6153b9a67 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ResiliencyConfigCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ResiliencyConfigCustomization.kt @@ -23,25 +23,26 @@ class ResiliencyConfigCustomization(codegenContext: ClientCodegenContext) : Conf private val timeoutModule = RuntimeType.smithyTypes(runtimeConfig).resolve("timeout") private val retries = RuntimeType.smithyRuntime(runtimeConfig).resolve("client::retries") private val moduleUseName = codegenContext.moduleUseName() - private val codegenScope = arrayOf( - *preludeScope, - "AsyncSleep" to configReexport(sleepModule.resolve("AsyncSleep")), - "SharedAsyncSleep" to configReexport(sleepModule.resolve("SharedAsyncSleep")), - "Sleep" to configReexport(sleepModule.resolve("Sleep")), - "ClientRateLimiter" to retries.resolve("ClientRateLimiter"), - "ClientRateLimiterPartition" to retries.resolve("ClientRateLimiterPartition"), - "debug" to RuntimeType.Tracing.resolve("debug"), - "IntoShared" to RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("shared::IntoShared"), - "RetryConfig" to retryConfig.resolve("RetryConfig"), - "RetryMode" to RuntimeType.smithyTypes(runtimeConfig).resolve("retry::RetryMode"), - "RetryPartition" to retries.resolve("RetryPartition"), - "SharedAsyncSleep" to configReexport(sleepModule.resolve("SharedAsyncSleep")), - "SharedRetryStrategy" to configReexport(RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::retries::SharedRetryStrategy")), - "SharedTimeSource" to configReexport(RuntimeType.smithyAsync(runtimeConfig).resolve("time::SharedTimeSource")), - "StandardRetryStrategy" to configReexport(retries.resolve("strategy::StandardRetryStrategy")), - "SystemTime" to RuntimeType.std.resolve("time::SystemTime"), - "TimeoutConfig" to timeoutModule.resolve("TimeoutConfig"), - ) + private val codegenScope = + arrayOf( + *preludeScope, + "AsyncSleep" to configReexport(sleepModule.resolve("AsyncSleep")), + "SharedAsyncSleep" to configReexport(sleepModule.resolve("SharedAsyncSleep")), + "Sleep" to configReexport(sleepModule.resolve("Sleep")), + "ClientRateLimiter" to retries.resolve("ClientRateLimiter"), + "ClientRateLimiterPartition" to retries.resolve("ClientRateLimiterPartition"), + "debug" to RuntimeType.Tracing.resolve("debug"), + "IntoShared" to RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("shared::IntoShared"), + "RetryConfig" to retryConfig.resolve("RetryConfig"), + "RetryMode" to RuntimeType.smithyTypes(runtimeConfig).resolve("retry::RetryMode"), + "RetryPartition" to retries.resolve("RetryPartition"), + "SharedAsyncSleep" to configReexport(sleepModule.resolve("SharedAsyncSleep")), + "SharedRetryStrategy" to configReexport(RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::retries::SharedRetryStrategy")), + "SharedTimeSource" to configReexport(RuntimeType.smithyAsync(runtimeConfig).resolve("time::SharedTimeSource")), + "StandardRetryStrategy" to configReexport(retries.resolve("strategy::StandardRetryStrategy")), + "SystemTime" to RuntimeType.std.resolve("time::SystemTime"), + "TimeoutConfig" to timeoutModule.resolve("TimeoutConfig"), + ) override fun section(section: ServiceConfig) = writable { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/RetryClassifierConfigCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/RetryClassifierConfigCustomization.kt index 8b23e4efbac..34dede78cf7 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/RetryClassifierConfigCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/RetryClassifierConfigCustomization.kt @@ -24,25 +24,27 @@ class RetryClassifierConfigCustomization(codegenContext: ClientCodegenContext) : private val retries = RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::retries") private val classifiers = retries.resolve("classifiers") - private val codegenScope = arrayOf( - "ClassifyRetry" to classifiers.resolve("ClassifyRetry"), - "RetryStrategy" to retries.resolve("RetryStrategy"), - "SharedRetryClassifier" to classifiers.resolve("SharedRetryClassifier"), - "RetryClassifierPriority" to classifiers.resolve("RetryClassifierPriority"), - ) + private val codegenScope = + arrayOf( + "ClassifyRetry" to classifiers.resolve("ClassifyRetry"), + "RetryStrategy" to retries.resolve("RetryStrategy"), + "SharedRetryClassifier" to classifiers.resolve("SharedRetryClassifier"), + "RetryClassifierPriority" to classifiers.resolve("RetryClassifierPriority"), + ) override fun section(section: ServiceConfig) = writable { when (section) { - ServiceConfig.ConfigImpl -> rustTemplate( - """ - /// Returns retry classifiers currently registered by the user. - pub fn retry_classifiers(&self) -> impl Iterator + '_ { - self.runtime_components.retry_classifiers() - } - """, - *codegenScope, - ) + ServiceConfig.ConfigImpl -> + rustTemplate( + """ + /// Returns retry classifiers currently registered by the user. + pub fn retry_classifiers(&self) -> impl Iterator + '_ { + self.runtime_components.retry_classifiers() + } + """, + *codegenScope, + ) ServiceConfig.BuilderImpl -> rustTemplate( @@ -243,20 +245,21 @@ class RetryClassifierServiceRuntimePluginCustomization(codegenContext: ClientCod private val runtimeConfig = codegenContext.runtimeConfig private val retries = RuntimeType.smithyRuntime(runtimeConfig).resolve("client::retries") - override fun section(section: ServiceRuntimePluginSection): Writable = writable { - when (section) { - is ServiceRuntimePluginSection.RegisterRuntimeComponents -> { - section.registerRetryClassifier(this) { - rustTemplate( - "#{HttpStatusCodeClassifier}::default()", - "HttpStatusCodeClassifier" to retries.resolve("classifiers::HttpStatusCodeClassifier"), - ) + override fun section(section: ServiceRuntimePluginSection): Writable = + writable { + when (section) { + is ServiceRuntimePluginSection.RegisterRuntimeComponents -> { + section.registerRetryClassifier(this) { + rustTemplate( + "#{HttpStatusCodeClassifier}::default()", + "HttpStatusCodeClassifier" to retries.resolve("classifiers::HttpStatusCodeClassifier"), + ) + } } - } - else -> emptySection + else -> emptySection + } } - } } class RetryClassifierOperationCustomization( @@ -266,32 +269,34 @@ class RetryClassifierOperationCustomization( private val runtimeConfig = codegenContext.runtimeConfig private val symbolProvider = codegenContext.symbolProvider - override fun section(section: OperationSection): Writable = writable { - val classifiers = RuntimeType.smithyRuntime(runtimeConfig).resolve("client::retries::classifiers") + override fun section(section: OperationSection): Writable = + writable { + val classifiers = RuntimeType.smithyRuntime(runtimeConfig).resolve("client::retries::classifiers") - val codegenScope = arrayOf( - *RuntimeType.preludeScope, - "TransientErrorClassifier" to classifiers.resolve("TransientErrorClassifier"), - "ModeledAsRetryableClassifier" to classifiers.resolve("ModeledAsRetryableClassifier"), - "OperationError" to symbolProvider.symbolForOperationError(operation), - ) + val codegenScope = + arrayOf( + *RuntimeType.preludeScope, + "TransientErrorClassifier" to classifiers.resolve("TransientErrorClassifier"), + "ModeledAsRetryableClassifier" to classifiers.resolve("ModeledAsRetryableClassifier"), + "OperationError" to symbolProvider.symbolForOperationError(operation), + ) - when (section) { - is OperationSection.RetryClassifiers -> { - section.registerRetryClassifier(this) { - rustTemplate( - "#{TransientErrorClassifier}::<#{OperationError}>::new()", - *codegenScope, - ) - } - section.registerRetryClassifier(this) { - rustTemplate( - "#{ModeledAsRetryableClassifier}::<#{OperationError}>::new()", - *codegenScope, - ) + when (section) { + is OperationSection.RetryClassifiers -> { + section.registerRetryClassifier(this) { + rustTemplate( + "#{TransientErrorClassifier}::<#{OperationError}>::new()", + *codegenScope, + ) + } + section.registerRetryClassifier(this) { + rustTemplate( + "#{ModeledAsRetryableClassifier}::<#{OperationError}>::new()", + *codegenScope, + ) + } } + else -> emptySection } - else -> emptySection } - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/SensitiveOutputDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/SensitiveOutputDecorator.kt index 5e484d4c861..b7281f3e983 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/SensitiveOutputDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/SensitiveOutputDecorator.kt @@ -33,15 +33,18 @@ private class SensitiveOutputCustomization( private val operation: OperationShape, ) : OperationCustomization() { private val sensitiveIndex = SensitiveIndex.of(codegenContext.model) - override fun section(section: OperationSection): Writable = writable { - if (section is OperationSection.AdditionalRuntimePluginConfig && sensitiveIndex.hasSensitiveOutput(operation)) { - rustTemplate( - """ - ${section.newLayerName}.store_put(#{SensitiveOutput}); - """, - "SensitiveOutput" to RuntimeType.smithyRuntimeApiClient(codegenContext.runtimeConfig) - .resolve("client::orchestrator::SensitiveOutput"), - ) + + override fun section(section: OperationSection): Writable = + writable { + if (section is OperationSection.AdditionalRuntimePluginConfig && sensitiveIndex.hasSensitiveOutput(operation)) { + rustTemplate( + """ + ${section.newLayerName}.store_put(#{SensitiveOutput}); + """, + "SensitiveOutput" to + RuntimeType.smithyRuntimeApiClient(codegenContext.runtimeConfig) + .resolve("client::orchestrator::SensitiveOutput"), + ) + } } - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/TimeSourceCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/TimeSourceCustomization.kt index 67b3664688c..498cbee4a36 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/TimeSourceCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/TimeSourceCustomization.kt @@ -16,15 +16,16 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope class TimeSourceCustomization(codegenContext: ClientCodegenContext) : ConfigCustomization() { - private val codegenScope = arrayOf( - *preludeScope, - "IntoShared" to RuntimeType.smithyRuntimeApi(codegenContext.runtimeConfig).resolve("shared::IntoShared"), - "SharedTimeSource" to RuntimeType.smithyAsync(codegenContext.runtimeConfig).resolve("time::SharedTimeSource"), - "StaticTimeSource" to RuntimeType.smithyAsync(codegenContext.runtimeConfig).resolve("time::StaticTimeSource"), - "TimeSource" to RuntimeType.smithyAsync(codegenContext.runtimeConfig).resolve("time::TimeSource"), - "UNIX_EPOCH" to RuntimeType.std.resolve("time::UNIX_EPOCH"), - "Duration" to RuntimeType.std.resolve("time::Duration"), - ) + private val codegenScope = + arrayOf( + *preludeScope, + "IntoShared" to RuntimeType.smithyRuntimeApi(codegenContext.runtimeConfig).resolve("shared::IntoShared"), + "SharedTimeSource" to RuntimeType.smithyAsync(codegenContext.runtimeConfig).resolve("time::SharedTimeSource"), + "StaticTimeSource" to RuntimeType.smithyAsync(codegenContext.runtimeConfig).resolve("time::StaticTimeSource"), + "TimeSource" to RuntimeType.smithyAsync(codegenContext.runtimeConfig).resolve("time::TimeSource"), + "UNIX_EPOCH" to RuntimeType.std.resolve("time::UNIX_EPOCH"), + "Duration" to RuntimeType.std.resolve("time::Duration"), + ) override fun section(section: ServiceConfig) = writable { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/ClientCodegenDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/ClientCodegenDecorator.kt index bfbbb056982..c676e5259a9 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/ClientCodegenDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/ClientCodegenDecorator.kt @@ -33,7 +33,9 @@ sealed interface AuthSchemeOption { val constructor: List, ) : AuthSchemeOption - class CustomResolver(/* unimplemented */) : AuthSchemeOption + class CustomResolver( + // unimplemented + ) : AuthSchemeOption } /** @@ -69,14 +71,20 @@ interface ClientCodegenDecorator : CoreCodegenDecorator, ): List = baseCustomizations - fun protocols(serviceId: ShapeId, currentProtocols: ClientProtocolMap): ClientProtocolMap = currentProtocols + fun protocols( + serviceId: ShapeId, + currentProtocols: ClientProtocolMap, + ): ClientProtocolMap = currentProtocols fun endpointCustomizations(codegenContext: ClientCodegenContext): List = listOf() /** * Hook to customize client construction documentation. */ - fun clientConstructionDocs(codegenContext: ClientCodegenContext, baseDocs: Writable): Writable = baseDocs + fun clientConstructionDocs( + codegenContext: ClientCodegenContext, + baseDocs: Writable, + ): Writable = baseDocs /** * Hooks to register additional service-level runtime plugins at codegen time @@ -111,33 +119,40 @@ open class CombinedClientCodegenDecorator(decorators: List, - ): List = combineCustomizations(baseAuthSchemeOptions) { decorator, authOptions -> - decorator.authOptions(codegenContext, operationShape, authOptions) - } + ): List = + combineCustomizations(baseAuthSchemeOptions) { decorator, authOptions -> + decorator.authOptions(codegenContext, operationShape, authOptions) + } override fun configCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = combineCustomizations(baseCustomizations) { decorator, customizations -> - decorator.configCustomizations(codegenContext, customizations) - } + ): List = + combineCustomizations(baseCustomizations) { decorator, customizations -> + decorator.configCustomizations(codegenContext, customizations) + } override fun operationCustomizations( codegenContext: ClientCodegenContext, operation: OperationShape, baseCustomizations: List, - ): List = combineCustomizations(baseCustomizations) { decorator, customizations -> - decorator.operationCustomizations(codegenContext, operation, customizations) - } + ): List = + combineCustomizations(baseCustomizations) { decorator, customizations -> + decorator.operationCustomizations(codegenContext, operation, customizations) + } override fun errorCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = combineCustomizations(baseCustomizations) { decorator, customizations -> - decorator.errorCustomizations(codegenContext, customizations) - } + ): List = + combineCustomizations(baseCustomizations) { decorator, customizations -> + decorator.errorCustomizations(codegenContext, customizations) + } - override fun protocols(serviceId: ShapeId, currentProtocols: ClientProtocolMap): ClientProtocolMap = + override fun protocols( + serviceId: ShapeId, + currentProtocols: ClientProtocolMap, + ): ClientProtocolMap = combineCustomizations(currentProtocols) { decorator, protocolMap -> decorator.protocols(serviceId, protocolMap) } @@ -145,7 +160,10 @@ open class CombinedClientCodegenDecorator(decorators: List = addCustomizations { decorator -> decorator.endpointCustomizations(codegenContext) } - override fun clientConstructionDocs(codegenContext: ClientCodegenContext, baseDocs: Writable): Writable = + override fun clientConstructionDocs( + codegenContext: ClientCodegenContext, + baseDocs: Writable, + ): Writable = combineCustomizations(baseDocs) { decorator, customizations -> decorator.clientConstructionDocs(codegenContext, customizations) } @@ -161,9 +179,10 @@ open class CombinedClientCodegenDecorator(decorators: List - decorator.protocolTestGenerator(codegenContext, gen) - } + ): ProtocolTestGenerator = + combineCustomizations(baseGenerator) { decorator, gen -> + decorator.protocolTestGenerator(codegenContext, gen) + } companion object { fun fromClasspath( @@ -171,16 +190,18 @@ open class CombinedClientCodegenDecorator(decorators: List, - ): List = baseCustomizations + - ResiliencyConfigCustomization(codegenContext) + - IdentityCacheConfigCustomization(codegenContext) + - InterceptorConfigCustomization(codegenContext) + - TimeSourceCustomization(codegenContext) + - RetryClassifierConfigCustomization(codegenContext) + ): List = + baseCustomizations + + ResiliencyConfigCustomization(codegenContext) + + IdentityCacheConfigCustomization(codegenContext) + + InterceptorConfigCustomization(codegenContext) + + TimeSourceCustomization(codegenContext) + + RetryClassifierConfigCustomization(codegenContext) override fun libRsCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = - baseCustomizations + AllowLintsCustomization() + ): List = baseCustomizations + AllowLintsCustomization() - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { val rc = codegenContext.runtimeConfig // Add rt-tokio feature for `ByteStream::from_path` @@ -126,7 +129,8 @@ class RequiredCustomizations : ClientCodegenDecorator { override fun serviceRuntimePluginCustomizations( codegenContext: ClientCodegenContext, baseCustomizations: List, - ): List = baseCustomizations + - ConnectionPoisoningRuntimePluginCustomization(codegenContext) + - RetryClassifierServiceRuntimePluginCustomization(codegenContext) + ): List = + baseCustomizations + + ConnectionPoisoningRuntimePluginCustomization(codegenContext) + + RetryClassifierServiceRuntimePluginCustomization(codegenContext) } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/ClientContextConfigCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/ClientContextConfigCustomization.kt index db842def8d0..96ddb2083c7 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/ClientContextConfigCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/ClientContextConfigCustomization.kt @@ -37,12 +37,16 @@ import software.amazon.smithy.rust.codegen.core.util.toSnakeCase */ class ClientContextConfigCustomization(ctx: ClientCodegenContext) : ConfigCustomization() { private val runtimeConfig = ctx.runtimeConfig - private val configParams = ctx.serviceShape.getTrait()?.parameters.orEmpty().toList() - .map { (key, value) -> fromClientParam(key, value, ctx.symbolProvider, runtimeConfig) } + private val configParams = + ctx.serviceShape.getTrait()?.parameters.orEmpty().toList() + .map { (key, value) -> fromClientParam(key, value, ctx.symbolProvider, runtimeConfig) } private val decorators = configParams.map { standardConfigParam(it, ctx) } companion object { - fun toSymbol(shapeType: ShapeType, symbolProvider: RustSymbolProvider): Symbol = + fun toSymbol( + shapeType: ShapeType, + symbolProvider: RustSymbolProvider, + ): Symbol = symbolProvider.toSymbol( when (shapeType) { ShapeType.STRING -> StringShape.builder().id("smithy.api#String").build() diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointConfigCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointConfigCustomization.kt index 1131c201d3a..f11a4bd92a2 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointConfigCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointConfigCustomization.kt @@ -29,15 +29,16 @@ internal class EndpointConfigCustomization( private val epModule = RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::endpoint") private val epRuntimeModule = RuntimeType.smithyRuntime(runtimeConfig).resolve("client::orchestrator::endpoints") - private val codegenScope = arrayOf( - *preludeScope, - "Params" to typesGenerator.paramsStruct(), - "Resolver" to RuntimeType.smithyRuntime(runtimeConfig).resolve("client::config_override::Resolver"), - "SharedEndpointResolver" to epModule.resolve("SharedEndpointResolver"), - "StaticUriEndpointResolver" to epRuntimeModule.resolve("StaticUriEndpointResolver"), - "ServiceSpecificResolver" to codegenContext.serviceSpecificEndpointResolver(), - "IntoShared" to RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("shared::IntoShared"), - ) + private val codegenScope = + arrayOf( + *preludeScope, + "Params" to typesGenerator.paramsStruct(), + "Resolver" to RuntimeType.smithyRuntime(runtimeConfig).resolve("client::config_override::Resolver"), + "SharedEndpointResolver" to epModule.resolve("SharedEndpointResolver"), + "StaticUriEndpointResolver" to epRuntimeModule.resolve("StaticUriEndpointResolver"), + "ServiceSpecificResolver" to codegenContext.serviceSpecificEndpointResolver(), + "IntoShared" to RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("shared::IntoShared"), + ) override fun section(section: ServiceConfig): Writable { return writable { @@ -55,17 +56,19 @@ internal class EndpointConfigCustomization( } ServiceConfig.BuilderImpl -> { - val endpointModule = ClientRustModule.Config.endpoint.fullyQualifiedPath() - .replace("crate::", "$moduleUseName::") + val endpointModule = + ClientRustModule.Config.endpoint.fullyQualifiedPath() + .replace("crate::", "$moduleUseName::") // if there are no rules, we don't generate a default resolver—we need to also suppress those docs. - val defaultResolverDocs = if (typesGenerator.defaultResolver() != null) { - """ - /// When unset, the client will used a generated endpoint resolver based on the endpoint resolution - /// rules for `$moduleUseName`. - """ - } else { - "/// This service does not define a default endpoint resolver." - } + val defaultResolverDocs = + if (typesGenerator.defaultResolver() != null) { + """ + /// When unset, the client will used a generated endpoint resolver based on the endpoint resolution + /// rules for `$moduleUseName`. + """ + } else { + "/// This service does not define a default endpoint resolver." + } if (codegenContext.settings.codegenConfig.includeEndpointUrlConfig) { rustTemplate( """ diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointParamsDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointParamsDecorator.kt index d752efef95c..6631cd5db94 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointParamsDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointParamsDecorator.kt @@ -37,13 +37,14 @@ private class EndpointParametersCustomization( private val codegenContext: ClientCodegenContext, private val operation: OperationShape, ) : OperationCustomization() { - override fun section(section: OperationSection): Writable = writable { - val symbolProvider = codegenContext.symbolProvider - val operationName = symbolProvider.toSymbol(operation).name - if (section is OperationSection.AdditionalInterceptors) { - section.registerInterceptor(codegenContext.runtimeConfig, this) { - rust("${operationName}EndpointParamsInterceptor") + override fun section(section: OperationSection): Writable = + writable { + val symbolProvider = codegenContext.symbolProvider + val operationName = symbolProvider.toSymbol(operation).name + if (section is OperationSection.AdditionalInterceptors) { + section.registerInterceptor(codegenContext.runtimeConfig, this) { + rust("${operationName}EndpointParamsInterceptor") + } } } - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointRulesetIndex.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointRulesetIndex.kt index a47aa2d8082..b6368624968 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointRulesetIndex.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointRulesetIndex.kt @@ -18,15 +18,15 @@ import java.util.concurrent.ConcurrentHashMap * Index to ensure that endpoint rulesets are parsed only once */ class EndpointRulesetIndex : KnowledgeIndex { - private val ruleSets: ConcurrentHashMap = ConcurrentHashMap() - fun endpointRulesForService(serviceShape: ServiceShape) = ruleSets.computeIfAbsent( - serviceShape, - ) { - serviceShape.getTrait()?.ruleSet?.let { EndpointRuleSet.fromNode(it) } - ?.also { it.typeCheck() } - } + fun endpointRulesForService(serviceShape: ServiceShape) = + ruleSets.computeIfAbsent( + serviceShape, + ) { + serviceShape.getTrait()?.ruleSet?.let { EndpointRuleSet.fromNode(it) } + ?.also { it.typeCheck() } + } fun endpointTests(serviceShape: ServiceShape) = serviceShape.getTrait()?.testCases ?: emptyList() diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointTypesGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointTypesGenerator.kt index d20e2d72b8f..081894b95e4 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointTypesGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointTypesGenerator.kt @@ -29,8 +29,9 @@ class EndpointTypesGenerator( val params: Parameters = rules?.parameters ?: Parameters.builder().build() private val runtimeConfig = codegenContext.runtimeConfig private val customizations = codegenContext.rootDecorator.endpointCustomizations(codegenContext) - private val stdlib = customizations - .flatMap { it.customRuntimeFunctions(codegenContext) } + private val stdlib = + customizations + .flatMap { it.customRuntimeFunctions(codegenContext) } companion object { fun fromContext(codegenContext: ClientCodegenContext): EndpointTypesGenerator { @@ -41,7 +42,9 @@ class EndpointTypesGenerator( } fun paramsStruct(): RuntimeType = EndpointParamsGenerator(codegenContext, params).paramsStruct() + fun paramsBuilder(): RuntimeType = EndpointParamsGenerator(codegenContext, params).paramsBuilder() + fun defaultResolver(): RuntimeType? = rules?.let { EndpointResolverGenerator(codegenContext, stdlib).defaultEndpointResolver(it) } @@ -63,9 +66,13 @@ class EndpointTypesGenerator( * * Exactly one endpoint customization must provide the value for this builtIn or null is returned. */ - fun builtInFor(parameter: Parameter, config: String): Writable? { - val defaultProviders = customizations - .mapNotNull { it.loadBuiltInFromServiceConfig(parameter, config) } + fun builtInFor( + parameter: Parameter, + config: String, + ): Writable? { + val defaultProviders = + customizations + .mapNotNull { it.loadBuiltInFromServiceConfig(parameter, config) } if (defaultProviders.size > 1) { error("Multiple providers provided a value for the builtin $parameter") } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt index 2e53a29dccf..cb940ddfa5b 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecorator.kt @@ -44,7 +44,10 @@ interface EndpointCustomization { * } * ``` */ - fun loadBuiltInFromServiceConfig(parameter: Parameter, configRef: String): Writable? = null + fun loadBuiltInFromServiceConfig( + parameter: Parameter, + configRef: String, + ): Writable? = null /** * Set a given builtIn value on the service config builder. If this builtIn is not recognized, return null @@ -65,7 +68,11 @@ interface EndpointCustomization { * ``` */ - fun setBuiltInOnServiceConfig(name: String, value: Node, configBuilderRef: String): Writable? = null + fun setBuiltInOnServiceConfig( + name: String, + value: Node, + configBuilderRef: String, + ): Writable? = null /** * Provide a list of additional endpoints standard library functions that rules can use @@ -113,22 +120,27 @@ class EndpointsDecorator : ClientCodegenDecorator { codegenContext: ClientCodegenContext, baseCustomizations: List, ): List { - return baseCustomizations + object : ServiceRuntimePluginCustomization() { - override fun section(section: ServiceRuntimePluginSection): Writable { - return when (section) { - is ServiceRuntimePluginSection.RegisterRuntimeComponents -> writable { - codegenContext.defaultEndpointResolver()?.also { resolver -> - section.registerEndpointResolver(this, resolver) - } - } + return baseCustomizations + + object : ServiceRuntimePluginCustomization() { + override fun section(section: ServiceRuntimePluginSection): Writable { + return when (section) { + is ServiceRuntimePluginSection.RegisterRuntimeComponents -> + writable { + codegenContext.defaultEndpointResolver()?.also { resolver -> + section.registerEndpointResolver(this, resolver) + } + } - else -> emptySection + else -> emptySection + } } } - } } - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { val generator = EndpointTypesGenerator.fromContext(codegenContext) rustCrate.withModule(ClientRustModule.Config.endpoint) { withInlineModule(endpointTestsModule(), rustCrate.moduleDocProvider) { @@ -146,7 +158,8 @@ class EndpointsDecorator : ClientCodegenDecorator { private fun ClientCodegenContext.defaultEndpointResolver(): Writable? { val generator = EndpointTypesGenerator.fromContext(this) val defaultResolver = generator.defaultResolver() ?: return null - val ctx = arrayOf("DefaultResolver" to defaultResolver, "ServiceSpecificResolver" to serviceSpecificEndpointResolver()) + val ctx = + arrayOf("DefaultResolver" to defaultResolver, "ServiceSpecificResolver" to serviceSpecificEndpointResolver()) return writable { rustTemplate( """{ diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt index 7d88408b738..24831d00272 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/Util.kt @@ -49,7 +49,8 @@ fun Identifier.rustName(): String { */ object EndpointsLib { val DiagnosticCollector = endpointsLib("diagnostic").toType().resolve("DiagnosticCollector") - fun PartitionResolver(runtimeConfig: RuntimeConfig) = + + fun partitionResolver(runtimeConfig: RuntimeConfig) = endpointsLib("partition", CargoDependency.smithyJson(runtimeConfig), CargoDependency.RegexLite).toType() .resolve("PartitionResolver") @@ -63,7 +64,10 @@ object EndpointsLib { endpointsLib("s3", endpointsLib("host"), CargoDependency.OnceCell, CargoDependency.RegexLite).toType() .resolve("is_virtual_hostable_s3_bucket") - private fun endpointsLib(name: String, vararg additionalDependency: RustDependency) = InlineDependency.forRustFile( + private fun endpointsLib( + name: String, + vararg additionalDependency: RustDependency, + ) = InlineDependency.forRustFile( RustModule.pubCrate( name, parent = EndpointStdLib, @@ -81,13 +85,14 @@ class Types(runtimeConfig: RuntimeConfig) { private val endpointRtApi = RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::endpoint") val resolveEndpointError = smithyHttpEndpointModule.resolve("ResolveEndpointError") - fun toArray() = arrayOf( - "Endpoint" to smithyEndpoint, - "EndpointFuture" to endpointFuture, - "SharedEndpointResolver" to endpointRtApi.resolve("SharedEndpointResolver"), - "EndpointResolverParams" to endpointRtApi.resolve("EndpointResolverParams"), - "ResolveEndpoint" to endpointRtApi.resolve("ResolveEndpoint"), - ) + fun toArray() = + arrayOf( + "Endpoint" to smithyEndpoint, + "EndpointFuture" to endpointFuture, + "SharedEndpointResolver" to endpointRtApi.resolve("SharedEndpointResolver"), + "EndpointResolverParams" to endpointRtApi.resolve("EndpointResolverParams"), + "ResolveEndpoint" to endpointRtApi.resolve("ResolveEndpoint"), + ) } /** @@ -103,11 +108,12 @@ fun ContextParamTrait.memberName(): String = this.name.unsafeToRustName() * Returns the symbol for a given parameter. This enables [software.amazon.smithy.rust.codegen.core.rustlang.RustWriter] to generate the correct [RustType]. */ fun Parameter.symbol(): Symbol { - val rustType = when (this.type) { - ParameterType.STRING -> RustType.String - ParameterType.BOOLEAN -> RustType.Bool - else -> TODO("unexpected type: ${this.type}") - } + val rustType = + when (this.type) { + ParameterType.STRING -> RustType.String + ParameterType.BOOLEAN -> RustType.Bool + else -> TODO("unexpected type: ${this.type}") + } // Parameter return types are always optional return Symbol.builder().rustType(rustType).build().letIf(!this.isRequired) { it.makeOptional() } } @@ -126,10 +132,10 @@ class AuthSchemeLister : RuleValueVisitor> { return endpoint.properties.getOrDefault(Identifier.of("authSchemes"), Literal.tupleLiteral(listOf())) .asTupleLiteral() .orNull()?.let { - it.map { authScheme -> - authScheme.asRecordLiteral().get()[Identifier.of("name")]!!.asStringLiteral().get().expectLiteral() - } - }?.toHashSet() ?: hashSetOf() + it.map { authScheme -> + authScheme.asRecordLiteral().get()[Identifier.of("name")]!!.asStringLiteral().get().expectLiteral() + } + }?.toHashSet() ?: hashSetOf() } override fun visitTreeRule(rules: MutableList): Set { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsGenerator.kt index 57a8f31de85..caab3d1e14e 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsGenerator.kt @@ -42,13 +42,14 @@ import software.amazon.smithy.rust.codegen.core.util.orNull // internals contains the actual resolver function fun endpointImplModule() = RustModule.private("internals", parent = ClientRustModule.Config.endpoint) -fun endpointTestsModule() = RustModule.new( - "test", - visibility = Visibility.PRIVATE, - parent = ClientRustModule.Config.endpoint, - inline = true, - documentationOverride = "", -).cfgTest() +fun endpointTestsModule() = + RustModule.new( + "test", + visibility = Visibility.PRIVATE, + parent = ClientRustModule.Config.endpoint, + inline = true, + documentationOverride = "", + ).cfgTest() // stdlib is isolated because it contains code generated names of stdlib functions–we want to ensure we avoid clashing val EndpointStdLib = RustModule.private("endpoint_lib") @@ -117,43 +118,47 @@ internal class EndpointParamsGenerator( ) { companion object { fun memberName(parameterName: String) = Identifier.of(parameterName).rustName() + fun setterName(parameterName: String) = "set_${memberName(parameterName)}" } - fun paramsStruct(): RuntimeType = RuntimeType.forInlineFun("Params", ClientRustModule.Config.endpoint) { - generateEndpointsStruct(this) - } + fun paramsStruct(): RuntimeType = + RuntimeType.forInlineFun("Params", ClientRustModule.Config.endpoint) { + generateEndpointsStruct(this) + } - internal fun paramsBuilder(): RuntimeType = RuntimeType.forInlineFun("ParamsBuilder", ClientRustModule.Config.endpoint) { - generateEndpointParamsBuilder(this) - } + internal fun paramsBuilder(): RuntimeType = + RuntimeType.forInlineFun("ParamsBuilder", ClientRustModule.Config.endpoint) { + generateEndpointParamsBuilder(this) + } - private fun paramsError(): RuntimeType = RuntimeType.forInlineFun("InvalidParams", ClientRustModule.Config.endpoint) { - rust( - """ - /// An error that occurred during endpoint resolution - ##[derive(Debug)] - pub struct InvalidParams { - field: std::borrow::Cow<'static, str> - } + private fun paramsError(): RuntimeType = + RuntimeType.forInlineFun("InvalidParams", ClientRustModule.Config.endpoint) { + rust( + """ + /// An error that occurred during endpoint resolution + ##[derive(Debug)] + pub struct InvalidParams { + field: std::borrow::Cow<'static, str> + } - impl InvalidParams { - ##[allow(dead_code)] - fn missing(field: &'static str) -> Self { - Self { field: field.into() } + impl InvalidParams { + ##[allow(dead_code)] + fn missing(field: &'static str) -> Self { + Self { field: field.into() } + } } - } - impl std::fmt::Display for InvalidParams { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "a required field was missing: `{}`", self.field) + impl std::fmt::Display for InvalidParams { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "a required field was missing: `{}`", self.field) + } } - } - impl std::error::Error for InvalidParams { } - """, - ) - } + impl std::error::Error for InvalidParams { } + """, + ) + } /** * Generates an endpoints struct based on the provided endpoint rules. The struct fields are `pub(crate)` @@ -165,11 +170,9 @@ internal class EndpointParamsGenerator( // Automatically implement standard Rust functionality Attribute(derive(RuntimeType.Debug, RuntimeType.PartialEq, RuntimeType.Clone)).render(writer) // Generate the struct block: - /* - pub struct Params { - ... members: pub(crate) field - } - */ + // pub struct Params { + // ... members: pub(crate) field + // } writer.docs("Configuration parameters for resolving the correct endpoint") writer.rustBlock("pub struct Params") { parameters.toList().forEach { parameter -> @@ -203,14 +206,15 @@ internal class EndpointParamsGenerator( """, "paramType" to type.makeOptional().mapRustType { t -> t.asDeref() }, - "param" to writable { - when { - type.isOptional() && type.rustType().isCopy() -> rust("self.$name") - type.isOptional() -> rust("self.$name.as_deref()") - type.rustType().isCopy() -> rust("Some(self.$name)") - else -> rust("Some(&self.$name)") - } - }, + "param" to + writable { + when { + type.isOptional() && type.rustType().isCopy() -> rust("self.$name") + type.isOptional() -> rust("self.$name.as_deref()") + type.rustType().isCopy() -> rust("Some(self.$name)") + else -> rust("Some(&self.$name)") + } + }, ) } } @@ -243,22 +247,23 @@ internal class EndpointParamsGenerator( "Params" to paramsStruct(), "ParamsError" to paramsError(), ) { - val params = writable { - Attribute.AllowClippyUnnecessaryLazyEvaluations.render(this) - rustBlockTemplate("#{Params}", "Params" to paramsStruct()) { - parameters.toList().forEach { parameter -> - rust("${parameter.memberName()}: self.${parameter.memberName()}") - parameter.default.orNull()?.also { default -> rust(".or_else(||Some(${value(default)}))") } - if (parameter.isRequired) { - rustTemplate( - ".ok_or_else(||#{Error}::missing(${parameter.memberName().dq()}))?", - "Error" to paramsError(), - ) + val params = + writable { + Attribute.AllowClippyUnnecessaryLazyEvaluations.render(this) + rustBlockTemplate("#{Params}", "Params" to paramsStruct()) { + parameters.toList().forEach { parameter -> + rust("${parameter.memberName()}: self.${parameter.memberName()}") + parameter.default.orNull()?.also { default -> rust(".or_else(||Some(${value(default)}))") } + if (parameter.isRequired) { + rustTemplate( + ".ok_or_else(||#{Error}::missing(${parameter.memberName().dq()}))?", + "Error" to paramsError(), + ) + } + rust(",") } - rust(",") } } - } rust("Ok(#W)", params) } parameters.toList().forEach { parameter -> @@ -282,15 +287,16 @@ internal class EndpointParamsGenerator( """, "nonOptionalType" to parameter.symbol().mapRustType { it.stripOuter() }, "type" to type, - "extraDocs" to writable { - if (parameter.default.isPresent || parameter.documentation.isPresent) { - docs("") - } - parameter.default.orNull()?.also { - docs("When unset, this parameter has a default value of `$it`.") - } - parameter.documentation.orNull()?.also { docs(it) } - }, + "extraDocs" to + writable { + if (parameter.default.isPresent || parameter.documentation.isPresent) { + docs("") + } + parameter.default.orNull()?.also { + docs("When unset, this parameter has a default value of `$it`.") + } + parameter.documentation.orNull()?.also { docs(it) } + }, ) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsInterceptorGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsInterceptorGenerator.kt index ec3b21417a1..458128842e3 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsInterceptorGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointParamsInterceptorGenerator.kt @@ -41,31 +41,35 @@ class EndpointParamsInterceptorGenerator( private val model = codegenContext.model private val symbolProvider = codegenContext.symbolProvider private val endpointTypesGenerator = EndpointTypesGenerator.fromContext(codegenContext) - private val codegenScope = codegenContext.runtimeConfig.let { rc -> - val endpointTypesGenerator = EndpointTypesGenerator.fromContext(codegenContext) - val runtimeApi = CargoDependency.smithyRuntimeApiClient(rc).toType() - val interceptors = runtimeApi.resolve("client::interceptors") - val orchestrator = runtimeApi.resolve("client::orchestrator") - arrayOf( - *preludeScope, - "BoxError" to RuntimeType.boxError(rc), - "ConfigBag" to RuntimeType.configBag(rc), - "ContextAttachedError" to interceptors.resolve("error::ContextAttachedError"), - "EndpointResolverParams" to runtimeApi.resolve("client::endpoint::EndpointResolverParams"), - "HttpRequest" to orchestrator.resolve("HttpRequest"), - "HttpResponse" to orchestrator.resolve("HttpResponse"), - "Intercept" to RuntimeType.intercept(rc), - "InterceptorContext" to RuntimeType.interceptorContext(rc), - "BeforeSerializationInterceptorContextRef" to RuntimeType.beforeSerializationInterceptorContextRef(rc), - "Input" to interceptors.resolve("context::Input"), - "Output" to interceptors.resolve("context::Output"), - "Error" to interceptors.resolve("context::Error"), - "InterceptorError" to interceptors.resolve("error::InterceptorError"), - "Params" to endpointTypesGenerator.paramsStruct(), - ) - } + private val codegenScope = + codegenContext.runtimeConfig.let { rc -> + val endpointTypesGenerator = EndpointTypesGenerator.fromContext(codegenContext) + val runtimeApi = CargoDependency.smithyRuntimeApiClient(rc).toType() + val interceptors = runtimeApi.resolve("client::interceptors") + val orchestrator = runtimeApi.resolve("client::orchestrator") + arrayOf( + *preludeScope, + "BoxError" to RuntimeType.boxError(rc), + "ConfigBag" to RuntimeType.configBag(rc), + "ContextAttachedError" to interceptors.resolve("error::ContextAttachedError"), + "EndpointResolverParams" to runtimeApi.resolve("client::endpoint::EndpointResolverParams"), + "HttpRequest" to orchestrator.resolve("HttpRequest"), + "HttpResponse" to orchestrator.resolve("HttpResponse"), + "Intercept" to RuntimeType.intercept(rc), + "InterceptorContext" to RuntimeType.interceptorContext(rc), + "BeforeSerializationInterceptorContextRef" to RuntimeType.beforeSerializationInterceptorContextRef(rc), + "Input" to interceptors.resolve("context::Input"), + "Output" to interceptors.resolve("context::Output"), + "Error" to interceptors.resolve("context::Error"), + "InterceptorError" to interceptors.resolve("error::InterceptorError"), + "Params" to endpointTypesGenerator.paramsStruct(), + ) + } - fun render(writer: RustWriter, operationShape: OperationShape) { + fun render( + writer: RustWriter, + operationShape: OperationShape, + ) { val operationName = symbolProvider.toSymbol(operationShape).name val operationInput = symbolProvider.toSymbol(operationShape.inputShape(model)) val interceptorName = "${operationName}EndpointParamsInterceptor" @@ -105,7 +109,10 @@ class EndpointParamsInterceptorGenerator( ) } - private fun paramSetters(operationShape: OperationShape, params: Parameters) = writable { + private fun paramSetters( + operationShape: OperationShape, + params: Parameters, + ) = writable { val idx = ContextIndex.of(codegenContext.model) val memberParams = idx.getContextParams(operationShape).toList().sortedBy { it.first.memberName } val builtInParams = params.toList().filter { it.isBuiltIn } @@ -154,26 +161,28 @@ class EndpointParamsInterceptorGenerator( } } - private fun endpointPrefix(operationShape: OperationShape): Writable = writable { - operationShape.getTrait(EndpointTrait::class.java).map { epTrait -> - val endpointTraitBindings = EndpointTraitBindings( - codegenContext.model, - symbolProvider, - codegenContext.runtimeConfig, - operationShape, - epTrait, - ) - withBlockTemplate( - "let endpoint_prefix = ", - """.map_err(|err| #{ContextAttachedError}::new("endpoint prefix could not be built", err))?;""", - *codegenScope, - ) { - endpointTraitBindings.render( - this, - "_input", - ) + private fun endpointPrefix(operationShape: OperationShape): Writable = + writable { + operationShape.getTrait(EndpointTrait::class.java).map { epTrait -> + val endpointTraitBindings = + EndpointTraitBindings( + codegenContext.model, + symbolProvider, + codegenContext.runtimeConfig, + operationShape, + epTrait, + ) + withBlockTemplate( + "let endpoint_prefix = ", + """.map_err(|err| #{ContextAttachedError}::new("endpoint prefix could not be built", err))?;""", + *codegenScope, + ) { + endpointTraitBindings.render( + this, + "_input", + ) + } + rust("cfg.interceptor_state().store_put(endpoint_prefix);") } - rust("cfg.interceptor_state().store_put(endpoint_prefix);") } - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointResolverGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointResolverGenerator.kt index 174bf8f5861..9aa441a6316 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointResolverGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointResolverGenerator.kt @@ -80,6 +80,7 @@ abstract class CustomRuntimeFunction { class FunctionRegistry(private val functions: List) { private var usedFunctions = mutableSetOf() + fun fnFor(id: String): CustomRuntimeFunction? = functions.firstOrNull { it.id == id }?.also { usedFunctions.add(it) } @@ -129,29 +130,31 @@ internal class EndpointResolverGenerator( private val runtimeConfig = codegenContext.runtimeConfig private val registry: FunctionRegistry = FunctionRegistry(stdlib) private val types = Types(runtimeConfig) - private val codegenScope = arrayOf( - "BoxError" to RuntimeType.boxError(runtimeConfig), - "endpoint" to types.smithyHttpEndpointModule, - "SmithyEndpoint" to types.smithyEndpoint, - "EndpointFuture" to types.endpointFuture, - "ResolveEndpointError" to types.resolveEndpointError, - "EndpointError" to types.resolveEndpointError, - "ServiceSpecificEndpointResolver" to codegenContext.serviceSpecificEndpointResolver(), - "DiagnosticCollector" to EndpointsLib.DiagnosticCollector, - ) - - private val allowLintsForResolver = listOf( - // we generate if x { if y { if z { ... } } } - "clippy::collapsible_if", - // we generate `if (true) == expr { ... }` - "clippy::bool_comparison", - // we generate `if !(a == b)` - "clippy::nonminimal_bool", - // we generate `if x == "" { ... }` - "clippy::comparison_to_empty", - // we generate `if let Some(_) = ... { ... }` - "clippy::redundant_pattern_matching", - ) + private val codegenScope = + arrayOf( + "BoxError" to RuntimeType.boxError(runtimeConfig), + "endpoint" to types.smithyHttpEndpointModule, + "SmithyEndpoint" to types.smithyEndpoint, + "EndpointFuture" to types.endpointFuture, + "ResolveEndpointError" to types.resolveEndpointError, + "EndpointError" to types.resolveEndpointError, + "ServiceSpecificEndpointResolver" to codegenContext.serviceSpecificEndpointResolver(), + "DiagnosticCollector" to EndpointsLib.DiagnosticCollector, + ) + + private val allowLintsForResolver = + listOf( + // we generate if x { if y { if z { ... } } } + "clippy::collapsible_if", + // we generate `if (true) == expr { ... }` + "clippy::bool_comparison", + // we generate `if !(a == b)` + "clippy::nonminimal_bool", + // we generate `if x == "" { ... }` + "clippy::comparison_to_empty", + // we generate `if let Some(_) = ... { ... }` + "clippy::redundant_pattern_matching", + ) private val context = Context(registry, runtimeConfig) companion object { @@ -234,36 +237,40 @@ internal class EndpointResolverGenerator( } } - private fun resolverFnBody(endpointRuleSet: EndpointRuleSet) = writable { - endpointRuleSet.parameters.toList().forEach { - Attribute.AllowUnusedVariables.render(this) - rust("let ${it.memberName()} = &$ParamsName.${it.memberName()};") + private fun resolverFnBody(endpointRuleSet: EndpointRuleSet) = + writable { + endpointRuleSet.parameters.toList().forEach { + Attribute.AllowUnusedVariables.render(this) + rust("let ${it.memberName()} = &$ParamsName.${it.memberName()};") + } + generateRulesList(endpointRuleSet.rules)(this) } - generateRulesList(endpointRuleSet.rules)(this) - } - private fun generateRulesList(rules: List) = writable { - rules.forEach { rule -> - rule.documentation.orNull()?.also { comment(escape(it)) } - generateRule(rule)(this) - } - if (!isExhaustive(rules.last())) { - // it's hard to figure out if these are always needed or not - Attribute.AllowUnreachableCode.render(this) - rustTemplate( - """return Err(#{EndpointError}::message(format!("No rules matched these parameters. This is a bug. {:?}", $ParamsName)));""", - *codegenScope, - ) + private fun generateRulesList(rules: List) = + writable { + rules.forEach { rule -> + rule.documentation.orNull()?.also { comment(escape(it)) } + generateRule(rule)(this) + } + if (!isExhaustive(rules.last())) { + // it's hard to figure out if these are always needed or not + Attribute.AllowUnreachableCode.render(this) + rustTemplate( + """return Err(#{EndpointError}::message(format!("No rules matched these parameters. This is a bug. {:?}", $ParamsName)));""", + *codegenScope, + ) + } } - } - private fun isExhaustive(rule: Rule): Boolean = rule.conditions.isEmpty() || rule.conditions.all { - when (it.function.type()) { - is BooleanType -> false - is OptionalType -> false - else -> true - } - } + private fun isExhaustive(rule: Rule): Boolean = + rule.conditions.isEmpty() || + rule.conditions.all { + when (it.function.type()) { + is BooleanType -> false + is OptionalType -> false + else -> true + } + } private fun generateRule(rule: Rule): Writable { return generateRuleInternal(rule, rule.conditions) @@ -284,7 +291,10 @@ internal class EndpointResolverGenerator( * * The resulting generated code is a series of nested-if statements, nesting each condition inside the previous. */ - private fun generateRuleInternal(rule: Rule, conditions: List): Writable { + private fun generateRuleInternal( + rule: Rule, + conditions: List, + ): Writable { if (conditions.isEmpty()) { return rule.accept(RuleVisitor()) } else { @@ -322,11 +332,12 @@ internal class EndpointResolverGenerator( "target" to target, "next" to next, // handle the rare but possible case where we bound the name of a variable to a boolean condition - "binding" to writable { - if (resultName != "_") { - rust("let $resultName = true;") - } - }, + "binding" to + writable { + if (resultName != "_") { + rust("let $resultName = true;") + } + }, ) } @@ -349,17 +360,19 @@ internal class EndpointResolverGenerator( inner class RuleVisitor : RuleValueVisitor { override fun visitTreeRule(rules: List) = generateRulesList(rules) - override fun visitErrorRule(error: Expression) = writable { - rustTemplate( - "return Err(#{EndpointError}::message(#{message:W}));", - *codegenScope, - "message" to ExpressionGenerator(Ownership.Owned, context).generate(error), - ) - } + override fun visitErrorRule(error: Expression) = + writable { + rustTemplate( + "return Err(#{EndpointError}::message(#{message:W}));", + *codegenScope, + "message" to ExpressionGenerator(Ownership.Owned, context).generate(error), + ) + } - override fun visitEndpointRule(endpoint: Endpoint): Writable = writable { - rust("return Ok(#W);", generateEndpoint(endpoint)) - } + override fun visitEndpointRule(endpoint: Endpoint): Writable = + writable { + rust("return Ok(#W);", generateEndpoint(endpoint)) + } } /** @@ -382,7 +395,8 @@ internal class EndpointResolverGenerator( fun ClientCodegenContext.serviceSpecificEndpointResolver(): RuntimeType { val generator = EndpointTypesGenerator.fromContext(this) return RuntimeType.forInlineFun("ResolveEndpoint", ClientRustModule.Config.endpoint) { - val ctx = arrayOf(*preludeScope, "Params" to generator.paramsStruct(), *Types(runtimeConfig).toArray(), "Debug" to RuntimeType.Debug) + val ctx = + arrayOf(*preludeScope, "Params" to generator.paramsStruct(), *Types(runtimeConfig).toArray(), "Debug" to RuntimeType.Debug) rustTemplate( """ /// Endpoint resolver trait specific to ${serviceShape.serviceNameOrDefault("this service")} diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointTestGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointTestGenerator.kt index d14c0f3d224..3e5f0ef3352 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointTestGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/generators/EndpointTestGenerator.kt @@ -41,13 +41,14 @@ internal class EndpointTestGenerator( ) { private val runtimeConfig = codegenContext.runtimeConfig private val types = Types(runtimeConfig) - private val codegenScope = arrayOf( - "Endpoint" to types.smithyEndpoint, - "Error" to types.resolveEndpointError, - "Document" to RuntimeType.document(runtimeConfig), - "HashMap" to RuntimeType.HashMap, - "capture_request" to RuntimeType.captureRequest(runtimeConfig), - ) + private val codegenScope = + arrayOf( + "Endpoint" to types.smithyEndpoint, + "Error" to types.resolveEndpointError, + "Document" to RuntimeType.document(runtimeConfig), + "HashMap" to RuntimeType.HashMap, + "capture_request" to RuntimeType.captureRequest(runtimeConfig), + ) private val instantiator = ClientInstantiator(codegenContext) @@ -56,64 +57,71 @@ internal class EndpointTestGenerator( return writable { docs(self.documentation.orElse("no docs")) } } - private fun generateBaseTest(testCase: EndpointTestCase, id: Int): Writable = writable { - rustTemplate( - """ - #{docs:W} - ##[test] - fn test_$id() { - let params = #{params:W}; - let resolver = #{resolver}::new(); - let endpoint = resolver.resolve_endpoint(¶ms); - #{assertion:W} - } - """, - *codegenScope, - "docs" to testCase.docs(), - "params" to params(testCase), - "resolver" to resolverType, - "assertion" to writable { - testCase.expect.endpoint.ifPresent { endpoint -> - rustTemplate( - """ - let endpoint = endpoint.expect("Expected valid endpoint: ${escape(endpoint.url)}"); - assert_eq!(endpoint, #{expected:W}); - """, - *codegenScope, "expected" to generateEndpoint(endpoint), - ) + private fun generateBaseTest( + testCase: EndpointTestCase, + id: Int, + ): Writable = + writable { + rustTemplate( + """ + #{docs:W} + ##[test] + fn test_$id() { + let params = #{params:W}; + let resolver = #{resolver}::new(); + let endpoint = resolver.resolve_endpoint(¶ms); + #{assertion:W} } - testCase.expect.error.ifPresent { error -> - val expectedError = - escape("expected error: $error [${testCase.documentation.orNull() ?: "no docs"}]") - rustTemplate( - """ - let error = endpoint.expect_err(${expectedError.dq()}); - assert_eq!(format!("{}", error), ${escape(error).dq()}) - """, - *codegenScope, - ) - } - }, - ) - } + """, + *codegenScope, + "docs" to testCase.docs(), + "params" to params(testCase), + "resolver" to resolverType, + "assertion" to + writable { + testCase.expect.endpoint.ifPresent { endpoint -> + rustTemplate( + """ + let endpoint = endpoint.expect("Expected valid endpoint: ${escape(endpoint.url)}"); + assert_eq!(endpoint, #{expected:W}); + """, + *codegenScope, "expected" to generateEndpoint(endpoint), + ) + } + testCase.expect.error.ifPresent { error -> + val expectedError = + escape("expected error: $error [${testCase.documentation.orNull() ?: "no docs"}]") + rustTemplate( + """ + let error = endpoint.expect_err(${expectedError.dq()}); + assert_eq!(format!("{}", error), ${escape(error).dq()}) + """, + *codegenScope, + ) + } + }, + ) + } - fun generate(): Writable = writable { - var id = 0 - testCases.forEach { testCase -> - id += 1 - generateBaseTest(testCase, id)(this) + fun generate(): Writable = + writable { + var id = 0 + testCases.forEach { testCase -> + id += 1 + generateBaseTest(testCase, id)(this) + } } - } - private fun params(testCase: EndpointTestCase) = writable { - rust("#T::builder()", paramsType) - testCase.params.members.forEach { (id, value) -> - if (params.get(Identifier.of(id)).isPresent) { - rust(".${Identifier.of(id).rustName()}(#W)", generateValue(Value.fromNode(value))) + private fun params(testCase: EndpointTestCase) = + writable { + rust("#T::builder()", paramsType) + testCase.params.members.forEach { (id, value) -> + if (params.get(Identifier.of(id)).isPresent) { + rust(".${Identifier.of(id).rustName()}(#W)", generateValue(Value.fromNode(value))) + } } + rust(""".build().expect("invalid params")""") } - rust(""".build().expect("invalid params")""") - } private fun generateValue(value: Value): Writable { return { @@ -161,19 +169,20 @@ internal class EndpointTestGenerator( } } - private fun generateEndpoint(value: ExpectedEndpoint) = writable { - rustTemplate("#{Endpoint}::builder().url(${escape(value.url).dq()})", *codegenScope) - value.headers.forEach { (headerName, values) -> - values.forEach { headerValue -> - rust(".header(${headerName.dq()}, ${headerValue.dq()})") + private fun generateEndpoint(value: ExpectedEndpoint) = + writable { + rustTemplate("#{Endpoint}::builder().url(${escape(value.url).dq()})", *codegenScope) + value.headers.forEach { (headerName, values) -> + values.forEach { headerValue -> + rust(".header(${headerName.dq()}, ${headerValue.dq()})") + } } + value.properties.forEach { (name, value) -> + rust( + ".property(${name.dq()}, #W)", + generateValue(Value.fromNode(value)), + ) + } + rust(".build()") } - value.properties.forEach { (name, value) -> - rust( - ".property(${name.dq()}, #W)", - generateValue(Value.fromNode(value)), - ) - } - rust(".build()") - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/ExpressionGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/ExpressionGenerator.kt index 562ba8e2018..6474d866b94 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/ExpressionGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/ExpressionGenerator.kt @@ -32,7 +32,6 @@ class ExpressionGenerator( private val ownership: Ownership, private val context: Context, ) { - @Contract(pure = true) fun generate(expr: Expression): Writable { return expr.accept(ExprGeneratorVisitor(ownership)) @@ -45,85 +44,99 @@ class ExpressionGenerator( private val ownership: Ownership, ) : ExpressionVisitor { - override fun visitLiteral(literal: Literal): Writable { return literal.accept(LiteralGenerator(ownership, context)) } - override fun visitRef(ref: Reference) = writable { - if (ownership == Ownership.Owned) { - when (ref.type()) { - is BooleanType -> rust("*${ref.name.rustName()}") - else -> rust("${ref.name.rustName()}.to_owned()") + override fun visitRef(ref: Reference) = + writable { + if (ownership == Ownership.Owned) { + when (ref.type()) { + is BooleanType -> rust("*${ref.name.rustName()}") + else -> rust("${ref.name.rustName()}.to_owned()") + } + } else { + rust(ref.name.rustName()) } - } else { - rust(ref.name.rustName()) } - } override fun visitGetAttr(getAttr: GetAttr): Writable { val target = ExpressionGenerator(Ownership.Borrowed, context).generate(getAttr.target) - val path = writable { - getAttr.path.toList().forEach { part -> - when (part) { - is GetAttr.Part.Key -> rust(".${part.key().rustName()}()") - is GetAttr.Part.Index -> { - if (part.index() == 0) { - // In this case, `.first()` is more idiomatic and `.get(0)` triggers lint warnings - rust(".first().cloned()") - } else { - rust(".get(${part.index()}).cloned()") // we end up with Option<&&T>, we need to get to Option<&T> + val path = + writable { + getAttr.path.toList().forEach { part -> + when (part) { + is GetAttr.Part.Key -> rust(".${part.key().rustName()}()") + is GetAttr.Part.Index -> { + if (part.index() == 0) { + // In this case, `.first()` is more idiomatic and `.get(0)` triggers lint warnings + rust(".first().cloned()") + } else { + rust(".get(${part.index()}).cloned()") // we end up with Option<&&T>, we need to get to Option<&T> + } } } } - } - if (ownership == Ownership.Owned && getAttr.type() != Type.booleanType()) { - if (getAttr.type() is OptionalType) { - rust(".map(|t|t.to_owned())") - } else { - rust(".to_owned()") + if (ownership == Ownership.Owned && getAttr.type() != Type.booleanType()) { + if (getAttr.type() is OptionalType) { + rust(".map(|t|t.to_owned())") + } else { + rust(".to_owned()") + } } } - } return writable { rust("#W#W", target, path) } } - override fun visitIsSet(fn: Expression) = writable { - val expressionGenerator = ExpressionGenerator(Ownership.Borrowed, context) - rust("#W.is_some()", expressionGenerator.generate(fn)) - } + override fun visitIsSet(fn: Expression) = + writable { + val expressionGenerator = ExpressionGenerator(Ownership.Borrowed, context) + rust("#W.is_some()", expressionGenerator.generate(fn)) + } - override fun visitNot(not: Expression) = writable { - rust("!(#W)", ExpressionGenerator(Ownership.Borrowed, context).generate(not)) - } + override fun visitNot(not: Expression) = + writable { + rust("!(#W)", ExpressionGenerator(Ownership.Borrowed, context).generate(not)) + } - override fun visitBoolEquals(left: Expression, right: Expression) = writable { + override fun visitBoolEquals( + left: Expression, + right: Expression, + ) = writable { val expressionGenerator = ExpressionGenerator(Ownership.Owned, context) rust("(#W) == (#W)", expressionGenerator.generate(left), expressionGenerator.generate(right)) } - override fun visitStringEquals(left: Expression, right: Expression) = writable { + override fun visitStringEquals( + left: Expression, + right: Expression, + ) = writable { val expressionGenerator = ExpressionGenerator(Ownership.Borrowed, context) rust("(#W) == (#W)", expressionGenerator.generate(left), expressionGenerator.generate(right)) } - override fun visitLibraryFunction(fn: FunctionDefinition, args: MutableList): Writable = writable { - val fnDefinition = context.functionRegistry.fnFor(fn.id) - ?: PANIC( - "no runtime function for ${fn.id} " + - "(hint: if this is a custom or aws-specific runtime function, ensure the relevant standard library has been loaded " + - "on the classpath)", + override fun visitLibraryFunction( + fn: FunctionDefinition, + args: MutableList, + ): Writable = + writable { + val fnDefinition = + context.functionRegistry.fnFor(fn.id) + ?: PANIC( + "no runtime function for ${fn.id} " + + "(hint: if this is a custom or aws-specific runtime function, ensure the relevant standard library has been loaded " + + "on the classpath)", + ) + val expressionGenerator = ExpressionGenerator(Ownership.Borrowed, context) + val argWritables = args.map { expressionGenerator.generate(it) } + rustTemplate( + "#{fn}(#{args}, ${EndpointResolverGenerator.DiagnosticCollector})", + "fn" to fnDefinition.usage(), + "args" to argWritables.join(","), ) - val expressionGenerator = ExpressionGenerator(Ownership.Borrowed, context) - val argWritables = args.map { expressionGenerator.generate(it) } - rustTemplate( - "#{fn}(#{args}, ${EndpointResolverGenerator.DiagnosticCollector})", - "fn" to fnDefinition.usage(), - "args" to argWritables.join(","), - ) - if (ownership == Ownership.Owned) { - rust(".to_owned()") + if (ownership == Ownership.Owned) { + rust(".to_owned()") + } } - } } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/LiteralGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/LiteralGenerator.kt index a986c50e6da..29337465c59 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/LiteralGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/LiteralGenerator.kt @@ -27,59 +27,69 @@ import java.util.stream.Stream class LiteralGenerator(private val ownership: Ownership, private val context: Context) : LiteralVisitor { private val runtimeConfig = context.runtimeConfig - private val codegenScope = arrayOf( - "Document" to RuntimeType.document(runtimeConfig), - "HashMap" to RuntimeType.HashMap, - ) - override fun visitBoolean(b: Boolean) = writable { - rust(b.toString()) - } - - override fun visitString(value: Template) = writable { - val parts: Stream = value.accept( - TemplateGenerator(ownership) { expr, ownership -> - ExpressionGenerator(ownership, context).generate(expr) - }, + private val codegenScope = + arrayOf( + "Document" to RuntimeType.document(runtimeConfig), + "HashMap" to RuntimeType.HashMap, ) - parts.forEach { part -> part(this) } - } - override fun visitRecord(members: MutableMap) = writable { - rustBlock("") { - rustTemplate( - "let mut out = #{HashMap}::::new();", - *codegenScope, - ) - members.keys.sortedBy { it.toString() }.map { k -> k to members[k]!! }.forEach { (identifier, literal) -> - rust( - "out.insert(${identifier.toString().dq()}.to_string(), #W.into());", - // When writing into the hashmap, it always needs to be an owned type - ExpressionGenerator(Ownership.Owned, context).generate(literal), + override fun visitBoolean(b: Boolean) = + writable { + rust(b.toString()) + } + + override fun visitString(value: Template) = + writable { + val parts: Stream = + value.accept( + TemplateGenerator(ownership) { expr, ownership -> + ExpressionGenerator(ownership, context).generate(expr) + }, ) - } - rustTemplate("out") + parts.forEach { part -> part(this) } } - } - override fun visitTuple(members: MutableList) = writable { - rustTemplate( - "vec![#{inner:W}]", *codegenScope, - "inner" to writable { - members.forEach { literal -> - rustTemplate( - "#{Document}::from(#{literal:W}),", - *codegenScope, - "literal" to ExpressionGenerator( - Ownership.Owned, - context, - ).generate(literal), + override fun visitRecord(members: MutableMap) = + writable { + rustBlock("") { + rustTemplate( + "let mut out = #{HashMap}::::new();", + *codegenScope, + ) + members.keys.sortedBy { it.toString() }.map { k -> k to members[k]!! }.forEach { (identifier, literal) -> + rust( + "out.insert(${identifier.toString().dq()}.to_string(), #W.into());", + // When writing into the hashmap, it always needs to be an owned type + ExpressionGenerator(Ownership.Owned, context).generate(literal), ) } - }, - ) - } + rustTemplate("out") + } + } - override fun visitInteger(value: Int) = writable { - rust("$value") - } + override fun visitTuple(members: MutableList) = + writable { + rustTemplate( + "vec![#{inner:W}]", *codegenScope, + "inner" to + writable { + members.forEach { literal -> + rustTemplate( + "#{Document}::from(#{literal:W}),", + *codegenScope, + "literal" to + ExpressionGenerator( + Ownership.Owned, + context, + ).generate(literal), + ) + } + }, + ) + } + + override fun visitInteger(value: Int) = + writable { + rust("$value") + } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/StdLib.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/StdLib.kt index 8bbb3cd9629..f9a55ae8479 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/StdLib.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/StdLib.kt @@ -21,19 +21,23 @@ import software.amazon.smithy.rust.codegen.core.util.dq /** * Standard library functions available to all generated crates (e.g. not `aws.` specific / prefixed) */ -internal val SmithyEndpointsStdLib: List = listOf( - SimpleRuntimeFunction("substring", EndpointsLib.substring), - SimpleRuntimeFunction("isValidHostLabel", EndpointsLib.isValidHostLabel), - SimpleRuntimeFunction("parseURL", EndpointsLib.parseUrl), - SimpleRuntimeFunction("uriEncode", EndpointsLib.uriEncode), -) +internal val SmithyEndpointsStdLib: List = + listOf( + SimpleRuntimeFunction("substring", EndpointsLib.substring), + SimpleRuntimeFunction("isValidHostLabel", EndpointsLib.isValidHostLabel), + SimpleRuntimeFunction("parseURL", EndpointsLib.parseUrl), + SimpleRuntimeFunction("uriEncode", EndpointsLib.uriEncode), + ) /** * AWS Standard library functions * * This is defined in client-codegen to support running tests—it is not used when generating smithy-native services. */ -fun awsStandardLib(runtimeConfig: RuntimeConfig, partitionsDotJson: Node) = listOf( +fun awsStandardLib( + runtimeConfig: RuntimeConfig, + partitionsDotJson: Node, +) = listOf( SimpleRuntimeFunction("aws.parseArn", EndpointsLib.awsParseArn), SimpleRuntimeFunction("aws.isVirtualHostableS3Bucket", EndpointsLib.awsIsVirtualHostableS3Bucket), AwsPartitionResolver(runtimeConfig, partitionsDotJson), @@ -47,45 +51,52 @@ fun awsStandardLib(runtimeConfig: RuntimeConfig, partitionsDotJson: Node) = list class AwsPartitionResolver(runtimeConfig: RuntimeConfig, private val partitionsDotJson: Node) : CustomRuntimeFunction() { override val id: String = "aws.partition" - private val codegenScope = arrayOf( - "PartitionResolver" to EndpointsLib.PartitionResolver(runtimeConfig), - "Lazy" to CargoDependency.OnceCell.toType().resolve("sync::Lazy"), - ) - - override fun structFieldInit() = writable { - val json = Node.printJson(partitionsDotJson).dq() - rustTemplate( - """partition_resolver: #{DEFAULT_PARTITION_RESOLVER}.clone()""", - *codegenScope, - "DEFAULT_PARTITION_RESOLVER" to RuntimeType.forInlineFun("DEFAULT_PARTITION_RESOLVER", EndpointStdLib) { - rustTemplate( - """ - // Loading the partition JSON is expensive since it involves many regex compilations, - // so cache the result so that it only need to be paid for the first constructed client. - pub(crate) static DEFAULT_PARTITION_RESOLVER: #{Lazy}<#{PartitionResolver}> = - #{Lazy}::new(|| #{PartitionResolver}::new_from_json(b$json).expect("valid JSON")); - """, - *codegenScope, - ) - }, + private val codegenScope = + arrayOf( + "PartitionResolver" to EndpointsLib.partitionResolver(runtimeConfig), + "Lazy" to CargoDependency.OnceCell.toType().resolve("sync::Lazy"), ) - } - override fun additionalArgsSignature(): Writable = writable { - rustTemplate("partition_resolver: &#{PartitionResolver}", *codegenScope) - } + override fun structFieldInit() = + writable { + val json = Node.printJson(partitionsDotJson).dq() + rustTemplate( + """partition_resolver: #{DEFAULT_PARTITION_RESOLVER}.clone()""", + *codegenScope, + "DEFAULT_PARTITION_RESOLVER" to + RuntimeType.forInlineFun("DEFAULT_PARTITION_RESOLVER", EndpointStdLib) { + rustTemplate( + """ + // Loading the partition JSON is expensive since it involves many regex compilations, + // so cache the result so that it only need to be paid for the first constructed client. + pub(crate) static DEFAULT_PARTITION_RESOLVER: #{Lazy}<#{PartitionResolver}> = + #{Lazy}::new(|| #{PartitionResolver}::new_from_json(b$json).expect("valid JSON")); + """, + *codegenScope, + ) + }, + ) + } + + override fun additionalArgsSignature(): Writable = + writable { + rustTemplate("partition_resolver: &#{PartitionResolver}", *codegenScope) + } - override fun additionalArgsInvocation(self: String) = writable { - rust("&$self.partition_resolver") - } + override fun additionalArgsInvocation(self: String) = + writable { + rust("&$self.partition_resolver") + } - override fun structField(): Writable = writable { - rustTemplate("partition_resolver: #{PartitionResolver}", *codegenScope) - } + override fun structField(): Writable = + writable { + rustTemplate("partition_resolver: #{PartitionResolver}", *codegenScope) + } - override fun usage() = writable { - rust("partition_resolver.resolve_partition") - } + override fun usage() = + writable { + rust("partition_resolver.resolve_partition") + } } /** diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/TemplateGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/TemplateGenerator.kt index 29b8a8d50f1..de8375444af 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/TemplateGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/TemplateGenerator.kt @@ -34,40 +34,45 @@ class TemplateGenerator( private val ownership: Ownership, private val exprGenerator: (Expression, Ownership) -> Writable, ) : TemplateVisitor { - override fun visitStaticTemplate(value: String) = writable { - // In the case of a static template, return the literal string, eg. `"foo"`. - rust(value.dq()) - if (ownership == Ownership.Owned) { - rust(".to_string()") + override fun visitStaticTemplate(value: String) = + writable { + // In the case of a static template, return the literal string, eg. `"foo"`. + rust(value.dq()) + if (ownership == Ownership.Owned) { + rust(".to_string()") + } } - } override fun visitSingleDynamicTemplate(expr: Expression): Writable { return exprGenerator(expr, ownership) } - override fun visitStaticElement(str: String) = writable { - when (str.length) { - 0 -> {} - 1 -> rust("out.push('$str');") - else -> rust("out.push_str(${str.dq()});") + override fun visitStaticElement(str: String) = + writable { + when (str.length) { + 0 -> {} + 1 -> rust("out.push('$str');") + else -> rust("out.push_str(${str.dq()});") + } } - } - override fun visitDynamicElement(expr: Expression) = writable { - // we don't need to own the argument to push_str - Attribute.AllowClippyNeedlessBorrow.render(this) - rust("out.push_str(&#W);", exprGenerator(expr, Ownership.Borrowed)) - } + override fun visitDynamicElement(expr: Expression) = + writable { + // we don't need to own the argument to push_str + Attribute.AllowClippyNeedlessBorrow.render(this) + rust("out.push_str(&#W);", exprGenerator(expr, Ownership.Borrowed)) + } - override fun startMultipartTemplate() = writable { - if (ownership == Ownership.Borrowed) { - rust("&") + override fun startMultipartTemplate() = + writable { + if (ownership == Ownership.Borrowed) { + rust("&") + } + rust("{ let mut out = String::new();") } - rust("{ let mut out = String::new();") - } - override fun finishMultipartTemplate() = writable { - rust(" out }") - } + override fun finishMultipartTemplate() = + writable { + rust(" out }") + } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/AuthOptionsPluginGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/AuthOptionsPluginGenerator.kt index 2fd61b38062..e58352a48ab 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/AuthOptionsPluginGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/AuthOptionsPluginGenerator.kt @@ -25,7 +25,11 @@ class AuthOptionsPluginGenerator(private val codegenContext: ClientCodegenContex private val runtimeConfig = codegenContext.runtimeConfig private val logger: Logger = Logger.getLogger(javaClass.name) - fun authPlugin(operationShape: OperationShape, authSchemeOptions: List) = writable { + + fun authPlugin( + operationShape: OperationShape, + authSchemeOptions: List, + ) = writable { rustTemplate( """ #{DefaultAuthOptionsPlugin}::new(vec![#{options}]) @@ -36,22 +40,27 @@ class AuthOptionsPluginGenerator(private val codegenContext: ClientCodegenContex ) } - private fun actualAuthSchemes(operationShape: OperationShape, authSchemeOptions: List): List { + private fun actualAuthSchemes( + operationShape: OperationShape, + authSchemeOptions: List, + ): List { val out: MutableList = mutableListOf() var noSupportedAuthSchemes = true - val authSchemes = ServiceIndex.of(codegenContext.model) - .getEffectiveAuthSchemes(codegenContext.serviceShape, operationShape) + val authSchemes = + ServiceIndex.of(codegenContext.model) + .getEffectiveAuthSchemes(codegenContext.serviceShape, operationShape) for (schemeShapeId in authSchemes.keys) { - val optionsForScheme = authSchemeOptions.filter { - when (it) { - is AuthSchemeOption.CustomResolver -> false - is AuthSchemeOption.StaticAuthSchemeOption -> { - it.schemeShapeId == schemeShapeId + val optionsForScheme = + authSchemeOptions.filter { + when (it) { + is AuthSchemeOption.CustomResolver -> false + is AuthSchemeOption.StaticAuthSchemeOption -> { + it.schemeShapeId == schemeShapeId + } } } - } if (optionsForScheme.isNotEmpty()) { out.addAll(optionsForScheme.flatMap { (it as AuthSchemeOption.StaticAuthSchemeOption).constructor }) @@ -64,10 +73,11 @@ class AuthOptionsPluginGenerator(private val codegenContext: ClientCodegenContex } } if (operationShape.hasTrait() || noSupportedAuthSchemes) { - val authOption = authSchemeOptions.find { - it is AuthSchemeOption.StaticAuthSchemeOption && it.schemeShapeId == noAuthSchemeShapeId - } - ?: throw IllegalStateException("Missing 'no auth' implementation. This is a codegen bug.") + val authOption = + authSchemeOptions.find { + it is AuthSchemeOption.StaticAuthSchemeOption && it.schemeShapeId == noAuthSchemeShapeId + } + ?: throw IllegalStateException("Missing 'no auth' implementation. This is a codegen bug.") out += (authOption as AuthSchemeOption.StaticAuthSchemeOption).constructor } if (out.any { it.isEmpty() }) { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientBuilderInstantiator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientBuilderInstantiator.kt index 453568c8c57..15911fbcd0b 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientBuilderInstantiator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientBuilderInstantiator.kt @@ -17,36 +17,46 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderGenerat import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderInstantiator class ClientBuilderInstantiator(private val clientCodegenContext: ClientCodegenContext) : BuilderInstantiator { - override fun setField(builder: String, value: Writable, field: MemberShape): Writable { + override fun setField( + builder: String, + value: Writable, + field: MemberShape, + ): Writable { return setFieldWithSetter(builder, value, field) } /** * For the client, we finalize builders with error correction enabled */ - override fun finalizeBuilder(builder: String, shape: StructureShape, mapErr: Writable?): Writable = writable { - val correctErrors = clientCodegenContext.correctErrors(shape) - val builderW = writable { - when { - correctErrors != null -> rustTemplate("#{correctErrors}($builder)", "correctErrors" to correctErrors) - else -> rustTemplate(builder) - } - } - if (BuilderGenerator.hasFallibleBuilder(shape, clientCodegenContext.symbolProvider)) { - rustTemplate( - "#{builder}.build()#{mapErr}", - "builder" to builderW, - "mapErr" to ( - mapErr?.map { - rust(".map_err(#T)?", it) - } ?: writable { } + override fun finalizeBuilder( + builder: String, + shape: StructureShape, + mapErr: Writable?, + ): Writable = + writable { + val correctErrors = clientCodegenContext.correctErrors(shape) + val builderW = + writable { + when { + correctErrors != null -> rustTemplate("#{correctErrors}($builder)", "correctErrors" to correctErrors) + else -> rustTemplate(builder) + } + } + if (BuilderGenerator.hasFallibleBuilder(shape, clientCodegenContext.symbolProvider)) { + rustTemplate( + "#{builder}.build()#{mapErr}", + "builder" to builderW, + "mapErr" to ( + mapErr?.map { + rust(".map_err(#T)?", it) + } ?: writable { } ), - ) - } else { - rustTemplate( - "#{builder}.build()", - "builder" to builderW, - ) + ) + } else { + rustTemplate( + "#{builder}.build()", + "builder" to builderW, + ) + } } - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt index 52b68ca2f6f..ec8e724acc0 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGenerator.kt @@ -38,84 +38,91 @@ data class InfallibleEnumType( const val UnknownVariantValue = "UnknownVariantValue" } - override fun implFromForStr(context: EnumGeneratorContext): Writable = writable { - rustTemplate( - """ - impl #{From}<&str> for ${context.enumName} { - fn from(s: &str) -> Self { - match s { - #{matchArms} + override fun implFromForStr(context: EnumGeneratorContext): Writable = + writable { + rustTemplate( + """ + impl #{From}<&str> for ${context.enumName} { + fn from(s: &str) -> Self { + match s { + #{matchArms} + } } } - } - """, - "From" to RuntimeType.From, - "matchArms" to writable { - context.sortedMembers.forEach { member -> - rust("${member.value.dq()} => ${context.enumName}::${member.derivedName()},") - } - rust( - "other => ${context.enumName}::$UnknownVariant(#T(other.to_owned()))", - unknownVariantValue(context), - ) - }, - ) - } - - override fun implFromStr(context: EnumGeneratorContext): Writable = writable { - rustTemplate( - """ - impl ::std::str::FromStr for ${context.enumName} { - type Err = ::std::convert::Infallible; - - fn from_str(s: &str) -> #{Result}::Err> { - #{Ok}(${context.enumName}::from(s)) - } - } - """, - *preludeScope, - ) - } + """, + "From" to RuntimeType.From, + "matchArms" to + writable { + context.sortedMembers.forEach { member -> + rust("${member.value.dq()} => ${context.enumName}::${member.derivedName()},") + } + rust( + "other => ${context.enumName}::$UnknownVariant(#T(other.to_owned()))", + unknownVariantValue(context), + ) + }, + ) + } - override fun additionalEnumImpls(context: EnumGeneratorContext): Writable = writable { - // `try_parse` isn't needed for unnamed enums - if (context.enumTrait.hasNames()) { + override fun implFromStr(context: EnumGeneratorContext): Writable = + writable { rustTemplate( """ - impl ${context.enumName} { - /// Parses the enum value while disallowing unknown variants. - /// - /// Unknown variants will result in an error. - pub fn try_parse(value: &str) -> #{Result} { - match Self::from(value) { - ##[allow(deprecated)] - Self::Unknown(_) => #{Err}(#{UnknownVariantError}::new(value)), - known => Ok(known), - } + impl ::std::str::FromStr for ${context.enumName} { + type Err = ::std::convert::Infallible; + + fn from_str(s: &str) -> #{Result}::Err> { + #{Ok}(${context.enumName}::from(s)) } } """, *preludeScope, - "UnknownVariantError" to unknownVariantError(), ) } - } - override fun additionalDocs(context: EnumGeneratorContext): Writable = writable { - renderForwardCompatibilityNote(context.enumName, context.sortedMembers, UnknownVariant, UnknownVariantValue) - } + override fun additionalEnumImpls(context: EnumGeneratorContext): Writable = + writable { + // `try_parse` isn't needed for unnamed enums + if (context.enumTrait.hasNames()) { + rustTemplate( + """ + impl ${context.enumName} { + /// Parses the enum value while disallowing unknown variants. + /// + /// Unknown variants will result in an error. + pub fn try_parse(value: &str) -> #{Result} { + match Self::from(value) { + ##[allow(deprecated)] + Self::Unknown(_) => #{Err}(#{UnknownVariantError}::new(value)), + known => Ok(known), + } + } + } + """, + *preludeScope, + "UnknownVariantError" to unknownVariantError(), + ) + } + } - override fun additionalEnumMembers(context: EnumGeneratorContext): Writable = writable { - docs("`$UnknownVariant` contains new variants that have been added since this code was generated.") - rust( - """##[deprecated(note = "Don't directly match on `$UnknownVariant`. See the docs on this enum for the correct way to handle unknown variants.")]""", - ) - rust("$UnknownVariant(#T)", unknownVariantValue(context)) - } + override fun additionalDocs(context: EnumGeneratorContext): Writable = + writable { + renderForwardCompatibilityNote(context.enumName, context.sortedMembers, UnknownVariant, UnknownVariantValue) + } - override fun additionalAsStrMatchArms(context: EnumGeneratorContext): Writable = writable { - rust("${context.enumName}::$UnknownVariant(value) => value.as_str()") - } + override fun additionalEnumMembers(context: EnumGeneratorContext): Writable = + writable { + docs("`$UnknownVariant` contains new variants that have been added since this code was generated.") + rust( + """##[deprecated(note = "Don't directly match on `$UnknownVariant`. See the docs on this enum for the correct way to handle unknown variants.")]""", + ) + rust("$UnknownVariant(#T)", unknownVariantValue(context)) + } + + override fun additionalAsStrMatchArms(context: EnumGeneratorContext): Writable = + writable { + rust("${context.enumName}::$UnknownVariant(value) => value.as_str()") + } private fun unknownVariantValue(context: EnumGeneratorContext): RuntimeType { return RuntimeType.forInlineFun(UnknownVariantValue, unknownVariantModule) { @@ -145,8 +152,10 @@ data class InfallibleEnumType( * forward-compatible way. */ private fun RustWriter.renderForwardCompatibilityNote( - enumName: String, sortedMembers: List, - unknownVariant: String, unknownVariantValue: String, + enumName: String, + sortedMembers: List, + unknownVariant: String, + unknownVariantValue: String, ) { docs( """ @@ -213,26 +222,27 @@ class ClientEnumGenerator(codegenContext: ClientCodegenContext, shape: StringSha ), ) -private fun unknownVariantError(): RuntimeType = RuntimeType.forInlineFun("UnknownVariantError", ClientRustModule.Error) { - rustTemplate( - """ - /// The given enum value failed to parse since it is not a known value. - ##[derive(Debug)] - pub struct UnknownVariantError { - value: #{String}, - } - impl UnknownVariantError { - pub(crate) fn new(value: impl #{Into}<#{String}>) -> Self { - Self { value: value.into() } +private fun unknownVariantError(): RuntimeType = + RuntimeType.forInlineFun("UnknownVariantError", ClientRustModule.Error) { + rustTemplate( + """ + /// The given enum value failed to parse since it is not a known value. + ##[derive(Debug)] + pub struct UnknownVariantError { + value: #{String}, } - } - impl ::std::fmt::Display for UnknownVariantError { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> #{Result}<(), ::std::fmt::Error> { - write!(f, "unknown enum variant: '{}'", self.value) + impl UnknownVariantError { + pub(crate) fn new(value: impl #{Into}<#{String}>) -> Self { + Self { value: value.into() } + } } - } - impl ::std::error::Error for UnknownVariantError {} - """, - *preludeScope, - ) -} + impl ::std::fmt::Display for UnknownVariantError { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> #{Result}<(), ::std::fmt::Error> { + write!(f, "unknown enum variant: '{}'", self.value) + } + } + impl ::std::error::Error for UnknownVariantError {} + """, + *preludeScope, + ) + } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGenerator.kt index 1c92575ea42..c5fabe49cef 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGenerator.kt @@ -18,23 +18,27 @@ class ConfigOverrideRuntimePluginGenerator( codegenContext: ClientCodegenContext, ) { private val moduleUseName = codegenContext.moduleUseName() - private val codegenScope = codegenContext.runtimeConfig.let { rc -> - val runtimeApi = RuntimeType.smithyRuntimeApiClient(rc) - val smithyTypes = RuntimeType.smithyTypes(rc) - arrayOf( - *RuntimeType.preludeScope, - "Cow" to RuntimeType.Cow, - "CloneableLayer" to smithyTypes.resolve("config_bag::CloneableLayer"), - "FrozenLayer" to smithyTypes.resolve("config_bag::FrozenLayer"), - "InterceptorRegistrar" to runtimeApi.resolve("client::interceptors::InterceptorRegistrar"), - "Layer" to smithyTypes.resolve("config_bag::Layer"), - "Resolver" to RuntimeType.smithyRuntime(rc).resolve("client::config_override::Resolver"), - "RuntimeComponentsBuilder" to RuntimeType.runtimeComponentsBuilder(rc), - "RuntimePlugin" to RuntimeType.runtimePlugin(rc), - ) - } + private val codegenScope = + codegenContext.runtimeConfig.let { rc -> + val runtimeApi = RuntimeType.smithyRuntimeApiClient(rc) + val smithyTypes = RuntimeType.smithyTypes(rc) + arrayOf( + *RuntimeType.preludeScope, + "Cow" to RuntimeType.Cow, + "CloneableLayer" to smithyTypes.resolve("config_bag::CloneableLayer"), + "FrozenLayer" to smithyTypes.resolve("config_bag::FrozenLayer"), + "InterceptorRegistrar" to runtimeApi.resolve("client::interceptors::InterceptorRegistrar"), + "Layer" to smithyTypes.resolve("config_bag::Layer"), + "Resolver" to RuntimeType.smithyRuntime(rc).resolve("client::config_override::Resolver"), + "RuntimeComponentsBuilder" to RuntimeType.runtimeComponentsBuilder(rc), + "RuntimePlugin" to RuntimeType.runtimePlugin(rc), + ) + } - fun render(writer: RustWriter, customizations: List) { + fun render( + writer: RustWriter, + customizations: List, + ) { writer.rustTemplate( """ /// A plugin that enables configuration for a single operation invocation @@ -81,12 +85,13 @@ class ConfigOverrideRuntimePluginGenerator( } """, *codegenScope, - "config" to writable { - writeCustomizations( - customizations, - ServiceConfig.OperationConfigOverride("layer"), - ) - }, + "config" to + writable { + writeCustomizations( + customizations, + ServiceConfig.OperationConfigOverride("layer"), + ) + }, ) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/EndpointTraitBindingGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/EndpointTraitBindingGenerator.kt index fe373a13bb4..9c24ae3ad33 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/EndpointTraitBindingGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/EndpointTraitBindingGenerator.kt @@ -31,7 +31,7 @@ class EndpointTraitBindings( private val endpointTrait: EndpointTrait, ) { private val inputShape = operationShape.inputShape(model) - private val endpointPrefix = RuntimeType.smithyHttp(runtimeConfig).resolve("endpoint::EndpointPrefix") + private val endpointPrefix = RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::endpoint::EndpointPrefix") /** * Render the `EndpointPrefix` struct. [input] refers to the symbol referring to the input of this operation. @@ -61,31 +61,33 @@ class EndpointTraitBindings( // build a list of args: `labelname = "field"` // these eventually end up in the format! macro invocation: // ```format!("some.{endpoint}", endpoint = endpoint);``` - val args = endpointTrait.hostPrefix.labels.map { label -> - val memberShape = inputShape.getMember(label.content).get() - val field = symbolProvider.toMemberName(memberShape) - if (symbolProvider.toSymbol(memberShape).isOptional()) { - rust("let $field = $input.$field.as_deref().unwrap_or_default();") - } else { - // NOTE: this is dead code until we start respecting @required - rust("let $field = &$input.$field;") + val args = + endpointTrait.hostPrefix.labels.map { label -> + val memberShape = inputShape.getMember(label.content).get() + val field = symbolProvider.toMemberName(memberShape) + if (symbolProvider.toSymbol(memberShape).isOptional()) { + rust("let $field = $input.$field.as_deref().unwrap_or_default();") + } else { + // NOTE: this is dead code until we start respecting @required + rust("let $field = &$input.$field;") + } + if (generateValidation) { + val errorString = "$field was unset or empty but must be set as part of the endpoint prefix" + val contents = + """ + if $field.is_empty() { + return Err(#{InvalidEndpointError}::failed_to_construct_uri("$errorString").into()); + } + """ + rustTemplate( + contents, + "InvalidEndpointError" to + RuntimeType.smithyRuntimeApiClient(runtimeConfig) + .resolve("client::endpoint::error::InvalidEndpointError"), + ) + } + "${label.content} = $field" } - if (generateValidation) { - val errorString = "$field was unset or empty but must be set as part of the endpoint prefix" - val contents = - """ - if $field.is_empty() { - return Err(#{InvalidEndpointError}::failed_to_construct_uri("$errorString").into()); - } - """ - rustTemplate( - contents, - "InvalidEndpointError" to RuntimeType.smithyHttp(runtimeConfig) - .resolve("endpoint::error::InvalidEndpointError"), - ) - } - "${label.content} = $field" - } rustTemplate( "#{EndpointPrefix}::new(format!($formatLiteral, ${args.joinToString()}))", "EndpointPrefix" to endpointPrefix, diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ErrorCorrection.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ErrorCorrection.kt index b05c0143836..07617d9301f 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ErrorCorrection.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ErrorCorrection.kt @@ -58,28 +58,32 @@ private fun ClientCodegenContext.errorCorrectedDefault(member: MemberShape): Wri val instantiator = PrimitiveInstantiator(runtimeConfig, symbolProvider) return writable { when { - target is EnumShape || target.hasTrait() -> rustTemplate( - """"no value was set".parse::<#{Shape}>().ok()""", - "Shape" to targetSymbol, - ) + target is EnumShape || target.hasTrait() -> + rustTemplate( + """"no value was set".parse::<#{Shape}>().ok()""", + "Shape" to targetSymbol, + ) - target is BooleanShape || target is NumberShape || target is StringShape || target is DocumentShape || target is ListShape || target is MapShape -> rust( - "Some(Default::default())", - ) + target is BooleanShape || target is NumberShape || target is StringShape || target is DocumentShape || target is ListShape || target is MapShape -> + rust( + "Some(Default::default())", + ) - target is StructureShape -> rustTemplate( - "{ let builder = #{Builder}::default(); #{instantiate} }", - "Builder" to symbolProvider.symbolForBuilder(target), - "instantiate" to builderInstantiator().finalizeBuilder("builder", target).map { - if (BuilderGenerator.hasFallibleBuilder(target, symbolProvider)) { - rust("#T.ok()", it) - } else { - it.some()(this) - } - }.letIf(memberSymbol.isRustBoxed()) { - it.plus { rustTemplate(".map(#{Box}::new)", *preludeScope) } - }, - ) + target is StructureShape -> + rustTemplate( + "{ let builder = #{Builder}::default(); #{instantiate} }", + "Builder" to symbolProvider.symbolForBuilder(target), + "instantiate" to + builderInstantiator().finalizeBuilder("builder", target).map { + if (BuilderGenerator.hasFallibleBuilder(target, symbolProvider)) { + rust("#T.ok()", it) + } else { + it.some()(this) + } + }.letIf(memberSymbol.isRustBoxed()) { + it.plus { rustTemplate(".map(#{Box}::new)", *preludeScope) } + }, + ) target is TimestampShape -> instantiator.instantiate(target, Node.from(0)).some()(this) target is BlobShape -> instantiator.instantiate(target, Node.from("")).some()(this) @@ -90,17 +94,18 @@ private fun ClientCodegenContext.errorCorrectedDefault(member: MemberShape): Wri fun ClientCodegenContext.correctErrors(shape: StructureShape): RuntimeType? { val name = symbolProvider.shapeFunctionName(serviceShape, shape) + "_correct_errors" - val corrections = writable { - shape.members().forEach { member -> - val memberName = symbolProvider.toMemberName(member) - errorCorrectedDefault(member)?.also { default -> - rustTemplate( - """if builder.$memberName.is_none() { builder.$memberName = #{default} }""", - "default" to default, - ) + val corrections = + writable { + shape.members().forEach { member -> + val memberName = symbolProvider.toMemberName(member) + errorCorrectedDefault(member)?.also { default -> + rustTemplate( + """if builder.$memberName.is_none() { builder.$memberName = #{default} }""", + "default" to default, + ) + } } } - } if (corrections.isEmpty()) { return null diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/NestedAccessorGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/NestedAccessorGenerator.kt index 138c7eb1231..49937301aad 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/NestedAccessorGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/NestedAccessorGenerator.kt @@ -29,7 +29,10 @@ class NestedAccessorGenerator(private val codegenContext: CodegenContext) { /** * Generate an accessor on [root] that consumes [root] and returns an `Option` for the nested item */ - fun generateOwnedAccessor(root: StructureShape, path: List): RuntimeType { + fun generateOwnedAccessor( + root: StructureShape, + path: List, + ): RuntimeType { check(path.isNotEmpty()) { "must not be called on an empty path" } val baseType = symbolProvider.toSymbol(path.last()) val fnName = symbolProvider.nestedAccessorName(codegenContext.serviceShape, "", root, path) @@ -48,7 +51,10 @@ class NestedAccessorGenerator(private val codegenContext: CodegenContext) { /** * Generate an accessor on [root] that takes a reference and returns an `Option<&T>` for the nested item */ - fun generateBorrowingAccessor(root: StructureShape, path: List): RuntimeType { + fun generateBorrowingAccessor( + root: StructureShape, + path: List, + ): RuntimeType { check(path.isNotEmpty()) { "must not be called on an empty path" } val baseType = symbolProvider.toSymbol(path.last()).makeOptional() val fnName = symbolProvider.nestedAccessorName(codegenContext.serviceShape, "ref", root, path) @@ -65,13 +71,17 @@ class NestedAccessorGenerator(private val codegenContext: CodegenContext) { } } - private fun generateBody(path: List, reference: Boolean): Writable = + private fun generateBody( + path: List, + reference: Boolean, + ): Writable = writable { - val ref = if (reference) { - "&" - } else { - "" - } + val ref = + if (reference) { + "&" + } else { + "" + } if (path.isEmpty()) { rustTemplate("#{Some}(input)", *preludeScope) } else { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationCustomization.kt index 176b85b1c8f..07ed4e51cba 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationCustomization.kt @@ -70,7 +70,11 @@ sealed class OperationSection(name: String) : Section(name) { override val customizations: List, val operationShape: OperationShape, ) : OperationSection("AdditionalInterceptors") { - fun registerInterceptor(runtimeConfig: RuntimeConfig, writer: RustWriter, interceptor: Writable) { + fun registerInterceptor( + runtimeConfig: RuntimeConfig, + writer: RustWriter, + interceptor: Writable, + ) { writer.rustTemplate( ".with_interceptor(#{interceptor})", "interceptor" to interceptor, @@ -95,11 +99,17 @@ sealed class OperationSection(name: String) : Section(name) { override val customizations: List, val operationShape: OperationShape, ) : OperationSection("AdditionalRuntimePlugins") { - fun addClientPlugin(writer: RustWriter, plugin: Writable) { + fun addClientPlugin( + writer: RustWriter, + plugin: Writable, + ) { writer.rustTemplate(".with_client_plugin(#{plugin})", "plugin" to plugin) } - fun addOperationRuntimePlugin(writer: RustWriter, plugin: Writable) { + fun addOperationRuntimePlugin( + writer: RustWriter, + plugin: Writable, + ) { writer.rustTemplate(".with_operation_plugin(#{plugin})", "plugin" to plugin) } } @@ -108,7 +118,10 @@ sealed class OperationSection(name: String) : Section(name) { override val customizations: List, val operationShape: OperationShape, ) : OperationSection("RetryClassifiers") { - fun registerRetryClassifier(writer: RustWriter, classifier: Writable) { + fun registerRetryClassifier( + writer: RustWriter, + classifier: Writable, + ) { writer.rustTemplate(".with_retry_classifier(#{classifier})", "classifier" to classifier) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationGenerator.kt index f96534ed9db..c2200003db0 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationGenerator.kt @@ -36,9 +36,10 @@ import software.amazon.smithy.rust.codegen.core.util.sdkId open class OperationGenerator( private val codegenContext: ClientCodegenContext, private val protocol: Protocol, - private val bodyGenerator: ProtocolPayloadGenerator = ClientHttpBoundProtocolPayloadGenerator( - codegenContext, protocol, - ), + private val bodyGenerator: ProtocolPayloadGenerator = + ClientHttpBoundProtocolPayloadGenerator( + codegenContext, protocol, + ), ) { private val model = codegenContext.model private val runtimeConfig = codegenContext.runtimeConfig @@ -87,31 +88,35 @@ open class OperationGenerator( val outputType = symbolProvider.toSymbol(operationShape.outputShape(model)) val errorType = symbolProvider.symbolForOperationError(operationShape) - val codegenScope = arrayOf( - *preludeScope, - "Arc" to RuntimeType.Arc, - "ConcreteInput" to symbolProvider.toSymbol(operationShape.inputShape(model)), - "Input" to RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::interceptors::context::Input"), - "Operation" to symbolProvider.toSymbol(operationShape), - "OperationError" to errorType, - "OperationOutput" to outputType, - "HttpResponse" to RuntimeType.smithyRuntimeApiClient(runtimeConfig) - .resolve("client::orchestrator::HttpResponse"), - "SdkError" to RuntimeType.sdkError(runtimeConfig), - ) - val additionalPlugins = writable { - writeCustomizations( - operationCustomizations, - OperationSection.AdditionalRuntimePlugins(operationCustomizations, operationShape), - ) - rustTemplate( - ".with_client_plugin(#{auth_plugin})", - "auth_plugin" to AuthOptionsPluginGenerator(codegenContext).authPlugin( - operationShape, - authSchemeOptions, - ), + val codegenScope = + arrayOf( + *preludeScope, + "Arc" to RuntimeType.Arc, + "ConcreteInput" to symbolProvider.toSymbol(operationShape.inputShape(model)), + "Input" to RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::interceptors::context::Input"), + "Operation" to symbolProvider.toSymbol(operationShape), + "OperationError" to errorType, + "OperationOutput" to outputType, + "HttpResponse" to + RuntimeType.smithyRuntimeApiClient(runtimeConfig) + .resolve("client::orchestrator::HttpResponse"), + "SdkError" to RuntimeType.sdkError(runtimeConfig), ) - } + val additionalPlugins = + writable { + writeCustomizations( + operationCustomizations, + OperationSection.AdditionalRuntimePlugins(operationCustomizations, operationShape), + ) + rustTemplate( + ".with_client_plugin(#{auth_plugin})", + "auth_plugin" to + AuthOptionsPluginGenerator(codegenContext).authPlugin( + operationShape, + authSchemeOptions, + ), + ) + } rustTemplate( """ pub(crate) async fn orchestrate( @@ -166,24 +171,27 @@ open class OperationGenerator( *codegenScope, "Error" to RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::interceptors::context::Error"), "InterceptorContext" to RuntimeType.interceptorContext(runtimeConfig), - "OrchestratorError" to RuntimeType.smithyRuntimeApiClient(runtimeConfig) - .resolve("client::orchestrator::error::OrchestratorError"), + "OrchestratorError" to + RuntimeType.smithyRuntimeApiClient(runtimeConfig) + .resolve("client::orchestrator::error::OrchestratorError"), "RuntimePlugin" to RuntimeType.runtimePlugin(runtimeConfig), "RuntimePlugins" to RuntimeType.runtimePlugins(runtimeConfig), "StopPoint" to RuntimeType.smithyRuntime(runtimeConfig).resolve("client::orchestrator::StopPoint"), - "invoke_with_stop_point" to RuntimeType.smithyRuntime(runtimeConfig) - .resolve("client::orchestrator::invoke_with_stop_point"), - "additional_runtime_plugins" to writable { - if (additionalPlugins.isNotEmpty()) { - rustTemplate( - """ - runtime_plugins = runtime_plugins - #{additional_runtime_plugins}; - """, - "additional_runtime_plugins" to additionalPlugins, - ) - } - }, + "invoke_with_stop_point" to + RuntimeType.smithyRuntime(runtimeConfig) + .resolve("client::orchestrator::invoke_with_stop_point"), + "additional_runtime_plugins" to + writable { + if (additionalPlugins.isNotEmpty()) { + rustTemplate( + """ + runtime_plugins = runtime_plugins + #{additional_runtime_plugins}; + """, + "additional_runtime_plugins" to additionalPlugins, + ) + } + }, ) writeCustomizations(operationCustomizations, OperationSection.OperationImplBlock(operationCustomizations)) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationRuntimePluginGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationRuntimePluginGenerator.kt index 4d4d32a8dd2..e17fdc71706 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationRuntimePluginGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationRuntimePluginGenerator.kt @@ -21,28 +21,29 @@ import software.amazon.smithy.rust.codegen.core.util.dq class OperationRuntimePluginGenerator( private val codegenContext: ClientCodegenContext, ) { - private val codegenScope = codegenContext.runtimeConfig.let { rc -> - val runtimeApi = RuntimeType.smithyRuntimeApiClient(rc) - val smithyTypes = RuntimeType.smithyTypes(rc) - arrayOf( - *preludeScope, - "AuthSchemeOptionResolverParams" to runtimeApi.resolve("client::auth::AuthSchemeOptionResolverParams"), - "BoxError" to RuntimeType.boxError(codegenContext.runtimeConfig), - "ConfigBag" to RuntimeType.configBag(codegenContext.runtimeConfig), - "Cow" to RuntimeType.Cow, - "FrozenLayer" to smithyTypes.resolve("config_bag::FrozenLayer"), - "IntoShared" to runtimeApi.resolve("shared::IntoShared"), - "Layer" to smithyTypes.resolve("config_bag::Layer"), - "RetryClassifiers" to runtimeApi.resolve("client::retries::RetryClassifiers"), - "RuntimeComponentsBuilder" to RuntimeType.runtimeComponentsBuilder(codegenContext.runtimeConfig), - "RuntimePlugin" to RuntimeType.runtimePlugin(codegenContext.runtimeConfig), - "SharedAuthSchemeOptionResolver" to runtimeApi.resolve("client::auth::SharedAuthSchemeOptionResolver"), - "SharedRequestSerializer" to runtimeApi.resolve("client::ser_de::SharedRequestSerializer"), - "SharedResponseDeserializer" to runtimeApi.resolve("client::ser_de::SharedResponseDeserializer"), - "StaticAuthSchemeOptionResolver" to runtimeApi.resolve("client::auth::static_resolver::StaticAuthSchemeOptionResolver"), - "StaticAuthSchemeOptionResolverParams" to runtimeApi.resolve("client::auth::static_resolver::StaticAuthSchemeOptionResolverParams"), - ) - } + private val codegenScope = + codegenContext.runtimeConfig.let { rc -> + val runtimeApi = RuntimeType.smithyRuntimeApiClient(rc) + val smithyTypes = RuntimeType.smithyTypes(rc) + arrayOf( + *preludeScope, + "AuthSchemeOptionResolverParams" to runtimeApi.resolve("client::auth::AuthSchemeOptionResolverParams"), + "BoxError" to RuntimeType.boxError(codegenContext.runtimeConfig), + "ConfigBag" to RuntimeType.configBag(codegenContext.runtimeConfig), + "Cow" to RuntimeType.Cow, + "FrozenLayer" to smithyTypes.resolve("config_bag::FrozenLayer"), + "IntoShared" to runtimeApi.resolve("shared::IntoShared"), + "Layer" to smithyTypes.resolve("config_bag::Layer"), + "RetryClassifiers" to runtimeApi.resolve("client::retries::RetryClassifiers"), + "RuntimeComponentsBuilder" to RuntimeType.runtimeComponentsBuilder(codegenContext.runtimeConfig), + "RuntimePlugin" to RuntimeType.runtimePlugin(codegenContext.runtimeConfig), + "SharedAuthSchemeOptionResolver" to runtimeApi.resolve("client::auth::SharedAuthSchemeOptionResolver"), + "SharedRequestSerializer" to runtimeApi.resolve("client::ser_de::SharedRequestSerializer"), + "SharedResponseDeserializer" to runtimeApi.resolve("client::ser_de::SharedResponseDeserializer"), + "StaticAuthSchemeOptionResolver" to runtimeApi.resolve("client::auth::static_resolver::StaticAuthSchemeOptionResolver"), + "StaticAuthSchemeOptionResolverParams" to runtimeApi.resolve("client::auth::static_resolver::StaticAuthSchemeOptionResolverParams"), + ) + } fun render( writer: RustWriter, @@ -82,34 +83,38 @@ class OperationRuntimePluginGenerator( """, *codegenScope, *preludeScope, - "additional_config" to writable { - writeCustomizations( - customizations, - OperationSection.AdditionalRuntimePluginConfig( + "additional_config" to + writable { + writeCustomizations( + customizations, + OperationSection.AdditionalRuntimePluginConfig( + customizations, + newLayerName = "cfg", + operationShape, + ), + ) + }, + "runtime_plugin_supporting_types" to + writable { + writeCustomizations( + customizations, + OperationSection.RuntimePluginSupportingTypes(customizations, "cfg", operationShape), + ) + }, + "interceptors" to + writable { + writeCustomizations( + customizations, + OperationSection.AdditionalInterceptors(customizations, operationShape), + ) + }, + "retry_classifiers" to + writable { + writeCustomizations( customizations, - newLayerName = "cfg", - operationShape, - ), - ) - }, - "runtime_plugin_supporting_types" to writable { - writeCustomizations( - customizations, - OperationSection.RuntimePluginSupportingTypes(customizations, "cfg", operationShape), - ) - }, - "interceptors" to writable { - writeCustomizations( - customizations, - OperationSection.AdditionalInterceptors(customizations, operationShape), - ) - }, - "retry_classifiers" to writable { - writeCustomizations( - customizations, - OperationSection.RetryClassifiers(customizations, operationShape), - ) - }, + OperationSection.RetryClassifiers(customizations, operationShape), + ) + }, ) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGenerator.kt index c9c342a2a31..3d9700993f4 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGenerator.kt @@ -56,158 +56,163 @@ class PaginatorGenerator private constructor( private val runtimeConfig = codegenContext.runtimeConfig private val paginatorName = "${operation.id.name.toPascalCase()}Paginator" private val idx = PaginatedIndex.of(model) - private val paginationInfo = idx.getPaginationInfo(codegenContext.serviceShape, operation).orNull() - ?: PANIC("failed to load pagination info") - private val module = RustModule.public( - "paginator", - parent = symbolProvider.moduleForShape(operation), - documentationOverride = "Paginator for this operation", - ) + private val paginationInfo = + idx.getPaginationInfo(codegenContext.serviceShape, operation).orNull() + ?: PANIC("failed to load pagination info") + private val module = + RustModule.public( + "paginator", + parent = symbolProvider.moduleForShape(operation), + documentationOverride = "Paginator for this operation", + ) private val inputType = symbolProvider.toSymbol(operation.inputShape(model)) private val outputShape = operation.outputShape(model) private val outputType = symbolProvider.toSymbol(outputShape) private val errorType = symbolProvider.symbolForOperationError(operation) - private fun paginatorType(): RuntimeType = RuntimeType.forInlineFun( - paginatorName, - module, - generate(), - ) - - private val codegenScope = arrayOf( - *preludeScope, - "page_size_setter" to pageSizeSetter(), - - // Operation Types - "operation" to symbolProvider.toSymbol(operation), - "Input" to inputType, - "Output" to outputType, - "Error" to errorType, - "Builder" to symbolProvider.symbolForBuilder(operation.inputShape(model)), - - // SDK Types - "HttpResponse" to RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::orchestrator::HttpResponse"), - "SdkError" to RuntimeType.sdkError(runtimeConfig), - "pagination_stream" to RuntimeType.smithyAsync(runtimeConfig).resolve("future::pagination_stream"), - - // External Types - "Stream" to RuntimeType.TokioStream.resolve("Stream"), + private fun paginatorType(): RuntimeType = + RuntimeType.forInlineFun( + paginatorName, + module, + generate(), + ) - ) + private val codegenScope = + arrayOf( + *preludeScope, + "page_size_setter" to pageSizeSetter(), + // Operation Types + "operation" to symbolProvider.toSymbol(operation), + "Input" to inputType, + "Output" to outputType, + "Error" to errorType, + "Builder" to symbolProvider.symbolForBuilder(operation.inputShape(model)), + // SDK Types + "HttpResponse" to RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::orchestrator::HttpResponse"), + "SdkError" to RuntimeType.sdkError(runtimeConfig), + "pagination_stream" to RuntimeType.smithyAsync(runtimeConfig).resolve("future::pagination_stream"), + // External Types + "Stream" to RuntimeType.TokioStream.resolve("Stream"), + ) /** Generate the paginator struct & impl **/ - private fun generate() = writable { - val outputTokenLens = NestedAccessorGenerator(codegenContext).generateBorrowingAccessor( - outputShape, - paginationInfo.outputTokenMemberPath, - ) - val inputTokenMember = symbolProvider.toMemberName(paginationInfo.inputTokenMember) - rustTemplate( - """ - /// Paginator for #{operation:D} - pub struct $paginatorName { - handle: std::sync::Arc, - builder: #{Builder}, - stop_on_duplicate_token: bool, - } + private fun generate() = + writable { + val outputTokenLens = + NestedAccessorGenerator(codegenContext).generateBorrowingAccessor( + outputShape, + paginationInfo.outputTokenMemberPath, + ) + val inputTokenMember = symbolProvider.toMemberName(paginationInfo.inputTokenMember) + rustTemplate( + """ + /// Paginator for #{operation:D} + pub struct $paginatorName { + handle: std::sync::Arc, + builder: #{Builder}, + stop_on_duplicate_token: bool, + } - impl $paginatorName { - /// Create a new paginator-wrapper - pub(crate) fn new(handle: std::sync::Arc, builder: #{Builder}) -> Self { - Self { - handle, - builder, - stop_on_duplicate_token: true, + impl $paginatorName { + /// Create a new paginator-wrapper + pub(crate) fn new(handle: std::sync::Arc, builder: #{Builder}) -> Self { + Self { + handle, + builder, + stop_on_duplicate_token: true, + } } - } - #{page_size_setter:W} + #{page_size_setter:W} - #{items_fn:W} + #{items_fn:W} - /// Stop paginating when the service returns the same pagination token twice in a row. - /// - /// Defaults to true. - /// - /// For certain operations, it may be useful to continue on duplicate token. For example, - /// if an operation is for tailing a log file in real-time, then continuing may be desired. - /// This option can be set to `false` to accommodate these use cases. - pub fn stop_on_duplicate_token(mut self, stop_on_duplicate_token: bool) -> Self { - self.stop_on_duplicate_token = stop_on_duplicate_token; - self - } + /// Stop paginating when the service returns the same pagination token twice in a row. + /// + /// Defaults to true. + /// + /// For certain operations, it may be useful to continue on duplicate token. For example, + /// if an operation is for tailing a log file in real-time, then continuing may be desired. + /// This option can be set to `false` to accommodate these use cases. + pub fn stop_on_duplicate_token(mut self, stop_on_duplicate_token: bool) -> Self { + self.stop_on_duplicate_token = stop_on_duplicate_token; + self + } - /// Create the pagination stream - /// - /// _Note:_ No requests will be dispatched until the stream is used - /// (e.g. with the [`.next().await`](aws_smithy_async::future::pagination_stream::PaginationStream::next) method). - pub fn send(self) -> #{pagination_stream}::PaginationStream<#{item_type}> { - // Move individual fields out of self for the borrow checker - let builder = self.builder; - let handle = self.handle; - #{runtime_plugin_init} - #{pagination_stream}::PaginationStream::new(#{pagination_stream}::fn_stream::FnStream::new(move |tx| #{Box}::pin(async move { - // Build the input for the first time. If required fields are missing, this is where we'll produce an early error. - let mut input = match builder.build().map_err(#{SdkError}::construction_failure) { - #{Ok}(input) => input, - #{Err}(e) => { let _ = tx.send(#{Err}(e)).await; return; } - }; - loop { - let resp = #{orchestrate}; - // If the input member is None or it was an error - let done = match resp { - #{Ok}(ref resp) => { - let new_token = #{output_token}(resp); - let is_empty = new_token.map(|token| token.is_empty()).unwrap_or(true); - if !is_empty && new_token == input.$inputTokenMember.as_ref() && self.stop_on_duplicate_token { - true - } else { - input.$inputTokenMember = new_token.cloned(); - is_empty - } - }, - #{Err}(_) => true, + /// Create the pagination stream + /// + /// _Note:_ No requests will be dispatched until the stream is used + /// (e.g. with the [`.next().await`](aws_smithy_async::future::pagination_stream::PaginationStream::next) method). + pub fn send(self) -> #{pagination_stream}::PaginationStream<#{item_type}> { + // Move individual fields out of self for the borrow checker + let builder = self.builder; + let handle = self.handle; + #{runtime_plugin_init} + #{pagination_stream}::PaginationStream::new(#{pagination_stream}::fn_stream::FnStream::new(move |tx| #{Box}::pin(async move { + // Build the input for the first time. If required fields are missing, this is where we'll produce an early error. + let mut input = match builder.build().map_err(#{SdkError}::construction_failure) { + #{Ok}(input) => input, + #{Err}(e) => { let _ = tx.send(#{Err}(e)).await; return; } }; - if tx.send(resp).await.is_err() { - // receiving end was dropped - return + loop { + let resp = #{orchestrate}; + // If the input member is None or it was an error + let done = match resp { + #{Ok}(ref resp) => { + let new_token = #{output_token}(resp); + let is_empty = new_token.map(|token| token.is_empty()).unwrap_or(true); + if !is_empty && new_token == input.$inputTokenMember.as_ref() && self.stop_on_duplicate_token { + true + } else { + input.$inputTokenMember = new_token.cloned(); + is_empty + } + }, + #{Err}(_) => true, + }; + if tx.send(resp).await.is_err() { + // receiving end was dropped + return + } + if done { + return + } } - if done { - return - } - } - }))) + }))) + } } - } - """, - *codegenScope, - "items_fn" to itemsFn(), - "output_token" to outputTokenLens, - "item_type" to writable { - rustTemplate("#{Result}<#{Output}, #{SdkError}<#{Error}, #{HttpResponse}>>", *codegenScope) - }, - "orchestrate" to writable { - rustTemplate( - "#{operation}::orchestrate(&runtime_plugins, input.clone()).await", - *codegenScope, - ) - }, - "runtime_plugin_init" to writable { - rustTemplate( - """ - let runtime_plugins = #{operation}::operation_runtime_plugins( - handle.runtime_plugins.clone(), - &handle.conf, - #{None}, - ); - """, - *codegenScope, - "RuntimePlugins" to RuntimeType.runtimePlugins(runtimeConfig), - ) - }, - ) - } + """, + *codegenScope, + "items_fn" to itemsFn(), + "output_token" to outputTokenLens, + "item_type" to + writable { + rustTemplate("#{Result}<#{Output}, #{SdkError}<#{Error}, #{HttpResponse}>>", *codegenScope) + }, + "orchestrate" to + writable { + rustTemplate( + "#{operation}::orchestrate(&runtime_plugins, input.clone()).await", + *codegenScope, + ) + }, + "runtime_plugin_init" to + writable { + rustTemplate( + """ + let runtime_plugins = #{operation}::operation_runtime_plugins( + handle.runtime_plugins.clone(), + &handle.conf, + #{None}, + ); + """, + *codegenScope, + "RuntimePlugins" to RuntimeType.runtimePlugins(runtimeConfig), + ) + }, + ) + } /** Type of the inner item of the paginator */ private fun itemType(): String { @@ -243,59 +248,63 @@ class PaginatorGenerator private constructor( } /** Generate a struct with a `items()` method that flattens the paginator **/ - private fun itemsPaginator(): RuntimeType? = if (paginationInfo.itemsMemberPath.isEmpty()) { - null - } else { - RuntimeType.forInlineFun("${paginatorName}Items", module) { - rustTemplate( - """ - /// Flattened paginator for `$paginatorName` - /// - /// This is created with [`.items()`]($paginatorName::items) - pub struct ${paginatorName}Items($paginatorName); - - impl ${paginatorName}Items { - /// Create the pagination stream - /// - /// _Note_: No requests will be dispatched until the stream is used - /// (e.g. with the [`.next().await`](aws_smithy_async::future::pagination_stream::PaginationStream::next) method). + private fun itemsPaginator(): RuntimeType? = + if (paginationInfo.itemsMemberPath.isEmpty()) { + null + } else { + RuntimeType.forInlineFun("${paginatorName}Items", module) { + rustTemplate( + """ + /// Flattened paginator for `$paginatorName` /// - /// To read the entirety of the paginator, use [`.collect::, _>()`](aws_smithy_async::future::pagination_stream::PaginationStream::collect). - pub fn send(self) -> #{pagination_stream}::PaginationStream<#{item_type}> { - #{pagination_stream}::TryFlatMap::new(self.0.send()).flat_map(|page| #{extract_items}(page).unwrap_or_default().into_iter()) + /// This is created with [`.items()`]($paginatorName::items) + pub struct ${paginatorName}Items($paginatorName); + + impl ${paginatorName}Items { + /// Create the pagination stream + /// + /// _Note_: No requests will be dispatched until the stream is used + /// (e.g. with the [`.next().await`](aws_smithy_async::future::pagination_stream::PaginationStream::next) method). + /// + /// To read the entirety of the paginator, use [`.collect::, _>()`](aws_smithy_async::future::pagination_stream::PaginationStream::collect). + pub fn send(self) -> #{pagination_stream}::PaginationStream<#{item_type}> { + #{pagination_stream}::TryFlatMap::new(self.0.send()).flat_map(|page| #{extract_items}(page).unwrap_or_default().into_iter()) + } } - } - """, - "extract_items" to NestedAccessorGenerator(codegenContext).generateOwnedAccessor( - outputShape, - paginationInfo.itemsMemberPath, - ), - "item_type" to writable { - rustTemplate("#{Result}<${itemType()}, #{SdkError}<#{Error}, #{HttpResponse}>>", *codegenScope) - }, - *codegenScope, - ) + """, + "extract_items" to + NestedAccessorGenerator(codegenContext).generateOwnedAccessor( + outputShape, + paginationInfo.itemsMemberPath, + ), + "item_type" to + writable { + rustTemplate("#{Result}<${itemType()}, #{SdkError}<#{Error}, #{HttpResponse}>>", *codegenScope) + }, + *codegenScope, + ) + } } - } - private fun pageSizeSetter() = writable { - paginationInfo.pageSizeMember.orNull()?.also { - val memberName = symbolProvider.toMemberName(it) - val pageSizeT = - symbolProvider.toSymbol(it).rustType().stripOuter().render(true) - rustTemplate( - """ - /// Set the page size - /// - /// _Note: this method will override any previously set value for `$memberName`_ - pub fn page_size(mut self, limit: $pageSizeT) -> Self { - self.builder.$memberName = #{Some}(limit); - self - } - """, - *preludeScope, - ) + private fun pageSizeSetter() = + writable { + paginationInfo.pageSizeMember.orNull()?.also { + val memberName = symbolProvider.toMemberName(it) + val pageSizeT = + symbolProvider.toSymbol(it).rustType().stripOuter().render(true) + rustTemplate( + """ + /// Set the page size + /// + /// _Note: this method will override any previously set value for `$memberName`_ + pub fn page_size(mut self, limit: $pageSizeT) -> Self { + self.builder.$memberName = #{Some}(limit); + self + } + """, + *preludeScope, + ) + } } - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/SensitiveIndex.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/SensitiveIndex.kt index 15e8d5361ce..8198b43aaed 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/SensitiveIndex.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/SensitiveIndex.kt @@ -17,6 +17,7 @@ class SensitiveIndex(model: Model) : KnowledgeIndex { private val sensitiveOutputs = sensitiveOutputSelector.select(model).map { it.id }.toSet() fun hasSensitiveInput(operationShape: OperationShape): Boolean = sensitiveInputs.contains(operationShape.id) + fun hasSensitiveOutput(operationShape: OperationShape): Boolean = sensitiveOutputs.contains(operationShape.id) companion object { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceGenerator.kt index dfdd302a31e..88591ef30c3 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceGenerator.kt @@ -41,10 +41,11 @@ class ServiceGenerator( ).render(rustCrate) rustCrate.withModule(ClientRustModule.config) { - val serviceConfigGenerator = ServiceConfigGenerator.withBaseBehavior( - codegenContext, - extraCustomizations = decorator.configCustomizations(codegenContext, listOf()), - ) + val serviceConfigGenerator = + ServiceConfigGenerator.withBaseBehavior( + codegenContext, + extraCustomizations = decorator.configCustomizations(codegenContext, listOf()), + ) serviceConfigGenerator.render(this) // Enable users to opt in to the test-utils in the runtime crate diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt index b58b8e97641..66095c1555d 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt @@ -32,26 +32,41 @@ sealed class ServiceRuntimePluginSection(name: String) : Section(name) { */ data class AdditionalConfig(val newLayerName: String, val serviceConfigName: String) : ServiceRuntimePluginSection("AdditionalConfig") { /** Adds a value to the config bag */ - fun putConfigValue(writer: RustWriter, value: Writable) { + fun putConfigValue( + writer: RustWriter, + value: Writable, + ) { writer.rust("$newLayerName.store_put(#T);", value) } } data class RegisterRuntimeComponents(val serviceConfigName: String) : ServiceRuntimePluginSection("RegisterRuntimeComponents") { /** Generates the code to register an interceptor */ - fun registerInterceptor(writer: RustWriter, interceptor: Writable) { + fun registerInterceptor( + writer: RustWriter, + interceptor: Writable, + ) { writer.rust("runtime_components.push_interceptor(#T);", interceptor) } - fun registerAuthScheme(writer: RustWriter, authScheme: Writable) { + fun registerAuthScheme( + writer: RustWriter, + authScheme: Writable, + ) { writer.rust("runtime_components.push_auth_scheme(#T);", authScheme) } - fun registerEndpointResolver(writer: RustWriter, resolver: Writable) { + fun registerEndpointResolver( + writer: RustWriter, + resolver: Writable, + ) { writer.rust("runtime_components.set_endpoint_resolver(Some(#T));", resolver) } - fun registerRetryClassifier(writer: RustWriter, classifier: Writable) { + fun registerRetryClassifier( + writer: RustWriter, + classifier: Writable, + ) { writer.rust("runtime_components.push_retry_classifier(#T);", classifier) } } @@ -64,30 +79,32 @@ typealias ServiceRuntimePluginCustomization = NamedCustomization - val runtimeApi = RuntimeType.smithyRuntimeApiClient(rc) - val smithyTypes = RuntimeType.smithyTypes(rc) - arrayOf( - *preludeScope, - "Arc" to RuntimeType.Arc, - "BoxError" to RuntimeType.boxError(codegenContext.runtimeConfig), - "Cow" to RuntimeType.Cow, - "FrozenLayer" to smithyTypes.resolve("config_bag::FrozenLayer"), - "IntoShared" to runtimeApi.resolve("shared::IntoShared"), - "Layer" to smithyTypes.resolve("config_bag::Layer"), - "RuntimeComponentsBuilder" to RuntimeType.runtimeComponentsBuilder(rc), - "RuntimePlugin" to RuntimeType.runtimePlugin(rc), - "Order" to runtimeApi.resolve("client::runtime_plugin::Order"), - ) - } + private val codegenScope = + codegenContext.runtimeConfig.let { rc -> + val runtimeApi = RuntimeType.smithyRuntimeApiClient(rc) + val smithyTypes = RuntimeType.smithyTypes(rc) + arrayOf( + *preludeScope, + "Arc" to RuntimeType.Arc, + "BoxError" to RuntimeType.boxError(codegenContext.runtimeConfig), + "Cow" to RuntimeType.Cow, + "FrozenLayer" to smithyTypes.resolve("config_bag::FrozenLayer"), + "IntoShared" to runtimeApi.resolve("shared::IntoShared"), + "Layer" to smithyTypes.resolve("config_bag::Layer"), + "RuntimeComponentsBuilder" to RuntimeType.runtimeComponentsBuilder(rc), + "RuntimePlugin" to RuntimeType.runtimePlugin(rc), + "Order" to runtimeApi.resolve("client::runtime_plugin::Order"), + ) + } fun render( writer: RustWriter, customizations: List, ) { - val additionalConfig = writable { - writeCustomizations(customizations, ServiceRuntimePluginSection.AdditionalConfig("cfg", "_service_config")) - } + val additionalConfig = + writable { + writeCustomizations(customizations, ServiceRuntimePluginSection.AdditionalConfig("cfg", "_service_config")) + } writer.rustTemplate( """ ##[derive(::std::fmt::Debug)] @@ -123,27 +140,30 @@ class ServiceRuntimePluginGenerator( #{declare_singletons} """, *codegenScope, - "config" to writable { - if (additionalConfig.isNotEmpty()) { - rustTemplate( - """ - let mut cfg = #{Layer}::new(${codegenContext.serviceShape.id.name.dq()}); - #{additional_config} - #{Some}(cfg.freeze()) - """, - *codegenScope, - "additional_config" to additionalConfig, - ) - } else { - rust("None") - } - }, - "runtime_components" to writable { - writeCustomizations(customizations, ServiceRuntimePluginSection.RegisterRuntimeComponents("_service_config")) - }, - "declare_singletons" to writable { - writeCustomizations(customizations, ServiceRuntimePluginSection.DeclareSingletons()) - }, + "config" to + writable { + if (additionalConfig.isNotEmpty()) { + rustTemplate( + """ + let mut cfg = #{Layer}::new(${codegenContext.serviceShape.id.name.dq()}); + #{additional_config} + #{Some}(cfg.freeze()) + """, + *codegenScope, + "additional_config" to additionalConfig, + ) + } else { + rust("None") + } + }, + "runtime_components" to + writable { + writeCustomizations(customizations, ServiceRuntimePluginSection.RegisterRuntimeComponents("_service_config")) + }, + "declare_singletons" to + writable { + writeCustomizations(customizations, ServiceRuntimePluginSection.DeclareSingletons()) + }, ) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGenerator.kt index 68ed17a95b7..403c8b1d3b7 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGenerator.kt @@ -28,31 +28,40 @@ class CustomizableOperationGenerator( private val runtimeConfig = codegenContext.runtimeConfig fun render(crate: RustCrate) { - val codegenScope = arrayOf( - *preludeScope, - "CustomizableOperation" to ClientRustModule.Client.customize.toType() - .resolve("CustomizableOperation"), - "CustomizableSend" to ClientRustModule.Client.customize.toType() - .resolve("internal::CustomizableSend"), - "HttpRequest" to RuntimeType.smithyRuntimeApiClient(runtimeConfig) - .resolve("client::orchestrator::HttpRequest"), - "HttpResponse" to RuntimeType.smithyRuntimeApiClient(runtimeConfig) - .resolve("client::orchestrator::HttpResponse"), - "Intercept" to RuntimeType.intercept(runtimeConfig), - "MapRequestInterceptor" to RuntimeType.smithyRuntime(runtimeConfig) - .resolve("client::interceptors::MapRequestInterceptor"), - "MutateRequestInterceptor" to RuntimeType.smithyRuntime(runtimeConfig) - .resolve("client::interceptors::MutateRequestInterceptor"), - "PhantomData" to RuntimeType.Phantom, - "RuntimePlugin" to RuntimeType.runtimePlugin(runtimeConfig), - "SharedRuntimePlugin" to RuntimeType.sharedRuntimePlugin(runtimeConfig), - "SendResult" to ClientRustModule.Client.customize.toType() - .resolve("internal::SendResult"), - "SdkBody" to RuntimeType.sdkBody(runtimeConfig), - "SdkError" to RuntimeType.sdkError(runtimeConfig), - "SharedInterceptor" to RuntimeType.smithyRuntimeApiClient(runtimeConfig) - .resolve("client::interceptors::SharedInterceptor"), - ) + val codegenScope = + arrayOf( + *preludeScope, + "CustomizableOperation" to + ClientRustModule.Client.customize.toType() + .resolve("CustomizableOperation"), + "CustomizableSend" to + ClientRustModule.Client.customize.toType() + .resolve("internal::CustomizableSend"), + "HttpRequest" to + RuntimeType.smithyRuntimeApiClient(runtimeConfig) + .resolve("client::orchestrator::HttpRequest"), + "HttpResponse" to + RuntimeType.smithyRuntimeApiClient(runtimeConfig) + .resolve("client::orchestrator::HttpResponse"), + "Intercept" to RuntimeType.intercept(runtimeConfig), + "MapRequestInterceptor" to + RuntimeType.smithyRuntime(runtimeConfig) + .resolve("client::interceptors::MapRequestInterceptor"), + "MutateRequestInterceptor" to + RuntimeType.smithyRuntime(runtimeConfig) + .resolve("client::interceptors::MutateRequestInterceptor"), + "PhantomData" to RuntimeType.Phantom, + "RuntimePlugin" to RuntimeType.runtimePlugin(runtimeConfig), + "SharedRuntimePlugin" to RuntimeType.sharedRuntimePlugin(runtimeConfig), + "SendResult" to + ClientRustModule.Client.customize.toType() + .resolve("internal::SendResult"), + "SdkBody" to RuntimeType.sdkBody(runtimeConfig), + "SdkError" to RuntimeType.sdkError(runtimeConfig), + "SharedInterceptor" to + RuntimeType.smithyRuntimeApiClient(runtimeConfig) + .resolve("client::interceptors::SharedInterceptor"), + ) val customizeModule = ClientRustModule.Client.customize crate.withModule(customizeModule) { @@ -174,17 +183,21 @@ class CustomizableOperationGenerator( } """, *codegenScope, - "additional_methods" to writable { - writeCustomizations( - customizations, - CustomizableOperationSection.CustomizableOperationImpl, - ) - }, + "additional_methods" to + writable { + writeCustomizations( + customizations, + CustomizableOperationSection.CustomizableOperationImpl, + ) + }, ) } } - private fun renderConvenienceAliases(parentModule: RustModule, writer: RustWriter) { + private fun renderConvenienceAliases( + parentModule: RustModule, + writer: RustWriter, + ) { writer.withInlineModule(RustModule.new("internal", Visibility.PUBCRATE, true, parentModule), null) { rustTemplate( """ @@ -206,8 +219,9 @@ class CustomizableOperationGenerator( } """, *preludeScope, - "HttpResponse" to RuntimeType.smithyRuntimeApiClient(runtimeConfig) - .resolve("client::orchestrator::HttpResponse"), + "HttpResponse" to + RuntimeType.smithyRuntimeApiClient(runtimeConfig) + .resolve("client::orchestrator::HttpResponse"), "SdkError" to RuntimeType.sdkError(runtimeConfig), ) } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientCore.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientCore.kt index 3073413efe6..b997142a990 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientCore.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientCore.kt @@ -20,7 +20,11 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.setterName class FluentClientCore(private val model: Model) { /** Generate and write Rust code for a builder method that sets a Vec */ - fun RustWriter.renderVecHelper(member: MemberShape, memberName: String, coreType: RustType.Vec) { + fun RustWriter.renderVecHelper( + member: MemberShape, + memberName: String, + coreType: RustType.Vec, + ) { docs("Appends an item to `${member.memberName}`.") rust("///") docs("To override the contents of this collection use [`${member.setterName()}`](Self::${member.setterName()}).") @@ -36,7 +40,11 @@ class FluentClientCore(private val model: Model) { } /** Generate and write Rust code for a builder method that sets a HashMap */ - fun RustWriter.renderMapHelper(member: MemberShape, memberName: String, coreType: RustType.HashMap) { + fun RustWriter.renderMapHelper( + member: MemberShape, + memberName: String, + coreType: RustType.HashMap, + ) { docs("Adds a key-value pair to `${member.memberName}`.") rust("///") docs("To override the contents of this collection use [`${member.setterName()}`](Self::${member.setterName()}).") @@ -58,7 +66,11 @@ class FluentClientCore(private val model: Model) { * `renderInputHelper(memberShape, "foo", RustType.String)` -> `pub fn foo(mut self, input: impl Into) -> Self { ... }` * `renderInputHelper(memberShape, "set_bar", RustType.Option)` -> `pub fn set_bar(mut self, input: Option) -> Self { ... }` */ - fun RustWriter.renderInputHelper(member: MemberShape, memberName: String, coreType: RustType) { + fun RustWriter.renderInputHelper( + member: MemberShape, + memberName: String, + coreType: RustType, + ) { val functionInput = coreType.asArgument("input") documentShape(member, model) @@ -72,7 +84,11 @@ class FluentClientCore(private val model: Model) { /** * Generate and write Rust code for a getter method that returns a reference to the inner data. */ - fun RustWriter.renderGetterHelper(member: MemberShape, memberName: String, coreType: RustType) { + fun RustWriter.renderGetterHelper( + member: MemberShape, + memberName: String, + coreType: RustType, + ) { documentShape(member, model) deprecatedShape(member) withBlockTemplate("pub fn $memberName(&self) -> &#{CoreType} {", "}", "CoreType" to coreType) { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDecorator.kt index 73296eb3378..76ed95ed1ce 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDecorator.kt @@ -29,7 +29,10 @@ class FluentClientDecorator : ClientCodegenDecorator { private fun applies(codegenContext: ClientCodegenContext): Boolean = codegenContext.settings.codegenConfig.includeFluentClient - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { if (!applies(codegenContext)) { return } @@ -50,14 +53,17 @@ class FluentClientDecorator : ClientCodegenDecorator { return baseCustomizations } - return baseCustomizations + object : LibRsCustomization() { - override fun section(section: LibRsSection) = when (section) { - is LibRsSection.Body -> writable { - rust("pub use client::Client;") - } - else -> emptySection + return baseCustomizations + + object : LibRsCustomization() { + override fun section(section: LibRsSection) = + when (section) { + is LibRsSection.Body -> + writable { + rust("pub use client::Client;") + } + else -> emptySection + } } - } } } @@ -77,20 +83,21 @@ abstract class FluentClientCustomization : NamedCustomization writable { - val serviceName = codegenContext.serviceShape.serviceNameOrDefault("the service") - docs( - """ - An ergonomic client for $serviceName. + is FluentClientSection.FluentClientDocs -> + writable { + val serviceName = codegenContext.serviceShape.serviceNameOrDefault("the service") + docs( + """ + An ergonomic client for $serviceName. - This client allows ergonomic access to $serviceName. - Each method corresponds to an API defined in the service's Smithy model, - and the request and response shapes are auto-generated from that same model. - """, - ) - FluentClientDocs.clientConstructionDocs(codegenContext)(this) - FluentClientDocs.clientUsageDocs(codegenContext)(this) - } + This client allows ergonomic access to $serviceName. + Each method corresponds to an API defined in the service's Smithy model, + and the request and response shapes are auto-generated from that same model. + """, + ) + FluentClientDocs.clientConstructionDocs(codegenContext)(this) + FluentClientDocs.clientUsageDocs(codegenContext)(this) + } else -> emptySection } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDocs.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDocs.kt index 448b576a9d3..be499c6ca6d 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDocs.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientDocs.kt @@ -14,85 +14,89 @@ import software.amazon.smithy.rust.codegen.core.util.inputShape import software.amazon.smithy.rust.codegen.core.util.serviceNameOrDefault object FluentClientDocs { - fun clientConstructionDocs(codegenContext: ClientCodegenContext) = writable { - val serviceName = codegenContext.serviceShape.serviceNameOrDefault("the service") - val moduleUseName = codegenContext.moduleUseName() - docsTemplate( - """ - Client for calling $serviceName. + fun clientConstructionDocs(codegenContext: ClientCodegenContext) = + writable { + val serviceName = codegenContext.serviceShape.serviceNameOrDefault("the service") + val moduleUseName = codegenContext.moduleUseName() + docsTemplate( + """ + Client for calling $serviceName. - #### Constructing a `Client` + #### Constructing a `Client` - A `Client` requires a config in order to be constructed. With the default set of Cargo features, - this config will only require an endpoint to produce a functioning client. However, some Smithy - features will require additional configuration. For example, `@auth` requires some kind of identity - or identity resolver to be configured. The config is used to customize various aspects of the client, - such as: + A `Client` requires a config in order to be constructed. With the default set of Cargo features, + this config will only require an endpoint to produce a functioning client. However, some Smithy + features will require additional configuration. For example, `@auth` requires some kind of identity + or identity resolver to be configured. The config is used to customize various aspects of the client, + such as: - - [HTTP Connector](crate::config::Builder::http_connector) - - [Retry](crate::config::Builder::retry_config) - - [Timeouts](crate::config::Builder::timeout_config) - - [... and more](crate::config::Builder) + - [HTTP Connector](crate::config::Builder::http_connector) + - [Retry](crate::config::Builder::retry_config) + - [Timeouts](crate::config::Builder::timeout_config) + - [... and more](crate::config::Builder) - Below is a minimal example of how to create a client: + Below is a minimal example of how to create a client: - ```rust,no_run - let config = $moduleUseName::Config::builder() - .endpoint_url("http://localhost:1234") - .build(); - let client = $moduleUseName::Client::from_conf(config); - ``` + ```rust,no_run + let config = $moduleUseName::Config::builder() + .endpoint_url("http://localhost:1234") + .build(); + let client = $moduleUseName::Client::from_conf(config); + ``` - _Note:_ Client construction is expensive due to connection thread pool initialization, and should be done - once at application start-up. Cloning a client is cheap (it's just an [`Arc`](std::sync::Arc) under the hood), - so creating it once at start-up and cloning it around the application as needed is recommended. - """.trimIndent(), - ) - } + _Note:_ Client construction is expensive due to connection thread pool initialization, and should be done + once at application start-up. Cloning a client is cheap (it's just an [`Arc`](std::sync::Arc) under the hood), + so creating it once at start-up and cloning it around the application as needed is recommended. + """.trimIndent(), + ) + } - fun clientUsageDocs(codegenContext: ClientCodegenContext) = writable { - val model = codegenContext.model - val symbolProvider = codegenContext.symbolProvider - if (model.operationShapes.isNotEmpty()) { - // Find an operation with a simple string member shape - val (operation, member) = codegenContext.serviceShape.operations - .map { id -> - val operationShape = model.expectShape(id, OperationShape::class.java) - val member = operationShape.inputShape(model) - .members() - .firstOrNull { model.expectShape(it.target) is StringShape } - operationShape to member - } - .sortedBy { it.first.id } - .firstOrNull { (_, member) -> member != null } ?: (null to null) - if (operation != null && member != null) { - val operationSymbol = symbolProvider.toSymbol(operation) - val memberSymbol = symbolProvider.toSymbol(member) - val operationFnName = FluentClientGenerator.clientOperationFnName(operation, symbolProvider) - docsTemplate( - """ - ## Using the `Client` + fun clientUsageDocs(codegenContext: ClientCodegenContext) = + writable { + val model = codegenContext.model + val symbolProvider = codegenContext.symbolProvider + if (model.operationShapes.isNotEmpty()) { + // Find an operation with a simple string member shape + val (operation, member) = + codegenContext.serviceShape.operations + .map { id -> + val operationShape = model.expectShape(id, OperationShape::class.java) + val member = + operationShape.inputShape(model) + .members() + .firstOrNull { model.expectShape(it.target) is StringShape } + operationShape to member + } + .sortedBy { it.first.id } + .firstOrNull { (_, member) -> member != null } ?: (null to null) + if (operation != null && member != null) { + val operationSymbol = symbolProvider.toSymbol(operation) + val memberSymbol = symbolProvider.toSymbol(member) + val operationFnName = FluentClientGenerator.clientOperationFnName(operation, symbolProvider) + docsTemplate( + """ + ## Using the `Client` - A client has a function for every operation that can be performed by the service. - For example, the [`${operationSymbol.name}`](${operationSymbol.namespace}) operation has - a [`Client::$operationFnName`], function which returns a builder for that operation. - The fluent builder ultimately has a `send()` function that returns an async future that - returns a result, as illustrated below: + A client has a function for every operation that can be performed by the service. + For example, the [`${operationSymbol.name}`](${operationSymbol.namespace}) operation has + a [`Client::$operationFnName`], function which returns a builder for that operation. + The fluent builder ultimately has a `send()` function that returns an async future that + returns a result, as illustrated below: - ```rust,ignore - let result = client.$operationFnName() - .${memberSymbol.name}("example") - .send() - .await; - ``` + ```rust,ignore + let result = client.$operationFnName() + .${memberSymbol.name}("example") + .send() + .await; + ``` - The underlying HTTP requests that get made by this can be modified with the `customize_operation` - function on the fluent builder. See the [`customize`](crate::client::customize) module for more - information. - """.trimIndent(), - "operation" to operationSymbol, - ) + The underlying HTTP requests that get made by this can be modified with the `customize_operation` + function on the fluent builder. See the [`customize`](crate::client::customize) module for more + information. + """.trimIndent(), + "operation" to operationSymbol, + ) + } } } - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt index 3865d5a0ab2..660f8e982b5 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGenerator.kt @@ -60,16 +60,21 @@ import software.amazon.smithy.rust.codegen.core.util.sdkId import software.amazon.smithy.rust.codegen.core.util.toSnakeCase private val BehaviorVersionLatest = Feature("behavior-version-latest", false, listOf()) + class FluentClientGenerator( private val codegenContext: ClientCodegenContext, private val customizations: List = emptyList(), ) { - companion object { - fun clientOperationFnName(operationShape: OperationShape, symbolProvider: RustSymbolProvider): String = - RustReservedWords.escapeIfNeeded(symbolProvider.toSymbol(operationShape).name.toSnakeCase()) - - fun clientOperationModuleName(operationShape: OperationShape, symbolProvider: RustSymbolProvider): String = + fun clientOperationFnName( + operationShape: OperationShape, + symbolProvider: RustSymbolProvider, + ): String = RustReservedWords.escapeIfNeeded(symbolProvider.toSymbol(operationShape).name.toSnakeCase()) + + fun clientOperationModuleName( + operationShape: OperationShape, + symbolProvider: RustSymbolProvider, + ): String = RustReservedWords.escapeIfNeeded( symbolProvider.toSymbol(operationShape).name.toSnakeCase(), EscapeFor.ModuleName, @@ -84,10 +89,14 @@ class FluentClientGenerator( private val runtimeConfig = codegenContext.runtimeConfig private val core = FluentClientCore(model) - fun render(crate: RustCrate, customizableOperationCustomizations: List = emptyList()) { + fun render( + crate: RustCrate, + customizableOperationCustomizations: List = emptyList(), + ) { renderFluentClient(crate) - val customizableOperationGenerator = CustomizableOperationGenerator(codegenContext, customizableOperationCustomizations) + val customizableOperationGenerator = + CustomizableOperationGenerator(codegenContext, customizableOperationCustomizations) operations.forEach { operation -> crate.withModule(symbolProvider.moduleForBuilder(operation)) { renderFluentBuilder(operation) @@ -159,15 +168,16 @@ class FluentClientGenerator( "Arc" to RuntimeType.Arc, "base_client_runtime_plugins" to baseClientRuntimePluginsFn(codegenContext), "BoxError" to RuntimeType.boxError(runtimeConfig), - "client_docs" to writable { - customizations.forEach { - it.section( - FluentClientSection.FluentClientDocs( - serviceShape, - ), - )(this) - } - }, + "client_docs" to + writable { + customizations.forEach { + it.section( + FluentClientSection.FluentClientDocs( + serviceShape, + ), + )(this) + } + }, "ConfigBag" to RuntimeType.configBag(runtimeConfig), "RuntimePlugins" to RuntimeType.runtimePlugins(runtimeConfig), "tracing" to CargoDependency.Tracing.toType(), @@ -183,24 +193,27 @@ class FluentClientGenerator( crate.withModule(privateModule) { rustBlock("impl super::Client") { val fullPath = operation.fullyQualifiedFluentBuilder(symbolProvider) - val maybePaginated = if (operation.isPaginated(model)) { - "\n/// This operation supports pagination; See [`into_paginator()`]($fullPath::into_paginator)." - } else { - "" - } + val maybePaginated = + if (operation.isPaginated(model)) { + "\n/// This operation supports pagination; See [`into_paginator()`]($fullPath::into_paginator)." + } else { + "" + } val output = operation.outputShape(model) val operationOk = symbolProvider.toSymbol(output) val operationErr = symbolProvider.symbolForOperationError(operation) - val inputFieldsBody = generateOperationShapeDocs(this, symbolProvider, operation, model) - .joinToString("\n") { "/// - $it" } + val inputFieldsBody = + generateOperationShapeDocs(this, symbolProvider, operation, model) + .joinToString("\n") { "/// - $it" } - val inputFieldsHead = if (inputFieldsBody.isNotEmpty()) { - "The fluent builder is configurable:\n" - } else { - "The fluent builder takes no input, just [`send`]($fullPath::send) it." - } + val inputFieldsHead = + if (inputFieldsBody.isNotEmpty()) { + "The fluent builder is configurable:\n" + } else { + "The fluent builder takes no input, just [`send`]($fullPath::send) it." + } val outputFieldsBody = generateShapeMemberDocs(this, symbolProvider, output, model).joinToString("\n") { @@ -347,20 +360,24 @@ class FluentClientGenerator( write("&self.inner") } - val orchestratorScope = arrayOf( - *preludeScope, - "CustomizableOperation" to ClientRustModule.Client.customize.toType() - .resolve("CustomizableOperation"), - "HttpResponse" to RuntimeType.smithyRuntimeApiClient(runtimeConfig) - .resolve("client::orchestrator::HttpResponse"), - "Operation" to operationSymbol, - "OperationError" to errorType, - "OperationOutput" to outputType, - "RuntimePlugins" to RuntimeType.runtimePlugins(runtimeConfig), - "SendResult" to ClientRustModule.Client.customize.toType() - .resolve("internal::SendResult"), - "SdkError" to RuntimeType.sdkError(runtimeConfig), - ) + val orchestratorScope = + arrayOf( + *preludeScope, + "CustomizableOperation" to + ClientRustModule.Client.customize.toType() + .resolve("CustomizableOperation"), + "HttpResponse" to + RuntimeType.smithyRuntimeApiClient(runtimeConfig) + .resolve("client::orchestrator::HttpResponse"), + "Operation" to operationSymbol, + "OperationError" to errorType, + "OperationOutput" to outputType, + "RuntimePlugins" to RuntimeType.runtimePlugins(runtimeConfig), + "SendResult" to + ClientRustModule.Client.customize.toType() + .resolve("internal::SendResult"), + "SdkError" to RuntimeType.sdkError(runtimeConfig), + ) rustTemplate( """ /// Sends the request and returns the response. @@ -454,67 +471,70 @@ class FluentClientGenerator( } } -private fun baseClientRuntimePluginsFn(codegenContext: ClientCodegenContext): RuntimeType = codegenContext.runtimeConfig.let { rc -> - RuntimeType.forInlineFun("base_client_runtime_plugins", ClientRustModule.config) { - val api = RuntimeType.smithyRuntimeApiClient(rc) - val rt = RuntimeType.smithyRuntime(rc) - val behaviorVersionError = "Invalid client configuration: A behavior major version must be set when sending a " + - "request or constructing a client. You must set it during client construction or by enabling the " + - "`${BehaviorVersionLatest.name}` cargo feature." - rustTemplate( - """ - pub(crate) fn base_client_runtime_plugins( - mut config: crate::Config, - ) -> #{RuntimePlugins} { - let mut configured_plugins = #{Vec}::new(); - ::std::mem::swap(&mut config.runtime_plugins, &mut configured_plugins); - ##[allow(unused_mut)] - let mut behavior_version = config.behavior_version.clone(); - #{update_bmv} - - let mut plugins = #{RuntimePlugins}::new() - // defaults - .with_client_plugins(#{default_plugins}( - #{DefaultPluginParams}::new() - .with_retry_partition_name(${codegenContext.serviceShape.sdkId().dq()}) - .with_behavior_version(behavior_version.expect(${behaviorVersionError.dq()})) - )) - // user config - .with_client_plugin( - #{StaticRuntimePlugin}::new() - .with_config(config.config.clone()) - .with_runtime_components(config.runtime_components.clone()) - ) - // codegen config - .with_client_plugin(crate::config::ServiceRuntimePlugin::new(config)) - .with_client_plugin(#{NoAuthRuntimePlugin}::new()); - - for plugin in configured_plugins { - plugins = plugins.with_client_plugin(plugin); - } - plugins - } - """, - *preludeScope, - "DefaultPluginParams" to rt.resolve("client::defaults::DefaultPluginParams"), - "default_plugins" to rt.resolve("client::defaults::default_plugins"), - "NoAuthRuntimePlugin" to rt.resolve("client::auth::no_auth::NoAuthRuntimePlugin"), - "RuntimePlugins" to RuntimeType.runtimePlugins(rc), - "StaticRuntimePlugin" to api.resolve("client::runtime_plugin::StaticRuntimePlugin"), - "update_bmv" to featureGatedBlock(BehaviorVersionLatest) { - rustTemplate( - """ - if behavior_version.is_none() { - behavior_version = Some(#{BehaviorVersion}::latest()); +private fun baseClientRuntimePluginsFn(codegenContext: ClientCodegenContext): RuntimeType = + codegenContext.runtimeConfig.let { rc -> + RuntimeType.forInlineFun("base_client_runtime_plugins", ClientRustModule.config) { + val api = RuntimeType.smithyRuntimeApiClient(rc) + val rt = RuntimeType.smithyRuntime(rc) + val behaviorVersionError = + "Invalid client configuration: A behavior major version must be set when sending a " + + "request or constructing a client. You must set it during client construction or by enabling the " + + "`${BehaviorVersionLatest.name}` cargo feature." + rustTemplate( + """ + pub(crate) fn base_client_runtime_plugins( + mut config: crate::Config, + ) -> #{RuntimePlugins} { + let mut configured_plugins = #{Vec}::new(); + ::std::mem::swap(&mut config.runtime_plugins, &mut configured_plugins); + ##[allow(unused_mut)] + let mut behavior_version = config.behavior_version.clone(); + #{update_bmv} + + let mut plugins = #{RuntimePlugins}::new() + // defaults + .with_client_plugins(#{default_plugins}( + #{DefaultPluginParams}::new() + .with_retry_partition_name(${codegenContext.serviceShape.sdkId().dq()}) + .with_behavior_version(behavior_version.expect(${behaviorVersionError.dq()})) + )) + // user config + .with_client_plugin( + #{StaticRuntimePlugin}::new() + .with_config(config.config.clone()) + .with_runtime_components(config.runtime_components.clone()) + ) + // codegen config + .with_client_plugin(crate::config::ServiceRuntimePlugin::new(config)) + .with_client_plugin(#{NoAuthRuntimePlugin}::new()); + + for plugin in configured_plugins { + plugins = plugins.with_client_plugin(plugin); } - - """, - "BehaviorVersion" to api.resolve("client::behavior_version::BehaviorVersion"), - ) - }, - ) + plugins + } + """, + *preludeScope, + "DefaultPluginParams" to rt.resolve("client::defaults::DefaultPluginParams"), + "default_plugins" to rt.resolve("client::defaults::default_plugins"), + "NoAuthRuntimePlugin" to rt.resolve("client::auth::no_auth::NoAuthRuntimePlugin"), + "RuntimePlugins" to RuntimeType.runtimePlugins(rc), + "StaticRuntimePlugin" to api.resolve("client::runtime_plugin::StaticRuntimePlugin"), + "update_bmv" to + featureGatedBlock(BehaviorVersionLatest) { + rustTemplate( + """ + if behavior_version.is_none() { + behavior_version = Some(#{BehaviorVersion}::latest()); + } + + """, + "BehaviorVersion" to api.resolve("client::behavior_version::BehaviorVersion"), + ) + }, + ) + } } -} /** * For a given `operation` shape, return a list of strings where each string describes the name and input type of one of @@ -537,10 +557,11 @@ private fun generateOperationShapeDocs( val builderSetterLink = docLink("$fluentBuilderFullyQualifiedName::${memberShape.setterName()}") val docTrait = memberShape.getMemberTrait(model, DocumentationTrait::class.java).orNull() - val docs = when (docTrait?.value?.isNotBlank()) { - true -> normalizeHtml(writer.escape(docTrait.value)).replace("\n", " ") - else -> "(undocumented)" - } + val docs = + when (docTrait?.value?.isNotBlank()) { + true -> normalizeHtml(writer.escape(docTrait.value)).replace("\n", " ") + else -> "(undocumented)" + } "[`$builderInputDoc`]($builderInputLink) / [`$builderSetterDoc`]($builderSetterLink):
required: **${memberShape.isRequired}**
$docs
" } @@ -563,10 +584,11 @@ private fun generateShapeMemberDocs( val name = symbolProvider.toMemberName(memberShape) val member = symbolProvider.toSymbol(memberShape).rustType().render(fullyQualified = false) val docTrait = memberShape.getMemberTrait(model, DocumentationTrait::class.java).orNull() - val docs = when (docTrait?.value?.isNotBlank()) { - true -> normalizeHtml(writer.escape(docTrait.value)).replace("\n", " ") - else -> "(undocumented)" - } + val docs = + when (docTrait?.value?.isNotBlank()) { + true -> normalizeHtml(writer.escape(docTrait.value)).replace("\n", " ") + else -> "(undocumented)" + } "[`$name($member)`](${docLink("$structName::$name")}): $docs" } @@ -582,9 +604,8 @@ internal fun OperationShape.fluentBuilderType(symbolProvider: RustSymbolProvider * * * _NOTE: This function generates the links that appear under **"The fluent builder is configurable:"**_ */ -private fun OperationShape.fullyQualifiedFluentBuilder( - symbolProvider: RustSymbolProvider, -): String = fluentBuilderType(symbolProvider).fullyQualifiedName() +private fun OperationShape.fullyQualifiedFluentBuilder(symbolProvider: RustSymbolProvider): String = + fluentBuilderType(symbolProvider).fullyQualifiedName() /** * Generate a string that looks like a Rust function pointer for documenting a fluent builder method e.g. @@ -596,11 +617,12 @@ internal fun MemberShape.asFluentBuilderInputDoc(symbolProvider: SymbolProvider) val memberName = symbolProvider.toMemberName(this) val outerType = symbolProvider.toSymbol(this).rustType().stripOuter() // We generate Vec/HashMap helpers - val renderedType = when (outerType) { - is RustType.Vec -> listOf(outerType.member) - is RustType.HashMap -> listOf(outerType.key, outerType.member) - else -> listOf(outerType) - } + val renderedType = + when (outerType) { + is RustType.Vec -> listOf(outerType.member) + is RustType.HashMap -> listOf(outerType.key, outerType.member) + else -> listOf(outerType) + } val args = renderedType.joinToString { it.asArgumentType(fullyQualified = false) } return "$memberName($args)" diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/IdempotencyTokenProviderCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/IdempotencyTokenProviderCustomization.kt index fd04a062248..c41764dfa81 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/IdempotencyTokenProviderCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/IdempotencyTokenProviderCustomization.kt @@ -19,40 +19,43 @@ import software.amazon.smithy.rust.codegen.core.smithy.customize.NamedCustomizat */ class IdempotencyTokenProviderCustomization(codegenContext: ClientCodegenContext) : NamedCustomization() { private val runtimeConfig = codegenContext.runtimeConfig - private val codegenScope = arrayOf( - *preludeScope, - "IdempotencyTokenProvider" to RuntimeType.idempotencyToken(runtimeConfig).resolve("IdempotencyTokenProvider"), - ) + private val codegenScope = + arrayOf( + *preludeScope, + "IdempotencyTokenProvider" to RuntimeType.idempotencyToken(runtimeConfig).resolve("IdempotencyTokenProvider"), + ) override fun section(section: ServiceConfig): Writable { return when (section) { - ServiceConfig.BuilderImpl -> writable { - rustTemplate( - """ - /// Sets the idempotency token provider to use for service calls that require tokens. - pub fn idempotency_token_provider(mut self, idempotency_token_provider: impl #{Into}<#{IdempotencyTokenProvider}>) -> Self { - self.set_idempotency_token_provider(#{Some}(idempotency_token_provider.into())); - self - } - """, - *codegenScope, - ) + ServiceConfig.BuilderImpl -> + writable { + rustTemplate( + """ + /// Sets the idempotency token provider to use for service calls that require tokens. + pub fn idempotency_token_provider(mut self, idempotency_token_provider: impl #{Into}<#{IdempotencyTokenProvider}>) -> Self { + self.set_idempotency_token_provider(#{Some}(idempotency_token_provider.into())); + self + } + """, + *codegenScope, + ) - rustTemplate( - """ - /// Sets the idempotency token provider to use for service calls that require tokens. - pub fn set_idempotency_token_provider(&mut self, idempotency_token_provider: #{Option}<#{IdempotencyTokenProvider}>) -> &mut Self { - self.config.store_or_unset(idempotency_token_provider); - self - } - """, - *codegenScope, - ) - } + rustTemplate( + """ + /// Sets the idempotency token provider to use for service calls that require tokens. + pub fn set_idempotency_token_provider(&mut self, idempotency_token_provider: #{Option}<#{IdempotencyTokenProvider}>) -> &mut Self { + self.config.store_or_unset(idempotency_token_provider); + self + } + """, + *codegenScope, + ) + } - is ServiceConfig.DefaultForTests -> writable { - rust("""${section.configBuilderRef}.set_idempotency_token_provider(Some("00000000-0000-4000-8000-000000000000".into()));""") - } + is ServiceConfig.DefaultForTests -> + writable { + rust("""${section.configBuilderRef}.set_idempotency_token_provider(Some("00000000-0000-4000-8000-000000000000".into()));""") + } else -> writable { } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGenerator.kt index 26f4cd7a634..38fecb7e486 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGenerator.kt @@ -118,7 +118,6 @@ data class ConfigParam( val getterDocs: Writable? = null, val optional: Boolean = true, ) { - data class Builder( var name: String? = null, var type: Symbol? = null, @@ -128,11 +127,17 @@ data class ConfigParam( var optional: Boolean = true, ) { fun name(name: String) = apply { this.name = name } + fun type(type: Symbol) = apply { this.type = type } + fun newtype(newtype: RuntimeType) = apply { this.newtype = newtype } + fun setterDocs(setterDocs: Writable?) = apply { this.setterDocs = setterDocs } + fun getterDocs(getterDocs: Writable?) = apply { this.getterDocs = getterDocs } + fun optional(optional: Boolean) = apply { this.optional = optional } + fun build() = ConfigParam(name!!, type!!, newtype, setterDocs, getterDocs, optional) } } @@ -143,23 +148,27 @@ data class ConfigParam( * When config parameters are stored in a config map in Rust, stored parameters are keyed by type. * Therefore, primitive types, such as bool and String, need to be wrapped in newtypes to make them distinct. */ -fun configParamNewtype(newtypeName: String, inner: Symbol, runtimeConfig: RuntimeConfig) = - RuntimeType.forInlineFun(newtypeName, ClientRustModule.config) { - val codegenScope = arrayOf( +fun configParamNewtype( + newtypeName: String, + inner: Symbol, + runtimeConfig: RuntimeConfig, +) = RuntimeType.forInlineFun(newtypeName, ClientRustModule.config) { + val codegenScope = + arrayOf( "Storable" to RuntimeType.smithyTypes(runtimeConfig).resolve("config_bag::Storable"), "StoreReplace" to RuntimeType.smithyTypes(runtimeConfig).resolve("config_bag::StoreReplace"), ) - rustTemplate( - """ - ##[derive(Debug, Clone)] - pub(crate) struct $newtypeName(pub(crate) $inner); - impl #{Storable} for $newtypeName { - type Storer = #{StoreReplace}; - } - """, - *codegenScope, - ) - } + rustTemplate( + """ + ##[derive(Debug, Clone)] + pub(crate) struct $newtypeName(pub(crate) $inner); + impl #{Storable} for $newtypeName { + type Storer = #{StoreReplace}; + } + """, + *codegenScope, + ) +} /** * Render an expression that loads a value from a config bag. @@ -167,21 +176,26 @@ fun configParamNewtype(newtypeName: String, inner: Symbol, runtimeConfig: Runtim * The expression to be rendered handles a case where a newtype is stored in the config bag, but the user expects * the underlying raw type after the newtype has been loaded from the bag. */ -fun loadFromConfigBag(innerTypeName: String, newtype: RuntimeType): Writable = writable { - rustTemplate( - """ - load::<#{newtype}>().map(#{f}) - """, - "newtype" to newtype, - "f" to writable { - if (innerTypeName == "bool") { - rust("|ty| ty.0") - } else { - rust("|ty| ty.0.clone()") - } - }, - ) -} +fun loadFromConfigBag( + innerTypeName: String, + newtype: RuntimeType, +): Writable = + writable { + rustTemplate( + """ + load::<#{newtype}>().map(#{f}) + """, + "newtype" to newtype, + "f" to + writable { + if (innerTypeName == "bool") { + rust("|ty| ty.0") + } else { + rust("|ty| ty.0.clone()") + } + }, + ) + } /** * Config customization for a config param with no special behavior: @@ -189,33 +203,37 @@ fun loadFromConfigBag(innerTypeName: String, newtype: RuntimeType): Writable = w * 2. convenience setter (non-optional) * 3. standard setter (&mut self) */ -fun standardConfigParam(param: ConfigParam, codegenContext: ClientCodegenContext): ConfigCustomization = +fun standardConfigParam( + param: ConfigParam, + codegenContext: ClientCodegenContext, +): ConfigCustomization = object : ConfigCustomization() { override fun section(section: ServiceConfig): Writable { return when (section) { - ServiceConfig.BuilderImpl -> writable { - docsOrFallback(param.setterDocs) - rust( - """ - pub fn ${param.name}(mut self, ${param.name}: impl Into<#T>) -> Self { - self.set_${param.name}(Some(${param.name}.into())); - self + ServiceConfig.BuilderImpl -> + writable { + docsOrFallback(param.setterDocs) + rust( + """ + pub fn ${param.name}(mut self, ${param.name}: impl Into<#T>) -> Self { + self.set_${param.name}(Some(${param.name}.into())); + self }""", - param.type, - ) - - docsOrFallback(param.setterDocs) - rustTemplate( - """ - pub fn set_${param.name}(&mut self, ${param.name}: Option<#{T}>) -> &mut Self { - self.config.store_or_unset(${param.name}.map(#{newtype})); - self - } - """, - "T" to param.type, - "newtype" to param.newtype!!, - ) - } + param.type, + ) + + docsOrFallback(param.setterDocs) + rustTemplate( + """ + pub fn set_${param.name}(&mut self, ${param.name}: Option<#{T}>) -> &mut Self { + self.config.store_or_unset(${param.name}.map(#{newtype})); + self + } + """, + "T" to param.type, + "newtype" to param.newtype!!, + ) + } else -> emptySection } @@ -267,81 +285,84 @@ class ServiceConfigGenerator( private val runtimeConfig = codegenContext.runtimeConfig private val enableUserConfigurableRuntimePlugins = codegenContext.enableUserConfigurableRuntimePlugins private val smithyTypes = RuntimeType.smithyTypes(runtimeConfig) - val codegenScope = arrayOf( - *preludeScope, - "BoxError" to RuntimeType.boxError(runtimeConfig), - "CloneableLayer" to smithyTypes.resolve("config_bag::CloneableLayer"), - "ConfigBag" to RuntimeType.configBag(codegenContext.runtimeConfig), - "Cow" to RuntimeType.Cow, - "FrozenLayer" to configReexport(smithyTypes.resolve("config_bag::FrozenLayer")), - "Layer" to configReexport(smithyTypes.resolve("config_bag::Layer")), - "Resolver" to RuntimeType.smithyRuntime(runtimeConfig).resolve("client::config_override::Resolver"), - "RuntimeComponentsBuilder" to configReexport(RuntimeType.runtimeComponentsBuilder(runtimeConfig)), - "RuntimePlugin" to configReexport(RuntimeType.runtimePlugin(runtimeConfig)), - "SharedRuntimePlugin" to configReexport(RuntimeType.sharedRuntimePlugin(runtimeConfig)), - "runtime_plugin" to RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::runtime_plugin"), - "BehaviorVersion" to configReexport( - RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::behavior_version::BehaviorVersion"), - ), - ) + val codegenScope = + arrayOf( + *preludeScope, + "BoxError" to RuntimeType.boxError(runtimeConfig), + "CloneableLayer" to smithyTypes.resolve("config_bag::CloneableLayer"), + "ConfigBag" to RuntimeType.configBag(codegenContext.runtimeConfig), + "Cow" to RuntimeType.Cow, + "FrozenLayer" to configReexport(smithyTypes.resolve("config_bag::FrozenLayer")), + "Layer" to configReexport(smithyTypes.resolve("config_bag::Layer")), + "Resolver" to RuntimeType.smithyRuntime(runtimeConfig).resolve("client::config_override::Resolver"), + "RuntimeComponentsBuilder" to configReexport(RuntimeType.runtimeComponentsBuilder(runtimeConfig)), + "RuntimePlugin" to configReexport(RuntimeType.runtimePlugin(runtimeConfig)), + "SharedRuntimePlugin" to configReexport(RuntimeType.sharedRuntimePlugin(runtimeConfig)), + "runtime_plugin" to RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::runtime_plugin"), + "BehaviorVersion" to + configReexport( + RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::behavior_version::BehaviorVersion"), + ), + ) - private fun behaviorMv() = writable { - val docs = """ - /// Sets the [`behavior major version`](crate::config::BehaviorVersion). - /// - /// Over time, new best-practice behaviors are introduced. However, these behaviors might not be backwards - /// compatible. For example, a change which introduces new default timeouts or a new retry-mode for - /// all operations might be the ideal behavior but could break existing applications. - /// - /// ## Examples - /// - /// Set the behavior major version to `latest`. This is equivalent to enabling the `behavior-version-latest` cargo feature. - /// ```no_run - /// use $moduleUseName::config::BehaviorVersion; - /// - /// let config = $moduleUseName::Config::builder() - /// .behavior_version(BehaviorVersion::latest()) - /// // ... - /// .build(); - /// let client = $moduleUseName::Client::from_conf(config); - /// ``` - /// - /// Customizing behavior major version: - /// ```no_run - /// use $moduleUseName::config::BehaviorVersion; - /// - /// let config = $moduleUseName::Config::builder() - /// .behavior_version(BehaviorVersion::v2023_11_09()) - /// // ... - /// .build(); - /// let client = $moduleUseName::Client::from_conf(config); - /// ``` - """ - rustTemplate( + private fun behaviorMv() = + writable { + val docs = """ + /// Sets the [`behavior major version`](crate::config::BehaviorVersion). + /// + /// Over time, new best-practice behaviors are introduced. However, these behaviors might not be backwards + /// compatible. For example, a change which introduces new default timeouts or a new retry-mode for + /// all operations might be the ideal behavior but could break existing applications. + /// + /// ## Examples + /// + /// Set the behavior major version to `latest`. This is equivalent to enabling the `behavior-version-latest` cargo feature. + /// ```no_run + /// use $moduleUseName::config::BehaviorVersion; + /// + /// let config = $moduleUseName::Config::builder() + /// .behavior_version(BehaviorVersion::latest()) + /// // ... + /// .build(); + /// let client = $moduleUseName::Client::from_conf(config); + /// ``` + /// + /// Customizing behavior major version: + /// ```no_run + /// use $moduleUseName::config::BehaviorVersion; + /// + /// let config = $moduleUseName::Config::builder() + /// .behavior_version(BehaviorVersion::v2023_11_09()) + /// // ... + /// .build(); + /// let client = $moduleUseName::Client::from_conf(config); + /// ``` """ - $docs - pub fn behavior_version(mut self, behavior_version: crate::config::BehaviorVersion) -> Self { - self.set_behavior_version(Some(behavior_version)); - self - } + rustTemplate( + """ + $docs + pub fn behavior_version(mut self, behavior_version: crate::config::BehaviorVersion) -> Self { + self.set_behavior_version(Some(behavior_version)); + self + } - $docs - pub fn set_behavior_version(&mut self, behavior_version: Option) -> &mut Self { - self.behavior_version = behavior_version; - self - } + $docs + pub fn set_behavior_version(&mut self, behavior_version: Option) -> &mut Self { + self.behavior_version = behavior_version; + self + } - /// Convenience method to set the latest behavior major version - /// - /// This is equivalent to enabling the `behavior-version-latest` Cargo feature - pub fn behavior_version_latest(mut self) -> Self { - self.set_behavior_version(Some(crate::config::BehaviorVersion::latest())); - self - } - """, - *codegenScope, - ) - } + /// Convenience method to set the latest behavior major version + /// + /// This is equivalent to enabling the `behavior-version-latest` Cargo feature + pub fn behavior_version_latest(mut self) -> Self { + self.set_behavior_version(Some(crate::config::BehaviorVersion::latest())); + self + } + """, + *codegenScope, + ) + } fun render(writer: RustWriter) { writer.docs("Configuration for a $moduleUseName service client.\n") @@ -435,11 +456,12 @@ class ServiceConfigGenerator( } behaviorMv()(this) - val visibility = if (enableUserConfigurableRuntimePlugins) { - "pub" - } else { - "pub(crate)" - } + val visibility = + if (enableUserConfigurableRuntimePlugins) { + "pub" + } else { + "pub(crate)" + } docs("Adds a runtime plugin to the config.") if (!enableUserConfigurableRuntimePlugins) { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/StalledStreamProtectionConfigCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/StalledStreamProtectionConfigCustomization.kt index 03164cbfab1..0c67acbf43c 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/StalledStreamProtectionConfigCustomization.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/StalledStreamProtectionConfigCustomization.kt @@ -43,55 +43,58 @@ class StalledStreamProtectionDecorator : ClientCodegenDecorator { */ class StalledStreamProtectionConfigCustomization(codegenContext: ClientCodegenContext) : NamedCustomization() { private val rc = codegenContext.runtimeConfig - private val codegenScope = arrayOf( - *preludeScope, - "StalledStreamProtectionConfig" to configReexport(RuntimeType.smithyRuntimeApi(rc).resolve("client::stalled_stream_protection::StalledStreamProtectionConfig")), - ) + private val codegenScope = + arrayOf( + *preludeScope, + "StalledStreamProtectionConfig" to configReexport(RuntimeType.smithyRuntimeApi(rc).resolve("client::stalled_stream_protection::StalledStreamProtectionConfig")), + ) override fun section(section: ServiceConfig): Writable { return when (section) { - ServiceConfig.ConfigImpl -> writable { - rustTemplate( - """ - /// Return a reference to the stalled stream protection configuration contained in this config, if any. - pub fn stalled_stream_protection(&self) -> #{Option}<&#{StalledStreamProtectionConfig}> { - self.config.load::<#{StalledStreamProtectionConfig}>() - } - """, - *codegenScope, - ) - } - ServiceConfig.BuilderImpl -> writable { - rustTemplate( - """ - /// Set the [`StalledStreamProtectionConfig`](#{StalledStreamProtectionConfig}) - /// to configure protection for stalled streams. - pub fn stalled_stream_protection( - mut self, - stalled_stream_protection_config: #{StalledStreamProtectionConfig} - ) -> Self { - self.set_stalled_stream_protection(#{Some}(stalled_stream_protection_config)); - self - } - """, - *codegenScope, - ) + ServiceConfig.ConfigImpl -> + writable { + rustTemplate( + """ + /// Return a reference to the stalled stream protection configuration contained in this config, if any. + pub fn stalled_stream_protection(&self) -> #{Option}<&#{StalledStreamProtectionConfig}> { + self.config.load::<#{StalledStreamProtectionConfig}>() + } + """, + *codegenScope, + ) + } + ServiceConfig.BuilderImpl -> + writable { + rustTemplate( + """ + /// Set the [`StalledStreamProtectionConfig`](#{StalledStreamProtectionConfig}) + /// to configure protection for stalled streams. + pub fn stalled_stream_protection( + mut self, + stalled_stream_protection_config: #{StalledStreamProtectionConfig} + ) -> Self { + self.set_stalled_stream_protection(#{Some}(stalled_stream_protection_config)); + self + } + """, + *codegenScope, + ) - rustTemplate( - """ - /// Set the [`StalledStreamProtectionConfig`](#{StalledStreamProtectionConfig}) - /// to configure protection for stalled streams. - pub fn set_stalled_stream_protection( - &mut self, - stalled_stream_protection_config: #{Option}<#{StalledStreamProtectionConfig}> - ) -> &mut Self { - self.config.store_or_unset(stalled_stream_protection_config); - self - } - """, - *codegenScope, - ) - } + rustTemplate( + """ + /// Set the [`StalledStreamProtectionConfig`](#{StalledStreamProtectionConfig}) + /// to configure protection for stalled streams. + pub fn set_stalled_stream_protection( + &mut self, + stalled_stream_protection_config: #{Option}<#{StalledStreamProtectionConfig}> + ) -> &mut Self { + self.config.store_or_unset(stalled_stream_protection_config); + self + } + """, + *codegenScope, + ) + } else -> emptySection } @@ -103,24 +106,25 @@ class StalledStreamProtectionOperationCustomization( ) : OperationCustomization() { private val rc = codegenContext.runtimeConfig - override fun section(section: OperationSection): Writable = writable { - when (section) { - is OperationSection.AdditionalInterceptors -> { - val stalledStreamProtectionModule = RuntimeType.smithyRuntime(rc).resolve("client::stalled_stream_protection") - section.registerInterceptor(rc, this) { - // Currently, only response bodies are protected/supported because - // we can't count on hyper to poll a request body on wake. - rustTemplate( - """ - #{StalledStreamProtectionInterceptor}::new(#{Kind}::ResponseBody) - """, - *preludeScope, - "StalledStreamProtectionInterceptor" to stalledStreamProtectionModule.resolve("StalledStreamProtectionInterceptor"), - "Kind" to stalledStreamProtectionModule.resolve("StalledStreamProtectionInterceptorKind"), - ) + override fun section(section: OperationSection): Writable = + writable { + when (section) { + is OperationSection.AdditionalInterceptors -> { + val stalledStreamProtectionModule = RuntimeType.smithyRuntime(rc).resolve("client::stalled_stream_protection") + section.registerInterceptor(rc, this) { + // Currently, only response bodies are protected/supported because + // we can't count on hyper to poll a request body on wake. + rustTemplate( + """ + #{StalledStreamProtectionInterceptor}::new(#{Kind}::ResponseBody) + """, + *preludeScope, + "StalledStreamProtectionInterceptor" to stalledStreamProtectionModule.resolve("StalledStreamProtectionInterceptor"), + "Kind" to stalledStreamProtectionModule.resolve("StalledStreamProtectionInterceptorKind"), + ) + } } + else -> { } } - else -> { } } - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/ErrorGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/ErrorGenerator.kt index d90fd441529..92d716d329f 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/ErrorGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/ErrorGenerator.kt @@ -46,19 +46,20 @@ class ErrorGenerator( model, symbolProvider, this, shape, listOf( object : StructureCustomization() { - override fun section(section: StructureSection): Writable = writable { - when (section) { - is StructureSection.AdditionalFields -> { - rust("pub(crate) meta: #T,", errorMetadata(runtimeConfig)) - } + override fun section(section: StructureSection): Writable = + writable { + when (section) { + is StructureSection.AdditionalFields -> { + rust("pub(crate) meta: #T,", errorMetadata(runtimeConfig)) + } - is StructureSection.AdditionalDebugFields -> { - rust("""${section.formatterName}.field("meta", &self.meta);""") - } + is StructureSection.AdditionalDebugFields -> { + rust("""${section.formatterName}.field("meta", &self.meta);""") + } - else -> {} + else -> {} + } } - } }, ), structSettings, @@ -89,38 +90,39 @@ class ErrorGenerator( model, symbolProvider, shape, listOf( object : BuilderCustomization() { - override fun section(section: BuilderSection): Writable = writable { - when (section) { - is BuilderSection.AdditionalFields -> { - rust("meta: std::option::Option<#T>,", errorMetadata(runtimeConfig)) - } + override fun section(section: BuilderSection): Writable = + writable { + when (section) { + is BuilderSection.AdditionalFields -> { + rust("meta: std::option::Option<#T>,", errorMetadata(runtimeConfig)) + } - is BuilderSection.AdditionalMethods -> { - rustTemplate( - """ - /// Sets error metadata - pub fn meta(mut self, meta: #{error_metadata}) -> Self { - self.meta = Some(meta); - self - } + is BuilderSection.AdditionalMethods -> { + rustTemplate( + """ + /// Sets error metadata + pub fn meta(mut self, meta: #{error_metadata}) -> Self { + self.meta = Some(meta); + self + } - /// Sets error metadata - pub fn set_meta(&mut self, meta: std::option::Option<#{error_metadata}>) -> &mut Self { - self.meta = meta; - self - } - """, - "error_metadata" to errorMetadata(runtimeConfig), - ) - } + /// Sets error metadata + pub fn set_meta(&mut self, meta: std::option::Option<#{error_metadata}>) -> &mut Self { + self.meta = meta; + self + } + """, + "error_metadata" to errorMetadata(runtimeConfig), + ) + } - is BuilderSection.AdditionalFieldsInBuild -> { - rust("meta: self.meta.unwrap_or_default(),") - } + is BuilderSection.AdditionalFieldsInBuild -> { + rust("meta: self.meta.unwrap_or_default(),") + } - else -> {} + else -> {} + } } - } }, ), ).render(this) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/OperationErrorGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/OperationErrorGenerator.kt index 280b06c2cac..03b97fffaaa 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/OperationErrorGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/OperationErrorGenerator.kt @@ -56,22 +56,25 @@ class OperationErrorGenerator( private fun operationErrors(): List = (operationOrEventStream as OperationShape).operationErrors(model).map { it.asStructureShape().get() } + private fun eventStreamErrors(): List = (operationOrEventStream as UnionShape).eventStreamErrors() .map { model.expectShape(it.asMemberShape().get().target, StructureShape::class.java) } fun render(writer: RustWriter) { - val (errorSymbol, errors) = when (operationOrEventStream) { - is OperationShape -> symbolProvider.symbolForOperationError(operationOrEventStream) to operationErrors() - is UnionShape -> symbolProvider.symbolForEventStreamError(operationOrEventStream) to eventStreamErrors() - else -> UNREACHABLE("OperationErrorGenerator only supports operation or event stream shapes") - } + val (errorSymbol, errors) = + when (operationOrEventStream) { + is OperationShape -> symbolProvider.symbolForOperationError(operationOrEventStream) to operationErrors() + is UnionShape -> symbolProvider.symbolForEventStreamError(operationOrEventStream) to eventStreamErrors() + else -> UNREACHABLE("OperationErrorGenerator only supports operation or event stream shapes") + } - val meta = RustMetadata( - derives = setOf(RuntimeType.Debug), - additionalAttributes = listOf(Attribute.NonExhaustive), - visibility = Visibility.PUBLIC, - ) + val meta = + RustMetadata( + derives = setOf(RuntimeType.Debug), + additionalAttributes = listOf(Attribute.NonExhaustive), + visibility = Visibility.PUBLIC, + ) writer.rust("/// Error type for the `${errorSymbol.name}` operation.") meta.render(writer) @@ -123,24 +126,28 @@ class OperationErrorGenerator( } } - private fun RustWriter.renderImplDisplay(errorSymbol: Symbol, errors: List) { + private fun RustWriter.renderImplDisplay( + errorSymbol: Symbol, + errors: List, + ) { rustBlock("impl #T for ${errorSymbol.name}", RuntimeType.Display) { rustBlock("fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result") { delegateToVariants(errors) { variantMatch -> when (variantMatch) { - is VariantMatch.Unhandled -> writable { - rustTemplate( - """ - if let #{Some}(code) = #{ProvideErrorMetadata}::code(self) { - write!(f, "unhandled error ({code})") - } else { - f.write_str("unhandled error") - } - """, - *preludeScope, - "ProvideErrorMetadata" to RuntimeType.provideErrorMetadataTrait(runtimeConfig), - ) - } + is VariantMatch.Unhandled -> + writable { + rustTemplate( + """ + if let #{Some}(code) = #{ProvideErrorMetadata}::code(self) { + write!(f, "unhandled error ({code})") + } else { + f.write_str("unhandled error") + } + """, + *preludeScope, + "ProvideErrorMetadata" to RuntimeType.provideErrorMetadataTrait(runtimeConfig), + ) + } is VariantMatch.Modeled -> writable { rust("_inner.fmt(f)") } } } @@ -148,7 +155,10 @@ class OperationErrorGenerator( } } - private fun RustWriter.renderImplProvideErrorMetadata(errorSymbol: Symbol, errors: List) { + private fun RustWriter.renderImplProvideErrorMetadata( + errorSymbol: Symbol, + errors: List, + ) { val errorMetadataTrait = RuntimeType.provideErrorMetadataTrait(runtimeConfig) rustBlock("impl #T for ${errorSymbol.name}", errorMetadataTrait) { rustBlock("fn meta(&self) -> &#T", errorMetadata(runtimeConfig)) { @@ -164,7 +174,10 @@ class OperationErrorGenerator( } } - private fun RustWriter.renderImplProvideErrorKind(errorSymbol: Symbol, errors: List) { + private fun RustWriter.renderImplProvideErrorKind( + errorSymbol: Symbol, + errors: List, + ) { val retryErrorKindT = RuntimeType.retryErrorKind(symbolProvider.config.runtimeConfig) rustBlock( "impl #T for ${errorSymbol.name}", @@ -198,7 +211,10 @@ class OperationErrorGenerator( } } - private fun RustWriter.renderImpl(errorSymbol: Symbol, errors: List) { + private fun RustWriter.renderImpl( + errorSymbol: Symbol, + errors: List, + ) { rustBlock("impl ${errorSymbol.name}") { rustTemplate( """ @@ -246,7 +262,10 @@ class OperationErrorGenerator( } } - private fun RustWriter.renderImplStdError(errorSymbol: Symbol, errors: List) { + private fun RustWriter.renderImplStdError( + errorSymbol: Symbol, + errors: List, + ) { rustBlock("impl #T for ${errorSymbol.name}", RuntimeType.StdError) { rustBlockTemplate( "fn source(&self) -> #{Option}<&(dyn #{StdError} + 'static)>", @@ -255,12 +274,14 @@ class OperationErrorGenerator( ) { delegateToVariants(errors) { variantMatch -> when (variantMatch) { - is VariantMatch.Unhandled -> writable { - rustTemplate("#{Some}(&*_inner.source)", *preludeScope) - } - is VariantMatch.Modeled -> writable { - rustTemplate("#{Some}(_inner)", *preludeScope) - } + is VariantMatch.Unhandled -> + writable { + rustTemplate("#{Some}(&*_inner.source)", *preludeScope) + } + is VariantMatch.Modeled -> + writable { + rustTemplate("#{Some}(_inner)", *preludeScope) + } } } } @@ -269,6 +290,7 @@ class OperationErrorGenerator( sealed class VariantMatch(name: String) : Section(name) { object Unhandled : VariantMatch("Unhandled") + data class Modeled(val symbol: Symbol, val shape: Shape) : VariantMatch("Modeled") } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/ServiceErrorGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/ServiceErrorGenerator.kt index 5a33941845b..0f8789d4e6f 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/ServiceErrorGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/ServiceErrorGenerator.kt @@ -57,11 +57,12 @@ class ServiceErrorGenerator( private val symbolProvider = codegenContext.symbolProvider private val model = codegenContext.model - private val allErrors = operations.flatMap { - it.allErrors(model) - }.map { it.id }.distinctBy { it.getName(codegenContext.serviceShape) } - .map { codegenContext.model.expectShape(it, StructureShape::class.java) } - .sortedBy { it.id.getName(codegenContext.serviceShape) } + private val allErrors = + operations.flatMap { + it.allErrors(model) + }.map { it.id }.distinctBy { it.getName(codegenContext.serviceShape) } + .map { codegenContext.model.expectShape(it, StructureShape::class.java) } + .sortedBy { it.id.getName(codegenContext.serviceShape) } private val sdkError = RuntimeType.sdkError(codegenContext.runtimeConfig) @@ -140,7 +141,10 @@ class ServiceErrorGenerator( ) } - private fun RustWriter.renderImplFrom(errorSymbol: Symbol, errors: List) { + private fun RustWriter.renderImplFrom( + errorSymbol: Symbol, + errors: List, + ) { if (errors.isNotEmpty() || CodegenTarget.CLIENT == codegenContext.target) { val operationErrors = errors.map { model.expectShape(it) } rustBlock( @@ -205,16 +209,19 @@ class ServiceErrorGenerator( } """, *preludeScope, - "ErrorMetadata" to RuntimeType.smithyTypes(codegenContext.runtimeConfig) - .resolve("error::metadata::ErrorMetadata"), - "ProvideErrorMetadata" to RuntimeType.smithyTypes(codegenContext.runtimeConfig) - .resolve("error::metadata::ProvideErrorMetadata"), - "matchers" to writable { - allErrors.forEach { errorShape -> - val errSymbol = symbolProvider.toSymbol(errorShape) - rust("Self::${errSymbol.name}(inner) => inner.meta(),") - } - }, + "ErrorMetadata" to + RuntimeType.smithyTypes(codegenContext.runtimeConfig) + .resolve("error::metadata::ErrorMetadata"), + "ProvideErrorMetadata" to + RuntimeType.smithyTypes(codegenContext.runtimeConfig) + .resolve("error::metadata::ProvideErrorMetadata"), + "matchers" to + writable { + allErrors.forEach { errorShape -> + val errSymbol = symbolProvider.toSymbol(errorShape) + rust("Self::${errSymbol.name}(inner) => inner.meta(),") + } + }, ) } @@ -238,47 +245,53 @@ class ServiceErrorGenerator( } } -fun unhandledError(rc: RuntimeConfig): RuntimeType = RuntimeType.forInlineFun( - "Unhandled", - // Place in a sealed module so that it can't be referenced at all - RustModule.pubCrate("sealed_unhandled", ClientRustModule.Error), +fun unhandledError(rc: RuntimeConfig): RuntimeType = + RuntimeType.forInlineFun( + "Unhandled", + // Place in a sealed module so that it can't be referenced at all + RustModule.pubCrate("sealed_unhandled", ClientRustModule.Error), + ) { + rustTemplate( + """ + /// This struct is not intended to be used. + /// + /// This struct holds information about an unhandled error, + /// but that information should be obtained by using the + /// [`ProvideErrorMetadata`](#{ProvideErrorMetadata}) trait + /// on the error type. + /// + /// This struct intentionally doesn't yield any useful information itself. + #{deprecation} + ##[derive(Debug)] + pub struct Unhandled { + pub(crate) source: #{BoxError}, + pub(crate) meta: #{ErrorMetadata}, + } + """, + "BoxError" to RuntimeType.smithyRuntimeApi(rc).resolve("box_error::BoxError"), + "deprecation" to writable { renderUnhandledErrorDeprecation(rc) }, + "ErrorMetadata" to RuntimeType.smithyTypes(rc).resolve("error::metadata::ErrorMetadata"), + "ProvideErrorMetadata" to RuntimeType.smithyTypes(rc).resolve("error::metadata::ProvideErrorMetadata"), + ) + } + +fun RustWriter.renderUnhandledErrorDeprecation( + rc: RuntimeConfig, + errorName: String? = null, ) { - rustTemplate( - """ - /// This struct is not intended to be used. - /// - /// This struct holds information about an unhandled error, - /// but that information should be obtained by using the - /// [`ProvideErrorMetadata`](#{ProvideErrorMetadata}) trait - /// on the error type. - /// - /// This struct intentionally doesn't yield any useful information itself. - #{deprecation} - ##[derive(Debug)] - pub struct Unhandled { - pub(crate) source: #{BoxError}, - pub(crate) meta: #{ErrorMetadata}, + val link = + if (errorName != null) { + "##impl-ProvideErrorMetadata-for-$errorName" + } else { + "#{ProvideErrorMetadata}" } - """, - "BoxError" to RuntimeType.smithyRuntimeApi(rc).resolve("box_error::BoxError"), - "deprecation" to writable { renderUnhandledErrorDeprecation(rc) }, - "ErrorMetadata" to RuntimeType.smithyTypes(rc).resolve("error::metadata::ErrorMetadata"), - "ProvideErrorMetadata" to RuntimeType.smithyTypes(rc).resolve("error::metadata::ProvideErrorMetadata"), - ) -} - -fun RustWriter.renderUnhandledErrorDeprecation(rc: RuntimeConfig, errorName: String? = null) { - val link = if (errorName != null) { - "##impl-ProvideErrorMetadata-for-$errorName" - } else { - "#{ProvideErrorMetadata}" - } - val message = """ + val message = + """ Matching `Unhandled` directly is not forwards compatible. Instead, match using a variable wildcard pattern and check `.code()`:
   `err if err.code() == Some("SpecificExceptionCode") => { /* handle the error */ }`
See [`ProvideErrorMetadata`]($link) for what information is available for the error. - """.trimIndent() + """.trimIndent() // `.dq()` doesn't quite do what we want here since we actually want a Rust multi-line string val messageEscaped = message.replace("\"", "\\\"").replace("\n", " \\\n").replace("
", "\n") rustTemplate( diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGenerator.kt index 0a4e5fb09b8..62b1d66d03a 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGenerator.kt @@ -29,6 +29,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.http.HttpBindi import software.amazon.smithy.rust.codegen.core.smithy.generators.operationBuildError import software.amazon.smithy.rust.codegen.core.smithy.isOptional import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol +import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.SerializerUtil import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.ValueExpression import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.expectMember @@ -39,13 +40,17 @@ fun HttpTrait.uriFormatString(): String { return uri.rustFormatString("/", "/") } -fun SmithyPattern.rustFormatString(prefix: String, separator: String): String { - val base = segments.joinToString(separator = separator, prefix = prefix) { - when { - it.isLabel -> "{${it.content}}" - else -> it.content +fun SmithyPattern.rustFormatString( + prefix: String, + separator: String, +): String { + val base = + segments.joinToString(separator = separator, prefix = prefix) { + when { + it.isLabel -> "{${it.content}}" + else -> it.content + } } - } return base.dq() } @@ -70,13 +75,15 @@ class RequestBindingGenerator( HttpBindingGenerator(protocol, codegenContext, codegenContext.symbolProvider, operationShape) private val index = HttpBindingIndex.of(model) private val encoder = RuntimeType.smithyTypes(runtimeConfig).resolve("primitive::Encoder") + private val util = SerializerUtil(model, symbolProvider) - private val codegenScope = arrayOf( - *preludeScope, - "BuildError" to runtimeConfig.operationBuildError(), - "HttpRequestBuilder" to RuntimeType.HttpRequestBuilder, - "Input" to symbolProvider.toSymbol(inputShape), - ) + private val codegenScope = + arrayOf( + *preludeScope, + "BuildError" to runtimeConfig.operationBuildError(), + "HttpRequestBuilder" to RuntimeType.HttpRequestBuilder, + "Input" to symbolProvider.toSymbol(inputShape), + ) /** * Generates `update_http_builder` and all necessary dependency functions into the impl block provided by @@ -113,7 +120,7 @@ class RequestBindingGenerator( } } - /** URI Generation **/ + // URI Generation ** /** * Generate a function to build the request URI @@ -122,10 +129,11 @@ class RequestBindingGenerator( val formatString = httpTrait.uriFormatString() // name of a local variable containing this member's component of the URI val local = { member: MemberShape -> symbolProvider.toMemberName(member) } - val args = httpTrait.uri.labels.map { label -> - val member = inputShape.expectMember(label.content) - "${label.content} = ${local(member)}" - } + val args = + httpTrait.uri.labels.map { label -> + val member = inputShape.expectMember(label.content) + "${label.content} = ${local(member)}" + } val combinedArgs = listOf(formatString, *args.toTypedArray()) writer.rustBlockTemplate( "fn uri_base(_input: &#{Input}, output: &mut #{String}) -> #{Result}<(), #{BuildError}>", @@ -213,13 +221,15 @@ class RequestBindingGenerator( val target = model.expectShape(memberShape.target) if (memberShape.isRequired) { - val codegenScope = arrayOf( - *preludeScope, - "BuildError" to OperationBuildError(runtimeConfig).missingField( - memberName, - "cannot be empty or unset", - ), - ) + val codegenScope = + arrayOf( + *preludeScope, + "BuildError" to + OperationBuildError(runtimeConfig).missingField( + memberName, + "cannot be empty or unset", + ), + ) val derefName = safeName("inner") rust("let $derefName = &_input.$memberName;") if (memberSymbol.isOptional()) { @@ -238,9 +248,15 @@ class RequestBindingGenerator( paramList(target, derefName, param, writer, memberShape) } else { - ifSet(target, memberSymbol, ValueExpression.Reference("&_input.$memberName")) { field -> - // if `param` is a list, generate another level of iteration - paramList(target, field.name, param, writer, memberShape) + // If we have an Option, there won't be a default so nothing to ignore. If it's a primitive + // boolean or number, we ignore the default. + ifSome(memberSymbol, ValueExpression.Reference("&_input.$memberName")) { field -> + with(util) { + ignoreDefaultsForNumbersAndBools(memberShape, field) { + // if `param` is a list, generate another level of iteration + paramList(target, field.name, param, writer, memberShape) + } + } } } } @@ -266,7 +282,12 @@ class RequestBindingGenerator( /** * Format [member] when used as a queryParam */ - private fun paramFmtFun(writer: RustWriter, target: Shape, member: MemberShape, targetName: String): String { + private fun paramFmtFun( + writer: RustWriter, + target: Shape, + member: MemberShape, + targetName: String, + ): String { return when { target.isStringShape -> { val func = writer.format(RuntimeType.queryFormat(runtimeConfig, "fmt_string")) @@ -291,13 +312,18 @@ class RequestBindingGenerator( } } - private fun RustWriter.serializeLabel(member: MemberShape, label: SmithyPattern.Segment, outputVar: String) { + private fun RustWriter.serializeLabel( + member: MemberShape, + label: SmithyPattern.Segment, + outputVar: String, + ) { val target = model.expectShape(member.target) val symbol = symbolProvider.toSymbol(member) - val buildError = OperationBuildError(runtimeConfig).missingField( - symbolProvider.toMemberName(member), - "cannot be empty or unset", - ) + val buildError = + OperationBuildError(runtimeConfig).missingField( + symbolProvider.toMemberName(member), + "cannot be empty or unset", + ) val input = safeName("input") rust("let $input = &_input.${symbolProvider.toMemberName(member)};") if (symbol.isOptional()) { @@ -306,11 +332,12 @@ class RequestBindingGenerator( when { target.isStringShape -> { val func = format(RuntimeType.labelFormat(runtimeConfig, "fmt_string")) - val encodingStrategy = if (label.isGreedyLabel) { - RuntimeType.labelFormat(runtimeConfig, "EncodingStrategy::Greedy") - } else { - RuntimeType.labelFormat(runtimeConfig, "EncodingStrategy::Default") - } + val encodingStrategy = + if (label.isGreedyLabel) { + RuntimeType.labelFormat(runtimeConfig, "EncodingStrategy::Greedy") + } else { + RuntimeType.labelFormat(runtimeConfig, "EncodingStrategy::Default") + } rust("let $outputVar = $func($input, #T);", encodingStrategy) } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolParserGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolParserGenerator.kt index 8ce713b457d..2181607b86b 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolParserGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolParserGenerator.kt @@ -50,14 +50,14 @@ class ProtocolParserGenerator( private val protocolFunctions = ProtocolFunctions(codegenContext) private val symbolProvider: RustSymbolProvider = codegenContext.symbolProvider - private val codegenScope = arrayOf( - "Bytes" to RuntimeType.Bytes, - "Headers" to RuntimeType.headers(codegenContext.runtimeConfig), - "Response" to RuntimeType.smithyRuntimeApi(codegenContext.runtimeConfig).resolve("http::Response"), - "http" to RuntimeType.Http, - "operation" to RuntimeType.operationModule(codegenContext.runtimeConfig), - "SdkBody" to RuntimeType.sdkBody(codegenContext.runtimeConfig), - ) + private val codegenScope = + arrayOf( + "Bytes" to RuntimeType.Bytes, + "Headers" to RuntimeType.headers(codegenContext.runtimeConfig), + "Response" to RuntimeType.smithyRuntimeApi(codegenContext.runtimeConfig).resolve("http::Response"), + "http" to RuntimeType.Http, + "SdkBody" to RuntimeType.sdkBody(codegenContext.runtimeConfig), + ) fun parseResponseFn( operationShape: OperationShape, @@ -151,11 +151,12 @@ class ProtocolParserGenerator( errorSymbol, listOf( object : OperationCustomization() { - override fun section(section: OperationSection): Writable = { - if (section is OperationSection.MutateOutput) { - rust("let output = output.meta(generic);") + override fun section(section: OperationSection): Writable = + { + if (section is OperationSection.MutateOutput) { + rust("let output = output.meta(generic);") + } } - } }, ), ) @@ -264,9 +265,10 @@ class ProtocolParserGenerator( } } - val mapErr = writable { - rust("#T::unhandled", errorSymbol) - } + val mapErr = + writable { + rust("#T::unhandled", errorSymbol) + } writeCustomizations( customizations, @@ -289,16 +291,17 @@ class ProtocolParserGenerator( val errorSymbol = symbolProvider.symbolForOperationError(operationShape) val member = binding.member return when (binding.location) { - HttpLocation.HEADER -> writable { - val fnName = httpBindingGenerator.generateDeserializeHeaderFn(binding) - rust( - """ - #T(_response_headers) - .map_err(|_|#T::unhandled("Failed to parse ${member.memberName} from header `${binding.locationName}"))? - """, - fnName, errorSymbol, - ) - } + HttpLocation.HEADER -> + writable { + val fnName = httpBindingGenerator.generateDeserializeHeaderFn(binding) + rust( + """ + #T(_response_headers) + .map_err(|_|#T::unhandled("Failed to parse ${member.memberName} from header `${binding.locationName}"))? + """, + fnName, errorSymbol, + ) + } HttpLocation.DOCUMENT -> { // document is handled separately null @@ -307,20 +310,22 @@ class ProtocolParserGenerator( val payloadParser: RustWriter.(String) -> Unit = { body -> rust("#T($body).map_err(#T::unhandled)", structuredDataParser.payloadParser(member), errorSymbol) } - val deserializer = httpBindingGenerator.generateDeserializePayloadFn( - binding, - errorSymbol, - payloadParser = payloadParser, - ) + val deserializer = + httpBindingGenerator.generateDeserializePayloadFn( + binding, + errorSymbol, + payloadParser = payloadParser, + ) return if (binding.member.isStreaming(model)) { writable { rust("Some(#T(_response_body)?)", deserializer) } } else { writable { rust("#T(_response_body)?", deserializer) } } } - HttpLocation.RESPONSE_CODE -> writable { - rust("Some(_response_status as _)") - } + HttpLocation.RESPONSE_CODE -> + writable { + rust("Some(_response_status as _)") + } HttpLocation.PREFIX_HEADERS -> { val sym = httpBindingGenerator.generateDeserializePrefixHeaderFn(binding) writable { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt index 133b0dddf72..ad1ce676208 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGenerator.kt @@ -67,7 +67,6 @@ class DefaultProtocolTestGenerator( override val codegenContext: ClientCodegenContext, override val protocolSupport: ProtocolSupport, override val operationShape: OperationShape, - private val renderClientCreation: RustWriter.(ClientCreationParams) -> Unit = { params -> rustTemplate( """ @@ -91,37 +90,44 @@ class DefaultProtocolTestGenerator( private val instantiator = ClientInstantiator(codegenContext) - private val codegenScope = arrayOf( - "SmithyHttp" to RT.smithyHttp(rc), - "AssertEq" to RT.PrettyAssertions.resolve("assert_eq!"), - "Uri" to RT.Http.resolve("Uri"), - ) + private val codegenScope = + arrayOf( + "SmithyHttp" to RT.smithyHttp(rc), + "AssertEq" to RT.PrettyAssertions.resolve("assert_eq!"), + "Uri" to RT.Http.resolve("Uri"), + ) sealed class TestCase { abstract val testCase: HttpMessageTestCase data class RequestTest(override val testCase: HttpRequestTestCase) : TestCase() + data class ResponseTest(override val testCase: HttpResponseTestCase, val targetShape: StructureShape) : TestCase() } override fun render(writer: RustWriter) { - val requestTests = operationShape.getTrait() - ?.getTestCasesFor(AppliesTo.CLIENT).orEmpty().map { TestCase.RequestTest(it) } - val responseTests = operationShape.getTrait() - ?.getTestCasesFor(AppliesTo.CLIENT).orEmpty().map { TestCase.ResponseTest(it, outputShape) } - val errorTests = operationIndex.getErrors(operationShape).flatMap { error -> - val testCases = error.getTrait() - ?.getTestCasesFor(AppliesTo.CLIENT).orEmpty() - testCases.map { TestCase.ResponseTest(it, error) } - } + val requestTests = + operationShape.getTrait() + ?.getTestCasesFor(AppliesTo.CLIENT).orEmpty().map { TestCase.RequestTest(it) } + val responseTests = + operationShape.getTrait() + ?.getTestCasesFor(AppliesTo.CLIENT).orEmpty().map { TestCase.ResponseTest(it, outputShape) } + val errorTests = + operationIndex.getErrors(operationShape).flatMap { error -> + val testCases = + error.getTrait() + ?.getTestCasesFor(AppliesTo.CLIENT).orEmpty() + testCases.map { TestCase.ResponseTest(it, error) } + } val allTests: List = (requestTests + responseTests + errorTests).filterMatching() if (allTests.isNotEmpty()) { val operationName = operationSymbol.name val testModuleName = "${operationName.toSnakeCase()}_request_test" - val additionalAttributes = listOf( - Attribute(allow("unreachable_code", "unused_variables")), - ) + val additionalAttributes = + listOf( + Attribute(allow("unreachable_code", "unused_variables")), + ) writer.withInlineModule( RustModule.inlineTests(testModuleName, additionalAttributes = additionalAttributes), null, @@ -168,41 +174,42 @@ class DefaultProtocolTestGenerator( testModuleWriter.write("Test ID: ${testCase.id}") testModuleWriter.newlinePrefix = "" Attribute.TokioTest.render(testModuleWriter) - val action = when (testCase) { - is HttpResponseTestCase -> Action.Response - is HttpRequestTestCase -> Action.Request - else -> throw CodegenException("unknown test case type") - } + val action = + when (testCase) { + is HttpResponseTestCase -> Action.Response + is HttpRequestTestCase -> Action.Request + else -> throw CodegenException("unknown test case type") + } if (expectFail(testCase)) { testModuleWriter.writeWithNoFormatting("#[should_panic]") } - val fnName = when (action) { - is Action.Response -> "_response" - is Action.Request -> "_request" - } + val fnName = + when (action) { + is Action.Response -> "_response" + is Action.Request -> "_request" + } Attribute.AllowUnusedMut.render(testModuleWriter) testModuleWriter.rustBlock("async fn ${testCase.id.toSnakeCase()}$fnName()") { block(this) } } - private fun RustWriter.renderHttpRequestTestCase( - httpRequestTestCase: HttpRequestTestCase, - ) { + private fun RustWriter.renderHttpRequestTestCase(httpRequestTestCase: HttpRequestTestCase) { if (!protocolSupport.requestSerialization) { rust("/* test case disabled for this protocol (not yet supported) */") return } - val customParams = httpRequestTestCase.vendorParams.getObjectMember("endpointParams").orNull()?.let { params -> - writable { - val customizations = codegenContext.rootDecorator.endpointCustomizations(codegenContext) - params.getObjectMember("builtInParams").orNull()?.members?.forEach { (name, value) -> - customizations.firstNotNullOf { - it.setBuiltInOnServiceConfig(name.value, value, "config_builder") - }(this) + val customParams = + httpRequestTestCase.vendorParams.getObjectMember("endpointParams").orNull()?.let { params -> + writable { + val customizations = codegenContext.rootDecorator.endpointCustomizations(codegenContext) + params.getObjectMember("builtInParams").orNull()?.members?.forEach { (name, value) -> + customizations.firstNotNullOf { + it.setBuiltInOnServiceConfig(name.value, value, "config_builder") + }(this) + } } - } - } ?: writable { } + } ?: writable { } // support test cases that set the host value, e.g: https://github.com/smithy-lang/smithy/blob/be68f3bbdfe5bf50a104b387094d40c8069f16b1/smithy-aws-protocol-tests/model/restJson1/endpoint-paths.smithy#L19 val host = "https://${httpRequestTestCase.host.orNull() ?: "example.com"}".dq() rustTemplate( @@ -212,8 +219,9 @@ class DefaultProtocolTestGenerator( #{customParams} """, - "capture_request" to CargoDependency.smithyRuntimeTestUtil(rc).toType() - .resolve("client::http::test_util::capture_request"), + "capture_request" to + CargoDependency.smithyRuntimeTestUtil(rc).toType() + .resolve("client::http::test_util::capture_request"), "config" to ClientRustModule.config, "customParams" to customParams, ) @@ -268,25 +276,28 @@ class DefaultProtocolTestGenerator( } } - private fun HttpMessageTestCase.action(): Action = when (this) { - is HttpRequestTestCase -> Action.Request - is HttpResponseTestCase -> Action.Response - else -> throw CodegenException("Unknown test case type") - } + private fun HttpMessageTestCase.action(): Action = + when (this) { + is HttpRequestTestCase -> Action.Request + is HttpResponseTestCase -> Action.Response + else -> throw CodegenException("Unknown test case type") + } - private fun expectFail(testCase: HttpMessageTestCase): Boolean = ExpectFail.find { - it.id == testCase.id && it.action == testCase.action() && it.service == codegenContext.serviceShape.id.toString() - } != null + private fun expectFail(testCase: HttpMessageTestCase): Boolean = + ExpectFail.find { + it.id == testCase.id && it.action == testCase.action() && it.service == codegenContext.serviceShape.id.toString() + } != null private fun RustWriter.renderHttpResponseTestCase( testCase: HttpResponseTestCase, expectedShape: StructureShape, ) { if (!protocolSupport.responseDeserialization || ( - !protocolSupport.errorDeserialization && expectedShape.hasTrait( - ErrorTrait::class.java, - ) - ) + !protocolSupport.errorDeserialization && + expectedShape.hasTrait( + ErrorTrait::class.java, + ) + ) ) { rust("/* test case disabled for this protocol (not yet supported) */") return @@ -329,8 +340,9 @@ class DefaultProtocolTestGenerator( }); """, "copy_from_slice" to RT.Bytes.resolve("copy_from_slice"), - "SharedResponseDeserializer" to RT.smithyRuntimeApiClient(rc) - .resolve("client::ser_de::SharedResponseDeserializer"), + "SharedResponseDeserializer" to + RT.smithyRuntimeApiClient(rc) + .resolve("client::ser_de::SharedResponseDeserializer"), "Operation" to codegenContext.symbolProvider.toSymbol(operationShape), "DeserializeResponse" to RT.smithyRuntimeApiClient(rc).resolve("client::ser_de::DeserializeResponse"), "RuntimePlugin" to RT.runtimePlugin(rc), @@ -394,7 +406,11 @@ class DefaultProtocolTestGenerator( } } - private fun checkBody(rustWriter: RustWriter, body: String, mediaType: String?) { + private fun checkBody( + rustWriter: RustWriter, + body: String, + mediaType: String?, + ) { rustWriter.write("""let body = http_request.body().bytes().expect("body should be strict");""") if (body == "") { rustWriter.rustTemplate( @@ -418,7 +434,11 @@ class DefaultProtocolTestGenerator( } } - private fun checkRequiredHeaders(rustWriter: RustWriter, actualExpression: String, requireHeaders: List) { + private fun checkRequiredHeaders( + rustWriter: RustWriter, + actualExpression: String, + requireHeaders: List, + ) { basicCheck( requireHeaders, rustWriter, @@ -428,7 +448,11 @@ class DefaultProtocolTestGenerator( ) } - private fun checkForbidHeaders(rustWriter: RustWriter, actualExpression: String, forbidHeaders: List) { + private fun checkForbidHeaders( + rustWriter: RustWriter, + actualExpression: String, + forbidHeaders: List, + ) { basicCheck( forbidHeaders, rustWriter, @@ -438,7 +462,11 @@ class DefaultProtocolTestGenerator( ) } - private fun checkHeaders(rustWriter: RustWriter, actualExpression: String, headers: Map) { + private fun checkHeaders( + rustWriter: RustWriter, + actualExpression: String, + headers: Map, + ) { if (headers.isEmpty()) { return } @@ -516,13 +544,19 @@ class DefaultProtocolTestGenerator( * wraps `inner` in a call to `aws_smithy_protocol_test::assert_ok`, a convenience wrapper * for pretty printing protocol test helper results */ - private fun assertOk(rustWriter: RustWriter, inner: Writable) { + private fun assertOk( + rustWriter: RustWriter, + inner: Writable, + ) { rustWriter.write("#T(", RT.protocolTest(rc, "assert_ok")) inner(rustWriter) rustWriter.write(");") } - private fun strSlice(writer: RustWriter, args: List) { + private fun strSlice( + writer: RustWriter, + args: List, + ) { writer.withBlock("&[", "]") { write(args.joinToString(",") { it.dq() }) } @@ -531,6 +565,7 @@ class DefaultProtocolTestGenerator( companion object { sealed class Action { object Request : Action() + object Response : Action() } @@ -546,25 +581,32 @@ class DefaultProtocolTestGenerator( private val RestXml = "aws.protocoltests.restxml#RestXml" private val AwsQuery = "aws.protocoltests.query#AwsQuery" private val Ec2Query = "aws.protocoltests.ec2#AwsEc2" - private val ExpectFail = setOf() + private val ExpectFail = + setOf( + // Failing because we don't serialize default values if they match the default + FailingTest(JsonRpc10, "AwsJson10ClientPopulatesDefaultsValuesWhenMissingInResponse", Action.Request), + FailingTest(JsonRpc10, "AwsJson10ClientUsesExplicitlyProvidedMemberValuesOverDefaults", Action.Request), + FailingTest(JsonRpc10, "AwsJson10ClientPopulatesDefaultValuesInInput", Action.Request), + ) private val RunOnly: Set? = null // These tests are not even attempted to be generated, either because they will not compile // or because they are flaky - private val DisableTests = setOf( - // TODO(https://github.com/smithy-lang/smithy-rs/issues/2891): Implement support for `@requestCompression` - "SDKAppendedGzipAfterProvidedEncoding_restJson1", - "SDKAppendedGzipAfterProvidedEncoding_restXml", - "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsJson1_0", - "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsJson1_1", - "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsQuery", - "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_ec2Query", - "SDKAppliedContentEncoding_awsJson1_0", - "SDKAppliedContentEncoding_awsJson1_1", - "SDKAppliedContentEncoding_awsQuery", - "SDKAppliedContentEncoding_ec2Query", - "SDKAppliedContentEncoding_restJson1", - "SDKAppliedContentEncoding_restXml", - ) + private val DisableTests = + setOf( + // TODO(https://github.com/smithy-lang/smithy-rs/issues/2891): Implement support for `@requestCompression` + "SDKAppendedGzipAfterProvidedEncoding_restJson1", + "SDKAppendedGzipAfterProvidedEncoding_restXml", + "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsJson1_0", + "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsJson1_1", + "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsQuery", + "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_ec2Query", + "SDKAppliedContentEncoding_awsJson1_0", + "SDKAppliedContentEncoding_awsJson1_1", + "SDKAppliedContentEncoding_awsQuery", + "SDKAppliedContentEncoding_ec2Query", + "SDKAppliedContentEncoding_restJson1", + "SDKAppliedContentEncoding_restXml", + ) } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/RequestSerializerGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/RequestSerializerGenerator.kt index f079cf1026a..d2c1f8fc2f5 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/RequestSerializerGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/RequestSerializerGenerator.kt @@ -46,18 +46,21 @@ class RequestSerializerGenerator( "HttpRequest" to runtimeApi.resolve("client::orchestrator::HttpRequest"), "HttpRequestBuilder" to RuntimeType.HttpRequestBuilder, "Input" to interceptorContext.resolve("Input"), - "operation" to RuntimeType.operationModule(codegenContext.runtimeConfig), "SerializeRequest" to runtimeApi.resolve("client::ser_de::SerializeRequest"), "SdkBody" to RuntimeType.sdkBody(codegenContext.runtimeConfig), - "HeaderSerializationSettings" to RuntimeType.forInlineDependency( - InlineDependency.serializationSettings( - codegenContext.runtimeConfig, - ), - ).resolve("HeaderSerializationSettings"), + "HeaderSerializationSettings" to + RuntimeType.forInlineDependency( + InlineDependency.serializationSettings( + codegenContext.runtimeConfig, + ), + ).resolve("HeaderSerializationSettings"), ) } - fun render(writer: RustWriter, operationShape: OperationShape) { + fun render( + writer: RustWriter, + operationShape: OperationShape, + ) { val inputShape = operationShape.inputShape(codegenContext.model) val operationName = symbolProvider.toSymbol(operationShape).name val inputSymbol = symbolProvider.toSymbol(inputShape) @@ -83,39 +86,42 @@ class RequestSerializerGenerator( *codegenScope, "ConcreteInput" to inputSymbol, "create_http_request" to createHttpRequest(operationShape), - "generate_body" to writable { - if (bodyGenerator != null) { - val body = writable { - bodyGenerator.generatePayload(this, "input", operationShape) - } - val streamingMember = inputShape.findStreamingMember(codegenContext.model) - val isBlobStreaming = - streamingMember != null && codegenContext.model.expectShape(streamingMember.target) is BlobShape - if (isBlobStreaming) { - // Consume the `ByteStream` into its inner `SdkBody`. - rust("#T.into_inner()", body) + "generate_body" to + writable { + if (bodyGenerator != null) { + val body = + writable { + bodyGenerator.generatePayload(this, "input", operationShape) + } + val streamingMember = inputShape.findStreamingMember(codegenContext.model) + val isBlobStreaming = + streamingMember != null && codegenContext.model.expectShape(streamingMember.target) is BlobShape + if (isBlobStreaming) { + // Consume the `ByteStream` into its inner `SdkBody`. + rust("#T.into_inner()", body) + } else { + rustTemplate("#{SdkBody}::from(#{body})", *codegenScope, "body" to body) + } } else { - rustTemplate("#{SdkBody}::from(#{body})", *codegenScope, "body" to body) + rustTemplate("#{SdkBody}::empty()", *codegenScope) + } + }, + "add_content_length" to + if (needsContentLength(operationShape)) { + writable { + rustTemplate( + """ + if let Some(content_length) = body.content_length() { + let content_length = content_length.to_string(); + request_builder = _header_serialization_settings.set_default_header(request_builder, #{http}::header::CONTENT_LENGTH, &content_length); + } + """, + *codegenScope, + ) } } else { - rustTemplate("#{SdkBody}::empty()", *codegenScope) - } - }, - "add_content_length" to if (needsContentLength(operationShape)) { - writable { - rustTemplate( - """ - if let Some(content_length) = body.content_length() { - let content_length = content_length.to_string(); - request_builder = _header_serialization_settings.set_default_header(request_builder, #{http}::header::CONTENT_LENGTH, &content_length); - } - """, - *codegenScope, - ) - } - } else { - writable { } - }, + writable { } + }, ) } @@ -124,34 +130,36 @@ class RequestSerializerGenerator( .any { it.location == HttpLocation.DOCUMENT || it.location == HttpLocation.PAYLOAD } } - private fun createHttpRequest(operationShape: OperationShape): Writable = writable { - val httpBindingGenerator = RequestBindingGenerator( - codegenContext, - protocol, - operationShape, - ) - httpBindingGenerator.renderUpdateHttpBuilder(this) - val contentType = httpBindingResolver.requestContentType(operationShape) + private fun createHttpRequest(operationShape: OperationShape): Writable = + writable { + val httpBindingGenerator = + RequestBindingGenerator( + codegenContext, + protocol, + operationShape, + ) + httpBindingGenerator.renderUpdateHttpBuilder(this) + val contentType = httpBindingResolver.requestContentType(operationShape) - rustTemplate("let mut builder = update_http_builder(&input, #{HttpRequestBuilder}::new())?;", *codegenScope) - if (contentType != null) { - rustTemplate( - "builder = _header_serialization_settings.set_default_header(builder, #{http}::header::CONTENT_TYPE, ${contentType.dq()});", - *codegenScope, - ) - } - for (header in protocol.additionalRequestHeaders(operationShape)) { - rustTemplate( - """ - builder = _header_serialization_settings.set_default_header( - builder, - #{http}::header::HeaderName::from_static(${header.first.dq()}), - ${header.second.dq()} - ); - """, - *codegenScope, - ) + rustTemplate("let mut builder = update_http_builder(&input, #{HttpRequestBuilder}::new())?;", *codegenScope) + if (contentType != null) { + rustTemplate( + "builder = _header_serialization_settings.set_default_header(builder, #{http}::header::CONTENT_TYPE, ${contentType.dq()});", + *codegenScope, + ) + } + for (header in protocol.additionalRequestHeaders(operationShape)) { + rustTemplate( + """ + builder = _header_serialization_settings.set_default_header( + builder, + #{http}::header::HeaderName::from_static(${header.first.dq()}), + ${header.second.dq()} + ); + """, + *codegenScope, + ) + } + rust("builder") } - rust("builder") - } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ResponseDeserializerGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ResponseDeserializerGenerator.kt index 2f183c3444e..ac797e1409e 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ResponseDeserializerGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ResponseDeserializerGenerator.kt @@ -52,7 +52,11 @@ class ResponseDeserializerGenerator( ) } - fun render(writer: RustWriter, operationShape: OperationShape, customizations: List) { + fun render( + writer: RustWriter, + operationShape: OperationShape, + customizations: List, + ) { val outputSymbol = symbolProvider.toSymbol(operationShape.outputShape(model)) val operationName = symbolProvider.toSymbol(operationShape).name val streaming = operationShape.outputShape(model).hasStreamingMember(model) @@ -72,17 +76,19 @@ class ResponseDeserializerGenerator( *codegenScope, "O" to outputSymbol, "E" to symbolProvider.symbolForOperationError(operationShape), - "deserialize_streaming" to writable { - if (streaming) { - deserializeStreaming(operationShape, customizations) - } - }, - "deserialize_nonstreaming" to writable { - when (streaming) { - true -> deserializeStreamingError(operationShape, customizations) - else -> deserializeNonStreaming(operationShape, customizations) - } - }, + "deserialize_streaming" to + writable { + if (streaming) { + deserializeStreaming(operationShape, customizations) + } + }, + "deserialize_nonstreaming" to + writable { + when (streaming) { + true -> deserializeStreamingError(operationShape, customizations) + else -> deserializeNonStreaming(operationShape, customizations) + } + }, ) } @@ -107,9 +113,10 @@ class ResponseDeserializerGenerator( """, *codegenScope, "parse_streaming_response" to parserGenerator.parseStreamingResponseFn(operationShape, customizations), - "BeforeParseResponse" to writable { - writeCustomizations(customizations, OperationSection.BeforeParseResponse(customizations, "response", "force_error", body = null)) - }, + "BeforeParseResponse" to + writable { + writeCustomizations(customizations, OperationSection.BeforeParseResponse(customizations, "response", "force_error", body = null)) + }, ) } @@ -151,26 +158,28 @@ class ResponseDeserializerGenerator( *codegenScope, "parse_error" to parserGenerator.parseErrorFn(operationShape, customizations), "parse_response" to parserGenerator.parseResponseFn(operationShape, customizations), - "BeforeParseResponse" to writable { - writeCustomizations(customizations, OperationSection.BeforeParseResponse(customizations, "response", "force_error", "body")) - }, + "BeforeParseResponse" to + writable { + writeCustomizations(customizations, OperationSection.BeforeParseResponse(customizations, "response", "force_error", "body")) + }, ) } - private fun typeEraseResult(): RuntimeType = ProtocolFunctions.crossOperationFn("type_erase_result") { fnName -> - rustTemplate( - """ - pub(crate) fn $fnName(result: #{Result}) -> #{Result}<#{Output}, #{OrchestratorError}<#{Error}>> - where - O: ::std::fmt::Debug + #{Send} + #{Sync} + 'static, - E: ::std::error::Error + std::fmt::Debug + #{Send} + #{Sync} + 'static, - { - result.map(|output| #{Output}::erase(output)) - .map_err(|error| #{Error}::erase(error)) - .map_err(#{Into}::into) - } - """, - *codegenScope, - ) - } + private fun typeEraseResult(): RuntimeType = + ProtocolFunctions.crossOperationFn("type_erase_result") { fnName -> + rustTemplate( + """ + pub(crate) fn $fnName(result: #{Result}) -> #{Result}<#{Output}, #{OrchestratorError}<#{Error}>> + where + O: ::std::fmt::Debug + #{Send} + #{Sync} + 'static, + E: ::std::error::Error + std::fmt::Debug + #{Send} + #{Sync} + 'static, + { + result.map(|output| #{Output}::erase(output)) + .map_err(|error| #{Error}::erase(error)) + .map_err(#{Into}::into) + } + """, + *codegenScope, + ) + } } diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/ClientProtocolLoader.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/ClientProtocolLoader.kt index cb9c7db7e5a..5c0f7e6e1a6 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/ClientProtocolLoader.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/ClientProtocolLoader.kt @@ -32,32 +32,33 @@ import software.amazon.smithy.rust.codegen.core.util.hasTrait class ClientProtocolLoader(supportedProtocols: ProtocolMap) : ProtocolLoader(supportedProtocols) { - companion object { - val DefaultProtocols = mapOf( - AwsJson1_0Trait.ID to ClientAwsJsonFactory(AwsJsonVersion.Json10), - AwsJson1_1Trait.ID to ClientAwsJsonFactory(AwsJsonVersion.Json11), - AwsQueryTrait.ID to ClientAwsQueryFactory(), - Ec2QueryTrait.ID to ClientEc2QueryFactory(), - RestJson1Trait.ID to ClientRestJsonFactory(), - RestXmlTrait.ID to ClientRestXmlFactory(), - ) + val DefaultProtocols = + mapOf( + AwsJson1_0Trait.ID to ClientAwsJsonFactory(AwsJsonVersion.Json10), + AwsJson1_1Trait.ID to ClientAwsJsonFactory(AwsJsonVersion.Json11), + AwsQueryTrait.ID to ClientAwsQueryFactory(), + Ec2QueryTrait.ID to ClientEc2QueryFactory(), + RestJson1Trait.ID to ClientRestJsonFactory(), + RestXmlTrait.ID to ClientRestXmlFactory(), + ) val Default = ClientProtocolLoader(DefaultProtocols) } } -private val CLIENT_PROTOCOL_SUPPORT = ProtocolSupport( - /* Client protocol codegen enabled */ - requestSerialization = true, - requestBodySerialization = true, - responseDeserialization = true, - errorDeserialization = true, - /* Server protocol codegen disabled */ - requestDeserialization = false, - requestBodyDeserialization = false, - responseSerialization = false, - errorSerialization = false, -) +private val CLIENT_PROTOCOL_SUPPORT = + ProtocolSupport( + // Client protocol codegen enabled + requestSerialization = true, + requestBodySerialization = true, + responseDeserialization = true, + errorDeserialization = true, + // Server protocol codegen disabled + requestDeserialization = false, + requestBodyDeserialization = false, + responseSerialization = false, + errorSerialization = false, + ) private class ClientAwsJsonFactory(private val version: AwsJsonVersion) : ProtocolGeneratorFactory { @@ -73,8 +74,10 @@ private class ClientAwsJsonFactory(private val version: AwsJsonVersion) : override fun support(): ProtocolSupport = CLIENT_PROTOCOL_SUPPORT - private fun compatibleWithAwsQuery(serviceShape: ServiceShape, version: AwsJsonVersion) = - serviceShape.hasTrait() && version == AwsJsonVersion.Json10 + private fun compatibleWithAwsQuery( + serviceShape: ServiceShape, + version: AwsJsonVersion, + ) = serviceShape.hasTrait() && version == AwsJsonVersion.Json10 } private class ClientAwsQueryFactory : ProtocolGeneratorFactory { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt index f3cc0abad08..c2cbc7c8572 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/HttpBoundProtocolGenerator.kt @@ -18,27 +18,28 @@ class ClientHttpBoundProtocolPayloadGenerator( codegenContext: ClientCodegenContext, protocol: Protocol, ) : ProtocolPayloadGenerator by HttpBoundProtocolPayloadGenerator( - codegenContext, protocol, HttpMessageType.REQUEST, - renderEventStreamBody = { writer, params -> - writer.rustTemplate( - """ - { - let error_marshaller = #{errorMarshallerConstructorFn}(); - let marshaller = #{marshallerConstructorFn}(); - let (signer, signer_sender) = #{DeferredSigner}::new(); - _cfg.interceptor_state().store_put(signer_sender); - let adapter: #{aws_smithy_http}::event_stream::MessageStreamAdapter<_, _> = - ${params.outerName}.${params.memberName}.into_body_stream(marshaller, error_marshaller, signer); - #{SdkBody}::from_body_0_4(#{hyper}::Body::wrap_stream(adapter)) - } - """, - "hyper" to CargoDependency.HyperWithStream.toType(), - "SdkBody" to CargoDependency.smithyTypes(codegenContext.runtimeConfig).withFeature("http-body-0-4-x") - .toType().resolve("body::SdkBody"), - "aws_smithy_http" to RuntimeType.smithyHttp(codegenContext.runtimeConfig), - "DeferredSigner" to RuntimeType.smithyEventStream(codegenContext.runtimeConfig).resolve("frame::DeferredSigner"), - "marshallerConstructorFn" to params.marshallerConstructorFn, - "errorMarshallerConstructorFn" to params.errorMarshallerConstructorFn, - ) - }, -) + codegenContext, protocol, HttpMessageType.REQUEST, + renderEventStreamBody = { writer, params -> + writer.rustTemplate( + """ + { + let error_marshaller = #{errorMarshallerConstructorFn}(); + let marshaller = #{marshallerConstructorFn}(); + let (signer, signer_sender) = #{DeferredSigner}::new(); + _cfg.interceptor_state().store_put(signer_sender); + let adapter: #{aws_smithy_http}::event_stream::MessageStreamAdapter<_, _> = + ${params.outerName}.${params.memberName}.into_body_stream(marshaller, error_marshaller, signer); + #{SdkBody}::from_body_0_4(#{hyper}::Body::wrap_stream(adapter)) + } + """, + "hyper" to CargoDependency.HyperWithStream.toType(), + "SdkBody" to + CargoDependency.smithyTypes(codegenContext.runtimeConfig).withFeature("http-body-0-4-x") + .toType().resolve("body::SdkBody"), + "aws_smithy_http" to RuntimeType.smithyHttp(codegenContext.runtimeConfig), + "DeferredSigner" to RuntimeType.smithyEventStream(codegenContext.runtimeConfig).resolve("frame::DeferredSigner"), + "marshallerConstructorFn" to params.marshallerConstructorFn, + "errorMarshallerConstructorFn" to params.errorMarshallerConstructorFn, + ) + }, + ) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/transformers/RemoveEventStreamOperations.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/transformers/RemoveEventStreamOperations.kt index 3d757e4bdb1..863f9daa88e 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/transformers/RemoveEventStreamOperations.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/transformers/RemoveEventStreamOperations.kt @@ -15,11 +15,15 @@ import software.amazon.smithy.rust.codegen.core.util.orNull import java.util.logging.Logger // TODO(EventStream): [CLEANUP] Remove this class once the Event Stream implementation is stable + /** Transformer to REMOVE operations that use EventStreaming until event streaming is supported */ object RemoveEventStreamOperations { private val logger = Logger.getLogger(javaClass.name) - fun transform(model: Model, settings: ClientRustSettings): Model { + fun transform( + model: Model, + settings: ClientRustSettings, + ): Model { // If Event Stream is allowed in build config, then don't remove the operations val allowList = settings.codegenConfig.eventStreamAllowList if (allowList.isEmpty() || allowList.contains(settings.moduleName)) { @@ -30,16 +34,18 @@ object RemoveEventStreamOperations { if (parentShape !is OperationShape) { true } else { - val ioShapes = listOfNotNull(parentShape.output.orNull(), parentShape.input.orNull()).map { - model.expectShape( - it, - StructureShape::class.java, - ) - } - val hasEventStream = ioShapes.any { ioShape -> - val streamingMember = ioShape.findStreamingMember(model)?.let { model.expectShape(it.target) } - streamingMember?.isUnionShape ?: false - } + val ioShapes = + listOfNotNull(parentShape.output.orNull(), parentShape.input.orNull()).map { + model.expectShape( + it, + StructureShape::class.java, + ) + } + val hasEventStream = + ioShapes.any { ioShape -> + val streamingMember = ioShape.findStreamingMember(model)?.let { model.expectShape(it.target) } + streamingMember?.isUnionShape ?: false + } // If a streaming member has a union trait, it is an event stream. Event Streams are not currently supported // by the SDK, so if we generate this API it won't work. (!hasEventStream).also { diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/testutil/ClientCodegenIntegrationTest.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/testutil/ClientCodegenIntegrationTest.kt index 5d6de735b99..5846a44221d 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/testutil/ClientCodegenIntegrationTest.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/testutil/ClientCodegenIntegrationTest.kt @@ -18,21 +18,26 @@ import java.nio.file.Path fun clientIntegrationTest( model: Model, - params: IntegrationTestParams = IntegrationTestParams(cargoCommand = "cargo test --features behavior-version-latest"), + params: IntegrationTestParams = + IntegrationTestParams(cargoCommand = "cargo test --features behavior-version-latest"), additionalDecorators: List = listOf(), test: (ClientCodegenContext, RustCrate) -> Unit = { _, _ -> }, ): Path { fun invokeRustCodegenPlugin(ctx: PluginContext) { - val codegenDecorator = object : ClientCodegenDecorator { - override val name: String = "Add tests" - override val order: Byte = 0 + val codegenDecorator = + object : ClientCodegenDecorator { + override val name: String = "Add tests" + override val order: Byte = 0 - override fun classpathDiscoverable(): Boolean = false + override fun classpathDiscoverable(): Boolean = false - override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { - test(codegenContext, rustCrate) + override fun extras( + codegenContext: ClientCodegenContext, + rustCrate: RustCrate, + ) { + test(codegenContext, rustCrate) + } } - } RustClientCodegenPlugin().executeWithDecorator(ctx, codegenDecorator, *additionalDecorators.toTypedArray()) } return codegenIntegrationTest(model, params, invokePlugin = ::invokeRustCodegenPlugin) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/testutil/TestHelpers.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/testutil/TestHelpers.kt index a65d734085d..e4b9e11ac5e 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/testutil/TestHelpers.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/testutil/TestHelpers.kt @@ -51,19 +51,23 @@ fun testClientRustSettings( customizationConfig, ) -val TestClientRustSymbolProviderConfig = RustSymbolProviderConfig( - runtimeConfig = TestRuntimeConfig, - renameExceptions = true, - nullabilityCheckMode = NullableIndex.CheckMode.CLIENT_ZERO_VALUE_V1, - moduleProvider = ClientModuleProvider, -) +val TestClientRustSymbolProviderConfig = + RustSymbolProviderConfig( + runtimeConfig = TestRuntimeConfig, + renameExceptions = true, + nullabilityCheckMode = NullableIndex.CheckMode.CLIENT_ZERO_VALUE_V1, + moduleProvider = ClientModuleProvider, + ) private class ClientTestCodegenDecorator : ClientCodegenDecorator { override val name = "test" override val order: Byte = 0 } -fun testSymbolProvider(model: Model, serviceShape: ServiceShape? = null): RustSymbolProvider = +fun testSymbolProvider( + model: Model, + serviceShape: ServiceShape? = null, +): RustSymbolProvider = RustClientCodegenPlugin.baseSymbolProvider( testClientRustSettings(), model, @@ -78,19 +82,22 @@ fun testClientCodegenContext( serviceShape: ServiceShape? = null, settings: ClientRustSettings = testClientRustSettings(), rootDecorator: ClientCodegenDecorator? = null, -): ClientCodegenContext = ClientCodegenContext( - model, - symbolProvider ?: testSymbolProvider(model), - TestModuleDocProvider, - serviceShape - ?: model.serviceShapes.firstOrNull() - ?: ServiceShape.builder().version("test").id("test#Service").build(), - ShapeId.from("test#Protocol"), - settings, - rootDecorator ?: CombinedClientCodegenDecorator(emptyList()), -) +): ClientCodegenContext = + ClientCodegenContext( + model, + symbolProvider ?: testSymbolProvider(model), + TestModuleDocProvider, + serviceShape + ?: model.serviceShapes.firstOrNull() + ?: ServiceShape.builder().version("test").id("test#Service").build(), + ShapeId.from("test#Protocol"), + settings, + rootDecorator ?: CombinedClientCodegenDecorator(emptyList()), + ) -fun ClientCodegenContext.withEnableUserConfigurableRuntimePlugins(enableUserConfigurableRuntimePlugins: Boolean): ClientCodegenContext = +fun ClientCodegenContext.withEnableUserConfigurableRuntimePlugins( + enableUserConfigurableRuntimePlugins: Boolean, +): ClientCodegenContext = copy(settings = settings.copy(codegenConfig = settings.codegenConfig.copy(enableUserConfigurableRuntimePlugins = enableUserConfigurableRuntimePlugins))) fun TestWriterDelegator.clientRustSettings() = @@ -100,4 +107,5 @@ fun TestWriterDelegator.clientRustSettings() = codegenConfig = codegenConfig as ClientCodegenConfig, ) -fun TestWriterDelegator.clientCodegenContext(model: Model) = testClientCodegenContext(model, settings = clientRustSettings()) +fun TestWriterDelegator.clientCodegenContext(model: Model) = + testClientCodegenContext(model, settings = clientRustSettings()) diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenVisitorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenVisitorTest.kt index f9cf52375b6..16e89f9feaa 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenVisitorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/ClientCodegenVisitorTest.kt @@ -18,7 +18,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.generatePluginContext class ClientCodegenVisitorTest { @Test fun `baseline transform verify mixins removed`() { - val model = """ + val model = + """ namespace com.example use aws.protocols#awsJson1_0 @@ -43,7 +44,7 @@ class ClientCodegenVisitorTest { ] { greeting: String } - """.asSmithyModel(smithyVersion = "2.0") + """.asSmithyModel(smithyVersion = "2.0") val (ctx, _) = generatePluginContext(model) val codegenDecorator = CombinedClientCodegenDecorator.fromClasspath( diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/EventStreamSymbolProviderTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/EventStreamSymbolProviderTest.kt index 6b8c28826cc..27ebff53cab 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/EventStreamSymbolProviderTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/EventStreamSymbolProviderTest.kt @@ -26,33 +26,35 @@ class EventStreamSymbolProviderTest { @Test fun `it should adjust types for operations with event streams`() { // Transform the model so that it has synthetic inputs/outputs - val model = OperationNormalizer.transform( - """ - namespace test - - structure Something { stuff: Blob } - - @streaming - union SomeStream { - Something: Something, - } - - structure TestInput { inputStream: SomeStream } - structure TestOutput { outputStream: SomeStream } - operation TestOperation { - input: TestInput, - output: TestOutput, - } - service TestService { version: "123", operations: [TestOperation] } - """.asSmithyModel(), - ) + val model = + OperationNormalizer.transform( + """ + namespace test + + structure Something { stuff: Blob } + + @streaming + union SomeStream { + Something: Something, + } + + structure TestInput { inputStream: SomeStream } + structure TestOutput { outputStream: SomeStream } + operation TestOperation { + input: TestInput, + output: TestOutput, + } + service TestService { version: "123", operations: [TestOperation] } + """.asSmithyModel(), + ) val service = model.expectShape(ShapeId.from("test#TestService")) as ServiceShape - val provider = EventStreamSymbolProvider( - TestRuntimeConfig, - SymbolVisitor(testClientRustSettings(), model, service, TestClientRustSymbolProviderConfig), - CodegenTarget.CLIENT, - ) + val provider = + EventStreamSymbolProvider( + TestRuntimeConfig, + SymbolVisitor(testClientRustSettings(), model, service, TestClientRustSymbolProviderConfig), + CodegenTarget.CLIENT, + ) // Look up the synthetic input/output rather than the original input/output val inputStream = model.expectShape(ShapeId.from("test.synthetic#TestOperationInput\$inputStream")) as MemberShape @@ -64,44 +66,48 @@ class EventStreamSymbolProviderTest { val someStream = RustType.Opaque("SomeStream", "crate::types") val someStreamError = RustType.Opaque("SomeStreamError", "crate::types::error") - inputType shouldBe RustType.Application( - RuntimeType.eventStreamSender(TestRuntimeConfig).toSymbol().rustType(), - listOf(someStream, someStreamError), - ) - outputType shouldBe RustType.Application( - RuntimeType.eventReceiver(TestRuntimeConfig).toSymbol().rustType(), - listOf(someStream, someStreamError), - ) + inputType shouldBe + RustType.Application( + RuntimeType.eventStreamSender(TestRuntimeConfig).toSymbol().rustType(), + listOf(someStream, someStreamError), + ) + outputType shouldBe + RustType.Application( + RuntimeType.eventReceiver(TestRuntimeConfig).toSymbol().rustType(), + listOf(someStream, someStreamError), + ) } @Test fun `it should leave alone types for operations without event streams`() { - val model = OperationNormalizer.transform( - """ - namespace test - - structure Something { stuff: Blob } - - union NotStreaming { - Something: Something, - } - - structure TestInput { inputStream: NotStreaming } - structure TestOutput { outputStream: NotStreaming } - operation TestOperation { - input: TestInput, - output: TestOutput, - } - service TestService { version: "123", operations: [TestOperation] } - """.asSmithyModel(), - ) + val model = + OperationNormalizer.transform( + """ + namespace test + + structure Something { stuff: Blob } + + union NotStreaming { + Something: Something, + } + + structure TestInput { inputStream: NotStreaming } + structure TestOutput { outputStream: NotStreaming } + operation TestOperation { + input: TestInput, + output: TestOutput, + } + service TestService { version: "123", operations: [TestOperation] } + """.asSmithyModel(), + ) val service = model.expectShape(ShapeId.from("test#TestService")) as ServiceShape - val provider = EventStreamSymbolProvider( - TestRuntimeConfig, - SymbolVisitor(testClientRustSettings(), model, service, TestClientRustSymbolProviderConfig), - CodegenTarget.CLIENT, - ) + val provider = + EventStreamSymbolProvider( + TestRuntimeConfig, + SymbolVisitor(testClientRustSettings(), model, service, TestClientRustSymbolProviderConfig), + CodegenTarget.CLIENT, + ) // Look up the synthetic input/output rather than the original input/output val inputStream = model.expectShape(ShapeId.from("test.synthetic#TestOperationInput\$inputStream")) as MemberShape diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/StreamingShapeSymbolProviderTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/StreamingShapeSymbolProviderTest.kt index 9846d9b0c00..61bf6562b1c 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/StreamingShapeSymbolProviderTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/StreamingShapeSymbolProviderTest.kt @@ -18,7 +18,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.util.lookup internal class StreamingShapeSymbolProviderTest { - val model = """ + val model = + """ namespace test operation GenerateSpeech { output: GenerateSpeechOutput, @@ -32,7 +33,7 @@ internal class StreamingShapeSymbolProviderTest { @streaming blob BlobStream - """.asSmithyModel() + """.asSmithyModel() @Test fun `generates a byte stream on streaming output`() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecoratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecoratorTest.kt index e235144f2d7..e81a2d2ee83 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecoratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecoratorTest.kt @@ -17,15 +17,18 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.integrationTest class HttpAuthDecoratorTest { - private fun codegenScope(runtimeConfig: RuntimeConfig): Array> = arrayOf( - "ReplayEvent" to CargoDependency.smithyRuntime(runtimeConfig) - .toDevDependency().withFeature("test-util").toType() - .resolve("client::http::test_util::ReplayEvent"), - "StaticReplayClient" to CargoDependency.smithyRuntime(runtimeConfig) - .toDevDependency().withFeature("test-util").toType() - .resolve("client::http::test_util::StaticReplayClient"), - "SdkBody" to RuntimeType.sdkBody(runtimeConfig), - ) + private fun codegenScope(runtimeConfig: RuntimeConfig): Array> = + arrayOf( + "ReplayEvent" to + CargoDependency.smithyRuntime(runtimeConfig) + .toDevDependency().withFeature("test-util").toType() + .resolve("client::http::test_util::ReplayEvent"), + "StaticReplayClient" to + CargoDependency.smithyRuntime(runtimeConfig) + .toDevDependency().withFeature("test-util").toType() + .resolve("client::http::test_util::StaticReplayClient"), + "SdkBody" to RuntimeType.sdkBody(runtimeConfig), + ) @Test fun multipleAuthSchemesSchemeSelection() { @@ -225,7 +228,6 @@ class HttpAuthDecoratorTest { fn compile() {} """, - ) Attribute.TokioTest.render(this) rustTemplate( @@ -255,8 +257,9 @@ class HttpAuthDecoratorTest { http_client.assert_requests_match(&[]); } """, - "capture_test_logs" to CargoDependency.smithyRuntimeTestUtil(ctx.runtimeConfig).toType() - .resolve("test_util::capture_test_logs::capture_test_logs"), + "capture_test_logs" to + CargoDependency.smithyRuntimeTestUtil(ctx.runtimeConfig).toType() + .resolve("test_util::capture_test_logs::capture_test_logs"), *codegenScope(ctx.runtimeConfig), ) } @@ -465,7 +468,8 @@ class HttpAuthDecoratorTest { } private object TestModels { - val allSchemes = """ + val allSchemes = + """ namespace test use aws.api#service @@ -492,9 +496,10 @@ private object TestModels { operation SomeOperation { output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() - val noSchemes = """ + val noSchemes = + """ namespace test use aws.api#service @@ -517,7 +522,8 @@ private object TestModels { output: SomeOutput }""".asSmithyModel() - val apiKeyInQueryString = """ + val apiKeyInQueryString = + """ namespace test use aws.api#service @@ -541,9 +547,10 @@ private object TestModels { operation SomeOperation { output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() - val apiKeyInHeaders = """ + val apiKeyInHeaders = + """ namespace test use aws.api#service @@ -567,9 +574,10 @@ private object TestModels { operation SomeOperation { output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() - val basicAuth = """ + val basicAuth = + """ namespace test use aws.api#service @@ -593,9 +601,10 @@ private object TestModels { operation SomeOperation { output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() - val bearerAuth = """ + val bearerAuth = + """ namespace test use aws.api#service @@ -619,9 +628,10 @@ private object TestModels { operation SomeOperation { output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() - val optionalAuth = """ + val optionalAuth = + """ namespace test use aws.api#service @@ -646,5 +656,5 @@ private object TestModels { operation SomeOperation { output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/MetadataCustomizationTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/MetadataCustomizationTest.kt index cac24f5b962..693fd2f6e63 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/MetadataCustomizationTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/MetadataCustomizationTest.kt @@ -16,22 +16,23 @@ import software.amazon.smithy.rust.codegen.core.testutil.testModule import software.amazon.smithy.rust.codegen.core.testutil.tokioTest class MetadataCustomizationTest { - @Test fun `extract metadata via customizable operation`() { clientIntegrationTest(BasicTestModels.AwsJson10TestModel) { clientCodegenContext, rustCrate -> val runtimeConfig = clientCodegenContext.runtimeConfig - val codegenScope = arrayOf( - *preludeScope, - "BeforeTransmitInterceptorContextMut" to RuntimeType.beforeTransmitInterceptorContextMut(runtimeConfig), - "BoxError" to RuntimeType.boxError(runtimeConfig), - "ConfigBag" to RuntimeType.configBag(runtimeConfig), - "Intercept" to RuntimeType.intercept(runtimeConfig), - "Metadata" to RuntimeType.operationModule(runtimeConfig).resolve("Metadata"), - "capture_request" to RuntimeType.captureRequest(runtimeConfig), - "RuntimeComponents" to RuntimeType.smithyRuntimeApiClient(runtimeConfig) - .resolve("client::runtime_components::RuntimeComponents"), - ) + val codegenScope = + arrayOf( + *preludeScope, + "BeforeTransmitInterceptorContextMut" to RuntimeType.beforeTransmitInterceptorContextMut(runtimeConfig), + "BoxError" to RuntimeType.boxError(runtimeConfig), + "ConfigBag" to RuntimeType.configBag(runtimeConfig), + "Intercept" to RuntimeType.intercept(runtimeConfig), + "Metadata" to RuntimeType.smithyRuntimeApiClient(runtimeConfig).resolve("client::orchestrator::Metadata"), + "capture_request" to RuntimeType.captureRequest(runtimeConfig), + "RuntimeComponents" to + RuntimeType.smithyRuntimeApiClient(runtimeConfig) + .resolve("client::runtime_components::RuntimeComponents"), + ) rustCrate.testModule { addDependency(CargoDependency.Tokio.toDevDependency().withFeature("test-util")) tokioTest("test_extract_metadata_via_customizable_operation") { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ResiliencyConfigCustomizationTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ResiliencyConfigCustomizationTest.kt index 30d046ff635..ddc636afbfd 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ResiliencyConfigCustomizationTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ResiliencyConfigCustomizationTest.kt @@ -12,7 +12,6 @@ import software.amazon.smithy.rust.codegen.core.testutil.BasicTestModels import software.amazon.smithy.rust.codegen.core.testutil.unitTest internal class ResiliencyConfigCustomizationTest { - @Test fun `generates a valid config`() { clientIntegrationTest(BasicTestModels.AwsJson10TestModel) { _, crate -> diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/SensitiveOutputDecoratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/SensitiveOutputDecoratorTest.kt index e97ad2921b9..e78e84e4846 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/SensitiveOutputDecoratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/SensitiveOutputDecoratorTest.kt @@ -16,14 +16,17 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.integrationTest class SensitiveOutputDecoratorTest { - private fun codegenScope(runtimeConfig: RuntimeConfig): Array> = arrayOf( - "capture_test_logs" to CargoDependency.smithyRuntimeTestUtil(runtimeConfig).toType() - .resolve("test_util::capture_test_logs::capture_test_logs"), - "capture_request" to RuntimeType.captureRequest(runtimeConfig), - "SdkBody" to RuntimeType.sdkBody(runtimeConfig), - ) + private fun codegenScope(runtimeConfig: RuntimeConfig): Array> = + arrayOf( + "capture_test_logs" to + CargoDependency.smithyRuntimeTestUtil(runtimeConfig).toType() + .resolve("test_util::capture_test_logs::capture_test_logs"), + "capture_request" to RuntimeType.captureRequest(runtimeConfig), + "SdkBody" to RuntimeType.sdkBody(runtimeConfig), + ) - private val model = """ + private val model = + """ namespace com.example use aws.protocols#awsJson1_0 @awsJson1_0 @@ -43,7 +46,7 @@ class SensitiveOutputDecoratorTest { structure TestOutput { credentials: Credentials, } - """.asSmithyModel() + """.asSmithyModel() @Test fun `sensitive output in model should redact response body`() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/ClientContextConfigCustomizationTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/ClientContextConfigCustomizationTest.kt index 15b6f0e5953..8a7c26ad4be 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/ClientContextConfigCustomizationTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/ClientContextConfigCustomizationTest.kt @@ -12,7 +12,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.unitTest class ClientContextConfigCustomizationTest { - val model = """ + val model = + """ namespace test use smithy.rules#clientContextParams use aws.protocols#awsJson1_0 @@ -27,7 +28,7 @@ class ClientContextConfigCustomizationTest { }) @awsJson1_0 service TestService { operations: [] } - """.asSmithyModel() + """.asSmithyModel() @Test fun `client params generate a valid customization`() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointResolverGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointResolverGeneratorTest.kt index aaa8cfa284f..110baeba6c2 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointResolverGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointResolverGeneratorTest.kt @@ -14,19 +14,20 @@ import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest class EndpointResolverGeneratorTest { companion object { - val testCases = listOf( - "default-values.smithy", - "deprecated-param.smithy", - "duplicate-param.smithy", - "get-attr-type-inference.smithy", - "headers.smithy", - "minimal-ruleset.smithy", - "parse-url.smithy", - "substring.smithy", - "uri-encode.smithy", - "valid-hostlabel.smithy", - "valid-model.smithy", - ) + val testCases = + listOf( + "default-values.smithy", + "deprecated-param.smithy", + "duplicate-param.smithy", + "get-attr-type-inference.smithy", + "headers.smithy", + "minimal-ruleset.smithy", + "parse-url.smithy", + "substring.smithy", + "uri-encode.smithy", + "valid-hostlabel.smithy", + "valid-model.smithy", + ) @JvmStatic fun testSuites(): List { @@ -40,11 +41,12 @@ class EndpointResolverGeneratorTest { } // for tests, load partitions.json from smithy—for real usage, this file will be inserted at codegen time - /*private val partitionsJson = - Node.parse( - this::class.java.getResource("/software/amazon/smithy/rulesengine/language/partitions.json")?.readText() - ?: throw CodegenException("partitions.json was not present in smithy bundle"), - )*/ + // + // private val partitionsJson = + // Node.parse( + // this::class.java.getResource("/software/amazon/smithy/rulesengine/language/partitions.json")?.readText() + // ?: throw CodegenException("partitions.json was not present in smithy bundle"), + // ) @ParameterizedTest(name = "{0}") @MethodSource("testSuites") diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecoratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecoratorTest.kt index 789315e2189..0e5ab3ff780 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecoratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/EndpointsDecoratorTest.kt @@ -23,7 +23,8 @@ import software.amazon.smithy.rust.codegen.core.util.runCommand * End-to-end test of endpoint resolvers, attaching a real resolver to a fully generated service */ class EndpointsDecoratorTest { - val model = """ + val model = + """ namespace test use smithy.rules#endpointRuleSet @@ -122,111 +123,114 @@ class EndpointsDecoratorTest { structure NestedStructure { field: String } - """.asSmithyModel(disableValidation = true) + """.asSmithyModel(disableValidation = true) @Test fun `resolve endpoint`() { - val testDir = clientIntegrationTest( - model, - // Just run integration tests. - IntegrationTestParams(command = { "cargo test --all-features --test *".runCommand(it) }), - ) { clientCodegenContext, rustCrate -> - rustCrate.integrationTest("endpoint_params_test") { - val moduleName = clientCodegenContext.moduleUseName() - Attribute.TokioTest.render(this) - rustTemplate( - """ - async fn endpoint_params_are_set() { - use #{NeverClient}; - use #{TokioSleep}; - use aws_smithy_runtime_api::box_error::BoxError; - use aws_smithy_runtime_api::client::endpoint::EndpointResolverParams; - use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents; - use aws_smithy_types::config_bag::ConfigBag; - use aws_smithy_types::endpoint::Endpoint; - use aws_smithy_types::timeout::TimeoutConfig; - use std::sync::atomic::AtomicBool; - use std::sync::atomic::Ordering; - use std::sync::Arc; - use std::time::Duration; - use $moduleName::{ - config::endpoint::Params, config::interceptors::BeforeTransmitInterceptorContextRef, - config::Intercept, config::SharedAsyncSleep, Client, Config, - }; - - ##[derive(Clone, Debug, Default)] - struct TestInterceptor { - called: Arc, - } - impl Intercept for TestInterceptor { - fn name(&self) -> &'static str { - "TestInterceptor" + val testDir = + clientIntegrationTest( + model, + // Just run integration tests. + IntegrationTestParams(command = { "cargo test --all-features --test *".runCommand(it) }), + ) { clientCodegenContext, rustCrate -> + rustCrate.integrationTest("endpoint_params_test") { + val moduleName = clientCodegenContext.moduleUseName() + Attribute.TokioTest.render(this) + rustTemplate( + """ + async fn endpoint_params_are_set() { + use #{NeverClient}; + use #{TokioSleep}; + use aws_smithy_runtime_api::box_error::BoxError; + use aws_smithy_runtime_api::client::endpoint::EndpointResolverParams; + use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents; + use aws_smithy_types::config_bag::ConfigBag; + use aws_smithy_types::endpoint::Endpoint; + use aws_smithy_types::timeout::TimeoutConfig; + use std::sync::atomic::AtomicBool; + use std::sync::atomic::Ordering; + use std::sync::Arc; + use std::time::Duration; + use $moduleName::{ + config::endpoint::Params, config::interceptors::BeforeTransmitInterceptorContextRef, + config::Intercept, config::SharedAsyncSleep, Client, Config, + }; + + ##[derive(Clone, Debug, Default)] + struct TestInterceptor { + called: Arc, } - - fn read_before_transmit( - &self, - _context: &BeforeTransmitInterceptorContextRef<'_>, - _runtime_components: &RuntimeComponents, - cfg: &mut ConfigBag, - ) -> Result<(), BoxError> { - let params = cfg - .load::() - .expect("params set in config"); - let params: &Params = params.get().expect("correct type"); - assert_eq!( - params, - &Params::builder() - .bucket("bucket-name".to_string()) - .built_in_with_default("some-default") - .bool_built_in_with_default(true) - .a_bool_param(false) - .a_string_param("hello".to_string()) - .region("us-east-2".to_string()) - .build() - .unwrap() - ); - - let endpoint = cfg.load::().expect("endpoint set in config"); - assert_eq!(endpoint.url(), "https://www.us-east-2.example.com"); - - self.called.store(true, Ordering::Relaxed); - Ok(()) + impl Intercept for TestInterceptor { + fn name(&self) -> &'static str { + "TestInterceptor" + } + + fn read_before_transmit( + &self, + _context: &BeforeTransmitInterceptorContextRef<'_>, + _runtime_components: &RuntimeComponents, + cfg: &mut ConfigBag, + ) -> Result<(), BoxError> { + let params = cfg + .load::() + .expect("params set in config"); + let params: &Params = params.get().expect("correct type"); + assert_eq!( + params, + &Params::builder() + .bucket("bucket-name".to_string()) + .built_in_with_default("some-default") + .bool_built_in_with_default(true) + .a_bool_param(false) + .a_string_param("hello".to_string()) + .region("us-east-2".to_string()) + .build() + .unwrap() + ); + + let endpoint = cfg.load::().expect("endpoint set in config"); + assert_eq!(endpoint.url(), "https://www.us-east-2.example.com"); + + self.called.store(true, Ordering::Relaxed); + Ok(()) + } } - } - let interceptor = TestInterceptor::default(); - let config = Config::builder() - .http_client(NeverClient::new()) - .interceptor(interceptor.clone()) - .timeout_config( - TimeoutConfig::builder() - .operation_timeout(Duration::from_millis(30)) - .build(), - ) - .sleep_impl(SharedAsyncSleep::new(TokioSleep::new())) - .a_string_param("hello") - .a_bool_param(false) - .build(); - let client = Client::from_conf(config); - - let _ = dbg!(client.test_operation().bucket("bucket-name").send().await); - assert!( - interceptor.called.load(Ordering::Relaxed), - "the interceptor should have been called" - ); - - // bucket_name is unset and marked as required on the model, so we'll refuse to construct this request - let err = client.test_operation().send().await.expect_err("param missing"); - assert_eq!(format!("{}", err), "failed to construct request"); - } - """, - "NeverClient" to CargoDependency.smithyRuntimeTestUtil(clientCodegenContext.runtimeConfig) - .toType().resolve("client::http::test_util::NeverClient"), - "TokioSleep" to CargoDependency.smithyAsync(clientCodegenContext.runtimeConfig) - .withFeature("rt-tokio").toType().resolve("rt::sleep::TokioSleep"), - ) + let interceptor = TestInterceptor::default(); + let config = Config::builder() + .http_client(NeverClient::new()) + .interceptor(interceptor.clone()) + .timeout_config( + TimeoutConfig::builder() + .operation_timeout(Duration::from_millis(30)) + .build(), + ) + .sleep_impl(SharedAsyncSleep::new(TokioSleep::new())) + .a_string_param("hello") + .a_bool_param(false) + .build(); + let client = Client::from_conf(config); + + let _ = dbg!(client.test_operation().bucket("bucket-name").send().await); + assert!( + interceptor.called.load(Ordering::Relaxed), + "the interceptor should have been called" + ); + + // bucket_name is unset and marked as required on the model, so we'll refuse to construct this request + let err = client.test_operation().send().await.expect_err("param missing"); + assert_eq!(format!("{}", err), "failed to construct request"); + } + """, + "NeverClient" to + CargoDependency.smithyRuntimeTestUtil(clientCodegenContext.runtimeConfig) + .toType().resolve("client::http::test_util::NeverClient"), + "TokioSleep" to + CargoDependency.smithyAsync(clientCodegenContext.runtimeConfig) + .withFeature("rt-tokio").toType().resolve("rt::sleep::TokioSleep"), + ) + } } - } // the model has an intentionally failing test—ensure it fails val failure = shouldThrow { "cargo test".runWithWarnings(testDir) } failure.output shouldContain "endpoint::test::test_1" diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/ExpressionGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/ExpressionGeneratorTest.kt index 58e23cb28b0..89e75fc36df 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/ExpressionGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/ExpressionGeneratorTest.kt @@ -43,14 +43,16 @@ internal class ExprGeneratorTest { @Test fun generateLiterals1() { - val literal = Literal.recordLiteral( - mutableMapOf( - Identifier.of("this") to Literal.integerLiteral(5), - Identifier.of("that") to Literal.stringLiteral( - Template.fromString("static"), + val literal = + Literal.recordLiteral( + mutableMapOf( + Identifier.of("this") to Literal.integerLiteral(5), + Identifier.of("that") to + Literal.stringLiteral( + Template.fromString("static"), + ), ), - ), - ) + ) TestWorkspace.testProject().unitTest { val generator = ExpressionGenerator(Ownership.Borrowed, testContext) @@ -61,13 +63,14 @@ internal class ExprGeneratorTest { @Test fun generateLiterals2() { val project = TestWorkspace.testProject() - val gen = ExpressionGenerator( - Ownership.Borrowed, - Context( - FunctionRegistry(listOf()), - TestRuntimeConfig, - ), - ) + val gen = + ExpressionGenerator( + Ownership.Borrowed, + Context( + FunctionRegistry(listOf()), + TestRuntimeConfig, + ), + ) project.unitTest { rust("""let extra = "helloworld";""") rust("assert_eq!(true, #W);", gen.generate(Expression.of(true))) @@ -83,12 +86,13 @@ internal class ExprGeneratorTest { assert_eq!(expected, #{actual:W}); """, "Document" to RuntimeType.document(TestRuntimeConfig), - "actual" to gen.generate( - Literal.fromNode( - Node.objectNode().withMember("a", true).withMember("b", "hello") - .withMember("c", ArrayNode.arrayNode(BooleanNode.from(true))), + "actual" to + gen.generate( + Literal.fromNode( + Node.objectNode().withMember("a", true).withMember("b", "hello") + .withMember("c", ArrayNode.arrayNode(BooleanNode.from(true))), + ), ), - ), ) } } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/TemplateGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/TemplateGeneratorTest.kt index 95188a9b5dd..282643d6813 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/TemplateGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/rulesgen/TemplateGeneratorTest.kt @@ -19,7 +19,10 @@ internal class TemplateGeneratorTest { /** * helper to assert that a template string is templated to the expected result */ - private fun assertTemplateEquals(template: String, result: String) { + private fun assertTemplateEquals( + template: String, + result: String, + ) { val literalTemplate = Template.fromString(template) // For testing, val exprFn = { expr: Expression, ownership: Ownership -> diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGeneratorTest.kt index 9c0817e5c55..27b59311bbe 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientEnumGeneratorTest.kt @@ -19,7 +19,11 @@ import software.amazon.smithy.rust.codegen.core.util.lookup class ClientEnumGeneratorTest { @Test fun `matching on enum should be forward-compatible`() { - fun expectMatchExpressionCompiles(model: Model, shapeId: String, enumToMatchOn: String) { + fun expectMatchExpressionCompiles( + model: Model, + shapeId: String, + enumToMatchOn: String, + ) { val shape = model.lookup(shapeId) val context = testClientCodegenContext(model) val project = TestWorkspace.testProject(context.symbolProvider) @@ -40,7 +44,8 @@ class ClientEnumGeneratorTest { project.compileAndTest() } - val modelV1 = """ + val modelV1 = + """ namespace test @enum([ @@ -48,11 +53,12 @@ class ClientEnumGeneratorTest { { name: "Variant2", value: "Variant2" }, ]) string SomeEnum - """.asSmithyModel() + """.asSmithyModel() val variant3AsUnknown = """SomeEnum::from("Variant3")""" expectMatchExpressionCompiles(modelV1, "test#SomeEnum", variant3AsUnknown) - val modelV2 = """ + val modelV2 = + """ namespace test @enum([ @@ -61,21 +67,22 @@ class ClientEnumGeneratorTest { { name: "Variant3", value: "Variant3" }, ]) string SomeEnum - """.asSmithyModel() + """.asSmithyModel() val variant3AsVariant3 = "SomeEnum::Variant3" expectMatchExpressionCompiles(modelV2, "test#SomeEnum", variant3AsVariant3) } @Test fun `impl debug for non-sensitive enum should implement the derived debug trait`() { - val model = """ + val model = + """ namespace test @enum([ { name: "Foo", value: "Foo" }, { name: "Bar", value: "Bar" }, ]) string SomeEnum - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#SomeEnum") val context = testClientCodegenContext(model) @@ -99,7 +106,8 @@ class ClientEnumGeneratorTest { @Test fun `it escapes the Unknown variant if the enum has an unknown value in the model`() { - val model = """ + val model = + """ namespace test @enum([ { name: "Known", value: "Known" }, @@ -107,7 +115,7 @@ class ClientEnumGeneratorTest { { name: "UnknownValue", value: "UnknownValue" }, ]) string SomeEnum - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#SomeEnum") val context = testClientCodegenContext(model) @@ -131,14 +139,15 @@ class ClientEnumGeneratorTest { @Test fun `generated named enums can roundtrip between string and enum value on the unknown variant`() { - val model = """ + val model = + """ namespace test @enum([ { value: "t2.nano", name: "T2_NANO" }, { value: "t2.micro", name: "T2_MICRO" }, ]) string InstanceType - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#InstanceType") val context = testClientCodegenContext(model) diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientInstantiatorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientInstantiatorTest.kt index 49905fdeb9c..00fa942961d 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientInstantiatorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ClientInstantiatorTest.kt @@ -19,7 +19,8 @@ import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.lookup internal class ClientInstantiatorTest { - private val model = """ + private val model = + """ namespace com.test @enum([ @@ -39,7 +40,7 @@ internal class ClientInstantiatorTest { }, ]) string NamedEnum - """.asSmithyModel() + """.asSmithyModel() private val codegenContext = testClientCodegenContext(model) private val symbolProvider = codegenContext.symbolProvider diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGeneratorTest.kt index b60f99a67de..fb1130784d3 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ConfigOverrideRuntimePluginGeneratorTest.kt @@ -18,7 +18,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.tokioTest import software.amazon.smithy.rust.codegen.core.testutil.unitTest internal class ConfigOverrideRuntimePluginGeneratorTest { - private val model = """ + private val model = + """ namespace com.example use aws.protocols#awsJson1_0 @@ -33,20 +34,22 @@ internal class ConfigOverrideRuntimePluginGeneratorTest { structure TestInput { foo: String, } - """.asSmithyModel() + """.asSmithyModel() @Test fun `operation overrides endpoint resolver`() { clientIntegrationTest(model) { clientCodegenContext, rustCrate -> val runtimeConfig = clientCodegenContext.runtimeConfig - val codegenScope = arrayOf( - *preludeScope, - "EndpointResolverParams" to RuntimeType.smithyRuntimeApi(runtimeConfig) - .resolve("client::endpoint::EndpointResolverParams"), - "RuntimePlugin" to RuntimeType.runtimePlugin(runtimeConfig), - "RuntimeComponentsBuilder" to RuntimeType.runtimeComponentsBuilder(runtimeConfig), - "capture_request" to RuntimeType.captureRequest(runtimeConfig), - ) + val codegenScope = + arrayOf( + *preludeScope, + "EndpointResolverParams" to + RuntimeType.smithyRuntimeApi(runtimeConfig) + .resolve("client::endpoint::EndpointResolverParams"), + "RuntimePlugin" to RuntimeType.runtimePlugin(runtimeConfig), + "RuntimeComponentsBuilder" to RuntimeType.runtimeComponentsBuilder(runtimeConfig), + "capture_request" to RuntimeType.captureRequest(runtimeConfig), + ) rustCrate.testModule { addDependency(CargoDependency.Tokio.toDevDependency().withFeature("test-util")) tokioTest("test_operation_overrides_endpoint_resolver") { @@ -72,10 +75,11 @@ internal class ConfigOverrideRuntimePluginGeneratorTest { fun `operation overrides http connector`() { clientIntegrationTest(model) { clientCodegenContext, rustCrate -> val runtimeConfig = clientCodegenContext.runtimeConfig - val codegenScope = arrayOf( - *preludeScope, - "RuntimePlugin" to RuntimeType.runtimePlugin(runtimeConfig), - ) + val codegenScope = + arrayOf( + *preludeScope, + "RuntimePlugin" to RuntimeType.runtimePlugin(runtimeConfig), + ) rustCrate.testModule { addDependency(CargoDependency.Tokio.toDevDependency().withFeature("test-util")) tokioTest("test_operation_overrides_http_client") { @@ -130,11 +134,13 @@ internal class ConfigOverrideRuntimePluginGeneratorTest { *codegenScope, "AsyncSleep" to RuntimeType.smithyAsync(runtimeConfig).resolve("rt::sleep::AsyncSleep"), "capture_request" to RuntimeType.captureRequest(runtimeConfig), - "NeverClient" to CargoDependency.smithyRuntimeTestUtil(runtimeConfig).toType() - .resolve("client::http::test_util::NeverClient"), + "NeverClient" to + CargoDependency.smithyRuntimeTestUtil(runtimeConfig).toType() + .resolve("client::http::test_util::NeverClient"), "Timeout" to RuntimeType.smithyAsync(runtimeConfig).resolve("future::timeout::Timeout"), - "TokioSleep" to CargoDependency.smithyAsync(runtimeConfig).withFeature("rt-tokio") - .toType().resolve("rt::sleep::TokioSleep"), + "TokioSleep" to + CargoDependency.smithyAsync(runtimeConfig).withFeature("rt-tokio") + .toType().resolve("rt::sleep::TokioSleep"), ) } } @@ -145,30 +151,38 @@ internal class ConfigOverrideRuntimePluginGeneratorTest { fun `operation overrides retry config`() { clientIntegrationTest(model) { clientCodegenContext, rustCrate -> val runtimeConfig = clientCodegenContext.runtimeConfig - val codegenScope = arrayOf( - *preludeScope, - "AlwaysRetry" to RuntimeType.smithyRuntimeApi(runtimeConfig) - .resolve("client::retries::AlwaysRetry"), - "ConfigBag" to RuntimeType.smithyTypes(runtimeConfig).resolve("config_bag::ConfigBag"), - "ErrorKind" to RuntimeType.smithyTypes(runtimeConfig).resolve("retry::ErrorKind"), - "Input" to RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::interceptors::context::Input"), - "InterceptorContext" to RuntimeType.interceptorContext(runtimeConfig), - "Layer" to RuntimeType.smithyTypes(runtimeConfig).resolve("config_bag::Layer"), - "OrchestratorError" to RuntimeType.smithyRuntimeApi(runtimeConfig) - .resolve("client::orchestrator::OrchestratorError"), - "RetryConfig" to RuntimeType.smithyTypes(clientCodegenContext.runtimeConfig) - .resolve("retry::RetryConfig"), - "RequestAttempts" to smithyRuntimeApiTestUtil(runtimeConfig).toType() - .resolve("client::retries::RequestAttempts"), - "RetryClassifiers" to RuntimeType.smithyRuntimeApi(runtimeConfig) - .resolve("client::retries::RetryClassifiers"), - "RuntimeComponentsBuilder" to RuntimeType.runtimeComponentsBuilder(runtimeConfig), - "RuntimePlugin" to RuntimeType.runtimePlugin(runtimeConfig), - "StandardRetryStrategy" to RuntimeType.smithyRuntime(runtimeConfig) - .resolve("client::retries::strategy::StandardRetryStrategy"), - "ShouldAttempt" to RuntimeType.smithyRuntimeApi(runtimeConfig) - .resolve("client::retries::ShouldAttempt"), - ) + val codegenScope = + arrayOf( + *preludeScope, + "AlwaysRetry" to + RuntimeType.smithyRuntimeApi(runtimeConfig) + .resolve("client::retries::AlwaysRetry"), + "ConfigBag" to RuntimeType.smithyTypes(runtimeConfig).resolve("config_bag::ConfigBag"), + "ErrorKind" to RuntimeType.smithyTypes(runtimeConfig).resolve("retry::ErrorKind"), + "Input" to RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::interceptors::context::Input"), + "InterceptorContext" to RuntimeType.interceptorContext(runtimeConfig), + "Layer" to RuntimeType.smithyTypes(runtimeConfig).resolve("config_bag::Layer"), + "OrchestratorError" to + RuntimeType.smithyRuntimeApi(runtimeConfig) + .resolve("client::orchestrator::OrchestratorError"), + "RetryConfig" to + RuntimeType.smithyTypes(clientCodegenContext.runtimeConfig) + .resolve("retry::RetryConfig"), + "RequestAttempts" to + smithyRuntimeApiTestUtil(runtimeConfig).toType() + .resolve("client::retries::RequestAttempts"), + "RetryClassifiers" to + RuntimeType.smithyRuntimeApi(runtimeConfig) + .resolve("client::retries::RetryClassifiers"), + "RuntimeComponentsBuilder" to RuntimeType.runtimeComponentsBuilder(runtimeConfig), + "RuntimePlugin" to RuntimeType.runtimePlugin(runtimeConfig), + "StandardRetryStrategy" to + RuntimeType.smithyRuntime(runtimeConfig) + .resolve("client::retries::strategy::StandardRetryStrategy"), + "ShouldAttempt" to + RuntimeType.smithyRuntimeApi(runtimeConfig) + .resolve("client::retries::ShouldAttempt"), + ) rustCrate.testModule { unitTest("test_operation_overrides_retry_config") { rustTemplate( diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/EndpointTraitBindingsTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/EndpointTraitBindingsTest.kt index c645759040f..1b845677aca 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/EndpointTraitBindingsTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/EndpointTraitBindingsTest.kt @@ -37,7 +37,8 @@ internal class EndpointTraitBindingsTest { @Test fun `generate endpoint prefixes`() { - val model = """ + val model = + """ namespace test @readonly @endpoint(hostPrefix: "{foo}a.data.") @@ -49,16 +50,17 @@ internal class EndpointTraitBindingsTest { @hostLabel foo: String } - """.asSmithyModel() + """.asSmithyModel() val operationShape: OperationShape = model.lookup("test#GetStatus") val symbolProvider = testSymbolProvider(model) - val endpointBindingGenerator = EndpointTraitBindings( - model, - symbolProvider, - TestRuntimeConfig, - operationShape, - operationShape.expectTrait(EndpointTrait::class.java), - ) + val endpointBindingGenerator = + EndpointTraitBindings( + model, + symbolProvider, + TestRuntimeConfig, + operationShape, + operationShape.expectTrait(EndpointTrait::class.java), + ) val project = TestWorkspace.testProject() project.withModule(RustModule.private("test")) { rust( @@ -70,8 +72,9 @@ internal class EndpointTraitBindingsTest { ) implBlock(symbolProvider.toSymbol(model.lookup("test#GetStatusInput"))) { rustBlockTemplate( - "fn endpoint_prefix(&self) -> std::result::Result<#{endpoint}::EndpointPrefix, #{endpoint}::error::InvalidEndpointError>", - "endpoint" to RuntimeType.smithyHttp(TestRuntimeConfig).resolve("endpoint"), + "fn endpoint_prefix(&self) -> std::result::Result<#{EndpointPrefix}, #{InvalidEndpointError}>", + "EndpointPrefix" to RuntimeType.smithyRuntimeApiClient(TestRuntimeConfig).resolve("client::endpoint::EndpointPrefix"), + "InvalidEndpointError" to RuntimeType.smithyRuntimeApiClient(TestRuntimeConfig).resolve("client::endpoint::error::InvalidEndpointError"), ) { endpointBindingGenerator.render(this, "self") } @@ -118,7 +121,8 @@ internal class EndpointTraitBindingsTest { @ExperimentalPathApi @Test fun `endpoint integration test`() { - val model = """ + val model = + """ namespace com.example use aws.protocols#awsJson1_0 use smithy.rules#endpointRuleSet @@ -150,7 +154,7 @@ internal class EndpointTraitBindingsTest { @hostLabel greeting: String } - """.asSmithyModel() + """.asSmithyModel() clientIntegrationTest(model) { clientCodegenContext, rustCrate -> val moduleName = clientCodegenContext.moduleUseName() rustCrate.integrationTest("test_endpoint_prefix") { @@ -159,8 +163,8 @@ internal class EndpointTraitBindingsTest { """ async fn test_endpoint_prefix() { use #{capture_request}; - use aws_smithy_http::endpoint::EndpointPrefix; use aws_smithy_runtime_api::box_error::BoxError; + use aws_smithy_runtime_api::client::endpoint::EndpointPrefix; use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents; use aws_smithy_types::body::SdkBody; use aws_smithy_types::config_bag::ConfigBag; @@ -244,8 +248,9 @@ internal class EndpointTraitBindingsTest { ); } """, - "capture_request" to CargoDependency.smithyRuntimeTestUtil(clientCodegenContext.runtimeConfig) - .toType().resolve("client::http::test_util::capture_request"), + "capture_request" to + CargoDependency.smithyRuntimeTestUtil(clientCodegenContext.runtimeConfig) + .toType().resolve("client::http::test_util::capture_request"), ) } } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ErrorCorrectionTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ErrorCorrectionTest.kt index 69691b476e5..5f0baf7816f 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ErrorCorrectionTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ErrorCorrectionTest.kt @@ -13,7 +13,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.unitTest import software.amazon.smithy.rust.codegen.core.util.lookup class ErrorCorrectionTest { - private val model = """ + private val model = + """ namespace com.example use aws.protocols#awsJson1_0 @@ -78,7 +79,7 @@ class ErrorCorrectionTest { key: String, value: StringList } - """.asSmithyModel(smithyVersion = "2.0") + """.asSmithyModel(smithyVersion = "2.0") @Test fun correctMissingFields() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGeneratorTest.kt index 4b3d7f3a5f7..8c8a4784e68 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/PaginatorGeneratorTest.kt @@ -13,7 +13,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.integrationTest internal class PaginatorGeneratorTest { - private val model = """ + private val model = + """ namespace test use aws.protocols#awsJson1_1 @@ -67,7 +68,7 @@ internal class PaginatorGeneratorTest { key: String, value: Integer } - """.asSmithyModel() + """.asSmithyModel() @Test fun `generate paginators that compile`() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/SensitiveIndexTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/SensitiveIndexTest.kt index cecf4235885..7cc3f01016e 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/SensitiveIndexTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/SensitiveIndexTest.kt @@ -11,7 +11,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.util.lookup class SensitiveIndexTest { - val model = """ + val model = + """ namespace com.example service TestService { operations: [ @@ -58,7 +59,7 @@ class SensitiveIndexTest { structure Inner { credentials: Credentials } - """.asSmithyModel(smithyVersion = "2.0") + """.asSmithyModel(smithyVersion = "2.0") @Test fun `correctly identify operations`() { @@ -66,13 +67,14 @@ class SensitiveIndexTest { data class TestCase(val shape: String, val sensitiveInput: Boolean, val sensitiveOutput: Boolean) - val testCases = listOf( - TestCase("NotSensitive", sensitiveInput = false, sensitiveOutput = false), - TestCase("SensitiveInput", sensitiveInput = true, sensitiveOutput = false), - TestCase("SensitiveOutput", sensitiveInput = false, sensitiveOutput = true), - TestCase("NestedSensitiveInput", sensitiveInput = true, sensitiveOutput = false), - TestCase("NestedSensitiveOutput", sensitiveInput = false, sensitiveOutput = true), - ) + val testCases = + listOf( + TestCase("NotSensitive", sensitiveInput = false, sensitiveOutput = false), + TestCase("SensitiveInput", sensitiveInput = true, sensitiveOutput = false), + TestCase("SensitiveOutput", sensitiveInput = false, sensitiveOutput = true), + TestCase("NestedSensitiveInput", sensitiveInput = true, sensitiveOutput = false), + TestCase("NestedSensitiveOutput", sensitiveInput = false, sensitiveOutput = true), + ) testCases.forEach { tc -> assertEquals(tc.sensitiveInput, index.hasSensitiveInput(model.lookup("com.example#${tc.shape}")), "input: $tc") assertEquals(tc.sensitiveOutput, index.hasSensitiveOutput(model.lookup("com.example#${tc.shape}")), "output: $tc ") diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGeneratorTest.kt index c14d6b21fbe..30090104f9e 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/CustomizableOperationGeneratorTest.kt @@ -15,7 +15,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.integrationTest class CustomizableOperationGeneratorTest { - val model = """ + val model = + """ namespace com.example use aws.protocols#awsJson1_0 @@ -30,7 +31,7 @@ class CustomizableOperationGeneratorTest { structure TestInput { foo: String, } - """.asSmithyModel() + """.asSmithyModel() @Test fun `CustomizableOperation is send and sync`() { @@ -51,8 +52,9 @@ class CustomizableOperationGeneratorTest { check_send_and_sync(client.say_hello().customize()); } """, - "NeverClient" to CargoDependency.smithyRuntimeTestUtil(codegenContext.runtimeConfig).toType() - .resolve("client::http::test_util::NeverClient"), + "NeverClient" to + CargoDependency.smithyRuntimeTestUtil(codegenContext.runtimeConfig).toType() + .resolve("client::http::test_util::NeverClient"), ) } } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGeneratorTest.kt index f36c0dbfdcc..b300dfa8c2f 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/client/FluentClientGeneratorTest.kt @@ -17,7 +17,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.integrationTest import software.amazon.smithy.rust.codegen.core.util.lookup class FluentClientGeneratorTest { - val model = """ + val model = + """ namespace com.example use aws.protocols#awsJson1_0 @@ -49,16 +50,17 @@ class FluentClientGeneratorTest { key: String, value: StringList } - """.asSmithyModel() + """.asSmithyModel() @Test fun `generate correct input docs`() { - val expectations = mapOf( - "listValue" to "list_value(impl Into)", - "doubleListValue" to "double_list_value(Vec::)", - "mapValue" to "map_value(impl Into, Vec::)", - "byteValue" to "byte_value(i8)", - ) + val expectations = + mapOf( + "listValue" to "list_value(impl Into)", + "doubleListValue" to "double_list_value(Vec::)", + "mapValue" to "map_value(impl Into, Vec::)", + "byteValue" to "byte_value(i8)", + ) expectations.forEach { (name, expect) -> val member = model.lookup("com.example#TestInput\$$name") member.asFluentBuilderInputDoc(testSymbolProvider(model)) shouldBe expect @@ -84,8 +86,9 @@ class FluentClientGeneratorTest { check_send(client.say_hello().send()); } """, - "NeverClient" to CargoDependency.smithyRuntimeTestUtil(codegenContext.runtimeConfig).toType() - .resolve("client::http::test_util::NeverClient"), + "NeverClient" to + CargoDependency.smithyRuntimeTestUtil(codegenContext.runtimeConfig).toType() + .resolve("client::http::test_util::NeverClient"), ) } } @@ -112,8 +115,9 @@ class FluentClientGeneratorTest { assert_eq!(*input.get_byte_value(), Some(4)); } """, - "NeverClient" to CargoDependency.smithyRuntimeTestUtil(codegenContext.runtimeConfig).toType() - .resolve("client::http::test_util::NeverClient"), + "NeverClient" to + CargoDependency.smithyRuntimeTestUtil(codegenContext.runtimeConfig).toType() + .resolve("client::http::test_util::NeverClient"), ) } } @@ -121,7 +125,8 @@ class FluentClientGeneratorTest { @Test fun `dead-code warning should not be issued when a service has no operations`() { - val model = """ + val model = + """ namespace com.example use aws.protocols#awsJson1_0 @@ -129,7 +134,7 @@ class FluentClientGeneratorTest { service HelloService { version: "1" } - """.asSmithyModel() + """.asSmithyModel() clientIntegrationTest(model) } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGeneratorTest.kt index 7cdd0f7b890..4e9e88f414e 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGeneratorTest.kt @@ -26,7 +26,8 @@ import software.amazon.smithy.rust.codegen.core.util.toPascalCase internal class ServiceConfigGeneratorTest { @Test fun `idempotency token when used`() { - fun model(trait: String) = """ + fun model(trait: String) = + """ namespace com.example use aws.protocols#restJson1 @@ -47,7 +48,7 @@ internal class ServiceConfigGeneratorTest { $trait tok: String } - """.asSmithyModel() + """.asSmithyModel() val withToken = model("@idempotencyToken") val withoutToken = model("") @@ -57,7 +58,8 @@ internal class ServiceConfigGeneratorTest { @Test fun `find idempotency token via resources`() { - val model = """ + val model = + """ namespace com.example service ResourceService { resources: [Resource], @@ -75,7 +77,7 @@ internal class ServiceConfigGeneratorTest { @idempotencyToken tok: String } - """.asSmithyModel() + """.asSmithyModel() model.lookup("com.example#ResourceService").needsIdempotencyToken(model) shouldBe true } @@ -83,57 +85,62 @@ internal class ServiceConfigGeneratorTest { fun `generate customizations as specified`() { class ServiceCustomizer(private val codegenContext: ClientCodegenContext) : NamedCustomization() { - override fun section(section: ServiceConfig): Writable { return when (section) { ServiceConfig.ConfigStructAdditionalDocs -> emptySection - ServiceConfig.ConfigImpl -> writable { - rustTemplate( - """ - ##[allow(missing_docs)] - pub fn config_field(&self) -> u64 { - self.config.load::<#{T}>().map(|u| u.0).unwrap() - } - """, - "T" to configParamNewtype( - "config_field".toPascalCase(), RuntimeType.U64.toSymbol(), - codegenContext.runtimeConfig, - ), - ) - } + ServiceConfig.ConfigImpl -> + writable { + rustTemplate( + """ + ##[allow(missing_docs)] + pub fn config_field(&self) -> u64 { + self.config.load::<#{T}>().map(|u| u.0).unwrap() + } + """, + "T" to + configParamNewtype( + "config_field".toPascalCase(), RuntimeType.U64.toSymbol(), + codegenContext.runtimeConfig, + ), + ) + } - ServiceConfig.BuilderImpl -> writable { - rustTemplate( - """ - ##[allow(missing_docs)] - pub fn config_field(mut self, config_field: u64) -> Self { - self.config.store_put(#{T}(config_field)); - self - } - """, - "T" to configParamNewtype( - "config_field".toPascalCase(), RuntimeType.U64.toSymbol(), - codegenContext.runtimeConfig, - ), - ) - } + ServiceConfig.BuilderImpl -> + writable { + rustTemplate( + """ + ##[allow(missing_docs)] + pub fn config_field(mut self, config_field: u64) -> Self { + self.config.store_put(#{T}(config_field)); + self + } + """, + "T" to + configParamNewtype( + "config_field".toPascalCase(), RuntimeType.U64.toSymbol(), + codegenContext.runtimeConfig, + ), + ) + } else -> emptySection } } } - val serviceDecorator = object : ClientCodegenDecorator { - override val name: String = "Add service plugin" - override val order: Byte = 0 - override fun configCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List { - return baseCustomizations + ServiceCustomizer(codegenContext) + val serviceDecorator = + object : ClientCodegenDecorator { + override val name: String = "Add service plugin" + override val order: Byte = 0 + + override fun configCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List { + return baseCustomizations + ServiceCustomizer(codegenContext) + } } - } clientIntegrationTest(BasicTestModels.AwsJson10TestModel, additionalDecorators = listOf(serviceDecorator)) { ctx, rustCrate -> rustCrate.withModule(ClientRustModule.config) { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/OperationErrorGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/OperationErrorGeneratorTest.kt index 1f1b7032411..656eb80acfa 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/OperationErrorGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/OperationErrorGeneratorTest.kt @@ -13,7 +13,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.unitTest import software.amazon.smithy.rust.codegen.core.util.lookup class OperationErrorGeneratorTest { - private val model = """ + private val model = + """ namespace error @aws.protocols#awsJson1_0 @@ -43,7 +44,7 @@ class OperationErrorGeneratorTest { @error("server") @deprecated structure Deprecated { } - """.asSmithyModel() + """.asSmithyModel() @Test fun `generates combined error enums`() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/ServiceErrorGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/ServiceErrorGeneratorTest.kt index a8ce5b832a0..a88079eee68 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/ServiceErrorGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/error/ServiceErrorGeneratorTest.kt @@ -15,7 +15,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.unitTest import software.amazon.smithy.rust.codegen.core.util.lookup internal class ServiceErrorGeneratorTest { - private val model = """ + private val model = + """ namespace com.example use aws.protocols#restJson1 @@ -44,7 +45,7 @@ internal class ServiceErrorGeneratorTest { @error("client") @deprecated structure MeDeprecated { } - """.asSmithyModel() + """.asSmithyModel() @Test fun `top level errors are send + sync`() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGeneratorTest.kt index a769504f134..c05b65b0cba 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/RequestBindingGeneratorTest.kt @@ -30,7 +30,8 @@ import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.expectTrait class RequestBindingGeneratorTest { - private val baseModel = """ + private val baseModel = + """ namespace smithy.example @idempotent @@ -120,7 +121,7 @@ class RequestBindingGeneratorTest { @sensitive string SensitiveStringHeader - """.asSmithyModel() + """.asSmithyModel() private val model = OperationNormalizer.transform(baseModel) private val symbolProvider = testSymbolProvider(model) private val operationShape = model.expectShape(ShapeId.from("smithy.example#PutObject"), OperationShape::class.java) @@ -131,12 +132,13 @@ class RequestBindingGeneratorTest { inputShape.renderWithModelBuilder(model, symbolProvider, rustCrate) rustCrate.withModule(operationModule) { val codegenContext = testClientCodegenContext(model) - val bindingGen = RequestBindingGenerator( - codegenContext, - // Any protocol is fine for this test. - RestJson(codegenContext), - operationShape, - ) + val bindingGen = + RequestBindingGenerator( + codegenContext, + // Any protocol is fine for this test. + RestJson(codegenContext), + operationShape, + ) rustBlock("impl PutObjectInput") { // RequestBindingGenerator's functions expect to be rendered inside a function, // but the unit test needs to call some of these functions individually. This generates diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/ResponseBindingGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/ResponseBindingGeneratorTest.kt index b02e6879b6d..e0a9f063470 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/ResponseBindingGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/http/ResponseBindingGeneratorTest.kt @@ -27,7 +27,8 @@ import software.amazon.smithy.rust.codegen.core.util.lookup import software.amazon.smithy.rust.codegen.core.util.outputShape class ResponseBindingGeneratorTest { - private val baseModel = """ + private val baseModel = + """ namespace smithy.example @idempotent @@ -64,7 +65,7 @@ class ResponseBindingGeneratorTest { // Sent in the body additional: String, } - """.asSmithyModel() + """.asSmithyModel() private val model = OperationNormalizer.transform(baseModel) private val operationShape: OperationShape = model.lookup("smithy.example#PutObject") private val outputShape: StructureShape = operationShape.outputShape(model) @@ -75,15 +76,17 @@ class ResponseBindingGeneratorTest { operationShape.outputShape(model).renderWithModelBuilder(model, symbolProvider, this) withModule(symbolProvider.moduleForShape(outputShape)) { rustBlock("impl PutObjectOutput") { - val bindings = HttpTraitHttpBindingResolver(model, ProtocolContentTypes.consistent("dont-care")) - .responseBindings(operationShape) - .filter { it.location == HttpLocation.HEADER } + val bindings = + HttpTraitHttpBindingResolver(model, ProtocolContentTypes.consistent("dont-care")) + .responseBindings(operationShape) + .filter { it.location == HttpLocation.HEADER } bindings.forEach { binding -> - val runtimeType = ResponseBindingGenerator( - RestJson(codegenContext), - codegenContext, - operationShape, - ).generateDeserializeHeaderFn(binding) + val runtimeType = + ResponseBindingGenerator( + RestJson(codegenContext), + codegenContext, + operationShape, + ).generateDeserializeHeaderFn(binding) // little hack to force these functions to be generated rust("// use #T;", runtimeType) } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolParserGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolParserGeneratorTest.kt index 760eced3874..86b2cacfc06 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolParserGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolParserGeneratorTest.kt @@ -10,19 +10,20 @@ import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel class ProtocolParserGeneratorTest { - private val model = """ + private val model = + """ ${'$'}version: "2.0" namespace test - + use aws.protocols#restJson1 - + @restJson1 service TestService { version: "2019-12-16", operations: [SomeOperation] errors: [SomeTopLevelError] } - + @http(uri: "/SomeOperation", method: "POST") operation SomeOperation { input: SomeOperationInputOutput, @@ -35,7 +36,7 @@ class ProtocolParserGeneratorTest { a: String, b: Integer } - + @error("server") structure SomeTopLevelError { @required @@ -48,7 +49,7 @@ class ProtocolParserGeneratorTest { context: String } - + @error("client") structure SomeOperationError { @required @@ -61,8 +62,8 @@ class ProtocolParserGeneratorTest { context: String } - """ - .asSmithyModel() + """ + .asSmithyModel() @Test fun `generate an complex error structure that compiles`() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGeneratorTest.kt index 401e7b8007f..83a6f52e9ae 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGeneratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/protocol/ProtocolTestGeneratorTest.kt @@ -31,97 +31,100 @@ private class TestServiceRuntimePluginCustomization( private val fakeRequestBuilder: String, private val fakeRequestBody: String, ) : ServiceRuntimePluginCustomization() { - override fun section(section: ServiceRuntimePluginSection): Writable = writable { - if (section is ServiceRuntimePluginSection.RegisterRuntimeComponents) { - val rc = context.runtimeConfig - section.registerInterceptor(this) { - rustTemplate( - """ - { - ##[derive(::std::fmt::Debug)] - struct TestInterceptor; - impl #{Intercept} for TestInterceptor { - fn name(&self) -> &'static str { - "TestInterceptor" - } + override fun section(section: ServiceRuntimePluginSection): Writable = + writable { + if (section is ServiceRuntimePluginSection.RegisterRuntimeComponents) { + val rc = context.runtimeConfig + section.registerInterceptor(this) { + rustTemplate( + """ + { + ##[derive(::std::fmt::Debug)] + struct TestInterceptor; + impl #{Intercept} for TestInterceptor { + fn name(&self) -> &'static str { + "TestInterceptor" + } - fn modify_before_retry_loop( - &self, - context: &mut #{BeforeTransmitInterceptorContextMut}<'_>, - _rc: &#{RuntimeComponents}, - _cfg: &mut #{ConfigBag}, - ) -> #{Result}<(), #{BoxError}> { - // Replace the serialized request - let mut fake_req = ::http::Request::builder() - $fakeRequestBuilder - .body(#{SdkBody}::from($fakeRequestBody)) - .expect("valid request").try_into().unwrap(); - ::std::mem::swap( - context.request_mut(), - &mut fake_req, - ); - Ok(()) + fn modify_before_retry_loop( + &self, + context: &mut #{BeforeTransmitInterceptorContextMut}<'_>, + _rc: &#{RuntimeComponents}, + _cfg: &mut #{ConfigBag}, + ) -> #{Result}<(), #{BoxError}> { + // Replace the serialized request + let mut fake_req = ::http::Request::builder() + $fakeRequestBuilder + .body(#{SdkBody}::from($fakeRequestBody)) + .expect("valid request").try_into().unwrap(); + ::std::mem::swap( + context.request_mut(), + &mut fake_req, + ); + Ok(()) + } } - } - TestInterceptor - } - """, - *preludeScope, - "BeforeTransmitInterceptorContextMut" to RT.beforeTransmitInterceptorContextMut(rc), - "BoxError" to RT.boxError(rc), - "ConfigBag" to RT.configBag(rc), - "Intercept" to RT.intercept(rc), - "RuntimeComponents" to RT.runtimeComponents(rc), - "SdkBody" to RT.sdkBody(rc), - ) + TestInterceptor + } + """, + *preludeScope, + "BeforeTransmitInterceptorContextMut" to RT.beforeTransmitInterceptorContextMut(rc), + "BoxError" to RT.boxError(rc), + "ConfigBag" to RT.configBag(rc), + "Intercept" to RT.intercept(rc), + "RuntimeComponents" to RT.runtimeComponents(rc), + "SdkBody" to RT.sdkBody(rc), + ) + } } } - } } private class TestOperationCustomization( private val context: ClientCodegenContext, private val fakeOutput: String, ) : OperationCustomization() { - override fun section(section: OperationSection): Writable = writable { - val rc = context.runtimeConfig - if (section is OperationSection.AdditionalRuntimePluginConfig) { - rustTemplate( - """ - // Override the default response deserializer with our fake output - ##[derive(::std::fmt::Debug)] - struct TestDeser; - impl #{DeserializeResponse} for TestDeser { - fn deserialize_nonstreaming( - &self, - _response: &#{HttpResponse}, - ) -> #{Result}<#{Output}, #{OrchestratorError}<#{Error}>> { - let fake_out: #{Result}< - crate::operation::say_hello::SayHelloOutput, - crate::operation::say_hello::SayHelloError, - > = $fakeOutput; - fake_out - .map(|o| #{Output}::erase(o)) - .map_err(|e| #{OrchestratorError}::operation(#{Error}::erase(e))) + override fun section(section: OperationSection): Writable = + writable { + val rc = context.runtimeConfig + if (section is OperationSection.AdditionalRuntimePluginConfig) { + rustTemplate( + """ + // Override the default response deserializer with our fake output + ##[derive(::std::fmt::Debug)] + struct TestDeser; + impl #{DeserializeResponse} for TestDeser { + fn deserialize_nonstreaming( + &self, + _response: &#{HttpResponse}, + ) -> #{Result}<#{Output}, #{OrchestratorError}<#{Error}>> { + let fake_out: #{Result}< + crate::operation::say_hello::SayHelloOutput, + crate::operation::say_hello::SayHelloError, + > = $fakeOutput; + fake_out + .map(|o| #{Output}::erase(o)) + .map_err(|e| #{OrchestratorError}::operation(#{Error}::erase(e))) + } } - } - cfg.store_put(#{SharedResponseDeserializer}::new(TestDeser)); - """, - *preludeScope, - "SharedResponseDeserializer" to RT.smithyRuntimeApi(rc).resolve("client::ser_de::SharedResponseDeserializer"), - "Error" to RT.smithyRuntimeApi(rc).resolve("client::interceptors::context::Error"), - "HttpResponse" to RT.smithyRuntimeApi(rc).resolve("client::orchestrator::HttpResponse"), - "OrchestratorError" to RT.smithyRuntimeApi(rc).resolve("client::orchestrator::OrchestratorError"), - "Output" to RT.smithyRuntimeApi(rc).resolve("client::interceptors::context::Output"), - "DeserializeResponse" to RT.smithyRuntimeApi(rc).resolve("client::ser_de::DeserializeResponse"), - ) + cfg.store_put(#{SharedResponseDeserializer}::new(TestDeser)); + """, + *preludeScope, + "SharedResponseDeserializer" to RT.smithyRuntimeApi(rc).resolve("client::ser_de::SharedResponseDeserializer"), + "Error" to RT.smithyRuntimeApi(rc).resolve("client::interceptors::context::Error"), + "HttpResponse" to RT.smithyRuntimeApi(rc).resolve("client::orchestrator::HttpResponse"), + "OrchestratorError" to RT.smithyRuntimeApi(rc).resolve("client::orchestrator::OrchestratorError"), + "Output" to RT.smithyRuntimeApi(rc).resolve("client::interceptors::context::Output"), + "DeserializeResponse" to RT.smithyRuntimeApi(rc).resolve("client::ser_de::DeserializeResponse"), + ) + } } - } } class ProtocolTestGeneratorTest { - private val model = """ + private val model = + """ namespace com.example use aws.protocols#restJson1 @@ -194,7 +197,7 @@ class ProtocolTestGeneratorTest { name: String } - """.asSmithyModel() + """.asSmithyModel() private val correctBody = """{"name": "Teddy"}""" /** @@ -207,26 +210,31 @@ class ProtocolTestGeneratorTest { fakeRequestBody: String = "${correctBody.dq()}.to_string()", fakeOutput: String = """Ok(crate::operation::say_hello::SayHelloOutput::builder().value("hey there!").build())""", ): Path { - val codegenDecorator = object : ClientCodegenDecorator { - override val name: String = "mock" - override val order: Byte = 0 - override fun classpathDiscoverable(): Boolean = false - - override fun serviceRuntimePluginCustomizations( - codegenContext: ClientCodegenContext, - baseCustomizations: List, - ): List = baseCustomizations + TestServiceRuntimePluginCustomization( - codegenContext, - fakeRequestBuilder, - fakeRequestBody, - ) - - override fun operationCustomizations( - codegenContext: ClientCodegenContext, - operation: OperationShape, - baseCustomizations: List, - ): List = baseCustomizations + TestOperationCustomization(codegenContext, fakeOutput) - } + val codegenDecorator = + object : ClientCodegenDecorator { + override val name: String = "mock" + override val order: Byte = 0 + + override fun classpathDiscoverable(): Boolean = false + + override fun serviceRuntimePluginCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = + baseCustomizations + + TestServiceRuntimePluginCustomization( + codegenContext, + fakeRequestBuilder, + fakeRequestBody, + ) + + override fun operationCustomizations( + codegenContext: ClientCodegenContext, + operation: OperationShape, + baseCustomizations: List, + ): List = + baseCustomizations + TestOperationCustomization(codegenContext, fakeOutput) + } return clientIntegrationTest( model, additionalDecorators = listOf(codegenDecorator), @@ -246,32 +254,34 @@ class ProtocolTestGeneratorTest { @Test fun `test incorrect response parsing`() { - val err = assertThrows { - testService( - """ - .uri("/?Hi=Hello%20there&required") - .header("X-Greeting", "Hi") - .method("POST") - """, - fakeOutput = "Ok(crate::operation::say_hello::SayHelloOutput::builder().build())", - ) - } + val err = + assertThrows { + testService( + """ + .uri("/?Hi=Hello%20there&required") + .header("X-Greeting", "Hi") + .method("POST") + """, + fakeOutput = "Ok(crate::operation::say_hello::SayHelloOutput::builder().build())", + ) + } err.message shouldContain "basic_response_test_response ... FAILED" } @Test fun `test invalid body`() { - val err = assertThrows { - testService( - """ - .uri("/?Hi=Hello%20there&required") - .header("X-Greeting", "Hi") - .method("POST") - """, - """"{}".to_string()""", - ) - } + val err = + assertThrows { + testService( + """ + .uri("/?Hi=Hello%20there&required") + .header("X-Greeting", "Hi") + .method("POST") + """, + """"{}".to_string()""", + ) + } err.message shouldContain "say_hello_request ... FAILED" err.message shouldContain "body did not match" @@ -279,15 +289,16 @@ class ProtocolTestGeneratorTest { @Test fun `test invalid url parameter`() { - val err = assertThrows { - testService( - """ - .uri("/?Hi=INCORRECT&required") - .header("X-Greeting", "Hi") - .method("POST") - """, - ) - } + val err = + assertThrows { + testService( + """ + .uri("/?Hi=INCORRECT&required") + .header("X-Greeting", "Hi") + .method("POST") + """, + ) + } // Verify the test actually ran err.message shouldContain "say_hello_request ... FAILED" err.message shouldContain "missing query param" @@ -295,15 +306,16 @@ class ProtocolTestGeneratorTest { @Test fun `test forbidden url parameter`() { - val err = assertThrows { - testService( - """ - .uri("/?goodbye&Hi=Hello%20there&required") - .header("X-Greeting", "Hi") - .method("POST") - """, - ) - } + val err = + assertThrows { + testService( + """ + .uri("/?goodbye&Hi=Hello%20there&required") + .header("X-Greeting", "Hi") + .method("POST") + """, + ) + } // Verify the test actually ran err.message shouldContain "say_hello_request ... FAILED" err.message shouldContain "forbidden query param" @@ -312,15 +324,16 @@ class ProtocolTestGeneratorTest { @Test fun `test required url parameter`() { // Hard coded implementation for this 1 test - val err = assertThrows { - testService( - """ - .uri("/?Hi=Hello%20there") - .header("X-Greeting", "Hi") - .method("POST") - """, - ) - } + val err = + assertThrows { + testService( + """ + .uri("/?Hi=Hello%20there") + .header("X-Greeting", "Hi") + .method("POST") + """, + ) + } // Verify the test actually ran err.message shouldContain "say_hello_request ... FAILED" @@ -329,15 +342,16 @@ class ProtocolTestGeneratorTest { @Test fun `test invalid path`() { - val err = assertThrows { - testService( - """ - .uri("/incorrect-path?required&Hi=Hello%20there") - .header("X-Greeting", "Hi") - .method("POST") - """, - ) - } + val err = + assertThrows { + testService( + """ + .uri("/incorrect-path?required&Hi=Hello%20there") + .header("X-Greeting", "Hi") + .method("POST") + """, + ) + } // Verify the test actually ran err.message shouldContain "say_hello_request ... FAILED" @@ -346,16 +360,17 @@ class ProtocolTestGeneratorTest { @Test fun `invalid header`() { - val err = assertThrows { - testService( - """ - .uri("/?Hi=Hello%20there&required") - // should be "Hi" - .header("X-Greeting", "Hey") - .method("POST") - """, - ) - } + val err = + assertThrows { + testService( + """ + .uri("/?Hi=Hello%20there&required") + // should be "Hi" + .header("X-Greeting", "Hey") + .method("POST") + """, + ) + } err.message shouldContain "say_hello_request ... FAILED" err.message shouldContain "invalid header value" diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/AwsQueryCompatibleTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/AwsQueryCompatibleTest.kt index 706e7b81c01..dcb322b4472 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/AwsQueryCompatibleTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/AwsQueryCompatibleTest.kt @@ -16,7 +16,8 @@ import software.amazon.smithy.rust.codegen.core.util.lookup class AwsQueryCompatibleTest { @Test fun `aws-query-compatible json with aws query error should allow for retrieving error code and type from custom header`() { - val model = """ + val model = + """ namespace test use aws.protocols#awsJson1_0 use aws.protocols#awsQueryCompatible @@ -48,7 +49,7 @@ class AwsQueryCompatibleTest { structure InvalidThingException { message: String } - """.asSmithyModel() + """.asSmithyModel() clientIntegrationTest(model) { context, rustCrate -> val operation: OperationShape = context.model.lookup("test#SomeOperation") @@ -91,8 +92,9 @@ class AwsQueryCompatibleTest { assert_eq!(Some("Sender"), error.meta().extra("type")); } """, - "infallible_client_fn" to CargoDependency.smithyRuntimeTestUtil(context.runtimeConfig) - .toType().resolve("client::http::test_util::infallible_client_fn"), + "infallible_client_fn" to + CargoDependency.smithyRuntimeTestUtil(context.runtimeConfig) + .toType().resolve("client::http::test_util::infallible_client_fn"), "tokio" to CargoDependency.Tokio.toType(), ) } @@ -101,7 +103,8 @@ class AwsQueryCompatibleTest { @Test fun `aws-query-compatible json without aws query error should allow for retrieving error code from payload`() { - val model = """ + val model = + """ namespace test use aws.protocols#awsJson1_0 use aws.protocols#awsQueryCompatible @@ -128,7 +131,7 @@ class AwsQueryCompatibleTest { structure InvalidThingException { message: String } - """.asSmithyModel() + """.asSmithyModel() clientIntegrationTest(model) { context, rustCrate -> val operation: OperationShape = context.model.lookup("test#SomeOperation") @@ -164,8 +167,9 @@ class AwsQueryCompatibleTest { assert_eq!(None, error.meta().extra("type")); } """, - "infallible_client_fn" to CargoDependency.smithyRuntimeTestUtil(context.runtimeConfig) - .toType().resolve("client::http::test_util::infallible_client_fn"), + "infallible_client_fn" to + CargoDependency.smithyRuntimeTestUtil(context.runtimeConfig) + .toType().resolve("client::http::test_util::infallible_client_fn"), "tokio" to CargoDependency.Tokio.toType(), ) } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/AwsQueryTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/AwsQueryTest.kt index 0e5f22ec70e..9f811158951 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/AwsQueryTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/AwsQueryTest.kt @@ -10,7 +10,8 @@ import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel class AwsQueryTest { - private val model = """ + private val model = + """ namespace test use aws.protocols#awsQuery @@ -31,7 +32,7 @@ class AwsQueryTest { a: String, b: Integer } - """.asSmithyModel() + """.asSmithyModel() @Test fun `generate an aws query service that compiles`() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/Ec2QueryTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/Ec2QueryTest.kt index 13779ca09f5..9a258254ab9 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/Ec2QueryTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/Ec2QueryTest.kt @@ -10,7 +10,8 @@ import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel class Ec2QueryTest { - private val model = """ + private val model = + """ namespace test use aws.protocols#ec2Query @@ -31,7 +32,7 @@ class Ec2QueryTest { a: String, b: Integer } - """.asSmithyModel() + """.asSmithyModel() @Test fun `generate an aws query service that compiles`() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/RestJsonTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/RestJsonTest.kt index 99a6b3a01c1..200019adb12 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/RestJsonTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/RestJsonTest.kt @@ -10,7 +10,8 @@ import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel internal class RestJsonTest { - val model = """ + val model = + """ namespace test use aws.protocols#restJson1 use aws.api#service @@ -36,7 +37,7 @@ internal class RestJsonTest { a: String, b: Integer } - """.asSmithyModel() + """.asSmithyModel() @Test fun `generate a rest json service that compiles`() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/RestXmlTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/RestXmlTest.kt index aad9e1d17f4..279bf964edd 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/RestXmlTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/protocols/RestXmlTest.kt @@ -10,8 +10,8 @@ import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel internal class RestXmlTest { - - private val model = """ + private val model = + """ namespace test use aws.protocols#restXml use aws.api#service @@ -81,7 +81,7 @@ internal class RestXmlTest { renamedWithPrefix: String } - """.asSmithyModel() + """.asSmithyModel() @Test fun `generate a rest xml service that compiles`() { diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/transformers/RemoveEventStreamOperationsTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/transformers/RemoveEventStreamOperationsTest.kt index 4cc9c594aaa..2396689b3af 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/transformers/RemoveEventStreamOperationsTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/transformers/RemoveEventStreamOperationsTest.kt @@ -16,7 +16,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import java.util.Optional internal class RemoveEventStreamOperationsTest { - private val model = """ + private val model = + """ namespace test operation EventStream { input: StreamingInput, @@ -43,28 +44,30 @@ internal class RemoveEventStreamOperationsTest { } structure Foo {} - """.asSmithyModel() + """.asSmithyModel() @Test fun `remove event stream ops from services that are not in the allow list`() { - val transformed = RemoveEventStreamOperations.transform( - model, - testClientRustSettings( - codegenConfig = ClientCodegenConfig(eventStreamAllowList = setOf("not-test-module")), - ), - ) + val transformed = + RemoveEventStreamOperations.transform( + model, + testClientRustSettings( + codegenConfig = ClientCodegenConfig(eventStreamAllowList = setOf("not-test-module")), + ), + ) transformed.expectShape(ShapeId.from("test#BlobStream")) transformed.getShape(ShapeId.from("test#EventStream")) shouldBe Optional.empty() } @Test fun `keep event stream ops from services that are in the allow list`() { - val transformed = RemoveEventStreamOperations.transform( - model, - testClientRustSettings( - codegenConfig = ClientCodegenConfig(eventStreamAllowList = setOf("test-module")), - ), - ) + val transformed = + RemoveEventStreamOperations.transform( + model, + testClientRustSettings( + codegenConfig = ClientCodegenConfig(eventStreamAllowList = setOf("test-module")), + ), + ) transformed.expectShape(ShapeId.from("test#BlobStream")) transformed.getShape(ShapeId.from("test#EventStream")) shouldNotBe Optional.empty() } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/testutil/Matchers.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/testutil/Matchers.kt index 53b9a20b64c..1d3c7eae5b5 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/testutil/Matchers.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/testutil/Matchers.kt @@ -7,7 +7,10 @@ package software.amazon.smithy.rust.codegen.client.testutil import io.kotest.matchers.shouldBe -fun String.shouldMatchResource(clazz: Class, resourceName: String) { +fun String.shouldMatchResource( + clazz: Class, + resourceName: String, +) { val resource = clazz.getResource(resourceName).readText() this.trim().shouldBe(resource.trim()) } diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/tool/TimeTestSuiteGenerator.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/tool/TimeTestSuiteGenerator.kt index 681bcbb406a..44835f11843 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/tool/TimeTestSuiteGenerator.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/tool/TimeTestSuiteGenerator.kt @@ -21,21 +21,29 @@ import java.util.Locale import kotlin.math.absoluteValue private val UTC = ZoneId.of("UTC") -private val YEARS = listOf(-9999, -100, -1, /* year 0 doesn't exist */ 1, 100, 1969, 1970, 2037, 2038, 9999) -private val DAYS_IN_MONTH = mapOf( - 1 to 31, - 2 to 28, - 3 to 31, - 4 to 30, - 5 to 31, - 6 to 30, - 7 to 31, - 8 to 31, - 9 to 30, - 10 to 31, - 11 to 30, - 12 to 31, -) +private val YEARS = + listOf( + -9999, -100, -1, + // year 0 doesn't exist + 1, + 100, 1969, 1970, 2037, 2038, 9999, + ) + +private val DAYS_IN_MONTH = + mapOf( + 1 to 31, + 2 to 28, + 3 to 31, + 4 to 30, + 5 to 31, + 6 to 30, + 7 to 31, + 8 to 31, + 9 to 30, + 10 to 31, + 11 to 30, + 12 to 31, + ) private val MILLI_FRACTIONS = listOf(0, 1_000_000, 10_000_000, 100_000_000, 234_000_000) private val MICRO_FRACTIONS = listOf(0, 1_000, 10_000, 100_000, 234_000) private val NANO_FRACTIONS = @@ -47,13 +55,14 @@ private data class TestCase( ) { fun toNode(): Node = time.toInstant().let { instant -> - val map = mutableMapOf( - "iso8601" to Node.from(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(time)), - // JSON numbers have 52 bits of precision, and canonical seconds needs 64 bits - "canonical_seconds" to Node.from(instant.epochSecond.toString()), - "canonical_nanos" to NumberNode(instant.nano, SourceLocation.NONE), - "error" to BooleanNode(formatted == null, SourceLocation.NONE), - ) + val map = + mutableMapOf( + "iso8601" to Node.from(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(time)), + // JSON numbers have 52 bits of precision, and canonical seconds needs 64 bits + "canonical_seconds" to Node.from(instant.epochSecond.toString()), + "canonical_nanos" to NumberNode(instant.nano, SourceLocation.NONE), + "error" to BooleanNode(formatted == null, SourceLocation.NONE), + ) if (formatted != null) { map["smithy_format_value"] = Node.from(formatted) } @@ -76,11 +85,12 @@ private fun generateTestTimes(allowed: AllowedSubseconds): List { val hour = i % 24 val minute = i % 60 val second = (i * 233).absoluteValue % 60 - val nanoOfSecond = when (allowed) { - AllowedSubseconds.NANOS -> NANO_FRACTIONS[i % NANO_FRACTIONS.size] - AllowedSubseconds.MICROS -> MICRO_FRACTIONS[i % MICRO_FRACTIONS.size] - AllowedSubseconds.MILLIS -> MILLI_FRACTIONS[i % MILLI_FRACTIONS.size] - } + val nanoOfSecond = + when (allowed) { + AllowedSubseconds.NANOS -> NANO_FRACTIONS[i % NANO_FRACTIONS.size] + AllowedSubseconds.MICROS -> MICRO_FRACTIONS[i % MICRO_FRACTIONS.size] + AllowedSubseconds.MILLIS -> MILLI_FRACTIONS[i % MILLI_FRACTIONS.size] + } result.add(ZonedDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond, UTC)) i += 1 } @@ -95,25 +105,27 @@ private fun generateTestTimes(allowed: AllowedSubseconds): List { } private fun generateEpochSecondsTests(): List { - val formatter = DateTimeFormatterBuilder() - .appendValue(ChronoField.INSTANT_SECONDS, 1, 19, SignStyle.NORMAL) - .optionalStart() - .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true) - .optionalEnd() - .toFormatter() + val formatter = + DateTimeFormatterBuilder() + .appendValue(ChronoField.INSTANT_SECONDS, 1, 19, SignStyle.NORMAL) + .optionalStart() + .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true) + .optionalEnd() + .toFormatter() return generateTestTimes(AllowedSubseconds.MICROS).map { time -> TestCase(time, formatter.format(time)) } } private fun generateHttpDateTests(parsing: Boolean): List { - val formatter = DateTimeFormatterBuilder() - .appendPattern("EEE, dd MMM yyyy HH:mm:ss") - .optionalStart() - .appendFraction(ChronoField.MILLI_OF_SECOND, 0, 3, true) - .optionalEnd() - .appendLiteral(" GMT") - .toFormatter(Locale.ENGLISH) + val formatter = + DateTimeFormatterBuilder() + .appendPattern("EEE, dd MMM yyyy HH:mm:ss") + .optionalStart() + .appendFraction(ChronoField.MILLI_OF_SECOND, 0, 3, true) + .optionalEnd() + .appendLiteral(" GMT") + .toFormatter(Locale.ENGLISH) return generateTestTimes(if (parsing) AllowedSubseconds.MILLIS else AllowedSubseconds.NANOS).map { time -> TestCase( time, @@ -126,13 +138,14 @@ private fun generateHttpDateTests(parsing: Boolean): List { } private fun generateDateTimeTests(parsing: Boolean): List { - val formatter = DateTimeFormatterBuilder() - .appendPattern("yyyy-MM-dd'T'HH:mm:ss") - .optionalStart() - .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true) - .optionalEnd() - .appendLiteral("Z") - .toFormatter(Locale.ENGLISH) + val formatter = + DateTimeFormatterBuilder() + .appendPattern("yyyy-MM-dd'T'HH:mm:ss") + .optionalStart() + .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true) + .optionalEnd() + .appendLiteral("Z") + .toFormatter(Locale.ENGLISH) return generateTestTimes(if (parsing) AllowedSubseconds.MICROS else AllowedSubseconds.NANOS).map { time -> TestCase( time, @@ -146,78 +159,85 @@ private fun generateDateTimeTests(parsing: Boolean): List { fun main() { val none = SourceLocation.NONE - val topLevels = mapOf( - "description" to ArrayNode( - """ - This file holds format and parse test cases for Smithy's built-in `epoch-seconds`, - `http-date`, and `date-time` timestamp formats. - - There are six top-level sections: - - `format_epoch_seconds`: Test cases for formatting timestamps into `epoch-seconds` - - `format_http_date`: Test cases for formatting timestamps into `http-date` - - `format_date_time`: Test cases for formatting timestamps into `date-time` - - `parse_epoch_seconds`: Test cases for parsing timestamps from `epoch-seconds` - - `parse_http_date`: Test cases for parsing timestamps from `http-date` - - `parse_date_time`: Test cases for parsing timestamps from `date-time` - - Each top-level section is an array of the same test case data structure: - ```typescript - type TestCase = { - // Human-readable ISO-8601 representation of the canonical date-time. This should not - // be used by tests, and is only present to make test failures more human readable. - iso8601: string, - - // The canonical number of seconds since the Unix epoch in UTC. - canonical_seconds: string, - - // The canonical nanosecond adjustment to the canonical number of seconds. - // If conversion from (canonical_seconds, canonical_nanos) into a 128-bit integer is required, - // DO NOT just add the two together as this will yield an incorrect value when - // canonical_seconds is negative. - canonical_nanos: number, - - // Will be true if this test case is expected to result in an error or exception - error: boolean, - - // String value of the timestamp in the Smithy format. For the `format_epoch_seconds` top-level, - // this will be in the `epoch-seconds` format, and for `parse_http_date`, it will be in the - // `http-date` format (and so on). - // - // For parsing tests, parse this value and compare the result against canonical_seconds - // and canonical_nanos. - // - // For formatting tests, form the canonical_seconds and canonical_nanos, and then compare - // the result against this value. - // - // This value will not be set for formatting tests if `error` is set to `true`. - smithy_format_value: string, - } - ``` - """.trimIndent().split("\n").map { Node.from(it) }, - none, - ), - "format_epoch_seconds" to ArrayNode(generateEpochSecondsTests().map(TestCase::toNode), none), - "format_http_date" to ArrayNode(generateHttpDateTests(parsing = false).map(TestCase::toNode), none), - "format_date_time" to ArrayNode(generateDateTimeTests(parsing = false).map(TestCase::toNode), none), - "parse_epoch_seconds" to ArrayNode( - generateEpochSecondsTests() - .filter { it.formatted != null } - .map(TestCase::toNode), - none, - ), - "parse_http_date" to ArrayNode( - generateHttpDateTests(parsing = true) - .filter { it.formatted != null } - .map(TestCase::toNode), - none, - ), - "parse_date_time" to ArrayNode( - generateDateTimeTests(parsing = true) - .filter { it.formatted != null } - .map(TestCase::toNode), - none, - ), - ).mapKeys { Node.from(it.key) } + val topLevels = + mapOf( + "description" to + ArrayNode( + """ + This file holds format and parse test cases for Smithy's built-in `epoch-seconds`, + `http-date`, and `date-time` timestamp formats. + + There are six top-level sections: + - `format_epoch_seconds`: Test cases for formatting timestamps into `epoch-seconds` + - `format_http_date`: Test cases for formatting timestamps into `http-date` + - `format_date_time`: Test cases for formatting timestamps into `date-time` + - `parse_epoch_seconds`: Test cases for parsing timestamps from `epoch-seconds` + - `parse_http_date`: Test cases for parsing timestamps from `http-date` + - `parse_date_time`: Test cases for parsing timestamps from `date-time` + + Each top-level section is an array of the same test case data structure: + ```typescript + type TestCase = { + // Human-readable ISO-8601 representation of the canonical date-time. This should not + // be used by tests, and is only present to make test failures more human readable. + iso8601: string, + + // The canonical number of seconds since the Unix epoch in UTC. + canonical_seconds: string, + + // The canonical nanosecond adjustment to the canonical number of seconds. + // If conversion from (canonical_seconds, canonical_nanos) into a 128-bit integer is required, + // DO NOT just add the two together as this will yield an incorrect value when + // canonical_seconds is negative. + canonical_nanos: number, + + // Will be true if this test case is expected to result in an error or exception + error: boolean, + + // String value of the timestamp in the Smithy format. For the `format_epoch_seconds` top-level, + // this will be in the `epoch-seconds` format, and for `parse_http_date`, it will be in the + // `http-date` format (and so on). + // + // For parsing tests, parse this value and compare the result against canonical_seconds + // and canonical_nanos. + // + // For formatting tests, form the canonical_seconds and canonical_nanos, and then compare + // the result against this value. + // + // This value will not be set for formatting tests if `error` is set to `true`. + smithy_format_value: string, + } + ``` + """.trimIndent().split("\n").map { + Node.from(it) + }, + none, + ), + "format_epoch_seconds" to ArrayNode(generateEpochSecondsTests().map(TestCase::toNode), none), + "format_http_date" to ArrayNode(generateHttpDateTests(parsing = false).map(TestCase::toNode), none), + "format_date_time" to ArrayNode(generateDateTimeTests(parsing = false).map(TestCase::toNode), none), + "parse_epoch_seconds" to + ArrayNode( + generateEpochSecondsTests() + .filter { it.formatted != null } + .map(TestCase::toNode), + none, + ), + "parse_http_date" to + ArrayNode( + generateHttpDateTests(parsing = true) + .filter { it.formatted != null } + .map(TestCase::toNode), + none, + ), + "parse_date_time" to + ArrayNode( + generateDateTimeTests(parsing = true) + .filter { it.formatted != null } + .map(TestCase::toNode), + none, + ), + ).mapKeys { Node.from(it.key) } println(Node.prettyPrintJson(ObjectNode(topLevels, none))) } diff --git a/codegen-core/build.gradle.kts b/codegen-core/build.gradle.kts index e72667f8984..e1386ca3498 100644 --- a/codegen-core/build.gradle.kts +++ b/codegen-core/build.gradle.kts @@ -53,52 +53,76 @@ fun gitCommitHash(): String { } val generateSmithyRuntimeCrateVersion by tasks.registering { - fun kv(key: String, value: String) = "\"$key\": \"$value\"" - // generate the version of the runtime to use as a resource. - // this keeps us from having to manually change version numbers in multiple places + // Generate the version of the runtime to use as a resource. + // This keeps us from having to manually change version numbers in multiple places. val resourcesDir = layout.buildDirectory.dir("resources/main/software/amazon/smithy/rust/codegen/core") - val versionFile = resourcesDir.get().file("runtime-crate-version.txt") - outputs.file(versionFile) + val versionsFile = resourcesDir.get().file("runtime-crate-versions.json") + outputs.file(versionsFile) + val stableCrateVersion = project.properties["smithy.rs.runtime.crate.stable.version"].toString() val unstableCrateVersion = project.properties["smithy.rs.runtime.crate.unstable.version"].toString() - inputs.property("crateVersion", stableCrateVersion) - // version format must be in sync with `software.amazon.smithy.rust.codegen.core.Version` - val version = StringBuilder().append("{") - version.append(kv("githash", gitCommitHash())).append(",") - version.append(kv("stableVersion", stableCrateVersion)).append(",") - version.append(kv("unstableVersion", unstableCrateVersion)).append(",") - // hack for internal build - val smithyStableCrates = listOf( - // AWS crates - "aws-config", - "aws-credential-types", - "aws-runtime", - "aws-runtime-api", - "aws-sigv4", - "aws-types", - - // smithy crates - "aws-smithy-async", - "aws-smithy-runtime-api", - "aws-smithy-runtime", - "aws-smithy-types", - ) - - val runtimeCrates = - smithyStableCrates.joinToString(separator = ",", prefix = "{", postfix = "}") { crate -> - kv(crate, stableCrateVersion) + inputs.property("stableCrateVersion", stableCrateVersion) + inputs.property("unstableCrateVersion", stableCrateVersion) + + val cargoTomls = mutableListOf() + for (runtimePath in arrayOf("../rust-runtime", "../aws/rust-runtime")) { + for (path in project.projectDir.resolve(runtimePath).listFiles()!!) { + val manifestPath = path.resolve("Cargo.toml") + if (manifestPath.exists()) { + cargoTomls.add(manifestPath) + inputs.file(manifestPath) + } } - - version.append(""""runtimeCrates": $runtimeCrates""").append("}") + } sourceSets.main.get().output.dir(resourcesDir) doLast { - versionFile.asFile.writeText(version.toString()) + // Version format must be kept in sync with `software.amazon.smithy.rust.codegen.core.Version` + versionsFile.asFile.writeText( + StringBuilder().append("{\n").also { json -> + fun StringBuilder.keyVal(key: String, value: String) = append("\"$key\": \"$value\"") + + json.append(" ").keyVal("gitHash", gitCommitHash()).append(",\n") + json.append(" \"runtimeCrates\": {\n") + json.append( + cargoTomls.map { path -> + path.parentFile.name to path.readLines() + } + .filter { (name, manifestLines) -> + val publish = manifestLines.none { line -> line == "publish = false" } + // HACK: The experimental/unpublished typescript runtime crate needs + // to be included since it is referenced by the code generator and tested in CI. + publish || name == "aws-smithy-http-server-typescript" + } + .map { (name, manifestLines) -> + val stable = manifestLines.any { line -> line == "stable = true" } + val versionLine = manifestLines.first { line -> line.startsWith("version = \"") } + val maybeVersion = versionLine.slice(("version = \"".length)..(versionLine.length - 2)) + val version = if (maybeVersion == "0.0.0-smithy-rs-head") { + when (stable) { + true -> stableCrateVersion + else -> unstableCrateVersion + } + } else { + maybeVersion + } + " \"$name\": \"$version\"" + } + .joinToString(",\n"), + ) + json.append(" }\n") + }.append("}").toString(), + ) } } +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + tasks.compileKotlin { - kotlinOptions.jvmTarget = "1.8" + kotlinOptions.jvmTarget = "11" dependsOn(generateSmithyRuntimeCrateVersion) } @@ -135,7 +159,7 @@ if (isTestingEnabled.toBoolean()) { } tasks.compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" + kotlinOptions.jvmTarget = "11" } tasks.test { diff --git a/codegen-core/common-test-models/rest-json-extras.smithy b/codegen-core/common-test-models/rest-json-extras.smithy index 2633fe00a83..a4ff54af966 100644 --- a/codegen-core/common-test-models/rest-json-extras.smithy +++ b/codegen-core/common-test-models/rest-json-extras.smithy @@ -68,6 +68,8 @@ service RestJsonExtras { // TODO(https://github.com/smithy-lang/smithy-rs/issues/2968): Remove the following once these tests are included in Smithy // They're being added in https://github.com/smithy-lang/smithy/pull/1908 HttpPayloadWithUnion, + // TODO(https://github.com/smithy-lang/smithy-rs/issues/3315) + ZeroAndFalseQueryParams, ], errors: [ExtraError] } @@ -351,3 +353,33 @@ structure EmptyStructWithContentOnWireOpOutput { operation EmptyStructWithContentOnWireOp { output: EmptyStructWithContentOnWireOpOutput, } +@http(uri: "/zero-and-false-query-params", method: "GET") +@httpRequestTests([ + { + id: "RestJsonZeroAndFalseQueryParamsAreSerialized", + protocol: restJson1, + code: 200, + method: "GET", + uri: "/zero-and-false-query-params", + body: "", + queryParams: [ + "Zero=0", + "False=false" + ], + params: { + zeroValue: 0, + falseValue: false + } + } +]) +operation ZeroAndFalseQueryParams { + input: ZeroAndFalseQueryParamsInput +} + +structure ZeroAndFalseQueryParamsInput { + @httpQuery("Zero") + zeroValue: Integer + + @httpQuery("False") + falseValue: Boolean +} diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/Version.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/Version.kt index 071f0a2089b..76ac68d6055 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/Version.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/Version.kt @@ -9,48 +9,33 @@ import software.amazon.smithy.codegen.core.CodegenException import software.amazon.smithy.model.node.Node // generated as part of the build, see codegen-core/build.gradle.kts -private const val VERSION_FILENAME = "runtime-crate-version.txt" +private const val VERSION_FILENAME = "runtime-crate-versions.json" data class Version( - val fullVersion: String, - val stableCrateVersion: String, - val unstableCrateVersion: String, + val gitHash: String, val crates: Map, ) { companion object { // Version must be in the "{smithy_rs_version}\n{git_commit_hash}" format fun parse(content: String): Version { val node = Node.parse(content).expectObjectNode() - val githash = node.expectStringMember("githash").value - val stableVersion = node.expectStringMember("stableVersion").value - val unstableVersion = node.expectStringMember("unstableVersion").value return Version( - "$stableVersion-$githash", - stableCrateVersion = stableVersion, - unstableCrateVersion = unstableVersion, + node.expectStringMember("gitHash").value, node.expectObjectMember("runtimeCrates").members.map { it.key.value to it.value.expectStringNode().value }.toMap(), ) } - // Returns full version in the "{smithy_rs_version}-{git_commit_hash}" format - fun fullVersion(): String = - fromDefaultResource().fullVersion - - fun stableCrateVersion(): String = - fromDefaultResource().stableCrateVersion - - fun unstableCrateVersion(): String = - fromDefaultResource().unstableCrateVersion - fun crateVersion(crate: String): String { val version = fromDefaultResource() - return version.crates[crate] ?: version.unstableCrateVersion + return version.crates[crate] ?: throw CodegenException("unknown version number for runtime crate $crate") } - fun fromDefaultResource(): Version = parse( - Version::class.java.getResource(VERSION_FILENAME)?.readText() - ?: throw CodegenException("$VERSION_FILENAME does not exist"), - ) + + fun fromDefaultResource(): Version = + parse( + Version::class.java.getResource(VERSION_FILENAME)?.readText() + ?: throw CodegenException("$VERSION_FILENAME does not exist"), + ) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt index 88416e45c45..23ce4428afb 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/CargoDependency.kt @@ -21,12 +21,16 @@ enum class DependencyScope { } sealed class DependencyLocation + data class CratesIo(val version: String) : DependencyLocation() + data class Local(val basePath: String, val version: String? = null) : DependencyLocation() sealed class RustDependency(open val name: String) : SymbolDependencyContainer { abstract fun version(): String + open fun dependencies(): List = listOf() + override fun getDependencies(): List { return listOf( SymbolDependency @@ -39,6 +43,7 @@ sealed class RustDependency(open val name: String) : SymbolDependencyContainer { companion object { private const val PropertyKey = "rustdep" + fun fromSymbolDependency(symbolDependency: SymbolDependency) = symbolDependency.getProperty(PropertyKey, RustDependency::class.java).get() } @@ -86,8 +91,10 @@ class InlineDependency( } } - private fun forInlineableRustFile(name: String, vararg additionalDependencies: RustDependency) = - forRustFile(RustModule.private(name), "/inlineable/src/$name.rs", *additionalDependencies) + private fun forInlineableRustFile( + name: String, + vararg additionalDependencies: RustDependency, + ) = forRustFile(RustModule.private(name), "/inlineable/src/$name.rs", *additionalDependencies) fun eventReceiver(runtimeConfig: RuntimeConfig) = forInlineableRustFile( @@ -97,7 +104,8 @@ class InlineDependency( CargoDependency.smithyTypes(runtimeConfig), ) - fun defaultAuthPlugin(runtimeConfig: RuntimeConfig) = forInlineableRustFile("auth_plugin", CargoDependency.smithyRuntimeApiClient(runtimeConfig)) + fun defaultAuthPlugin(runtimeConfig: RuntimeConfig) = + forInlineableRustFile("auth_plugin", CargoDependency.smithyRuntimeApiClient(runtimeConfig)) fun jsonErrors(runtimeConfig: RuntimeConfig) = forInlineableRustFile( @@ -130,12 +138,13 @@ class InlineDependency( fun unwrappedXmlErrors(runtimeConfig: RuntimeConfig): InlineDependency = forInlineableRustFile("rest_xml_unwrapped_errors", CargoDependency.smithyXml(runtimeConfig)) - fun serializationSettings(runtimeConfig: RuntimeConfig): InlineDependency = forInlineableRustFile( - "serialization_settings", - CargoDependency.Http, - CargoDependency.smithyHttp(runtimeConfig), - CargoDependency.smithyTypes(runtimeConfig), - ) + fun serializationSettings(runtimeConfig: RuntimeConfig): InlineDependency = + forInlineableRustFile( + "serialization_settings", + CargoDependency.Http, + CargoDependency.smithyHttp(runtimeConfig), + CargoDependency.smithyTypes(runtimeConfig), + ) fun constrained(): InlineDependency = InlineDependency.forRustFile(ConstrainedModule, "/inlineable/src/constrained.rs") @@ -174,10 +183,11 @@ data class CargoDependency( fun toDevDependency() = copy(scope = DependencyScope.Dev) - override fun version(): String = when (location) { - is CratesIo -> location.version - is Local -> "local" - } + override fun version(): String = + when (location) { + is CratesIo -> location.version + is Local -> "local" + } fun toMap(): Map { val attribs = mutableMapOf() @@ -274,45 +284,63 @@ data class CargoDependency( DependencyScope.Dev, features = setOf("macros", "test-util", "rt-multi-thread"), ) - val TracingAppender: CargoDependency = CargoDependency( - "tracing-appender", - CratesIo("0.2.2"), - DependencyScope.Dev, - ) - val TracingSubscriber: CargoDependency = CargoDependency( - "tracing-subscriber", - CratesIo("0.3.16"), - DependencyScope.Dev, - features = setOf("env-filter", "json"), - ) - val TracingTest: CargoDependency = CargoDependency( - "tracing-test", - CratesIo("0.2.4"), - DependencyScope.Dev, - features = setOf("no-env-filter"), - ) + val TracingAppender: CargoDependency = + CargoDependency( + "tracing-appender", + CratesIo("0.2.2"), + DependencyScope.Dev, + ) + val TracingSubscriber: CargoDependency = + CargoDependency( + "tracing-subscriber", + CratesIo("0.3.16"), + DependencyScope.Dev, + features = setOf("env-filter", "json"), + ) + val TracingTest: CargoDependency = + CargoDependency( + "tracing-test", + CratesIo("0.2.4"), + DependencyScope.Dev, + features = setOf("no-env-filter"), + ) fun smithyAsync(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-async") + fun smithyChecksums(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-checksums") fun smithyEventStream(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-eventstream") + fun smithyHttp(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-http") + fun smithyJson(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-json") + fun smithyProtocolTestHelpers(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-protocol-test", scope = DependencyScope.Dev) fun smithyQuery(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-query") - fun smithyRuntime(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-runtime") - .withFeature("client") - fun smithyRuntimeTestUtil(runtimeConfig: RuntimeConfig) = smithyRuntime(runtimeConfig).toDevDependency().withFeature("test-util") + + fun smithyRuntime(runtimeConfig: RuntimeConfig) = + runtimeConfig.smithyRuntimeCrate("smithy-runtime") + .withFeature("client") + + fun smithyRuntimeTestUtil(runtimeConfig: RuntimeConfig) = + smithyRuntime(runtimeConfig).toDevDependency().withFeature("test-util") + fun smithyRuntimeApi(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-runtime-api") - fun smithyRuntimeApiClient(runtimeConfig: RuntimeConfig) = smithyRuntimeApi(runtimeConfig).withFeature("client").withFeature("http-02x") + + fun smithyRuntimeApiClient(runtimeConfig: RuntimeConfig) = + smithyRuntimeApi(runtimeConfig).withFeature("client").withFeature("http-02x") + fun smithyRuntimeApiTestUtil(runtimeConfig: RuntimeConfig) = smithyRuntimeApi(runtimeConfig).toDevDependency().withFeature("test-util") + fun smithyTypes(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-types") + fun smithyXml(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-xml") // behind feature-gate - val Serde = CargoDependency("serde", CratesIo("1.0"), features = setOf("derive"), scope = DependencyScope.CfgUnstable) + val Serde = + CargoDependency("serde", CratesIo("1.0"), features = setOf("derive"), scope = DependencyScope.CfgUnstable) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustGenerics.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustGenerics.kt index b5de87b76ca..80b33e260db 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustGenerics.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustGenerics.kt @@ -118,14 +118,15 @@ class RustGenerics(vararg genericTypeArgs: GenericTypeArg) { * // } * ``` */ - fun bounds() = writable { - // Only write bounds for generic type params with a bound - for ((typeArg, bound) in typeArgs) { - if (bound != null) { - rustTemplate("$typeArg: #{bound},\n", "bound" to bound) + fun bounds() = + writable { + // Only write bounds for generic type params with a bound + for ((typeArg, bound) in typeArgs) { + if (bound != null) { + rustTemplate("$typeArg: #{bound},\n", "bound" to bound) + } } } - } /** * Combine two `GenericsGenerator`s into one. Type args for the first `GenericsGenerator` will appear before diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustModule.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustModule.kt index 78dee92daef..6b0a725925b 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustModule.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustModule.kt @@ -16,7 +16,6 @@ import software.amazon.smithy.rust.codegen.core.util.PANIC * - There is no guarantee _which_ module will be rendered. */ sealed class RustModule { - /** lib.rs */ object LibRs : RustModule() @@ -33,11 +32,10 @@ sealed class RustModule { val rustMetadata: RustMetadata, val parent: RustModule = LibRs, val inline: Boolean = false, - /* module is a cfg(test) module */ + // module is a cfg(test) module val tests: Boolean = false, val documentationOverride: String? = null, ) : RustModule() { - init { check(!name.contains("::")) { "Module names CANNOT contain `::`—modules must be nested with parent (name was: `$name`)" @@ -52,14 +50,14 @@ sealed class RustModule { } /** Convert a module into a module gated with `#[cfg(test)]` */ - fun cfgTest(): LeafModule = this.copy( - rustMetadata = rustMetadata.copy(additionalAttributes = rustMetadata.additionalAttributes + Attribute.CfgTest), - tests = true, - ) + fun cfgTest(): LeafModule = + this.copy( + rustMetadata = rustMetadata.copy(additionalAttributes = rustMetadata.additionalAttributes + Attribute.CfgTest), + tests = true, + ) } companion object { - /** Creates a new module with the specified visibility */ fun new( name: String, @@ -84,29 +82,33 @@ sealed class RustModule { parent: RustModule = LibRs, documentationOverride: String? = null, additionalAttributes: List = emptyList(), - ): LeafModule = new( - name, - visibility = Visibility.PUBLIC, - inline = false, - parent = parent, - documentationOverride = documentationOverride, - additionalAttributes = additionalAttributes, - ) + ): LeafModule = + new( + name, + visibility = Visibility.PUBLIC, + inline = false, + parent = parent, + documentationOverride = documentationOverride, + additionalAttributes = additionalAttributes, + ) /** Creates a new private module */ - fun private(name: String, parent: RustModule = LibRs): LeafModule = - new(name, visibility = Visibility.PRIVATE, inline = false, parent = parent) + fun private( + name: String, + parent: RustModule = LibRs, + ): LeafModule = new(name, visibility = Visibility.PRIVATE, inline = false, parent = parent) fun pubCrate( name: String, parent: RustModule = LibRs, additionalAttributes: List = emptyList(), - ): LeafModule = new( - name, visibility = Visibility.PUBCRATE, - inline = false, - parent = parent, - additionalAttributes = additionalAttributes, - ) + ): LeafModule = + new( + name, visibility = Visibility.PUBCRATE, + inline = false, + parent = parent, + additionalAttributes = additionalAttributes, + ) fun inlineTests( name: String = "test", @@ -121,29 +123,32 @@ sealed class RustModule { ).cfgTest() } - fun isInline(): Boolean = when (this) { - is LibRs -> false - is LeafModule -> this.inline - } + fun isInline(): Boolean = + when (this) { + is LibRs -> false + is LeafModule -> this.inline + } /** * Fully qualified path to this module, e.g. `crate::grandparent::parent::child` */ - fun fullyQualifiedPath(): String = when (this) { - is LibRs -> "crate" - is LeafModule -> parent.fullyQualifiedPath() + "::" + name - } + fun fullyQualifiedPath(): String = + when (this) { + is LibRs -> "crate" + is LeafModule -> parent.fullyQualifiedPath() + "::" + name + } /** * The file this module is homed in, e.g. `src/grandparent/parent/child.rs` */ - fun definitionFile(): String = when (this) { - is LibRs -> "src/lib.rs" - is LeafModule -> { - val path = fullyQualifiedPath().split("::").drop(1).joinToString("/") - "src/$path.rs" + fun definitionFile(): String = + when (this) { + is LibRs -> "src/lib.rs" + is LeafModule -> { + val path = fullyQualifiedPath().split("::").drop(1).joinToString("/") + "src/$path.rs" + } } - } /** * Renders the usage statement, approximately: @@ -152,7 +157,10 @@ sealed class RustModule { * pub mod my_module_name * ``` */ - fun renderModStatement(writer: RustWriter, moduleDocProvider: ModuleDocProvider) { + fun renderModStatement( + writer: RustWriter, + moduleDocProvider: ModuleDocProvider, + ) { when (this) { is LeafModule -> { if (name.startsWith("r#")) { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt index 260cb62295a..cc37f891eda 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWords.kt @@ -97,85 +97,92 @@ enum class EscapeFor { } object RustReservedWords : ReservedWords { - private val RustKeywords = setOf( - "as", - "break", - "const", - "continue", - "crate", - "else", - "enum", - "extern", - "false", - "fn", - "for", - "if", - "impl", - "in", - "let", - "loop", - "match", - "mod", - "move", - "mut", - "pub", - "ref", - "return", - "self", - "Self", - "static", - "struct", - "super", - "trait", - "true", - "type", - "unsafe", - "use", - "where", - "while", - - "async", - "await", - "dyn", - - "abstract", - "become", - "box", - "do", - "final", - "macro", - "override", - "priv", - "typeof", - "unsized", - "virtual", - "yield", - "try", - ) + private val RustKeywords = + setOf( + "as", + "break", + "const", + "continue", + "crate", + "else", + "enum", + "extern", + "false", + "fn", + "for", + "if", + "impl", + "in", + "let", + "loop", + "match", + "mod", + "move", + "mut", + "pub", + "ref", + "return", + "self", + "Self", + "static", + "struct", + "super", + "trait", + "true", + "type", + "unsafe", + "use", + "where", + "while", + "async", + "await", + "dyn", + "abstract", + "become", + "box", + "do", + "final", + "macro", + "override", + "priv", + "typeof", + "unsized", + "virtual", + "yield", + "try", + ) // Some things can't be used as a raw identifier, so we can't use the normal escaping strategy // https://internals.rust-lang.org/t/raw-identifiers-dont-work-for-all-identifiers/9094/4 - private val keywordEscapingMap = mapOf( - "crate" to "crate_", - "super" to "super_", - "self" to "self_", - "Self" to "SelfValue", - // Real models won't end in `_` so it's safe to stop here - "SelfValue" to "SelfValue_", - ) + private val keywordEscapingMap = + mapOf( + "crate" to "crate_", + "super" to "super_", + "self" to "self_", + "Self" to "SelfValue", + // Real models won't end in `_` so it's safe to stop here + "SelfValue" to "SelfValue_", + ) override fun escape(word: String): String = doEscape(word, EscapeFor.TypeName) - private fun doEscape(word: String, escapeFor: EscapeFor = EscapeFor.TypeName): String = + private fun doEscape( + word: String, + escapeFor: EscapeFor = EscapeFor.TypeName, + ): String = when (val mapped = keywordEscapingMap[word]) { - null -> when (escapeFor) { - EscapeFor.TypeName -> "r##$word" - EscapeFor.ModuleName -> "${word}_" - } + null -> + when (escapeFor) { + EscapeFor.TypeName -> "r##$word" + EscapeFor.ModuleName -> "${word}_" + } else -> mapped } - fun escapeIfNeeded(word: String, escapeFor: EscapeFor = EscapeFor.TypeName): String = + fun escapeIfNeeded( + word: String, + escapeFor: EscapeFor = EscapeFor.TypeName, + ): String = when (isReserved(word)) { true -> doEscape(word, escapeFor) else -> word diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt index b23ea5696f4..e6b46295c27 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustType.kt @@ -15,11 +15,12 @@ import software.amazon.smithy.rust.codegen.core.util.dq * * Clippy is upset about `*&`, so if [input] is already referenced, simply strip the leading '&' */ -fun autoDeref(input: String) = if (input.startsWith("&")) { - input.removePrefix("&") -} else { - "*$input" -} +fun autoDeref(input: String) = + if (input.startsWith("&")) { + input.removePrefix("&") + } else { + "*$input" + } /** * A hierarchy of types handled by Smithy codegen @@ -212,20 +213,22 @@ fun RustType.asArgumentType(fullyQualified: Boolean = true): String { } /** Format this Rust type so that it may be used as an argument type in a function definition */ -fun RustType.asArgumentValue(name: String) = when (this) { - is RustType.String, is RustType.Box -> "$name.into()" - else -> name -} +fun RustType.asArgumentValue(name: String) = + when (this) { + is RustType.String, is RustType.Box -> "$name.into()" + else -> name + } /** * For a given name, generate an `Argument` data class containing pre-formatted strings for using this type when * writing a Rust function. */ -fun RustType.asArgument(name: String) = Argument( - "$name: ${this.asArgumentType()}", - this.asArgumentValue(name), - this.render(), -) +fun RustType.asArgument(name: String) = + Argument( + "$name: ${this.asArgumentType()}", + this.asArgumentValue(name), + this.render(), + ) /** * Render this type, including references and generic parameters. @@ -233,38 +236,40 @@ fun RustType.asArgument(name: String) = Argument( * - To generate something like `std::collections::HashMap`, use [qualifiedName] */ fun RustType.render(fullyQualified: Boolean = true): String { - val namespace = if (fullyQualified) { - this.namespace?.let { "$it::" } ?: "" - } else { - "" - } - val base = when (this) { - is RustType.Unit -> this.name - is RustType.Bool -> this.name - is RustType.Float -> this.name - is RustType.Integer -> this.name - is RustType.String -> this.name - is RustType.Vec -> "${this.name}::<${this.member.render(fullyQualified)}>" - is RustType.Slice -> "[${this.member.render(fullyQualified)}]" - is RustType.HashMap -> "${this.name}::<${this.key.render(fullyQualified)}, ${this.member.render(fullyQualified)}>" - is RustType.HashSet -> "${this.name}::<${this.member.render(fullyQualified)}>" - is RustType.Reference -> { - if (this.lifetime == "&") { - "&${this.member.render(fullyQualified)}" - } else { - "&${this.lifetime?.let { "'$it" } ?: ""} ${this.member.render(fullyQualified)}" - } + val namespace = + if (fullyQualified) { + this.namespace?.let { "$it::" } ?: "" + } else { + "" } - is RustType.Application -> { - val args = this.args.joinToString(", ") { it.render(fullyQualified) } - "${this.name}<$args>" + val base = + when (this) { + is RustType.Unit -> this.name + is RustType.Bool -> this.name + is RustType.Float -> this.name + is RustType.Integer -> this.name + is RustType.String -> this.name + is RustType.Vec -> "${this.name}::<${this.member.render(fullyQualified)}>" + is RustType.Slice -> "[${this.member.render(fullyQualified)}]" + is RustType.HashMap -> "${this.name}::<${this.key.render(fullyQualified)}, ${this.member.render(fullyQualified)}>" + is RustType.HashSet -> "${this.name}::<${this.member.render(fullyQualified)}>" + is RustType.Reference -> { + if (this.lifetime == "&") { + "&${this.member.render(fullyQualified)}" + } else { + "&${this.lifetime?.let { "'$it" } ?: ""} ${this.member.render(fullyQualified)}" + } + } + is RustType.Application -> { + val args = this.args.joinToString(", ") { it.render(fullyQualified) } + "${this.name}<$args>" + } + is RustType.Option -> "${this.name}<${this.member.render(fullyQualified)}>" + is RustType.Box -> "${this.name}<${this.member.render(fullyQualified)}>" + is RustType.Dyn -> "${this.name} ${this.member.render(fullyQualified)}" + is RustType.Opaque -> this.name + is RustType.MaybeConstrained -> "${this.name}<${this.member.render(fullyQualified)}>" } - is RustType.Option -> "${this.name}<${this.member.render(fullyQualified)}>" - is RustType.Box -> "${this.name}<${this.member.render(fullyQualified)}>" - is RustType.Dyn -> "${this.name} ${this.member.render(fullyQualified)}" - is RustType.Opaque -> this.name - is RustType.MaybeConstrained -> "${this.name}<${this.member.render(fullyQualified)}>" - } return "$namespace$base" } @@ -273,29 +278,33 @@ fun RustType.render(fullyQualified: Boolean = true): String { * Option.contains(DateTime) would return true. * Option.contains(Blob) would return false. */ -fun RustType.contains(t: T): Boolean = when (this) { - t -> true - is RustType.Container -> this.member.contains(t) - else -> false -} +fun RustType.contains(t: T): Boolean = + when (this) { + t -> true + is RustType.Container -> this.member.contains(t) + else -> false + } -inline fun RustType.stripOuter(): RustType = when (this) { - is T -> this.member - else -> this -} +inline fun RustType.stripOuter(): RustType = + when (this) { + is T -> this.member + else -> this + } /** Extracts the inner Reference type */ -fun RustType.innerReference(): RustType? = when (this) { - is RustType.Reference -> this - is RustType.Container -> this.member.innerReference() - else -> null -} +fun RustType.innerReference(): RustType? = + when (this) { + is RustType.Reference -> this + is RustType.Container -> this.member.innerReference() + else -> null + } /** Wraps a type in Option if it isn't already */ -fun RustType.asOptional(): RustType = when (this) { - is RustType.Option -> this - else -> RustType.Option(this) -} +fun RustType.asOptional(): RustType = + when (this) { + is RustType.Option -> this + else -> RustType.Option(this) + } /** * Converts type to a reference @@ -304,11 +313,12 @@ fun RustType.asOptional(): RustType = when (this) { * - `String` -> `&String` * - `Option` -> `Option<&T>` */ -fun RustType.asRef(): RustType = when (this) { - is RustType.Reference -> this - is RustType.Option -> RustType.Option(member.asRef()) - else -> RustType.Reference(null, this) -} +fun RustType.asRef(): RustType = + when (this) { + is RustType.Reference -> this + is RustType.Option -> RustType.Option(member.asRef()) + else -> RustType.Reference(null, this) + } /** * Converts type to its Deref target @@ -318,64 +328,77 @@ fun RustType.asRef(): RustType = when (this) { * - `Option` -> `Option<&str>` * - `Box` -> `&Something` */ -fun RustType.asDeref(): RustType = when (this) { - is RustType.Option -> if (member.isDeref()) { - RustType.Option(member.asDeref().asRef()) - } else { - this - } +fun RustType.asDeref(): RustType = + when (this) { + is RustType.Option -> + if (member.isDeref()) { + RustType.Option(member.asDeref().asRef()) + } else { + this + } - is RustType.Box -> RustType.Reference(null, member) - is RustType.String -> RustType.Opaque("str") - is RustType.Vec -> RustType.Slice(member) - else -> this -} + is RustType.Box -> RustType.Reference(null, member) + is RustType.String -> RustType.Opaque("str") + is RustType.Vec -> RustType.Slice(member) + else -> this + } /** Returns true if the type implements Deref */ -fun RustType.isDeref(): Boolean = when (this) { - is RustType.Box -> true - is RustType.String -> true - is RustType.Vec -> true - else -> false -} +fun RustType.isDeref(): Boolean = + when (this) { + is RustType.Box -> true + is RustType.String -> true + is RustType.Vec -> true + else -> false + } /** Returns true if the type implements Copy */ -fun RustType.isCopy(): Boolean = when (this) { - is RustType.Float -> true - is RustType.Integer -> true - is RustType.Reference -> true - is RustType.Bool -> true - is RustType.Slice -> true - is RustType.Option -> this.member.isCopy() - else -> false -} +fun RustType.isCopy(): Boolean = + when (this) { + is RustType.Float -> true + is RustType.Integer -> true + is RustType.Reference -> true + is RustType.Bool -> true + is RustType.Slice -> true + is RustType.Option -> this.member.isCopy() + else -> false + } /** Returns true if the type implements Eq */ -fun RustType.isEq(): Boolean = when (this) { - is RustType.Integer -> true - is RustType.Bool -> true - is RustType.String -> true - is RustType.Unit -> true - is RustType.Container -> this.member.isEq() - else -> false -} +fun RustType.isEq(): Boolean = + when (this) { + is RustType.Integer -> true + is RustType.Bool -> true + is RustType.String -> true + is RustType.Unit -> true + is RustType.Container -> this.member.isEq() + else -> false + } enum class Visibility { - PRIVATE, PUBCRATE, PUBLIC; + PRIVATE, + PUBCRATE, + PUBLIC, + ; companion object { - fun publicIf(condition: Boolean, ifNot: Visibility): Visibility = if (condition) { - PUBLIC - } else { - ifNot - } + fun publicIf( + condition: Boolean, + ifNot: Visibility, + ): Visibility = + if (condition) { + PUBLIC + } else { + ifNot + } } - fun toRustQualifier(): String = when (this) { - PRIVATE -> "" - PUBCRATE -> "pub(crate)" - PUBLIC -> "pub" - } + fun toRustQualifier(): String = + when (this) { + PRIVATE -> "" + PUBCRATE -> "pub(crate)" + PUBLIC -> "pub" + } } /** @@ -386,11 +409,9 @@ data class RustMetadata( val additionalAttributes: List = listOf(), val visibility: Visibility = Visibility.PRIVATE, ) { - fun withDerives(vararg newDerives: RuntimeType): RustMetadata = - this.copy(derives = derives + newDerives) + fun withDerives(vararg newDerives: RuntimeType): RustMetadata = this.copy(derives = derives + newDerives) - fun withoutDerives(vararg withoutDerives: RuntimeType) = - this.copy(derives = derives - withoutDerives.toSet()) + fun withoutDerives(vararg withoutDerives: RuntimeType) = this.copy(derives = derives - withoutDerives.toSet()) fun renderAttributes(writer: RustWriter): RustMetadata { val (deriveHelperAttrs, otherAttrs) = additionalAttributes.partition { it.isDeriveHelper } @@ -473,7 +494,10 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { constructor(str: String, isDeriveHelper: Boolean) : this(writable(str), isDeriveHelper) constructor(runtimeType: RuntimeType) : this(runtimeType.writable) - fun render(writer: RustWriter, attributeKind: AttributeKind = AttributeKind.Outer) { + fun render( + writer: RustWriter, + attributeKind: AttributeKind = AttributeKind.Outer, + ) { // Writing "#[]" with nothing inside it is meaningless if (inner.isNotEmpty()) { when (attributeKind) { @@ -485,19 +509,20 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { // These were supposed to be a part of companion object but we decided to move it out to here to avoid NPE // You can find the discussion here. - // https://github.com/awslabs/smithy-rs/discussions/2248 - public fun SerdeSerialize(): Attribute { + // https://github.com/smithy-lang/smithy-rs/discussions/2248 + fun serdeSerialize(): Attribute { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-serialize")), derive(RuntimeType.SerdeSerialize))) } - public fun SerdeDeserialize(): Attribute { + + fun serdeDeserialize(): Attribute { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), feature("serde-deserialize")), derive(RuntimeType.SerdeDeserialize))) } - public fun serdeSkip(): Attribute { + fun serdeSkip(): Attribute { return Attribute(cfgAttr(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))), serde("skip"))) } - public fun SerdeSerializeOrDeserialize(): Attribute { + fun serdeSerializeOrDeserialize(): Attribute { return Attribute(cfg(all(writable("aws_sdk_unstable"), any(feature("serde-serialize"), feature("serde-deserialize"))))) } @@ -527,6 +552,7 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { val DocHidden = Attribute(doc("hidden")) val DocInline = Attribute(doc("inline")) val NoImplicitPrelude = Attribute("no_implicit_prelude") + fun shouldPanic(expectedMessage: String) = Attribute(macroWithArgs("should_panic", "expected = ${expectedMessage.dq()}")) @@ -546,40 +572,62 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { */ val Deprecated = Attribute("deprecated") - private fun macroWithArgs(name: String, vararg args: RustWriter.() -> Unit): Writable = { - // Macros that require args can't be empty - if (args.isNotEmpty()) { - rustInline("$name(#W)", args.toList().join(", ")) + private fun macroWithArgs( + name: String, + vararg args: RustWriter.() -> Unit, + ): Writable = + { + // Macros that require args can't be empty + if (args.isNotEmpty()) { + rustInline("$name(#W)", args.toList().join(", ")) + } } - } - private fun macroWithArgs(name: String, vararg args: String): Writable = { - // Macros that require args can't be empty - if (args.isNotEmpty()) { - rustInline("$name(${args.joinToString(", ")})") + private fun macroWithArgs( + name: String, + vararg args: String, + ): Writable = + { + // Macros that require args can't be empty + if (args.isNotEmpty()) { + rustInline("$name(${args.joinToString(", ")})") + } } - } fun all(vararg attrMacros: Writable): Writable = macroWithArgs("all", *attrMacros) + fun cfgAttr(vararg attrMacros: Writable): Writable = macroWithArgs("cfg_attr", *attrMacros) fun allow(lints: Collection): Writable = macroWithArgs("allow", *lints.toTypedArray()) + fun allow(vararg lints: String): Writable = macroWithArgs("allow", *lints) + fun deny(vararg lints: String): Writable = macroWithArgs("deny", *lints) + fun serde(vararg lints: String): Writable = macroWithArgs("serde", *lints) + fun any(vararg attrMacros: Writable): Writable = macroWithArgs("any", *attrMacros) + fun cfg(vararg attrMacros: Writable): Writable = macroWithArgs("cfg", *attrMacros) + fun cfg(vararg attrMacros: String): Writable = macroWithArgs("cfg", *attrMacros) + fun doc(vararg attrMacros: Writable): Writable = macroWithArgs("doc", *attrMacros) + fun doc(str: String): Writable = macroWithArgs("doc", writable(str)) + fun not(vararg attrMacros: Writable): Writable = macroWithArgs("not", *attrMacros) fun feature(feature: String) = writable("feature = ${feature.dq()}") + fun featureGate(featureName: String): Attribute { return Attribute(cfg(feature(featureName))) } - fun deprecated(since: String? = null, note: String? = null): Writable { + fun deprecated( + since: String? = null, + note: String? = null, + ): Writable { val optionalFields = mutableListOf() if (!note.isNullOrEmpty()) { optionalFields.add(pair("note" to note.dq())) @@ -597,14 +645,15 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { } } - fun derive(vararg runtimeTypes: RuntimeType): Writable = { - // Empty derives are meaningless - if (runtimeTypes.isNotEmpty()) { - // Sorted derives look nicer than unsorted, and it makes test output easier to predict - val writables = runtimeTypes.sortedBy { it.path }.map { it.writable }.join(", ") - rustInline("derive(#W)", writables) + fun derive(vararg runtimeTypes: RuntimeType): Writable = + { + // Empty derives are meaningless + if (runtimeTypes.isNotEmpty()) { + // Sorted derives look nicer than unsorted, and it makes test output easier to predict + val writables = runtimeTypes.sortedBy { it.path }.map { it.writable }.join(", ") + rustInline("derive(#W)", writables) + } } - } fun attributeWithStringAsArgument(runtimeType: RuntimeType, comment: String): Writable = { // Sorted derives look nicer than unsorted, and it makes test output easier to predict @@ -613,10 +662,11 @@ class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) { fun derive(runtimeTypes: Collection): Writable = derive(*runtimeTypes.toTypedArray()) - fun pair(pair: Pair): Writable = { - val (key, value) = pair - rustInline("$key = $value") - } + fun pair(pair: Pair): Writable = + { + val (key, value) = pair + rustInline("$key = $value") + } } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt index e8bf22ff7c7..8481cfadb54 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriter.kt @@ -14,6 +14,7 @@ import software.amazon.smithy.codegen.core.SymbolDependencyContainer import software.amazon.smithy.codegen.core.SymbolWriter import software.amazon.smithy.codegen.core.SymbolWriter.Factory import software.amazon.smithy.model.Model +import software.amazon.smithy.model.node.Node import software.amazon.smithy.model.shapes.BooleanShape import software.amazon.smithy.model.shapes.CollectionShape import software.amazon.smithy.model.shapes.DoubleShape @@ -24,9 +25,11 @@ import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.traits.DeprecatedTrait import software.amazon.smithy.model.traits.DocumentationTrait import software.amazon.smithy.rust.codegen.core.rustlang.Attribute.Companion.deprecated +import software.amazon.smithy.rust.codegen.core.smithy.Default import software.amazon.smithy.rust.codegen.core.smithy.ModuleDocProvider import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope +import software.amazon.smithy.rust.codegen.core.smithy.defaultValue import software.amazon.smithy.rust.codegen.core.smithy.isOptional import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.ValueExpression import software.amazon.smithy.rust.codegen.core.smithy.rustType @@ -76,7 +79,11 @@ fun > T.withBlock( return conditionalBlock(textBeforeNewLine, textAfterNewLine, conditional = true, block = block, args = args) } -fun > T.assignment(variableName: String, vararg ctx: Pair, block: T.() -> Unit) { +fun > T.assignment( + variableName: String, + vararg ctx: Pair, + block: T.() -> Unit, +) { withBlockTemplate("let $variableName =", ";", *ctx) { block() } @@ -185,26 +192,31 @@ fun RustWriter.rustInline( this.writeInline(contents, *args) } -/* rewrite #{foo} to #{foo:T} (the smithy template format) */ -private fun transformTemplate(template: String, scope: Array>, trim: Boolean = true): String { +// rewrite #{foo} to #{foo:T} (the smithy template format) +private fun transformTemplate( + template: String, + scope: Array>, + trim: Boolean = true, +): String { check( scope.distinctBy { it.first.lowercase() }.size == scope.distinctBy { it.first }.size, ) { "Duplicate cased keys not supported" } - val output = template.replace(Regex("""#\{([a-zA-Z_0-9]+)(:\w)?\}""")) { matchResult -> - val keyName = matchResult.groupValues[1] - val templateType = matchResult.groupValues[2].ifEmpty { ":T" } - if (!scope.toMap().keys.contains(keyName)) { - throw CodegenException( - """ - Rust block template expected `$keyName` but was not present in template. - Hint: Template contains: ${scope.map { "`${it.first}`" }} - """.trimIndent(), - ) + val output = + template.replace(Regex("""#\{([a-zA-Z_0-9]+)(:\w)?\}""")) { matchResult -> + val keyName = matchResult.groupValues[1] + val templateType = matchResult.groupValues[2].ifEmpty { ":T" } + if (!scope.toMap().keys.contains(keyName)) { + throw CodegenException( + """ + Rust block template expected `$keyName` but was not present in template. + Hint: Template contains: ${scope.map { "`${it.first}`" }} + """.trimIndent(), + ) + } + "#{${keyName.lowercase()}$templateType}" } - "#{${keyName.lowercase()}$templateType}" - } return output.letIf(trim) { output.trim() } } @@ -298,13 +310,14 @@ fun > T.docsOrFallback( autoSuppressMissingDocs: Boolean = true, note: String? = null, ): T { - val htmlDocs: (T.() -> Unit)? = when (docString?.isNotBlank()) { - true -> { - { docs(normalizeHtml(escape(docString))) } - } + val htmlDocs: (T.() -> Unit)? = + when (docString?.isNotBlank()) { + true -> { + { docs(normalizeHtml(escape(docString))) } + } - else -> null - } + else -> null + } return docsOrFallback(htmlDocs, autoSuppressMissingDocs, note) } @@ -334,7 +347,11 @@ fun > T.docsOrFallback( * Document the containing entity (e.g. module, crate, etc.) * Instead of prefixing lines with `///` lines are prefixed with `//!` */ -fun RustWriter.containerDocs(text: String, vararg args: Any, trimStart: Boolean = true): RustWriter { +fun RustWriter.containerDocs( + text: String, + vararg args: Any, + trimStart: Boolean = true, +): RustWriter { return docs(text, newlinePrefix = "//! ", args = args, trimStart = trimStart) } @@ -366,13 +383,14 @@ fun > T.docs( this.ensureNewline() pushState() setNewlinePrefix(newlinePrefix) - val cleaned = text.lines() - .joinToString("\n") { - when (trimStart) { - true -> it.trimStart() - else -> it - }.replace("\t", " ") // Rustdoc warns on tabs in documentation - } + val cleaned = + text.lines() + .joinToString("\n") { + when (trimStart) { + true -> it.trimStart() + else -> it + }.replace("\t", " ") // Rustdoc warns on tabs in documentation + } write(cleaned, *args) popState() return this @@ -386,16 +404,20 @@ fun > T.docsTemplate( vararg args: Pair, newlinePrefix: String = "/// ", trimStart: Boolean = false, -): T = withTemplate(text, args, trim = false) { template -> - docs(template, newlinePrefix = newlinePrefix, trimStart = trimStart) -} +): T = + withTemplate(text, args, trim = false) { template -> + docs(template, newlinePrefix = newlinePrefix, trimStart = trimStart) + } /** * Writes a comment into the code * * Equivalent to [docs] but lines are preceded with `// ` instead of `///` */ -fun > T.comment(text: String, vararg args: Any): T { +fun > T.comment( + text: String, + vararg args: Any, +): T { return docs(text, *args, newlinePrefix = "// ") } @@ -441,19 +463,28 @@ private fun Element.changeInto(tagName: String) { } /** Write an `impl` block for the given symbol */ -fun RustWriter.implBlock(symbol: Symbol, block: Writable) { +fun RustWriter.implBlock( + symbol: Symbol, + block: Writable, +) { rustBlock("impl ${symbol.name}") { block() } } /** Write a `#[cfg(feature = "...")]` block for the given feature */ -fun RustWriter.featureGateBlock(feature: String, block: Writable) { +fun RustWriter.featureGateBlock( + feature: String, + block: Writable, +) { featureGatedBlock(feature, block)(this) } /** Write a `#[cfg(feature = "...")]` block for the given feature */ -fun featureGatedBlock(feature: String, block: Writable): Writable { +fun featureGatedBlock( + feature: String, + block: Writable, +): Writable { return writable { rustBlock("##[cfg(feature = ${feature.dq()})]") { block() @@ -461,7 +492,10 @@ fun featureGatedBlock(feature: String, block: Writable): Writable { } } -fun featureGatedBlock(feature: Feature, block: Writable): Writable { +fun featureGatedBlock( + feature: Feature, + block: Writable, +): Writable { return writable { rustBlock("##[cfg(feature = ${feature.name.dq()})]") { block() @@ -477,10 +511,12 @@ fun RustWriter.raw(text: String) = writeInline(escape(text)) /** * [rustTemplate] equivalent for `raw()`. Note: This function won't automatically escape formatter symbols. */ -fun RustWriter.rawTemplate(text: String, vararg args: Pair) = - withTemplate(text, args, trim = false) { templated -> - writeInline(templated) - } +fun RustWriter.rawTemplate( + text: String, + vararg args: Pair, +) = withTemplate(text, args, trim = false) { templated -> + writeInline(templated) +} /** * Rustdoc doesn't support `r#` for raw identifiers. @@ -499,353 +535,416 @@ class RustWriter private constructor( val devDependenciesOnly: Boolean = false, ) : SymbolWriter(UseDeclarations(namespace)) { + companion object { + fun root() = forModule(null) + + fun forModule(module: String?): RustWriter = + if (module == null) { + RustWriter("lib.rs", "crate") + } else { + RustWriter("$module.rs", "crate::$module") + } - companion object { - fun root() = forModule(null) - fun forModule(module: String?): RustWriter = if (module == null) { - RustWriter("lib.rs", "crate") - } else { - RustWriter("$module.rs", "crate::$module") - } + fun factory(debugMode: Boolean): Factory = + Factory { fileName: String, namespace: String -> + when { + fileName.endsWith(".toml") -> RustWriter(fileName, namespace, "#", debugMode = debugMode) + fileName.endsWith(".py") -> RustWriter(fileName, namespace, "#", debugMode = debugMode) + fileName.endsWith(".md") -> rawWriter(fileName, debugMode = debugMode) + fileName == "LICENSE" -> rawWriter(fileName, debugMode = debugMode) + fileName.startsWith("tests/") -> + RustWriter( + fileName, + namespace, + debugMode = debugMode, + devDependenciesOnly = true, + ) + + fileName == "package.json" -> rawWriter(fileName, debugMode = debugMode) + fileName == "stubgen.sh" -> rawWriter(fileName, debugMode = debugMode) + else -> RustWriter(fileName, namespace, debugMode = debugMode) + } + } - fun factory(debugMode: Boolean): Factory = Factory { fileName: String, namespace: String -> - when { - fileName.endsWith(".toml") -> RustWriter(fileName, namespace, "#", debugMode = debugMode) - fileName.endsWith(".py") -> RustWriter(fileName, namespace, "#", debugMode = debugMode) - fileName.endsWith(".md") -> rawWriter(fileName, debugMode = debugMode) - fileName == "LICENSE" -> rawWriter(fileName, debugMode = debugMode) - fileName.startsWith("tests/") -> RustWriter( + fun toml( + fileName: String, + debugMode: Boolean = false, + ): RustWriter = + RustWriter( fileName, - namespace, + namespace = "ignore", + commentCharacter = "#", + printWarning = false, debugMode = debugMode, - devDependenciesOnly = true, ) - fileName == "package.json" -> rawWriter(fileName, debugMode = debugMode) - fileName == "stubgen.sh" -> rawWriter(fileName, debugMode = debugMode) - else -> RustWriter(fileName, namespace, debugMode = debugMode) - } + private fun rawWriter( + fileName: String, + debugMode: Boolean, + ): RustWriter = + RustWriter( + fileName, + namespace = "ignore", + commentCharacter = "ignore", + printWarning = false, + debugMode = debugMode, + ) } - fun toml(fileName: String, debugMode: Boolean = false): RustWriter = - RustWriter( - fileName, - namespace = "ignore", - commentCharacter = "#", - printWarning = false, - debugMode = debugMode, - ) - - private fun rawWriter(fileName: String, debugMode: Boolean): RustWriter = - RustWriter( - fileName, - namespace = "ignore", - commentCharacter = "ignore", - printWarning = false, - debugMode = debugMode, - ) - } + override fun write( + content: Any?, + vararg args: Any?, + ): RustWriter { + // TODO(https://github.com/rust-lang/rustfmt/issues/5425): The second condition introduced here is to prevent + // this rustfmt bug + val contentIsNotJustAComma = (content as? String?)?.let { it.trim() != "," } ?: false + if (debugMode && contentIsNotJustAComma) { + val location = Thread.currentThread().stackTrace + location.first { it.isRelevant() }?.let { "/* ${it.fileName}:${it.lineNumber} */" } + ?.also { super.writeInline(it) } + } - override fun write(content: Any?, vararg args: Any?): RustWriter { - // TODO(https://github.com/rust-lang/rustfmt/issues/5425): The second condition introduced here is to prevent - // this rustfmt bug - val contentIsNotJustAComma = (content as? String?)?.let { it.trim() != "," } ?: false - if (debugMode && contentIsNotJustAComma) { - val location = Thread.currentThread().stackTrace - location.first { it.isRelevant() }?.let { "/* ${it.fileName}:${it.lineNumber} */" } - ?.also { super.writeInline(it) } + return super.write(content, *args) } - return super.write(content, *args) - } - - fun dirty() = super.toString().isNotBlank() || preamble.isNotEmpty() + fun dirty() = super.toString().isNotBlank() || preamble.isNotEmpty() - /** Helper function to determine if a stack frame is relevant for debug purposes */ - private fun StackTraceElement.isRelevant(): Boolean { - if (this.className.contains("AbstractCodeWriter") || this.className.startsWith("java.lang")) { - return false + /** Helper function to determine if a stack frame is relevant for debug purposes */ + private fun StackTraceElement.isRelevant(): Boolean { + if (this.className.contains("AbstractCodeWriter") || this.className.startsWith("java.lang")) { + return false + } + return this.fileName != "RustWriter.kt" } - return this.fileName != "RustWriter.kt" - } - private val preamble = mutableListOf() - private val formatter = RustSymbolFormatter() - private var n = 0 + private val preamble = mutableListOf() + private val formatter = RustSymbolFormatter() + private var n = 0 - init { - expressionStart = '#' - if (filename.endsWith(".rs")) { - require(namespace.startsWith("crate") || filename.startsWith("tests/") || filename == "build.rs") { - "We can only write into files in the crate (got $namespace)" + init { + expressionStart = '#' + if (filename.endsWith(".rs")) { + require(namespace.startsWith("crate") || filename.startsWith("tests/") || filename == "build.rs") { + "We can only write into files in the crate (got $namespace)" + } } + putFormatter('T', formatter) + putFormatter('D', RustDocLinker()) + putFormatter('W', RustWriteableInjector()) } - putFormatter('T', formatter) - putFormatter('D', RustDocLinker()) - putFormatter('W', RustWriteableInjector()) - } - - fun module(): String? = if (filename.startsWith("src") && filename.endsWith(".rs")) { - filename.removeSuffix(".rs").substringAfterLast(File.separatorChar) - } else { - null - } - - fun safeName(prefix: String = "var"): String { - n += 1 - return "${prefix}_$n" - } - - fun first(preWriter: Writable) { - preamble.add(preWriter) - } - private fun addDependencyTestAware(dependencyContainer: SymbolDependencyContainer): RustWriter { - if (!devDependenciesOnly) { - super.addDependency(dependencyContainer) - } else { - dependencyContainer.dependencies.forEach { dependency -> - super.addDependency( - when (val dep = RustDependency.fromSymbolDependency(dependency)) { - is CargoDependency -> dep.toDevDependency() - else -> dependencyContainer - }, - ) + fun module(): String? = + if (filename.startsWith("src") && filename.endsWith(".rs")) { + filename.removeSuffix(".rs").substringAfterLast(File.separatorChar) + } else { + null } - } - return this - } - /** - * Create an inline module. Instead of being in a new file, inline modules are written as a `mod { ... }` block - * directly into the parent. - * - * Callers must take care to use [this] when writing to ensure code is written to the right place: - * ```kotlin - * val writer = RustWriter.forModule("model") - * writer.withInlineModule(RustModule.public("nested")) { - * Generator(...).render(this) // GOOD - * Generator(...).render(writer) // WRONG! - * } - * ``` - * - * The returned writer will inject any local imports into the module as needed. - */ - fun withInlineModule( - module: RustModule.LeafModule, - moduleDocProvider: ModuleDocProvider?, - moduleWriter: Writable, - ): RustWriter { - check(module.isInline()) { - "Only inline modules may be used with `withInlineModule`: $module" + fun safeName(prefix: String = "var"): String { + n += 1 + return "${prefix}_$n" } - // In Rust, modules must specify their own imports—they don't have access to the parent scope. - // To easily handle this, create a new inner writer to collect imports, then dump it - // into an inline module. - val innerWriter = RustWriter( - this.filename, - "${this.namespace}::${module.name}", - printWarning = false, - devDependenciesOnly = devDependenciesOnly || module.tests, - ) - moduleWriter(innerWriter) - ModuleDocProvider.writeDocs(moduleDocProvider, module, this) - module.rustMetadata.render(this) - rustBlock("mod ${module.name}") { - writeWithNoFormatting(innerWriter.toString()) + fun first(preWriter: Writable) { + preamble.add(preWriter) } - innerWriter.dependencies.forEach { addDependencyTestAware(it) } - return this - } - /** - * Generate a wrapping if statement around a nullable value. - * The provided code block will only be called if the value is not `None`. - */ - fun ifSome(member: Symbol, value: ValueExpression, block: RustWriter.(value: ValueExpression) -> Unit) { - when { - member.isOptional() -> { - val innerValue = ValueExpression.Reference(safeName("inner")) - rustBlockTemplate("if let #{Some}(${innerValue.name}) = ${value.asRef()}", *preludeScope) { - block(innerValue) + private fun addDependencyTestAware(dependencyContainer: SymbolDependencyContainer): RustWriter { + if (!devDependenciesOnly) { + super.addDependency(dependencyContainer) + } else { + dependencyContainer.dependencies.forEach { dependency -> + super.addDependency( + when (val dep = RustDependency.fromSymbolDependency(dependency)) { + is CargoDependency -> dep.toDevDependency() + else -> dependencyContainer + }, + ) } } - - else -> this.block(value) + return this } - } - - /** - * Generate a wrapping if statement around a primitive field. - * The specified block will only be called if the field is not set to its default value - `0` for - * numbers, `false` for booleans. - */ - fun ifNotDefault(shape: Shape, variable: ValueExpression, block: RustWriter.(field: ValueExpression) -> Unit) { - when (shape) { - is FloatShape, is DoubleShape -> rustBlock("if ${variable.asValue()} != 0.0") { - block(variable) - } - - is NumberShape -> rustBlock("if ${variable.asValue()} != 0") { - block(variable) - } - is BooleanShape -> rustBlock("if ${variable.asValue()}") { - block(variable) + /** + * Create an inline module. Instead of being in a new file, inline modules are written as a `mod { ... }` block + * directly into the parent. + * + * Callers must take care to use [this] when writing to ensure code is written to the right place: + * ```kotlin + * val writer = RustWriter.forModule("model") + * writer.withInlineModule(RustModule.public("nested")) { + * Generator(...).render(this) // GOOD + * Generator(...).render(writer) // WRONG! + * } + * ``` + * + * The returned writer will inject any local imports into the module as needed. + */ + fun withInlineModule( + module: RustModule.LeafModule, + moduleDocProvider: ModuleDocProvider?, + moduleWriter: Writable, + ): RustWriter { + check(module.isInline()) { + "Only inline modules may be used with `withInlineModule`: $module" } - else -> rustBlock("") { - this.block(variable) + // In Rust, modules must specify their own imports—they don't have access to the parent scope. + // To easily handle this, create a new inner writer to collect imports, then dump it + // into an inline module. + val innerWriter = + RustWriter( + this.filename, + "${this.namespace}::${module.name}", + printWarning = false, + devDependenciesOnly = devDependenciesOnly || module.tests, + ) + moduleWriter(innerWriter) + ModuleDocProvider.writeDocs(moduleDocProvider, module, this) + module.rustMetadata.render(this) + rustBlock("mod ${module.name}") { + writeWithNoFormatting(innerWriter.toString()) } + innerWriter.dependencies.forEach { addDependencyTestAware(it) } + return this } - } - /** - * Generate a wrapping if statement around a field. - * - * - If the field is optional, it will only be called if the field is present - * - If the field is an unboxed primitive, it will only be called if the field is non-zero - * - * # Example - * - * For a nullable structure shape (e.g. `Option`), the following code will be generated: - * - * ``` - * if let Some(v) = my_nullable_struct { - * /* {block(variable)} */ - * } - * ``` - * - * # Example - * - * For a non-nullable integer shape, the following code will be generated: - * - * ``` - * if my_int != 0 { - * /* {block(variable)} */ - * } - * ``` - */ - fun ifSet( - shape: Shape, - member: Symbol, - variable: ValueExpression, - block: RustWriter.(field: ValueExpression) -> Unit, - ) { - ifSome(member, variable) { inner -> ifNotDefault(shape, inner, block) } - } + /** + * Generate a wrapping if statement around a nullable value. + * The provided code block will only be called if the value is not `None`. + */ + fun ifSome( + member: Symbol, + value: ValueExpression, + block: RustWriter.(value: ValueExpression) -> Unit, + ) { + when { + member.isOptional() -> { + val innerValue = ValueExpression.Reference(safeName("inner")) + rustBlockTemplate("if let #{Some}(${innerValue.name}) = ${value.asRef()}", *preludeScope) { + block(innerValue) + } + } - fun listForEach( - target: Shape, - outerField: String, - block: RustWriter.(field: String, target: ShapeId) -> Unit, - ) { - if (target is CollectionShape) { - val derefName = safeName("inner") - rustBlock("for $derefName in $outerField") { - block(derefName, target.member.target) + else -> this.block(value) } - } else { - this.block(outerField, target.toShapeId()) } - } - override fun toString(): String { - val contents = super.toString() - val preheader = if (preamble.isNotEmpty()) { - val prewriter = - RustWriter(filename, namespace, printWarning = false, devDependenciesOnly = devDependenciesOnly) - preamble.forEach { it(prewriter) } - prewriter.toString() - } else { - null + /** + * Generate a wrapping if statement around a primitive field. + * If the field is a number or boolean, the specified block is only called if the field is not equal to the + * member's default value. + */ + fun ifNotNumberOrBoolDefault( + shape: Shape, + memberSymbol: Symbol, + variable: ValueExpression, + block: RustWriter.(field: ValueExpression) -> Unit, + ) { + when (shape) { + is NumberShape, is BooleanShape -> { + if (memberSymbol.defaultValue() is Default.RustDefault) { + when (shape) { + is FloatShape, is DoubleShape -> + rustBlock("if ${variable.asValue()} != 0.0") { + block(variable) + } + + is NumberShape -> + rustBlock("if ${variable.asValue()} != 0") { + block(variable) + } + + is BooleanShape -> + rustBlock("if ${variable.asValue()}") { + block(variable) + } + } + } else if (memberSymbol.defaultValue() is Default.NonZeroDefault) { + val default = Node.printJson((memberSymbol.defaultValue() as Default.NonZeroDefault).value) + when (shape) { + // We know that the default is 'true' since it's the only possible non-zero default + // for a boolean. Don't explicitly check against `true` to avoid a clippy lint. + is BooleanShape -> + rustBlock("if !${variable.asValue()}") { + block(variable) + } + + else -> + rustBlock("if ${variable.asValue()} != $default") { + block(variable) + } + } + } else { + rustBlock("") { + block(variable) + } + } + } + else -> + rustBlock("") { + block(variable) + } + } } - // Hack to support TOML: the [commentCharacter] is overridden to support writing TOML. - val header = if (printWarning) { - "$commentCharacter Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT." - } else { - null - } - val useDecls = importContainer.toString().ifEmpty { - null + /** + * Generate a wrapping if statement around a field. + * + * - If the field is optional, it will only be called if the field is present + * - If the field is an unboxed primitive, it will only be called if the field is non-zero + * + * # Example + * + * For a nullable structure shape (e.g. `Option`), the following code will be generated: + * + * ``` + * if let Some(v) = my_nullable_struct { + * /* {block(variable)} */ + * } + * ``` + * + * # Example + * + * For a non-nullable integer shape, the following code will be generated: + * + * ``` + * if my_int != 0 { + * /* {block(variable)} */ + * } + * ``` + */ + fun ifSet( + shape: Shape, + member: Symbol, + variable: ValueExpression, + block: RustWriter.(field: ValueExpression) -> Unit, + ) { + ifSome(member, variable) { inner -> ifNotNumberOrBoolDefault(shape, member, inner, block) } } - return listOfNotNull(preheader, header, useDecls, contents).joinToString(separator = "\n", postfix = "\n") - } - fun format(r: Any) = formatter.apply(r, "") - - fun addDepsRecursively(symbol: Symbol) { - addDependencyTestAware(symbol) - symbol.references.forEach { addDepsRecursively(it.symbol) } - } - - /** - * Generate RustDoc links, e.g. [`Abc`](crate::module::Abc) - */ - inner class RustDocLinker : BiFunction { - override fun apply(t: Any, u: String): String { - return when (t) { - is Symbol -> "[`${t.name}`](${docLink(t.rustType().qualifiedName())})" - else -> throw CodegenException("Invalid type provided to RustDocLinker ($t) expected Symbol") + fun listForEach( + target: Shape, + outerField: String, + block: RustWriter.(field: String, target: ShapeId) -> Unit, + ) { + if (target is CollectionShape) { + val derefName = safeName("inner") + rustBlock("for $derefName in $outerField") { + block(derefName, target.member.target) + } + } else { + this.block(outerField, target.toShapeId()) } } - } - - /** - * Formatter to enable formatting any [writable] with the #W formatter. - */ - inner class RustWriteableInjector : BiFunction { - override fun apply(t: Any, u: String): String { - @Suppress("UNCHECKED_CAST") - val func = - t as? Writable ?: throw CodegenException("RustWriteableInjector.apply choked on non-function t ($t)") - val innerWriter = - RustWriter(filename, namespace, printWarning = false, devDependenciesOnly = devDependenciesOnly) - func(innerWriter) - innerWriter.dependencies.forEach { addDependencyTestAware(it) } - return innerWriter.toString().trimEnd() - } - } - inner class RustSymbolFormatter : BiFunction { - override fun apply(t: Any, u: String): String { - return when (t) { - is RuntimeType -> { - t.dependency?.also { addDependencyTestAware(it) } - // for now, use the fully qualified type name - t.fullyQualifiedName() + override fun toString(): String { + val contents = super.toString() + val preheader = + if (preamble.isNotEmpty()) { + val prewriter = + RustWriter(filename, namespace, printWarning = false, devDependenciesOnly = devDependenciesOnly) + preamble.forEach { it(prewriter) } + prewriter.toString() + } else { + null } - is RustModule -> { - t.fullyQualifiedPath() + // Hack to support TOML: the [commentCharacter] is overridden to support writing TOML. + val header = + if (printWarning) { + "$commentCharacter Code generated by software.amazon.smithy.rust.codegen.smithy-rs. DO NOT EDIT." + } else { + null } - - is Symbol -> { - addDepsRecursively(t) - t.rustType().render(fullyQualified = true) + val useDecls = + importContainer.toString().ifEmpty { + null } + return listOfNotNull(preheader, header, useDecls, contents).joinToString(separator = "\n", postfix = "\n") + } - is RustType -> { - t.render(fullyQualified = true) - } + fun format(r: Any) = formatter.apply(r, "") - is Function<*> -> { - @Suppress("UNCHECKED_CAST") - val func = - t as? Writable ?: throw CodegenException("Invalid function type (expected writable) ($t)") - val innerWriter = - RustWriter(filename, namespace, printWarning = false, devDependenciesOnly = devDependenciesOnly) - func(innerWriter) - innerWriter.dependencies.forEach { addDependencyTestAware(it) } - return innerWriter.toString().trimEnd() + fun addDepsRecursively(symbol: Symbol) { + addDependencyTestAware(symbol) + symbol.references.forEach { addDepsRecursively(it.symbol) } + } + + /** + * Generate RustDoc links, e.g. [`Abc`](crate::module::Abc) + */ + inner class RustDocLinker : BiFunction { + override fun apply( + t: Any, + u: String, + ): String { + return when (t) { + is Symbol -> "[`${t.name}`](${docLink(t.rustType().qualifiedName())})" + else -> throw CodegenException("Invalid type provided to RustDocLinker ($t) expected Symbol") } + } + } + + /** + * Formatter to enable formatting any [writable] with the #W formatter. + */ + inner class RustWriteableInjector : BiFunction { + override fun apply( + t: Any, + u: String, + ): String { + @Suppress("UNCHECKED_CAST") + val func = + t as? Writable ?: throw CodegenException("RustWriteableInjector.apply choked on non-function t ($t)") + val innerWriter = + RustWriter(filename, namespace, printWarning = false, devDependenciesOnly = devDependenciesOnly) + func(innerWriter) + innerWriter.dependencies.forEach { addDependencyTestAware(it) } + return innerWriter.toString().trimEnd() + } + } - else -> throw CodegenException("Invalid type provided to RustSymbolFormatter: $t") - // escaping generates `##` sequences for all the common cases where - // it will be run through templating, but in this context, we won't be escaped - }.replace("##", "#") + inner class RustSymbolFormatter : BiFunction { + override fun apply( + t: Any, + u: String, + ): String { + return when (t) { + is RuntimeType -> { + t.dependency?.also { addDependencyTestAware(it) } + // for now, use the fully qualified type name + t.fullyQualifiedName() + } + + is RustModule -> { + t.fullyQualifiedPath() + } + + is Symbol -> { + addDepsRecursively(t) + t.rustType().render(fullyQualified = true) + } + + is RustType -> { + t.render(fullyQualified = true) + } + + is Function<*> -> { + @Suppress("UNCHECKED_CAST") + val func = + t as? Writable ?: throw CodegenException("Invalid function type (expected writable) ($t)") + val innerWriter = + RustWriter(filename, namespace, printWarning = false, devDependenciesOnly = devDependenciesOnly) + func(innerWriter) + innerWriter.dependencies.forEach { addDependencyTestAware(it) } + return innerWriter.toString().trimEnd() + } + + else -> throw CodegenException("Invalid type provided to RustSymbolFormatter: $t") + // escaping generates `##` sequences for all the common cases where + // it will be run through templating, but in this context, we won't be escaped + }.replace("##", "#") + } } } -} diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/UseDeclarations.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/UseDeclarations.kt index 4e409bf126e..bbfc8696ba3 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/UseDeclarations.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/UseDeclarations.kt @@ -10,7 +10,12 @@ import software.amazon.smithy.codegen.core.Symbol class UseDeclarations(private val namespace: String) : ImportContainer { private val imports: MutableSet = mutableSetOf() - fun addImport(moduleName: String, symbolName: String, alias: String = symbolName) { + + fun addImport( + moduleName: String, + symbolName: String, + alias: String = symbolName, + ) { imports.add(UseStatement(moduleName, symbolName, alias)) } @@ -18,7 +23,10 @@ class UseDeclarations(private val namespace: String) : ImportContainer { return imports.map { it.toString() }.sorted().joinToString(separator = "\n") } - override fun importSymbol(symbol: Symbol, alias: String?) { + override fun importSymbol( + symbol: Symbol, + alias: String?, + ) { if (symbol.namespace.isNotEmpty() && symbol.namespace != namespace) { addImport(symbol.namespace, symbol.name, alias ?: symbol.name) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/Writable.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/Writable.kt index 8ef68e9ef25..ad4b07c2308 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/Writable.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/Writable.kt @@ -105,31 +105,33 @@ fun Array.join(separator: Writable) = asIterable().join(separator) * some_fn::(); * ``` */ -fun rustTypeParameters( - vararg typeParameters: Any, -): Writable = writable { - if (typeParameters.isNotEmpty()) { - val items = typeParameters.map { typeParameter -> - writable { - when (typeParameter) { - is Symbol, is RuntimeType, is RustType -> rustInlineTemplate("#{it}", "it" to typeParameter) - is String -> rustInlineTemplate(typeParameter) - is RustGenerics -> rustInlineTemplate( - "#{gg:W}", - "gg" to typeParameter.declaration(withAngleBrackets = false), - ) - - else -> { - // Check if it's a writer. If it is, invoke it; Else, throw a codegen error. - @Suppress("UNCHECKED_CAST") - val func = typeParameter as? Writable - ?: throw CodegenException("Unhandled type '$typeParameter' encountered by rustTypeParameters writer") - func.invoke(this) +fun rustTypeParameters(vararg typeParameters: Any): Writable = + writable { + if (typeParameters.isNotEmpty()) { + val items = + typeParameters.map { typeParameter -> + writable { + when (typeParameter) { + is Symbol, is RuntimeType, is RustType -> rustInlineTemplate("#{it}", "it" to typeParameter) + is String -> rustInlineTemplate(typeParameter) + is RustGenerics -> + rustInlineTemplate( + "#{gg:W}", + "gg" to typeParameter.declaration(withAngleBrackets = false), + ) + + else -> { + // Check if it's a writer. If it is, invoke it; Else, throw a codegen error. + @Suppress("UNCHECKED_CAST") + val func = + typeParameter as? Writable + ?: throw CodegenException("Unhandled type '$typeParameter' encountered by rustTypeParameters writer") + func.invoke(this) + } + } } } - } - } - rustInlineTemplate("<#{Items:W}>", "Items" to items.join(", ")) + rustInlineTemplate("<#{Items:W}>", "Items" to items.join(", ")) + } } -} diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenContext.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenContext.kt index a08eddb5ed5..eba03b6f71d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenContext.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenContext.kt @@ -27,32 +27,26 @@ abstract class CodegenContext( * an entry point. */ open val model: Model, - /** * The "canonical" symbol provider to convert Smithy [Shape]s into [Symbol]s, which have an associated [RustType]. */ open val symbolProvider: RustSymbolProvider, - /** * Provider of documentation for generated Rust modules. */ open val moduleDocProvider: ModuleDocProvider?, - /** * Entrypoint service shape for code generation. */ open val serviceShape: ServiceShape, - /** * Shape indicating the protocol to generate, e.g. RestJson1. */ open val protocol: ShapeId, - /** * Settings loaded from `smithy-build.json`. */ open val settings: CoreRustSettings, - /** * Are we generating code for a smithy-rs client or server? * @@ -63,22 +57,23 @@ abstract class CodegenContext( */ open val target: CodegenTarget, ) { - /** * Configuration of the runtime package: * - Where are the runtime crates (smithy-*) located on the file system? Or are they versioned? * - What are they called? + * + * This is just a convenience. To avoid typing `context.settings.runtimeConfig`, you can simply write + * `context.runtimeConfig`. */ - // This is just a convenience. To avoid typing `context.settings.runtimeConfig`, you can simply write - // `context.runtimeConfig`. val runtimeConfig: RuntimeConfig by lazy { settings.runtimeConfig } /** * The name of the cargo crate to generate e.g. `aws-sdk-s3` * This is loaded from the smithy-build.json during codegen. + * + * This is just a convenience. To avoid typing `context.settings.moduleName`, you can simply write + * `context.moduleName`. */ - // This is just a convenience. To avoid typing `context.settings.moduleName`, you can simply write - // `context.moduleName`. val moduleName: String by lazy { settings.moduleName } /** @@ -88,9 +83,10 @@ abstract class CodegenContext( fun moduleUseName() = moduleName.replace("-", "_") /** Return a ModuleDocProvider or panic if one wasn't configured */ - fun expectModuleDocProvider(): ModuleDocProvider = checkNotNull(moduleDocProvider) { - "A ModuleDocProvider must be set on the CodegenContext" - } + fun expectModuleDocProvider(): ModuleDocProvider = + checkNotNull(moduleDocProvider) { + "A ModuleDocProvider must be set on the CodegenContext" + } fun structSettings() = StructSettings(settings.codegenConfig.flattenCollectionAccessors) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt index d52359d6c40..d494ea0caff 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegator.kt @@ -31,7 +31,11 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.ManifestCustom /** Provider of documentation for generated Rust modules */ interface ModuleDocProvider { companion object { - fun writeDocs(provider: ModuleDocProvider?, module: RustModule.LeafModule, writer: RustWriter) { + fun writeDocs( + provider: ModuleDocProvider?, + module: RustModule.LeafModule, + writer: RustWriter, + ) { check( provider != null || module.documentationOverride != null || @@ -90,7 +94,10 @@ open class RustCrate( /** * Write into the module that this shape is [locatedIn] */ - fun useShapeWriter(shape: Shape, f: Writable) { + fun useShapeWriter( + shape: Shape, + f: Writable, + ) { val module = symbolProvider.toSymbol(shape).module() check(!module.isInline()) { "Cannot use useShapeWriter with inline modules—use [RustWriter.withInlineModule] instead" @@ -191,9 +198,10 @@ open class RustCrate( } else { // Create a dependency which adds the mod statement for this module. This will be added to the writer // so that _usage_ of this module will generate _exactly one_ `mod ` with the correct modifiers. - val modStatement = RuntimeType.forInlineFun("mod_" + module.fullyQualifiedPath(), module.parent) { - module.renderModStatement(this, moduleDocProvider) - } + val modStatement = + RuntimeType.forInlineFun("mod_" + module.fullyQualifiedPath(), module.parent) { + module.renderModStatement(this, moduleDocProvider) + } val path = module.fullyQualifiedPath().split("::").drop(1).joinToString("/") inner.useFileWriter("src/$path.rs", module.fullyQualifiedPath()) { writer -> moduleWriter(writer) @@ -208,13 +216,18 @@ open class RustCrate( /** * Returns the module for a given Shape. */ - fun moduleFor(shape: Shape, moduleWriter: Writable): RustCrate = - withModule((symbolProvider as RustSymbolProvider).moduleForShape(shape), moduleWriter) + fun moduleFor( + shape: Shape, + moduleWriter: Writable, + ): RustCrate = withModule((symbolProvider as RustSymbolProvider).moduleForShape(shape), moduleWriter) /** * Create a new file directly */ - fun withFile(filename: String, fileWriter: Writable) { + fun withFile( + filename: String, + fileWriter: Writable, + ) { inner.useFileWriter(filename) { fileWriter(it) } @@ -227,7 +240,11 @@ open class RustCrate( * @param symbol: The symbol of the thing being rendered, which will be re-exported. This symbol * should be the public-facing symbol rather than the private symbol. */ - fun inPrivateModuleWithReexport(privateModule: RustModule.LeafModule, symbol: Symbol, writer: Writable) { + fun inPrivateModuleWithReexport( + privateModule: RustModule.LeafModule, + symbol: Symbol, + writer: Writable, + ) { withModule(privateModule, writer) privateModule.toType().resolve(symbol.name).toSymbol().also { privateSymbol -> withModule(symbol.module()) { @@ -264,13 +281,14 @@ fun WriterDelegator.finalize( .mergeDependencyFeatures() .mergeIdenticalTestDependencies() this.useFileWriter("Cargo.toml") { - val cargoToml = CargoTomlGenerator( - settings, - it, - manifestCustomizations, - cargoDependencies, - features, - ) + val cargoToml = + CargoTomlGenerator( + settings, + it, + manifestCustomizations, + cargoDependencies, + features, + ) cargoToml.render() } flushWriters() diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenTarget.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenTarget.kt index b1dba3e33f9..fff8f264a27 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenTarget.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenTarget.kt @@ -9,23 +9,27 @@ package software.amazon.smithy.rust.codegen.core.smithy * Code generation mode: In some situations, codegen has different behavior for client vs. server (eg. required fields) */ enum class CodegenTarget { - CLIENT, SERVER; + CLIENT, + SERVER, + ; /** * Convenience method to execute thunk if the target is for CLIENT */ - fun ifClient(thunk: () -> B): B? = if (this == CLIENT) { - thunk() - } else { - null - } + fun ifClient(thunk: () -> B): B? = + if (this == CLIENT) { + thunk() + } else { + null + } /** * Convenience method to execute thunk if the target is for SERVER */ - fun ifServer(thunk: () -> B): B? = if (this == SERVER) { - thunk() - } else { - null - } + fun ifServer(thunk: () -> B): B? = + if (this == SERVER) { + thunk() + } else { + null + } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CoreRustSettings.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CoreRustSettings.kt index 5e103f14625..18c9fa5d7a6 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CoreRustSettings.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CoreRustSettings.kt @@ -79,7 +79,6 @@ open class CoreRustSettings( open val moduleAuthors: List, open val moduleDescription: String?, open val moduleRepository: String?, - /** * Configuration of the runtime package: * - Where are the runtime crates (smithy-*) located on the file system? Or are they versioned? @@ -91,7 +90,6 @@ open class CoreRustSettings( open val examplesUri: String? = null, open val customizationConfig: ObjectNode? = null, ) { - /** * Get the corresponding [ServiceShape] from a model. * @return Returns the found `Service` @@ -111,10 +109,11 @@ open class CoreRustSettings( // Infer the service to generate from a model. @JvmStatic protected fun inferService(model: Model): ShapeId { - val services = model.shapes(ServiceShape::class.java) - .map(Shape::getId) - .sorted() - .toList() + val services = + model.shapes(ServiceShape::class.java) + .map(Shape::getId) + .sorted() + .toList() when { services.isEmpty() -> { @@ -144,7 +143,10 @@ open class CoreRustSettings( * @param config Config object to load * @return Returns the extracted settings */ - fun from(model: Model, config: ObjectNode): CoreRustSettings { + fun from( + model: Model, + config: ObjectNode, + ): CoreRustSettings { val codegenSettings = config.getObjectMember(CODEGEN_SETTINGS) val coreCodegenConfig = CoreCodegenConfig.fromNode(codegenSettings) return fromCodegenConfig(model, config, coreCodegenConfig) @@ -158,7 +160,11 @@ open class CoreRustSettings( * @param coreCodegenConfig CodegenConfig object to use * @return Returns the extracted settings */ - private fun fromCodegenConfig(model: Model, config: ObjectNode, coreCodegenConfig: CoreCodegenConfig): CoreRustSettings { + private fun fromCodegenConfig( + model: Model, + config: ObjectNode, + coreCodegenConfig: CoreCodegenConfig, + ): CoreRustSettings { config.warnIfAdditionalProperties( arrayListOf( SERVICE, @@ -175,9 +181,10 @@ open class CoreRustSettings( ), ) - val service = config.getStringMember(SERVICE) - .map(StringNode::expectShapeId) - .orElseGet { inferService(model) } + val service = + config.getStringMember(SERVICE) + .map(StringNode::expectShapeId) + .orElseGet { inferService(model) } val runtimeConfig = config.getObjectMember(RUNTIME_CONFIG) return CoreRustSettings( diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/DirectedWalker.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/DirectedWalker.kt index f48b996045e..5ce1a3bed7a 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/DirectedWalker.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/DirectedWalker.kt @@ -21,6 +21,9 @@ class DirectedWalker(model: Model) { fun walkShapes(shape: Shape): Set = walkShapes(shape) { true } - fun walkShapes(shape: Shape, predicate: Predicate): Set = + fun walkShapes( + shape: Shape, + predicate: Predicate, + ): Set = inner.walkShapes(shape) { rel -> predicate.test(rel) && rel.direction == RelationshipDirection.DIRECTED } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/EventStreamSymbolProvider.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/EventStreamSymbolProvider.kt index 97ef843fe7a..ee19295897f 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/EventStreamSymbolProvider.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/EventStreamSymbolProvider.kt @@ -34,33 +34,38 @@ class EventStreamSymbolProvider( // We only want to wrap with Event Stream types when dealing with member shapes if (shape is MemberShape && shape.isEventStream(model)) { // Determine if the member has a container that is a synthetic input or output - val operationShape = model.expectShape(shape.container).let { maybeInputOutput -> - val operationId = maybeInputOutput.getTrait()?.operation - ?: maybeInputOutput.getTrait()?.operation - operationId?.let { model.expectShape(it, OperationShape::class.java) } - } + val operationShape = + model.expectShape(shape.container).let { maybeInputOutput -> + val operationId = + maybeInputOutput.getTrait()?.operation + ?: maybeInputOutput.getTrait()?.operation + operationId?.let { model.expectShape(it, OperationShape::class.java) } + } // If we find an operation shape, then we can wrap the type if (operationShape != null) { val unionShape = model.expectShape(shape.target).asUnionShape().get() - val error = if (target == CodegenTarget.SERVER && unionShape.eventStreamErrors().isEmpty()) { - RuntimeType.smithyHttp(runtimeConfig).resolve("event_stream::MessageStreamError").toSymbol() - } else { - symbolForEventStreamError(unionShape) - } + val error = + if (target == CodegenTarget.SERVER && unionShape.eventStreamErrors().isEmpty()) { + RuntimeType.smithyHttp(runtimeConfig).resolve("event_stream::MessageStreamError").toSymbol() + } else { + symbolForEventStreamError(unionShape) + } val errorT = error.rustType() val innerT = initial.rustType().stripOuter() - val isSender = (shape.isInputEventStream(model) && target == CodegenTarget.CLIENT) || - (shape.isOutputEventStream(model) && target == CodegenTarget.SERVER) - val outer = when (isSender) { - true -> RuntimeType.eventStreamSender(runtimeConfig).toSymbol().rustType() - else -> { - if (target == CodegenTarget.SERVER) { - RuntimeType.eventStreamReceiver(runtimeConfig).toSymbol().rustType() - } else { - RuntimeType.eventReceiver(runtimeConfig).toSymbol().rustType() + val isSender = + (shape.isInputEventStream(model) && target == CodegenTarget.CLIENT) || + (shape.isOutputEventStream(model) && target == CodegenTarget.SERVER) + val outer = + when (isSender) { + true -> RuntimeType.eventStreamSender(runtimeConfig).toSymbol().rustType() + else -> { + if (target == CodegenTarget.SERVER) { + RuntimeType.eventStreamReceiver(runtimeConfig).toSymbol().rustType() + } else { + RuntimeType.eventReceiver(runtimeConfig).toSymbol().rustType() + } } } - } val rustType = RustType.Application(outer, listOf(innerT, errorT)) return initial.toBuilder() .name(rustType.name) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt index 6235af28447..f0fc3e833e3 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeType.kt @@ -5,7 +5,6 @@ package software.amazon.smithy.rust.codegen.core.smithy -import software.amazon.smithy.codegen.core.CodegenException import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.node.Node import software.amazon.smithy.model.node.ObjectNode @@ -27,8 +26,6 @@ import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.util.orNull import java.util.Optional -private const val DEFAULT_KEY = "DEFAULT" - /** * Location of the runtime crates (aws-smithy-http, aws-smithy-types etc.) * @@ -36,14 +33,15 @@ private const val DEFAULT_KEY = "DEFAULT" */ data class RuntimeCrateLocation(val path: String?, val versions: CrateVersionMap) { companion object { - fun Path(path: String) = RuntimeCrateLocation(path, CrateVersionMap(emptyMap())) + fun path(path: String) = RuntimeCrateLocation(path, CrateVersionMap(emptyMap())) } } fun RuntimeCrateLocation.crateLocation(crateName: String): DependencyLocation { - val version = crateName.let { - versions.map[crateName] - } ?: Version.crateVersion(crateName) + val version = + crateName.let { + versions.map[crateName] + } ?: Version.crateVersion(crateName) return when (this.path) { // CratesIo needs an exact version. However, for local runtime crates we do not // provide a detected version unless the user explicitly sets one via the `versions` map. @@ -52,14 +50,6 @@ fun RuntimeCrateLocation.crateLocation(crateName: String): DependencyLocation { } } -fun defaultRuntimeCrateVersion(): String { - try { - return Version.stableCrateVersion() - } catch (ex: Exception) { - throw CodegenException("failed to get crate version which sets the default client-runtime version", ex) - } -} - /** * A mapping from crate name to a user-specified version. */ @@ -73,10 +63,9 @@ value class CrateVersionMap( */ data class RuntimeConfig( val cratePrefix: String = "aws", - val runtimeCrateLocation: RuntimeCrateLocation = RuntimeCrateLocation.Path("../"), + val runtimeCrateLocation: RuntimeCrateLocation = RuntimeCrateLocation.path("../"), ) { companion object { - /** * Load a `RuntimeConfig` from an [ObjectNode] (JSON) */ @@ -144,12 +133,13 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) /** * Get a writable for this `RuntimeType` */ - val writable = writable { - rustInlineTemplate( - "#{this:T}", - "this" to this@RuntimeType, - ) - } + val writable = + writable { + rustInlineTemplate( + "#{this:T}", + "this" to this@RuntimeType, + ) + } /** * Convert this [RuntimeType] into a [Symbol]. @@ -158,11 +148,12 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) * (e.g. when bringing a trait into scope). See [CodegenWriter.addUseImports]. */ fun toSymbol(): Symbol { - val builder = Symbol - .builder() - .name(name) - .namespace(namespace, "::") - .rustType(RustType.Opaque(name, namespace)) + val builder = + Symbol + .builder() + .name(name) + .namespace(namespace, "::") + .rustType(RustType.Opaque(name, namespace)) dependency?.run { builder.addDependency(this) } return builder.build() @@ -240,7 +231,6 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) "String" to String, "ToString" to std.resolve("string::ToString"), "Vec" to Vec, - // 2021 Edition "TryFrom" to std.resolve("convert::TryFrom"), "TryInto" to std.resolve("convert::TryInto"), @@ -315,19 +305,28 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) // smithy runtime types fun smithyAsync(runtimeConfig: RuntimeConfig) = CargoDependency.smithyAsync(runtimeConfig).toType() + fun smithyChecksums(runtimeConfig: RuntimeConfig) = CargoDependency.smithyChecksums(runtimeConfig).toType() fun smithyEventStream(runtimeConfig: RuntimeConfig) = CargoDependency.smithyEventStream(runtimeConfig).toType() + fun smithyHttp(runtimeConfig: RuntimeConfig) = CargoDependency.smithyHttp(runtimeConfig).toType() + fun smithyJson(runtimeConfig: RuntimeConfig) = CargoDependency.smithyJson(runtimeConfig).toType() + fun smithyQuery(runtimeConfig: RuntimeConfig) = CargoDependency.smithyQuery(runtimeConfig).toType() + fun smithyRuntime(runtimeConfig: RuntimeConfig) = CargoDependency.smithyRuntime(runtimeConfig).toType() + fun smithyRuntimeApi(runtimeConfig: RuntimeConfig) = CargoDependency.smithyRuntimeApi(runtimeConfig).toType() + fun smithyRuntimeApiClient(runtimeConfig: RuntimeConfig) = CargoDependency.smithyRuntimeApiClient(runtimeConfig).toType() fun smithyTypes(runtimeConfig: RuntimeConfig) = CargoDependency.smithyTypes(runtimeConfig).toType() + fun smithyXml(runtimeConfig: RuntimeConfig) = CargoDependency.smithyXml(runtimeConfig).toType() + private fun smithyProtocolTest(runtimeConfig: RuntimeConfig) = CargoDependency.smithyProtocolTestHelpers(runtimeConfig).toType() @@ -402,11 +401,17 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) smithyRuntimeApi(runtimeConfig).resolve("http::Headers") fun blob(runtimeConfig: RuntimeConfig) = smithyTypes(runtimeConfig).resolve("Blob") + fun byteStream(runtimeConfig: RuntimeConfig) = smithyTypes(runtimeConfig).resolve("byte_stream::ByteStream") + fun dateTime(runtimeConfig: RuntimeConfig) = smithyTypes(runtimeConfig).resolve("DateTime") + fun document(runtimeConfig: RuntimeConfig): RuntimeType = smithyTypes(runtimeConfig).resolve("Document") + fun format(runtimeConfig: RuntimeConfig) = smithyTypes(runtimeConfig).resolve("date_time::Format") + fun retryErrorKind(runtimeConfig: RuntimeConfig) = smithyTypes(runtimeConfig).resolve("retry::ErrorKind") + fun eventStreamReceiver(runtimeConfig: RuntimeConfig): RuntimeType = smithyHttp(runtimeConfig).resolve("event_stream::Receiver") @@ -420,6 +425,7 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) smithyHttp(runtimeConfig).resolve("futures_stream_adapter::FuturesStreamCompatByteStream") fun errorMetadata(runtimeConfig: RuntimeConfig) = smithyTypes(runtimeConfig).resolve("error::ErrorMetadata") + fun errorMetadataBuilder(runtimeConfig: RuntimeConfig) = smithyTypes(runtimeConfig).resolve("error::metadata::Builder") @@ -427,6 +433,7 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) smithyTypes(runtimeConfig).resolve("error::metadata::ProvideErrorMetadata") fun jsonErrors(runtimeConfig: RuntimeConfig) = forInlineDependency(InlineDependency.jsonErrors(runtimeConfig)) + fun awsQueryCompatibleErrors(runtimeConfig: RuntimeConfig) = forInlineDependency(InlineDependency.awsQueryCompatibleErrors(runtimeConfig)) @@ -434,17 +441,26 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) RuntimeType.forInlineDependency(InlineDependency.defaultAuthPlugin(runtimeConfig)) .resolve("DefaultAuthOptionsPlugin") - fun labelFormat(runtimeConfig: RuntimeConfig, func: String) = smithyHttp(runtimeConfig).resolve("label::$func") + fun labelFormat( + runtimeConfig: RuntimeConfig, + func: String, + ) = smithyHttp(runtimeConfig).resolve("label::$func") + fun operation(runtimeConfig: RuntimeConfig) = smithyHttp(runtimeConfig).resolve("operation::Operation") - fun operationModule(runtimeConfig: RuntimeConfig) = smithyHttp(runtimeConfig).resolve("operation") - fun protocolTest(runtimeConfig: RuntimeConfig, func: String): RuntimeType = - smithyProtocolTest(runtimeConfig).resolve(func) + fun protocolTest( + runtimeConfig: RuntimeConfig, + func: String, + ): RuntimeType = smithyProtocolTest(runtimeConfig).resolve(func) fun provideErrorKind(runtimeConfig: RuntimeConfig) = smithyTypes(runtimeConfig).resolve("retry::ProvideErrorKind") - fun queryFormat(runtimeConfig: RuntimeConfig, func: String) = smithyHttp(runtimeConfig).resolve("query::$func") + fun queryFormat( + runtimeConfig: RuntimeConfig, + func: String, + ) = smithyHttp(runtimeConfig).resolve("query::$func") + fun sdkBody(runtimeConfig: RuntimeConfig): RuntimeType = smithyTypes(runtimeConfig).resolve("body::SdkBody") fun parseTimestampFormat( @@ -452,13 +468,14 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) runtimeConfig: RuntimeConfig, format: TimestampFormatTrait.Format, ): RuntimeType { - val timestampFormat = when (format) { - TimestampFormatTrait.Format.EPOCH_SECONDS -> "EpochSeconds" - // clients allow offsets, servers do nt - TimestampFormatTrait.Format.DATE_TIME -> codegenTarget.ifClient { "DateTimeWithOffset" } ?: "DateTime" - TimestampFormatTrait.Format.HTTP_DATE -> "HttpDate" - TimestampFormatTrait.Format.UNKNOWN -> TODO() - } + val timestampFormat = + when (format) { + TimestampFormatTrait.Format.EPOCH_SECONDS -> "EpochSeconds" + // clients allow offsets, servers do nt + TimestampFormatTrait.Format.DATE_TIME -> codegenTarget.ifClient { "DateTimeWithOffset" } ?: "DateTime" + TimestampFormatTrait.Format.HTTP_DATE -> "HttpDate" + TimestampFormatTrait.Format.UNKNOWN -> TODO() + } return smithyTypes(runtimeConfig).resolve("date_time::Format::$timestampFormat") } @@ -467,24 +484,30 @@ data class RuntimeType(val path: String, val dependency: RustDependency? = null) runtimeConfig: RuntimeConfig, format: TimestampFormatTrait.Format, ): RuntimeType { - val timestampFormat = when (format) { - TimestampFormatTrait.Format.EPOCH_SECONDS -> "EpochSeconds" - // clients allow offsets, servers do not - TimestampFormatTrait.Format.DATE_TIME -> "DateTime" - TimestampFormatTrait.Format.HTTP_DATE -> "HttpDate" - TimestampFormatTrait.Format.UNKNOWN -> TODO() - } + val timestampFormat = + when (format) { + TimestampFormatTrait.Format.EPOCH_SECONDS -> "EpochSeconds" + // clients allow offsets, servers do not + TimestampFormatTrait.Format.DATE_TIME -> "DateTime" + TimestampFormatTrait.Format.HTTP_DATE -> "HttpDate" + TimestampFormatTrait.Format.UNKNOWN -> TODO() + } return smithyTypes(runtimeConfig).resolve("date_time::Format::$timestampFormat") } - fun captureRequest(runtimeConfig: RuntimeConfig) = CargoDependency.smithyRuntimeTestUtil(runtimeConfig).toType() - .resolve("client::http::test_util::capture_request") + fun captureRequest(runtimeConfig: RuntimeConfig) = + CargoDependency.smithyRuntimeTestUtil(runtimeConfig).toType() + .resolve("client::http::test_util::capture_request") fun forInlineDependency(inlineDependency: InlineDependency) = RuntimeType("crate::${inlineDependency.name}", inlineDependency) - fun forInlineFun(name: String, module: RustModule, func: Writable) = RuntimeType( + fun forInlineFun( + name: String, + module: RustModule, + func: Writable, + ) = RuntimeType( "${module.fullyQualifiedPath()}::$name", dependency = InlineDependency(name, module, listOf(), func), ) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RustSymbolProvider.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RustSymbolProvider.kt index 2314007aa93..78ab4bfebcf 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RustSymbolProvider.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RustSymbolProvider.kt @@ -26,10 +26,13 @@ interface RustSymbolProvider : SymbolProvider { fun moduleForShape(shape: Shape): RustModule.LeafModule = config.moduleProvider.moduleForShape(moduleProviderContext, shape) + fun moduleForOperationError(operation: OperationShape): RustModule.LeafModule = config.moduleProvider.moduleForOperationError(moduleProviderContext, operation) + fun moduleForEventStreamError(eventStream: UnionShape): RustModule.LeafModule = config.moduleProvider.moduleForEventStreamError(moduleProviderContext, eventStream) + fun moduleForBuilder(shape: Shape): RustModule.LeafModule = config.moduleProvider.moduleForBuilder(moduleProviderContext, shape, toSymbol(shape)) @@ -61,16 +64,29 @@ fun CodegenContext.toModuleProviderContext(): ModuleProviderContext = */ interface ModuleProvider { /** Returns the module for a shape */ - fun moduleForShape(context: ModuleProviderContext, shape: Shape): RustModule.LeafModule + fun moduleForShape( + context: ModuleProviderContext, + shape: Shape, + ): RustModule.LeafModule /** Returns the module for an operation error */ - fun moduleForOperationError(context: ModuleProviderContext, operation: OperationShape): RustModule.LeafModule + fun moduleForOperationError( + context: ModuleProviderContext, + operation: OperationShape, + ): RustModule.LeafModule /** Returns the module for an event stream error */ - fun moduleForEventStreamError(context: ModuleProviderContext, eventStream: UnionShape): RustModule.LeafModule + fun moduleForEventStreamError( + context: ModuleProviderContext, + eventStream: UnionShape, + ): RustModule.LeafModule /** Returns the module for a builder */ - fun moduleForBuilder(context: ModuleProviderContext, shape: Shape, symbol: Symbol): RustModule.LeafModule + fun moduleForBuilder( + context: ModuleProviderContext, + shape: Shape, + symbol: Symbol, + ): RustModule.LeafModule } /** @@ -93,9 +109,13 @@ open class WrappingSymbolProvider(private val base: RustSymbolProvider) : RustSy override val config: RustSymbolProviderConfig get() = base.config override fun toSymbol(shape: Shape): Symbol = base.toSymbol(shape) + override fun toMemberName(shape: MemberShape): String = base.toMemberName(shape) + override fun symbolForOperationError(operation: OperationShape): Symbol = base.symbolForOperationError(operation) + override fun symbolForEventStreamError(eventStream: UnionShape): Symbol = base.symbolForEventStreamError(eventStream) + override fun symbolForBuilder(shape: Shape): Symbol = base.symbolForBuilder(shape) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/StreamingTraitSymbolProvider.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/StreamingTraitSymbolProvider.kt index 051f3c3d1ee..646fb3d5ca9 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/StreamingTraitSymbolProvider.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/StreamingTraitSymbolProvider.kt @@ -77,11 +77,16 @@ class StreamingShapeMetadataProvider(private val base: RustSymbolProvider) : Sym } override fun memberMeta(memberShape: MemberShape) = base.toSymbol(memberShape).expectRustMetadata() + override fun enumMeta(stringShape: StringShape) = base.toSymbol(stringShape).expectRustMetadata() override fun listMeta(listShape: ListShape) = base.toSymbol(listShape).expectRustMetadata() + override fun mapMeta(mapShape: MapShape) = base.toSymbol(mapShape).expectRustMetadata() + override fun stringMeta(stringShape: StringShape) = base.toSymbol(stringShape).expectRustMetadata() + override fun numberMeta(numberShape: NumberShape) = base.toSymbol(numberShape).expectRustMetadata() + override fun blobMeta(blobShape: BlobShape) = base.toSymbol(blobShape).expectRustMetadata() } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolExt.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolExt.kt index 35a278a3182..78b348e6c2e 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolExt.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolExt.kt @@ -118,10 +118,11 @@ fun Symbol.canUseDefault(): Boolean = this.defaultValue() != Default.NoDefault /** * True when [this] is will be represented by Option in Rust */ -fun Symbol.isOptional(): Boolean = when (this.rustType()) { - is RustType.Option -> true - else -> false -} +fun Symbol.isOptional(): Boolean = + when (this.rustType()) { + is RustType.Option -> true + else -> false + } fun Symbol.isRustBoxed(): Boolean = rustType().stripOuter() is RustType.Box @@ -133,12 +134,21 @@ private const val SYMBOL_DEFAULT = "symboldefault" // Symbols should _always_ be created with a Rust type & shape attached fun Symbol.rustType(): RustType = this.expectProperty(RUST_TYPE_KEY, RustType::class.java) + fun Symbol.Builder.rustType(rustType: RustType): Symbol.Builder = this.putProperty(RUST_TYPE_KEY, rustType) + fun Symbol.shape(): Shape = this.expectProperty(SHAPE_KEY, Shape::class.java) + fun Symbol.Builder.shape(shape: Shape?): Symbol.Builder = this.putProperty(SHAPE_KEY, shape) + fun Symbol.module(): RustModule.LeafModule = this.expectProperty(RUST_MODULE_KEY, RustModule.LeafModule::class.java) + fun Symbol.Builder.module(module: RustModule.LeafModule): Symbol.Builder = this.putProperty(RUST_MODULE_KEY, module) + fun Symbol.renamedFrom(): String? = this.getProperty(RENAMED_FROM_KEY, String::class.java).orNull() + fun Symbol.Builder.renamedFrom(name: String): Symbol.Builder = this.putProperty(RENAMED_FROM_KEY, name) + fun Symbol.defaultValue(): Default = this.getProperty(SYMBOL_DEFAULT, Default::class.java).orElse(Default.NoDefault) + fun Symbol.Builder.setDefault(default: Default): Symbol.Builder = this.putProperty(SYMBOL_DEFAULT, default) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolMetadataProvider.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolMetadataProvider.kt index 6476dd538e3..6da78fa44cf 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolMetadataProvider.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolMetadataProvider.kt @@ -10,6 +10,7 @@ import software.amazon.smithy.codegen.core.Symbol import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.BlobShape import software.amazon.smithy.model.shapes.CollectionShape +import software.amazon.smithy.model.shapes.IntEnumShape import software.amazon.smithy.model.shapes.ListShape import software.amazon.smithy.model.shapes.MapShape import software.amazon.smithy.model.shapes.MemberShape @@ -33,34 +34,43 @@ import software.amazon.smithy.rust.codegen.core.util.hasTrait abstract class SymbolMetadataProvider(private val base: RustSymbolProvider) : WrappingSymbolProvider(base) { override fun toSymbol(shape: Shape): Symbol { val baseSymbol = base.toSymbol(shape) - val meta = when (shape) { - is MemberShape -> memberMeta(shape) - is StructureShape -> structureMeta(shape) - is UnionShape -> unionMeta(shape) - is ListShape -> listMeta(shape) - is MapShape -> mapMeta(shape) - is NumberShape -> numberMeta(shape) - is BlobShape -> blobMeta(shape) - is StringShape -> if (shape.hasTrait()) { - enumMeta(shape) - } else { - stringMeta(shape) + val meta = + when (shape) { + is MemberShape -> memberMeta(shape) + is StructureShape -> structureMeta(shape) + is UnionShape -> unionMeta(shape) + is ListShape -> listMeta(shape) + is MapShape -> mapMeta(shape) + is NumberShape -> numberMeta(shape) + is BlobShape -> blobMeta(shape) + is StringShape -> + if (shape.hasTrait()) { + enumMeta(shape) + } else { + stringMeta(shape) + } + + else -> null } - - else -> null - } return baseSymbol.toBuilder().meta(meta).build() } abstract fun memberMeta(memberShape: MemberShape): RustMetadata + abstract fun structureMeta(structureShape: StructureShape): RustMetadata + abstract fun unionMeta(unionShape: UnionShape): RustMetadata + abstract fun enumMeta(stringShape: StringShape): RustMetadata abstract fun listMeta(listShape: ListShape): RustMetadata + abstract fun mapMeta(mapShape: MapShape): RustMetadata + abstract fun stringMeta(stringShape: StringShape): RustMetadata + abstract fun numberMeta(numberShape: NumberShape): RustMetadata + abstract fun blobMeta(blobShape: BlobShape): RustMetadata } @@ -71,12 +81,13 @@ fun containerDefaultMetadata( ): RustMetadata { val derives = mutableSetOf(RuntimeType.Debug, RuntimeType.PartialEq, RuntimeType.Clone) - val isSensitive = shape.hasTrait() || - // Checking the shape's direct members for the sensitive trait should suffice. - // Whether their descendants, i.e. a member's member, is sensitive does not - // affect the inclusion/exclusion of the derived `Debug` trait of _this_ container - // shape; any sensitive descendant should still be printed as redacted. - shape.members().any { it.getMemberTrait(model, SensitiveTrait::class.java).isPresent } + val isSensitive = + shape.hasTrait() || + // Checking the shape's direct members for the sensitive trait should suffice. + // Whether their descendants, i.e. a member's member, is sensitive does not + // affect the inclusion/exclusion of the derived `Debug` trait of _this_ container + // shape; any sensitive descendant should still be printed as redacted. + shape.members().any { it.getMemberTrait(model, SensitiveTrait::class.java).isPresent } if (isSensitive) { derives.remove(RuntimeType.Debug) @@ -95,7 +106,6 @@ class BaseSymbolMetadataProvider( base: RustSymbolProvider, private val additionalAttributes: List, ) : SymbolMetadataProvider(base) { - override fun memberMeta(memberShape: MemberShape): RustMetadata = when (val container = model.expectShape(memberShape.container)) { is StructureShape -> RustMetadata(visibility = Visibility.PUBLIC) @@ -105,11 +115,14 @@ class BaseSymbolMetadataProvider( // This covers strings with the enum trait for now, and can be removed once we're fully on EnumShape // TODO(https://github.com/smithy-lang/smithy-rs/issues/1700): Remove this `is StringShape` match arm is StringShape -> RustMetadata(visibility = Visibility.PUBLIC) + is IntEnumShape -> RustMetadata(visibility = Visibility.PUBLIC) else -> TODO("Unrecognized container type: $container") } - override fun structureMeta(structureShape: StructureShape) = containerDefaultMetadata(structureShape, model, additionalAttributes) + override fun structureMeta(structureShape: StructureShape) = + containerDefaultMetadata(structureShape, model, additionalAttributes) + override fun unionMeta(unionShape: UnionShape) = containerDefaultMetadata(unionShape, model, additionalAttributes) override fun enumMeta(stringShape: StringShape): RustMetadata = @@ -127,17 +140,23 @@ class BaseSymbolMetadataProvider( private fun defaultRustMetadata() = RustMetadata(visibility = Visibility.PRIVATE) override fun listMeta(listShape: ListShape) = defaultRustMetadata() + override fun mapMeta(mapShape: MapShape) = defaultRustMetadata() + override fun stringMeta(stringShape: StringShape) = defaultRustMetadata() + override fun numberMeta(numberShape: NumberShape) = defaultRustMetadata() + override fun blobMeta(blobShape: BlobShape) = defaultRustMetadata() } private const val META_KEY = "meta" + fun Symbol.Builder.meta(rustMetadata: RustMetadata?): Symbol.Builder = this.putProperty(META_KEY, rustMetadata) -fun Symbol.expectRustMetadata(): RustMetadata = this.getProperty(META_KEY, RustMetadata::class.java).orElseThrow { - CodegenException( - "Expected `$this` to have metadata attached but it did not.", - ) -} +fun Symbol.expectRustMetadata(): RustMetadata = + this.getProperty(META_KEY, RustMetadata::class.java).orElseThrow { + CodegenException( + "Expected `$this` to have metadata attached but it did not.", + ) + } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitor.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitor.kt index af74c80d9f6..89d50554486 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitor.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitor.kt @@ -56,17 +56,18 @@ import software.amazon.smithy.rust.codegen.core.util.toSnakeCase import kotlin.reflect.KClass /** Map from Smithy Shapes to Rust Types */ -val SimpleShapes: Map, RustType> = mapOf( - BooleanShape::class to RustType.Bool, - FloatShape::class to RustType.Float(32), - DoubleShape::class to RustType.Float(64), - ByteShape::class to RustType.Integer(8), - ShortShape::class to RustType.Integer(16), - IntegerShape::class to RustType.Integer(32), - IntEnumShape::class to RustType.Integer(32), - LongShape::class to RustType.Integer(64), - StringShape::class to RustType.String, -) +val SimpleShapes: Map, RustType> = + mapOf( + BooleanShape::class to RustType.Bool, + FloatShape::class to RustType.Float(32), + DoubleShape::class to RustType.Float(64), + ByteShape::class to RustType.Integer(8), + ShortShape::class to RustType.Integer(16), + IntegerShape::class to RustType.Integer(32), + IntEnumShape::class to RustType.Integer(32), + LongShape::class to RustType.Integer(64), + StringShape::class to RustType.String, + ) /** * Track both the past and current name of a symbol @@ -82,7 +83,10 @@ data class MaybeRenamed(val name: String, val renamedFrom: String?) /** * Make the return [value] optional if the [member] symbol is as well optional. */ -fun SymbolProvider.wrapOptional(member: MemberShape, value: String): String = +fun SymbolProvider.wrapOptional( + member: MemberShape, + value: String, +): String = value.letIf(toSymbol(member).isOptional()) { "Some($value)" } @@ -90,7 +94,10 @@ fun SymbolProvider.wrapOptional(member: MemberShape, value: String): String = /** * Make the return [value] optional if the [member] symbol is not optional. */ -fun SymbolProvider.toOptional(member: MemberShape, value: String): String = +fun SymbolProvider.toOptional( + member: MemberShape, + value: String, +): String = value.letIf(!toSymbol(member).isOptional()) { "Some($value)" } @@ -139,10 +146,11 @@ open class SymbolVisitor( module.toType().resolve("${symbol.name}Error").toSymbol().toBuilder().locatedIn(module).build() } - override fun symbolForBuilder(shape: Shape): Symbol = toSymbol(shape).let { symbol -> - val module = moduleForBuilder(shape) - module.toType().resolve(config.nameBuilderFor(symbol)).toSymbol().toBuilder().locatedIn(module).build() - } + override fun symbolForBuilder(shape: Shape): Symbol = + toSymbol(shape).let { symbol -> + val module = moduleForBuilder(shape) + module.toType().resolve(config.nameBuilderFor(symbol)).toSymbol().toBuilder().locatedIn(module).build() + } override fun toMemberName(shape: MemberShape): String { val container = model.expectShape(shape.container) @@ -160,7 +168,10 @@ open class SymbolVisitor( /** * Produce `Box` when the shape has the `RustBoxTrait` */ - private fun handleRustBoxing(symbol: Symbol, shape: Shape): Symbol { + private fun handleRustBoxing( + symbol: Symbol, + shape: Shape, + ): Symbol { return if (shape.hasTrait()) { val rustType = RustType.Box(symbol.rustType()) with(Symbol.builder()) { @@ -179,14 +190,21 @@ open class SymbolVisitor( } override fun booleanShape(shape: BooleanShape): Symbol = simpleShape(shape) + override fun byteShape(shape: ByteShape): Symbol = simpleShape(shape) + override fun shortShape(shape: ShortShape): Symbol = simpleShape(shape) + override fun integerShape(shape: IntegerShape): Symbol = simpleShape(shape) + override fun longShape(shape: LongShape): Symbol = simpleShape(shape) + override fun floatShape(shape: FloatShape): Symbol = simpleShape(shape) + override fun doubleShape(shape: DoubleShape): Symbol = simpleShape(shape) override fun intEnumShape(shape: IntEnumShape): Symbol = simpleShape(shape) + override fun stringShape(shape: StringShape): Symbol { return if (shape.hasTrait()) { val rustType = RustType.Opaque(shape.contextName(serviceShape).toPascalCase()) @@ -203,12 +221,13 @@ open class SymbolVisitor( override fun setShape(shape: SetShape): Symbol { val inner = this.toSymbol(shape.member) - val builder = if (model.expectShape(shape.member.target).isStringShape) { - symbolBuilder(shape, RustType.HashSet(inner.rustType())) - } else { - // only strings get put into actual sets because floats are unhashable - symbolBuilder(shape, RustType.Vec(inner.rustType())) - } + val builder = + if (model.expectShape(shape.member.target).isStringShape) { + symbolBuilder(shape, RustType.HashSet(inner.rustType())) + } else { + // only strings get put into actual sets because floats are unhashable + symbolBuilder(shape, RustType.Vec(inner.rustType())) + } return builder.addReference(inner).build() } @@ -255,9 +274,10 @@ open class SymbolVisitor( override fun structureShape(shape: StructureShape): Symbol { val isError = shape.hasTrait() - val name = shape.contextName(serviceShape).toPascalCase().letIf(isError && config.renameExceptions) { - it.replace("Exception", "Error") - } + val name = + shape.contextName(serviceShape).toPascalCase().letIf(isError && config.renameExceptions) { + it.replace("Exception", "Error") + } return symbolBuilder(shape, RustType.Opaque(name)).locatedIn(moduleForShape(shape)).build() } @@ -268,17 +288,18 @@ open class SymbolVisitor( override fun memberShape(shape: MemberShape): Symbol { val target = model.expectShape(shape.target) - val defaultValue = shape.getMemberTrait(model, DefaultTrait::class.java).orNull()?.let { trait -> - if (target.isDocumentShape || target.isTimestampShape) { - Default.NonZeroDefault(trait.toNode()) - } else { - when (val value = trait.toNode()) { - Node.from(""), Node.from(0), Node.from(false), Node.arrayNode(), Node.objectNode() -> Default.RustDefault - Node.nullNode() -> Default.NoDefault - else -> Default.NonZeroDefault(value) + val defaultValue = + shape.getMemberTrait(model, DefaultTrait::class.java).orNull()?.let { trait -> + if (target.isDocumentShape || target.isTimestampShape) { + Default.NonZeroDefault(trait.toNode()) + } else { + when (val value = trait.toNode()) { + Node.from(""), Node.from(0), Node.from(false), Node.arrayNode(), Node.objectNode() -> Default.RustDefault + Node.nullNode() -> Default.NoDefault + else -> Default.NonZeroDefault(value) + } } - } - } ?: Default.NoDefault + } ?: Default.NoDefault // Handle boxing first, so we end up with Option>, not Box>. return handleOptionality( handleRustBoxing(toSymbol(target), shape), @@ -299,14 +320,20 @@ open class SymbolVisitor( * * See `RecursiveShapeBoxer.kt` for the model transformation pass that annotates model shapes with [RustBoxTrait]. */ -fun handleRustBoxing(symbol: Symbol, shape: MemberShape): Symbol = +fun handleRustBoxing( + symbol: Symbol, + shape: MemberShape, +): Symbol = if (shape.hasTrait()) { symbol.makeRustBoxed() } else { symbol } -fun symbolBuilder(shape: Shape?, rustType: RustType): Symbol.Builder = +fun symbolBuilder( + shape: Shape?, + rustType: RustType, +): Symbol.Builder = Symbol.builder().shape(shape).rustType(rustType) .name(rustType.name) // Every symbol that actually gets defined somewhere should set a definition file @@ -318,8 +345,7 @@ fun handleOptionality( member: MemberShape, nullableIndex: NullableIndex, nullabilityCheckMode: CheckMode, -): Symbol = - symbol.letIf(nullableIndex.isMemberNullable(member, nullabilityCheckMode)) { symbol.makeOptional() } +): Symbol = symbol.letIf(nullableIndex.isMemberNullable(member, nullabilityCheckMode)) { symbol.makeOptional() } /** * Creates a test module for this symbol. diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/AllowLintsCustomization.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/AllowLintsCustomization.kt index 43eb40696e3..d7ee63fd273 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/AllowLintsCustomization.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/AllowLintsCustomization.kt @@ -12,71 +12,72 @@ import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection -private val allowedRustcLints = listOf( - // Deprecated items should be safe to compile, so don't block the compilation. - "deprecated", -) - -private val allowedClippyLints = listOf( - // Sometimes operations are named the same as our module e.g. output leading to `output::output`. - "module_inception", - - // Currently, we don't re-case acronyms in models, e.g. `SSEVersion`. - "upper_case_acronyms", - - // Large errors trigger this warning, we are unlikely to optimize this case currently. - "large_enum_variant", - - // Some models have members with `is` in the name, which leads to builder functions with the wrong self convention. - "wrong_self_convention", - - // Models like ecs use method names like `add()` which confuses Clippy. - "should_implement_trait", - - // Protocol tests use silly names like `baz`, don't flag that. - "disallowed_names", - - // Forcing use of `vec![]` can make codegen harder in some cases. - "vec_init_then_push", - - // Some models have shapes that generate complex Rust types (e.g. nested collection and map shapes). - "type_complexity", - - // Determining if the expression is the last one (to remove return) can make codegen harder in some cases. - "needless_return", - - // For backwards compatibility, we often don't derive Eq - "derive_partial_eq_without_eq", - - // Keeping errors small in a backwards compatible way is challenging - "result_large_err", -) - -private val allowedRustdocLints = listOf( - // Rust >=1.53.0 requires links to be wrapped in ``. This is extremely hard to enforce for - // docs that come from the modeled documentation, so we need to disable this lint - "bare_urls", -) +private val allowedRustcLints = + listOf( + // Deprecated items should be safe to compile, so don't block the compilation. + "deprecated", + // Unknown lints need to be allowed since we use both nightly and our MSRV, and sometimes we need + // to disable lints that are in nightly but don't exist in the MSRV. + "unknown_lints", + ) + +private val allowedClippyLints = + listOf( + // Sometimes operations are named the same as our module e.g. output leading to `output::output`. + "module_inception", + // Currently, we don't re-case acronyms in models, e.g. `SSEVersion`. + "upper_case_acronyms", + // Large errors trigger this warning, we are unlikely to optimize this case currently. + "large_enum_variant", + // Some models have members with `is` in the name, which leads to builder functions with the wrong self convention. + "wrong_self_convention", + // Models like ecs use method names like `add()` which confuses Clippy. + "should_implement_trait", + // Protocol tests use silly names like `baz`, don't flag that. + "disallowed_names", + // Forcing use of `vec![]` can make codegen harder in some cases. + "vec_init_then_push", + // Some models have shapes that generate complex Rust types (e.g. nested collection and map shapes). + "type_complexity", + // Determining if the expression is the last one (to remove return) can make codegen harder in some cases. + "needless_return", + // For backwards compatibility, we often don't derive Eq + "derive_partial_eq_without_eq", + // Keeping errors small in a backwards compatible way is challenging + "result_large_err", + ) + +private val allowedRustdocLints = + listOf( + // Rust >=1.53.0 requires links to be wrapped in ``. This is extremely hard to enforce for + // docs that come from the modeled documentation, so we need to disable this lint + "bare_urls", + // Rustdoc warns about redundant explicit links in doc comments. This is fine for handwritten + // crates, but is impractical to manage for code generated crates. Thus, allow it. + "redundant_explicit_links", + ) class AllowLintsCustomization( private val rustcLints: List = allowedRustcLints, private val clippyLints: List = allowedClippyLints, private val rustdocLints: List = allowedRustdocLints, ) : LibRsCustomization() { - override fun section(section: LibRsSection) = when (section) { - is LibRsSection.Attributes -> writable { - rustcLints.forEach { - Attribute(allow(it)).render(this, AttributeKind.Inner) - } - clippyLints.forEach { - Attribute(allow("clippy::$it")).render(this, AttributeKind.Inner) - } - rustdocLints.forEach { - Attribute(allow("rustdoc::$it")).render(this, AttributeKind.Inner) - } - // add a newline at the end - this.write("") + override fun section(section: LibRsSection) = + when (section) { + is LibRsSection.Attributes -> + writable { + rustcLints.forEach { + Attribute(allow(it)).render(this, AttributeKind.Inner) + } + clippyLints.forEach { + Attribute(allow("clippy::$it")).render(this, AttributeKind.Inner) + } + rustdocLints.forEach { + Attribute(allow("rustdoc::$it")).render(this, AttributeKind.Inner) + } + // add a newline at the end + this.write("") + } + else -> emptySection } - else -> emptySection - } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/CrateVersionCustomization.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/CrateVersionCustomization.kt index 93db223c20e..310e125bd0d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/CrateVersionCustomization.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/CrateVersionCustomization.kt @@ -16,13 +16,15 @@ import software.amazon.smithy.rust.codegen.core.smithy.RustCrate object CrateVersionCustomization { fun pkgVersion(module: RustModule): RuntimeType = RuntimeType(module.fullyQualifiedPath() + "::PKG_VERSION") - fun extras(rustCrate: RustCrate, module: RustModule) = - rustCrate.withModule(module) { - rust( - """ - /// Crate version number. - pub static PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); - """, - ) - } + fun extras( + rustCrate: RustCrate, + module: RustModule, + ) = rustCrate.withModule(module) { + rust( + """ + /// Crate version number. + pub static PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); + """, + ) + } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtra.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtra.kt index 2a285ca13f3..dac62172a86 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtra.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtra.kt @@ -14,6 +14,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.eventReceiver import software.amazon.smithy.rust.codegen.core.smithy.RustCrate import software.amazon.smithy.rust.codegen.core.util.hasEventStreamMember import software.amazon.smithy.rust.codegen.core.util.hasEventStreamOperations @@ -30,12 +31,16 @@ private fun hasStreamingOperations(model: Model): Boolean { } // TODO(https://github.com/smithy-lang/smithy-rs/issues/2111): Fix this logic to consider collection/map shapes -private fun structUnionMembersMatchPredicate(model: Model, predicate: (Shape) -> Boolean): Boolean = +private fun structUnionMembersMatchPredicate( + model: Model, + predicate: (Shape) -> Boolean, +): Boolean = model.structureShapes.any { structure -> structure.members().any { member -> predicate(model.expectShape(member.target)) } - } || model.unionShapes.any { union -> - union.members().any { member -> predicate(model.expectShape(member.target)) } - } + } || + model.unionShapes.any { union -> + union.members().any { member -> predicate(model.expectShape(member.target)) } + } /** Returns true if the model uses any blob shapes */ private fun hasBlobs(model: Model): Boolean = structUnionMembersMatchPredicate(model, Shape::isBlobShape) @@ -44,59 +49,70 @@ private fun hasBlobs(model: Model): Boolean = structUnionMembersMatchPredicate(m private fun hasDateTimes(model: Model): Boolean = structUnionMembersMatchPredicate(model, Shape::isTimestampShape) /** Adds re-export statements for Smithy primitives */ -fun pubUseSmithyPrimitives(codegenContext: CodegenContext, model: Model, rustCrate: RustCrate): Writable = writable { - val rc = codegenContext.runtimeConfig - if (hasBlobs(model)) { - rustTemplate("pub use #{Blob};", "Blob" to RuntimeType.blob(rc)) - } - if (hasDateTimes(model)) { - rustTemplate( - """ - pub use #{DateTime}; - pub use #{Format} as DateTimeFormat; - """, - "DateTime" to RuntimeType.dateTime(rc), - "Format" to RuntimeType.format(rc), - ) - } - if (hasStreamingOperations(model)) { - rustCrate.mergeFeature( - Feature( - "rt-tokio", - true, - listOf("aws-smithy-types/rt-tokio"), - ), - ) - rustTemplate( - """ - pub use #{ByteStream}; - pub use #{AggregatedBytes}; - pub use #{Error} as ByteStreamError; - pub use #{SdkBody}; - """, - "ByteStream" to RuntimeType.smithyTypes(rc).resolve("byte_stream::ByteStream"), - "AggregatedBytes" to RuntimeType.smithyTypes(rc).resolve("byte_stream::AggregatedBytes"), - "Error" to RuntimeType.smithyTypes(rc).resolve("byte_stream::error::Error"), - "SdkBody" to RuntimeType.smithyTypes(rc).resolve("body::SdkBody"), - ) +fun pubUseSmithyPrimitives( + codegenContext: CodegenContext, + model: Model, + rustCrate: RustCrate, +): Writable = + writable { + val rc = codegenContext.runtimeConfig + if (hasBlobs(model)) { + rustTemplate("pub use #{Blob};", "Blob" to RuntimeType.blob(rc)) + } + if (hasDateTimes(model)) { + rustTemplate( + """ + pub use #{DateTime}; + pub use #{Format} as DateTimeFormat; + """, + "DateTime" to RuntimeType.dateTime(rc), + "Format" to RuntimeType.format(rc), + ) + } + if (hasStreamingOperations(model)) { + rustCrate.mergeFeature( + Feature( + "rt-tokio", + true, + listOf("aws-smithy-types/rt-tokio"), + ), + ) + rustTemplate( + """ + pub use #{ByteStream}; + pub use #{AggregatedBytes}; + pub use #{Error} as ByteStreamError; + pub use #{SdkBody}; + """, + "ByteStream" to RuntimeType.smithyTypes(rc).resolve("byte_stream::ByteStream"), + "AggregatedBytes" to RuntimeType.smithyTypes(rc).resolve("byte_stream::AggregatedBytes"), + "Error" to RuntimeType.smithyTypes(rc).resolve("byte_stream::error::Error"), + "SdkBody" to RuntimeType.smithyTypes(rc).resolve("body::SdkBody"), + ) + } } -} /** Adds re-export statements for event-stream-related Smithy primitives */ -fun pubUseSmithyPrimitivesEventStream(codegenContext: CodegenContext, model: Model): Writable = writable { - val rc = codegenContext.runtimeConfig - if (codegenContext.serviceShape.hasEventStreamOperations(model)) { - rustTemplate( - """ - pub use #{Header}; - pub use #{HeaderValue}; - pub use #{Message}; - pub use #{StrBytes}; - """, - "Header" to RuntimeType.smithyTypes(rc).resolve("event_stream::Header"), - "HeaderValue" to RuntimeType.smithyTypes(rc).resolve("event_stream::HeaderValue"), - "Message" to RuntimeType.smithyTypes(rc).resolve("event_stream::Message"), - "StrBytes" to RuntimeType.smithyTypes(rc).resolve("str_bytes::StrBytes"), - ) +fun pubUseSmithyPrimitivesEventStream( + codegenContext: CodegenContext, + model: Model, +): Writable = + writable { + val rc = codegenContext.runtimeConfig + if (codegenContext.serviceShape.hasEventStreamOperations(model)) { + rustTemplate( + """ + pub use #{EventReceiver}; + pub use #{Header}; + pub use #{HeaderValue}; + pub use #{Message}; + pub use #{StrBytes}; + """, + "EventReceiver" to eventReceiver(rc), + "Header" to RuntimeType.smithyTypes(rc).resolve("event_stream::Header"), + "HeaderValue" to RuntimeType.smithyTypes(rc).resolve("event_stream::HeaderValue"), + "Message" to RuntimeType.smithyTypes(rc).resolve("event_stream::Message"), + "StrBytes" to RuntimeType.smithyTypes(rc).resolve("str_bytes::StrBytes"), + ) + } } -} diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customize/CoreCodegenDecorator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customize/CoreCodegenDecorator.kt index 923f4fce554..f5fd23f4fc5 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customize/CoreCodegenDecorator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customize/CoreCodegenDecorator.kt @@ -43,12 +43,19 @@ interface CoreCodegenDecorator { /** * Hook to transform the Smithy model before codegen takes place. */ - fun transformModel(service: ServiceShape, model: Model, settings: CodegenSettings): Model = model + fun transformModel( + service: ServiceShape, + model: Model, + settings: CodegenSettings, + ): Model = model /** * Hook to add additional modules to the generated crate. */ - fun extras(codegenContext: CodegenContext, rustCrate: RustCrate) {} + fun extras( + codegenContext: CodegenContext, + rustCrate: RustCrate, + ) {} /** * Customize the documentation provider for module documentation. @@ -84,6 +91,7 @@ interface CoreCodegenDecorator { ): List = baseCustomizations // TODO(https://github.com/smithy-lang/smithy-rs/issues/1401): Move builder customizations into `ClientCodegenDecorator` + /** * Hook to customize generated builders. */ @@ -124,11 +132,18 @@ abstract class CombinedCoreCodegenDecorator decorator.transformModel(otherModel.expectShape(service.id, ServiceShape::class.java), otherModel, settings) } @@ -136,9 +151,10 @@ abstract class CombinedCoreCodegenDecorator - decorator.moduleDocumentationCustomization(codegenContext, base) - } + ): ModuleDocProvider = + combineCustomizations(baseModuleDocProvider) { decorator, base -> + decorator.moduleDocumentationCustomization(codegenContext, base) + } final override fun libRsCustomizations( codegenContext: CodegenContext, @@ -151,23 +167,26 @@ abstract class CombinedCoreCodegenDecorator, - ): List = combineCustomizations(baseCustomizations) { decorator, customizations -> - decorator.structureCustomizations(codegenContext, customizations) - } + ): List = + combineCustomizations(baseCustomizations) { decorator, customizations -> + decorator.structureCustomizations(codegenContext, customizations) + } override fun builderCustomizations( codegenContext: CodegenContext, baseCustomizations: List, - ): List = combineCustomizations(baseCustomizations) { decorator, customizations -> - decorator.builderCustomizations(codegenContext, customizations) - } + ): List = + combineCustomizations(baseCustomizations) { decorator, customizations -> + decorator.builderCustomizations(codegenContext, customizations) + } override fun errorImplCustomizations( codegenContext: CodegenContext, baseCustomizations: List, - ): List = combineCustomizations(baseCustomizations) { decorator, customizations -> - decorator.errorImplCustomizations(codegenContext, customizations) - } + ): List = + combineCustomizations(baseCustomizations) { decorator, customizations -> + decorator.errorImplCustomizations(codegenContext, customizations) + } final override fun extraSections(codegenContext: CodegenContext): List = addCustomizations { decorator -> decorator.extraSections(codegenContext) } @@ -215,16 +234,18 @@ abstract class CombinedCoreCodegenDecorator { - val decorators = ServiceLoader.load( - decoratorClass, - context.pluginClassLoader.orElse(decoratorClass.classLoader), - ) - - val filteredDecorators = decorators.asSequence() - .onEach { logger.info("Discovered Codegen Decorator: ${it!!::class.java.name}") } - .filter { it!!.classpathDiscoverable() } - .onEach { logger.info("Adding Codegen Decorator: ${it!!::class.java.name}") } - .toList() + val decorators = + ServiceLoader.load( + decoratorClass, + context.pluginClassLoader.orElse(decoratorClass.classLoader), + ) + + val filteredDecorators = + decorators.asSequence() + .onEach { logger.info("Discovered Codegen Decorator: ${it!!::class.java.name}") } + .filter { it!!.classpathDiscoverable() } + .onEach { logger.info("Adding Codegen Decorator: ${it!!::class.java.name}") } + .toList() return filteredDecorators + extras } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customize/Customization.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customize/Customization.kt index c174c81d954..79ff1bdb6f4 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customize/Customization.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customize/Customization.kt @@ -37,11 +37,12 @@ inline fun adhocCustomization( crossinline customization: RustWriter.(T) -> Unit, ): AdHocCustomization = object : AdHocCustomization() { - override fun section(section: AdHocSection): Writable = writable { - if (section is T) { - customization(section) + override fun section(section: AdHocSection): Writable = + writable { + if (section is T) { + customization(section) + } } - } } /** @@ -51,11 +52,15 @@ inline fun adhocCustomization( */ abstract class NamedCustomization { abstract fun section(section: T): Writable + protected val emptySection = writable { } } /** Convenience for rendering a list of customizations for a given section */ -fun RustWriter.writeCustomizations(customizations: List>, section: T) { +fun RustWriter.writeCustomizations( + customizations: List>, + section: T, +) { for (customization in customizations) { customization.section(section)(this) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt index a86afa07569..90554a1e5d5 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGenerator.kt @@ -76,6 +76,7 @@ sealed class BuilderSection(name: String) : Section(name) { abstract class BuilderCustomization : NamedCustomization() fun RuntimeConfig.operationBuildError() = RuntimeType.smithyTypes(this).resolve("error::operation::BuildError") + fun RuntimeConfig.serializationError() = RuntimeType.smithyTypes(this).resolve("error::operation::SerializationError") fun MemberShape.enforceRequired( @@ -88,31 +89,43 @@ fun MemberShape.enforceRequired( } val shape = this val isOptional = codegenContext.symbolProvider.toSymbol(shape).isOptional() - val field2 = field.letIf(!isOptional) { field.map { rust("Some(#T)", it) } } - val error = OperationBuildError(codegenContext.runtimeConfig).missingField( - codegenContext.symbolProvider.toMemberName(shape), "A required field was not set", - ) - val unwrapped = when (codegenContext.model.expectShape(this.target)) { - is StringShape -> writable { - rustTemplate( - "#{field}.filter(|f|!AsRef::::as_ref(f).trim().is_empty())", - "field" to field2, - ) - } + val field = field.letIf(!isOptional) { field.map { rust("Some(#T)", it) } } + val error = + OperationBuildError(codegenContext.runtimeConfig).missingField( + codegenContext.symbolProvider.toMemberName(shape), "A required field was not set", + ) + val unwrapped = + when (codegenContext.model.expectShape(this.target)) { + is StringShape -> + writable { + rustTemplate( + "#{field}.filter(|f|!AsRef::::as_ref(f).trim().is_empty())", + "field" to field, + ) + } - else -> field2 - }.map { base -> rustTemplate("#{base}.ok_or_else(||#{error})?", "base" to base, "error" to error) } + else -> field + }.map { base -> rustTemplate("#{base}.ok_or_else(||#{error})?", "base" to base, "error" to error) } return unwrapped.letIf(produceOption) { w -> w.map { rust("Some(#T)", it) } } } class OperationBuildError(private val runtimeConfig: RuntimeConfig) { - - fun missingField(field: String, details: String) = writable { + fun missingField( + field: String, + details: String, + ) = writable { rust("#T::missing_field(${field.dq()}, ${details.dq()})", runtimeConfig.operationBuildError()) } - fun invalidField(field: String, details: String) = invalidField(field) { rust(details.dq()) } - fun invalidField(field: String, details: Writable) = writable { + fun invalidField( + field: String, + details: String, + ) = invalidField(field) { rust(details.dq()) } + + fun invalidField( + field: String, + details: Writable, + ) = writable { rustTemplate( "#{error}::invalid_field(${field.dq()}, #{details:W})", "error" to runtimeConfig.operationBuildError(), @@ -138,7 +151,10 @@ class BuilderGenerator( * Returns whether a structure shape, whose builder has been generated with [BuilderGenerator], requires a * fallible builder to be constructed. */ - fun hasFallibleBuilder(structureShape: StructureShape, symbolProvider: SymbolProvider): Boolean = + fun hasFallibleBuilder( + structureShape: StructureShape, + symbolProvider: SymbolProvider, + ): Boolean = // All operation inputs should have fallible builders in case a new required field is added in the future. structureShape.hasTrait() || structureShape @@ -149,7 +165,11 @@ class BuilderGenerator( !it.isOptional() && !it.canUseDefault() } - fun renderConvenienceMethod(implBlock: RustWriter, symbolProvider: RustSymbolProvider, shape: StructureShape) { + fun renderConvenienceMethod( + implBlock: RustWriter, + symbolProvider: RustSymbolProvider, + shape: StructureShape, + ) { implBlock.docs("Creates a new builder-style object to manufacture #D.", symbolProvider.toSymbol(shape)) symbolProvider.symbolForBuilder(shape).also { builderSymbol -> implBlock.rustBlock("pub fn builder() -> #T", builderSymbol) { @@ -165,9 +185,10 @@ class BuilderGenerator( private val metadata = structureSymbol.expectRustMetadata() // Filter out any derive that isn't Debug, PartialEq, or Clone. Then add a Default derive - private val builderDerives = metadata.derives.filter { - it == RuntimeType.Debug || it == RuntimeType.PartialEq || it == RuntimeType.Clone - } + RuntimeType.Default + private val builderDerives = + metadata.derives.filter { + it == RuntimeType.Debug || it == RuntimeType.PartialEq || it == RuntimeType.Clone + } + RuntimeType.Default private val builderName = symbolProvider.symbolForBuilder(shape).name fun render(writer: RustWriter) { @@ -181,10 +202,11 @@ class BuilderGenerator( private fun renderBuildFn(implBlockWriter: RustWriter) { val fallibleBuilder = hasFallibleBuilder(shape, symbolProvider) val outputSymbol = symbolProvider.toSymbol(shape) - val returnType = when (fallibleBuilder) { - true -> "#{Result}<${implBlockWriter.format(outputSymbol)}, ${implBlockWriter.format(runtimeConfig.operationBuildError())}>" - false -> implBlockWriter.format(outputSymbol) - } + val returnType = + when (fallibleBuilder) { + true -> "#{Result}<${implBlockWriter.format(outputSymbol)}, ${implBlockWriter.format(runtimeConfig.operationBuildError())}>" + false -> implBlockWriter.format(outputSymbol) + } implBlockWriter.docs("Consumes the builder and constructs a #D.", outputSymbol) val trulyRequiredMembers = members.filter { trulyRequired(it) } if (trulyRequiredMembers.isNotEmpty()) { @@ -209,7 +231,11 @@ class BuilderGenerator( } // TODO(EventStream): [DX] Consider updating builders to take EventInputStream as Into - private fun renderBuilderMember(writer: RustWriter, memberName: String, memberSymbol: Symbol) { + private fun renderBuilderMember( + writer: RustWriter, + memberName: String, + memberSymbol: Symbol, + ) { // Builder members are crate-public to enable using them directly in serializers/deserializers. // During XML deserialization, `builder..take` is used to append to lists and maps. writer.write("pub(crate) $memberName: #T,", memberSymbol) @@ -338,7 +364,11 @@ class BuilderGenerator( } } - private fun RustWriter.renderVecHelper(member: MemberShape, memberName: String, coreType: RustType.Vec) { + private fun RustWriter.renderVecHelper( + member: MemberShape, + memberName: String, + coreType: RustType.Vec, + ) { docs("Appends an item to `$memberName`.") rust("///") docs("To override the contents of this collection use [`${member.setterName()}`](Self::${member.setterName()}).") @@ -360,7 +390,11 @@ class BuilderGenerator( } } - private fun RustWriter.renderMapHelper(member: MemberShape, memberName: String, coreType: RustType.HashMap) { + private fun RustWriter.renderMapHelper( + member: MemberShape, + memberName: String, + coreType: RustType.HashMap, + ) { docs("Adds a key-value pair to `$memberName`.") rust("///") docs("To override the contents of this collection use [`${member.setterName()}`](Self::${member.setterName()}).") @@ -385,9 +419,10 @@ class BuilderGenerator( } } - private fun trulyRequired(member: MemberShape) = symbolProvider.toSymbol(member).let { - !it.isOptional() && !it.canUseDefault() - } + private fun trulyRequired(member: MemberShape) = + symbolProvider.toSymbol(member).let { + !it.isOptional() && !it.canUseDefault() + } /** * The core builder of the inner type. If the structure requires a fallible builder, this may use `?` to return @@ -412,8 +447,10 @@ class BuilderGenerator( if (default != null) { if (default.isRustDefault) { rust(".unwrap_or_default()") + } else if (default.complexType) { + rust(".unwrap_or_else(|| #T)", default.expr) } else { - rust(".unwrap_or_else(#T)", default.expr) + rust(".unwrap_or(#T)", default.expr) } } else { withBlock( diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderInstantiator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderInstantiator.kt index fd62ced0668..f73e8d5a055 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderInstantiator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderInstantiator.kt @@ -17,16 +17,28 @@ import software.amazon.smithy.rust.codegen.core.rustlang.writable * */ interface BuilderInstantiator { /** Set a field on a builder. */ - fun setField(builder: String, value: Writable, field: MemberShape): Writable + fun setField( + builder: String, + value: Writable, + field: MemberShape, + ): Writable /** Finalize a builder, turning it into a built object * - In the case of builders-of-builders, the value should be returned directly * - If an error is returned, you MUST use `mapErr` to convert the error type */ - fun finalizeBuilder(builder: String, shape: StructureShape, mapErr: Writable? = null): Writable + fun finalizeBuilder( + builder: String, + shape: StructureShape, + mapErr: Writable? = null, + ): Writable /** Set a field on a builder using the `$setterName` method. $value will be passed directly. */ - fun setFieldWithSetter(builder: String, value: Writable, field: MemberShape) = writable { + fun setFieldWithSetter( + builder: String, + value: Writable, + field: MemberShape, + ) = writable { rustTemplate("$builder = $builder.${field.setterName()}(#{value})", "value" to value) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/CargoTomlGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/CargoTomlGenerator.kt index ec11ea3265e..a5901a375fd 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/CargoTomlGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/CargoTomlGenerator.kt @@ -79,33 +79,40 @@ class CargoTomlGenerator( cargoFeatures.add("default" to features.filter { it.default }.map { it.name }) } - val cargoToml = mapOf( - "package" to listOfNotNull( - "name" to moduleName, - "version" to moduleVersion, - "authors" to moduleAuthors, - moduleDescription?.let { "description" to it }, - "edition" to "2021", - "license" to moduleLicense, - "repository" to moduleRepository, - "metadata" to listOfNotNull( - "smithy" to listOfNotNull( - "codegen-version" to Version.fullVersion(), + val cargoToml = + mapOf( + "package" to + listOfNotNull( + "name" to moduleName, + "version" to moduleVersion, + "authors" to moduleAuthors, + moduleDescription?.let { "description" to it }, + "edition" to "2021", + "license" to moduleLicense, + "repository" to moduleRepository, + "metadata" to + listOfNotNull( + "smithy" to + listOfNotNull( + "codegen-version" to Version.fromDefaultResource().gitHash, + ).toMap(), + ).toMap(), ).toMap(), - ).toMap(), - ).toMap(), - "dependencies" to dependencies.filter { it.scope == DependencyScope.Compile } + "dependencies" to + dependencies.filter { it.scope == DependencyScope.Compile } + .associate { it.name to it.toMap() }, + "build-dependencies" to + dependencies.filter { it.scope == DependencyScope.Build } + .associate { it.name to it.toMap() }, + "dev-dependencies" to + dependencies.filter { it.scope == DependencyScope.Dev } + .associate { it.name to it.toMap() }, + "target.'cfg(aws_sdk_unstable)'.dependencies" to dependencies.filter { + it.scope == DependencyScope.CfgUnstable + } .associate { it.name to it.toMap() }, - "build-dependencies" to dependencies.filter { it.scope == DependencyScope.Build } - .associate { it.name to it.toMap() }, - "dev-dependencies" to dependencies.filter { it.scope == DependencyScope.Dev } - .associate { it.name to it.toMap() }, - "target.'cfg(aws_sdk_unstable)'.dependencies" to dependencies.filter { - it.scope == DependencyScope.CfgUnstable - } - .associate { it.name to it.toMap() }, - "features" to cargoFeatures.toMap(), - ).deepMergeWith(manifestCustomizations) + "features" to cargoFeatures.toMap(), + ).deepMergeWith(manifestCustomizations) // NOTE: without this it will produce ["target.'cfg(aws_sdk_unstable)'.dependencies"] // In JSON, this is an equivalent of: {"target.'cfg(aws_sdk_unstable)'.dependencies" : ...} diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/DefaultValueGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/DefaultValueGenerator.kt index 38001bf102e..6c04c8141d2 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/DefaultValueGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/DefaultValueGenerator.kt @@ -6,7 +6,10 @@ package software.amazon.smithy.rust.codegen.core.smithy.generators import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.BooleanShape +import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.MemberShape +import software.amazon.smithy.model.shapes.NumberShape import software.amazon.smithy.model.shapes.SimpleShape import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.rust @@ -23,17 +26,22 @@ class DefaultValueGenerator( ) { private val instantiator = PrimitiveInstantiator(runtimeConfig, symbolProvider) - data class DefaultValue(val isRustDefault: Boolean, val expr: Writable) + data class DefaultValue(val isRustDefault: Boolean, val expr: Writable, val complexType: Boolean) /** Returns the default value as set by the defaultValue trait */ fun defaultValue(member: MemberShape): DefaultValue? { val target = model.expectShape(member.target) + val complexType = + when (target) { + is NumberShape, is EnumShape, is BooleanShape -> false + else -> true + } return when (val default = symbolProvider.toSymbol(member).defaultValue()) { is Default.NoDefault -> null - is Default.RustDefault -> DefaultValue(isRustDefault = true, writable("Default::default")) + is Default.RustDefault -> DefaultValue(isRustDefault = true, writable("Default::default"), complexType) is Default.NonZeroDefault -> { val instantiation = instantiator.instantiate(target as SimpleShape, default.value) - DefaultValue(isRustDefault = false, writable { rust("||#T", instantiation) }) + DefaultValue(isRustDefault = false, writable { rust("#T", instantiation) }, complexType) } } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt index fc3e394851c..1c765b745fd 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGenerator.kt @@ -138,7 +138,10 @@ class EnumMemberModel( } } -private fun RustWriter.docWithNote(doc: String?, note: String?) { +private fun RustWriter.docWithNote( + doc: String?, + note: String?, +) { if (doc.isNullOrBlank() && note.isNullOrBlank()) { // If the model doesn't have any documentation for the shape, then suppress the missing docs lint // since the lack of documentation is a modeling issue rather than a codegen issue. @@ -166,12 +169,13 @@ open class EnumGenerator( private val enumTrait: EnumTrait = shape.expectTrait() private val symbol: Symbol = symbolProvider.toSymbol(shape) - private val context = EnumGeneratorContext( - enumName = symbol.name, - enumMeta = symbol.expectRustMetadata(), - enumTrait = enumTrait, - sortedMembers = enumTrait.values.sortedBy { it.value }.map { EnumMemberModel(shape, it, symbolProvider) }, - ) + private val context = + EnumGeneratorContext( + enumName = symbol.name, + enumMeta = symbol.expectRustMetadata(), + enumTrait = enumTrait, + sortedMembers = enumTrait.values.sortedBy { it.value }.map { EnumMemberModel(shape, it, symbolProvider) }, + ) fun render(writer: RustWriter) { enumType.additionalEnumAttributes(context).forEach { attribute -> @@ -200,14 +204,15 @@ open class EnumGenerator( insertTrailingNewline() // impl Blah { pub fn as_str(&self) -> &str implBlock( - asStrImpl = writable { - rustBlock("match self") { - context.sortedMembers.forEach { member -> - rust("""${context.enumName}::${member.derivedName()} => ${member.value.dq()},""") + asStrImpl = + writable { + rustBlock("match self") { + context.sortedMembers.forEach { member -> + rust("""${context.enumName}::${member.derivedName()} => ${member.value.dq()},""") + } + enumType.additionalAsStrMatchArms(context)(this) } - enumType.additionalAsStrMatchArms(context)(this) - } - }, + }, ) rustTemplate( """ @@ -229,9 +234,10 @@ open class EnumGenerator( context.enumMeta.render(this) rust("struct ${context.enumName}(String);") implBlock( - asStrImpl = writable { - rust("&self.0") - }, + asStrImpl = + writable { + rust("&self.0") + }, ) // Add an infallible FromStr implementation for uniformity @@ -299,9 +305,10 @@ open class EnumGenerator( } """, "asStrImpl" to asStrImpl, - "Values" to writable { - rust(context.sortedMembers.joinToString(", ") { it.value.dq() }) - }, + "Values" to + writable { + rust(context.sortedMembers.joinToString(", ") { it.value.dq() }) + }, ) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/Instantiator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/Instantiator.kt index 795a6b5a1dc..de73ab760d9 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/Instantiator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/Instantiator.kt @@ -18,7 +18,9 @@ import software.amazon.smithy.model.shapes.BlobShape import software.amazon.smithy.model.shapes.BooleanShape import software.amazon.smithy.model.shapes.CollectionShape import software.amazon.smithy.model.shapes.DocumentShape +import software.amazon.smithy.model.shapes.DoubleShape import software.amazon.smithy.model.shapes.EnumShape +import software.amazon.smithy.model.shapes.FloatShape import software.amazon.smithy.model.shapes.ListShape import software.amazon.smithy.model.shapes.MapShape import software.amazon.smithy.model.shapes.MemberShape @@ -120,6 +122,7 @@ open class Instantiator( // in the structure field's type. The latter's method name is the field's name, whereas the former is prefixed // with `set_`. Client instantiators call the `set_*` builder setters. fun setterName(memberShape: MemberShape): String + fun doesSetterTakeInOption(memberShape: MemberShape): Boolean } @@ -135,7 +138,12 @@ open class Instantiator( override fun generate(shape: Shape): Writable? = null } - fun generate(shape: Shape, data: Node, headers: Map = mapOf(), ctx: Ctx = Ctx()) = writable { + fun generate( + shape: Shape, + data: Node, + headers: Map = mapOf(), + ctx: Ctx = Ctx(), + ) = writable { render(this, shape, data, headers, ctx) } @@ -162,11 +170,12 @@ open class Instantiator( // Members, supporting potentially optional members is MemberShape -> renderMember(writer, shape, data, ctx) - is SimpleShape -> PrimitiveInstantiator(runtimeConfig, symbolProvider).instantiate( - shape, - data, - customWritable, - )(writer) + is SimpleShape -> + PrimitiveInstantiator(runtimeConfig, symbolProvider).instantiate( + shape, + data, + customWritable, + )(writer) else -> writer.writeWithNoFormatting("todo!() /* $shape $data */") } @@ -177,7 +186,12 @@ open class Instantiator( * If the shape is optional: `Some(inner)` or `None`. * Otherwise: `inner`. */ - private fun renderMember(writer: RustWriter, memberShape: MemberShape, data: Node, ctx: Ctx) { + private fun renderMember( + writer: RustWriter, + memberShape: MemberShape, + data: Node, + ctx: Ctx, + ) { val targetShape = model.expectShape(memberShape.target) val symbol = symbolProvider.toSymbol(memberShape) customWritable.generate(memberShape) @@ -195,11 +209,13 @@ open class Instantiator( "#{Some}(", ")", // The conditions are not commutative: note client builders always take in `Option`. - conditional = symbol.isOptional() || - ( - model.expectShape(memberShape.container) is StructureShape && builderKindBehavior.doesSetterTakeInOption( - memberShape, - ) + conditional = + symbol.isOptional() || + ( + model.expectShape(memberShape.container) is StructureShape && + builderKindBehavior.doesSetterTakeInOption( + memberShape, + ) ), *preludeScope, ) { @@ -225,8 +241,12 @@ open class Instantiator( } } - private fun renderSet(writer: RustWriter, shape: SetShape, data: ArrayNode, ctx: Ctx) = - renderList(writer, shape, data, ctx) + private fun renderSet( + writer: RustWriter, + shape: SetShape, + data: ArrayNode, + ctx: Ctx, + ) = renderList(writer, shape, data, ctx) /** * ```rust @@ -238,7 +258,12 @@ open class Instantiator( * } * ``` */ - private fun renderMap(writer: RustWriter, shape: MapShape, data: ObjectNode, ctx: Ctx) { + private fun renderMap( + writer: RustWriter, + shape: MapShape, + data: ObjectNode, + ctx: Ctx, + ) { if (data.members.isEmpty()) { writer.rust("#T::new()", RuntimeType.HashMap) } else { @@ -264,18 +289,24 @@ open class Instantiator( * MyUnion::Variant(...) * ``` */ - private fun renderUnion(writer: RustWriter, shape: UnionShape, data: ObjectNode, ctx: Ctx) { + private fun renderUnion( + writer: RustWriter, + shape: UnionShape, + data: ObjectNode, + ctx: Ctx, + ) { val unionSymbol = symbolProvider.toSymbol(shape) - val variant = if (defaultsForRequiredFields && data.members.isEmpty()) { - val (name, memberShape) = shape.allMembers.entries.first() - val targetShape = model.expectShape(memberShape.target) - Node.from(name) to fillDefaultValue(targetShape) - } else { - check(data.members.size == 1) - val entry = data.members.iterator().next() - entry.key to entry.value - } + val variant = + if (defaultsForRequiredFields && data.members.isEmpty()) { + val (name, memberShape) = shape.allMembers.entries.first() + val targetShape = model.expectShape(memberShape.target) + Node.from(name) to fillDefaultValue(targetShape) + } else { + check(data.members.size == 1) + val entry = data.members.iterator().next() + entry.key to entry.value + } val memberName = variant.first.value val member = shape.expectMember(memberName) @@ -293,7 +324,12 @@ open class Instantiator( * vec![..., ..., ...] * ``` */ - private fun renderList(writer: RustWriter, shape: CollectionShape, data: ArrayNode, ctx: Ctx) { + private fun renderList( + writer: RustWriter, + shape: CollectionShape, + data: ArrayNode, + ctx: Ctx, + ) { writer.withBlock("vec![", "]") { data.elements.forEach { v -> renderMember(this, shape.member, v, ctx) @@ -344,7 +380,11 @@ open class Instantiator( ctx: Ctx, ) { val renderedMembers = mutableSetOf() - fun renderMemberHelper(memberShape: MemberShape, value: Node) { + + fun renderMemberHelper( + memberShape: MemberShape, + value: Node, + ) { renderedMembers.add(memberShape) when (constructPattern) { InstantiatorConstructPattern.DIRECT -> { @@ -410,24 +450,25 @@ open class Instantiator( * * Warning: this method does not take into account any constraint traits attached to the shape. */ - private fun fillDefaultValue(shape: Shape): Node = when (shape) { - is MemberShape -> fillDefaultValue(model.expectShape(shape.target)) - - // Aggregate shapes. - is StructureShape -> Node.objectNode() - is UnionShape -> Node.objectNode() - is CollectionShape -> Node.arrayNode() - is MapShape -> Node.objectNode() - - // Simple Shapes - is TimestampShape -> Node.from(0) // Number node for timestamp - is BlobShape -> Node.from("") // String node for bytes - is StringShape -> Node.from("") - is NumberShape -> Node.from(0) - is BooleanShape -> Node.from(false) - is DocumentShape -> Node.objectNode() - else -> throw CodegenException("Unrecognized shape `$shape`") - } + private fun fillDefaultValue(shape: Shape): Node = + when (shape) { + is MemberShape -> fillDefaultValue(model.expectShape(shape.target)) + + // Aggregate shapes. + is StructureShape -> Node.objectNode() + is UnionShape -> Node.objectNode() + is CollectionShape -> Node.arrayNode() + is MapShape -> Node.objectNode() + + // Simple Shapes + is TimestampShape -> Node.from(0) // Number node for timestamp + is BlobShape -> Node.from("") // String node for bytes + is StringShape -> Node.from("") + is NumberShape -> Node.from(0) + is BooleanShape -> Node.from(false) + is DocumentShape -> Node.objectNode() + else -> throw CodegenException("Unrecognized shape `$shape`") + } } class PrimitiveInstantiator(private val runtimeConfig: RuntimeConfig, private val symbolProvider: SymbolProvider) { @@ -455,56 +496,68 @@ class PrimitiveInstantiator(private val runtimeConfig: RuntimeConfig, private va * Blob::new("arg") * ``` */ - is BlobShape -> if (shape.hasTrait()) { - rust( - "#T::from_static(b${(data as StringNode).value.dq()})", - RuntimeType.byteStream(runtimeConfig), - ) - } else { - rust( - "#T::new(${(data as StringNode).value.dq()})", - RuntimeType.blob(runtimeConfig), - ) - } - - is StringShape -> renderString(shape, data as StringNode)(this) - is NumberShape -> when (data) { - is StringNode -> { - val numberSymbol = symbolProvider.toSymbol(shape) - // support Smithy custom values, such as Infinity + is BlobShape -> + if (shape.hasTrait()) { rust( - """<#T as #T>::parse_smithy_primitive(${data.value.dq()}).expect("invalid string for number")""", - numberSymbol, - RuntimeType.smithyTypes(runtimeConfig).resolve("primitive::Parse"), + "#T::from_static(b${(data as StringNode).value.dq()})", + RuntimeType.byteStream(runtimeConfig), + ) + } else { + rust( + "#T::new(${(data as StringNode).value.dq()})", + RuntimeType.blob(runtimeConfig), ) } - is NumberNode -> write(data.value) - } + is StringShape -> renderString(shape, data as StringNode)(this) + is NumberShape -> + when (data) { + is StringNode -> { + val numberSymbol = symbolProvider.toSymbol(shape) + // support Smithy custom values, such as Infinity + rust( + """<#T as #T>::parse_smithy_primitive(${data.value.dq()}).expect("invalid string for number")""", + numberSymbol, + RuntimeType.smithyTypes(runtimeConfig).resolve("primitive::Parse"), + ) + } + + is NumberNode -> + when (shape) { + is FloatShape -> rust("${data.value}_f32") + is DoubleShape -> rust("${data.value}_f64") + else -> rust(data.value.toString()) + } + } is BooleanShape -> rust(data.asBooleanNode().get().toString()) - is DocumentShape -> rustBlock("") { - val smithyJson = CargoDependency.smithyJson(runtimeConfig).toType() - rustTemplate( - """ - let json_bytes = br##"${Node.prettyPrintJson(data)}"##; - let mut tokens = #{json_token_iter}(json_bytes).peekable(); - #{expect_document}(&mut tokens).expect("well formed json") - """, - "expect_document" to smithyJson.resolve("deserialize::token::expect_document"), - "json_token_iter" to smithyJson.resolve("deserialize::json_token_iter"), - ) - } + is DocumentShape -> + rustBlock("") { + val smithyJson = CargoDependency.smithyJson(runtimeConfig).toType() + rustTemplate( + """ + let json_bytes = br##"${Node.prettyPrintJson(data)}"##; + let mut tokens = #{json_token_iter}(json_bytes).peekable(); + #{expect_document}(&mut tokens).expect("well formed json") + """, + "expect_document" to smithyJson.resolve("deserialize::token::expect_document"), + "json_token_iter" to smithyJson.resolve("deserialize::json_token_iter"), + ) + } } } - private fun renderString(shape: StringShape, arg: StringNode): Writable = { - val data = escape(arg.value).dq() - if (shape.hasTrait() || shape is EnumShape) { - val enumSymbol = symbolProvider.toSymbol(shape) - rust("""$data.parse::<#T>().expect("static value validated to member")""", enumSymbol) - } else { - rust("$data.to_owned()") + private fun renderString( + shape: StringShape, + arg: StringNode, + ): Writable = + { + val data = escape(arg.value).dq() + if (shape.hasTrait() || shape is EnumShape) { + val enumSymbol = symbolProvider.toSymbol(shape) + rust("""$data.parse::<#T>().expect("static value validated to member")""", enumSymbol) + } else { + rust("$data.to_owned()") + } } - } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt index ab87afa1b89..85fc05ee985 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt @@ -21,7 +21,9 @@ import software.amazon.smithy.rust.codegen.core.util.getTrait sealed class ModuleDocSection { data class ServiceDocs(val documentationTraitValue: String?) : ModuleDocSection() + object CrateOrganization : ModuleDocSection() + object Examples : ModuleDocSection() } @@ -41,9 +43,10 @@ class LibRsGenerator( private val customizations: List, private val requireDocs: Boolean, ) { - private fun docSection(section: ModuleDocSection): List = customizations - .map { customization -> customization.section(LibRsSection.ModuleDoc(section)) } - .filter { it.isNotEmpty() } + private fun docSection(section: ModuleDocSection): List = + customizations + .map { customization -> customization.section(LibRsSection.ModuleDoc(section)) } + .filter { it.isNotEmpty() } fun render(writer: RustWriter) { writer.first { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt index 3875c697d9f..2c77cd13bbf 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGenerator.kt @@ -68,20 +68,22 @@ open class StructureGenerator( ) { companion object { /** Reserved struct member names */ - val structureMemberNameMap: Map = mapOf( - "build" to "build_value", - "builder" to "builder_value", - "default" to "default_value", - ) + val structureMemberNameMap: Map = + mapOf( + "build" to "build_value", + "builder" to "builder_value", + "default" to "default_value", + ) } private val errorTrait = shape.getTrait() protected val members: List = shape.allMembers.values.toList() - private val accessorMembers: List = when (errorTrait) { - null -> members - // Let the ErrorGenerator render the error message accessor if this is an error struct - else -> members.filter { "message" != symbolProvider.toMemberName(it) } - } + private val accessorMembers: List = + when (errorTrait) { + null -> members + // Let the ErrorGenerator render the error message accessor if this is an error struct + else -> members.filter { "message" != symbolProvider.toMemberName(it) } + } protected val name: String = symbolProvider.toSymbol(shape).name fun render() { @@ -129,18 +131,19 @@ open class StructureGenerator( forEachMember(accessorMembers) { member, memberName, memberSymbol -> val memberType = memberSymbol.rustType() var unwrapOrDefault = false - val returnType = when { - // Automatically flatten vecs - structSettings.flattenVecAccessors && memberType is RustType.Option && memberType.stripOuter() is RustType.Vec -> { - unwrapOrDefault = true - memberType.stripOuter().asDeref().asRef() + val returnType = + when { + // Automatically flatten vecs + structSettings.flattenVecAccessors && memberType is RustType.Option && memberType.stripOuter() is RustType.Vec -> { + unwrapOrDefault = true + memberType.stripOuter().asDeref().asRef() + } + + memberType.isCopy() -> memberType + memberType is RustType.Option && memberType.member.isDeref() -> memberType.asDeref() + memberType.isDeref() -> memberType.asDeref().asRef() + else -> memberType.asRef() } - - memberType.isCopy() -> memberType - memberType is RustType.Option && memberType.member.isDeref() -> memberType.asDeref() - memberType.isDeref() -> memberType.asDeref().asRef() - else -> memberType.asRef() - } writer.renderMemberDoc(member, memberSymbol) if (unwrapOrDefault) { // Add a newline @@ -164,7 +167,12 @@ open class StructureGenerator( } } - open fun renderStructureMember(writer: RustWriter, member: MemberShape, memberName: String, memberSymbol: Symbol) { + open fun renderStructureMember( + writer: RustWriter, + member: MemberShape, + memberName: String, + memberSymbol: Symbol, + ) { RenderSerdeAttribute.skipIfStream(writer, member, model, shape) writer.renderMemberDoc(member, memberSymbol) RenderSerdeAttribute.addSensitiveWarningDoc(writer, shape, model) @@ -209,12 +217,16 @@ open class StructureGenerator( } } - private fun RustWriter.renderMemberDoc(member: MemberShape, memberSymbol: Symbol) { + private fun RustWriter.renderMemberDoc( + member: MemberShape, + memberSymbol: Symbol, + ) { documentShape( member, model, - note = memberSymbol.renamedFrom() - ?.let { oldName -> "This member has been renamed from `$oldName`." }, + note = + memberSymbol.renamedFrom() + ?.let { oldName -> "This member has been renamed from `$oldName`." }, ) } } @@ -224,10 +236,11 @@ open class StructureGenerator( * e.g. `<'a, 'b>` */ fun StructureShape.lifetimeDeclaration(symbolProvider: RustSymbolProvider): String { - val lifetimes = this.members() - .mapNotNull { symbolProvider.toSymbol(it).rustType().innerReference()?.let { it as RustType.Reference } } - .mapNotNull { it.lifetime } - .toSet().sorted() + val lifetimes = + this.members() + .mapNotNull { symbolProvider.toSymbol(it).rustType().innerReference()?.let { it as RustType.Reference } } + .mapNotNull { it.lifetime } + .toSet().sorted() return if (lifetimes.isNotEmpty()) { "<${lifetimes.joinToString { "'$it" }}>" } else { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt index 7b9ec298396..50c908e8df7 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGenerator.kt @@ -34,10 +34,11 @@ import software.amazon.smithy.rust.codegen.core.util.isTargetUnit import software.amazon.smithy.rust.codegen.core.util.shouldRedact import software.amazon.smithy.rust.codegen.core.util.toSnakeCase -fun CodegenTarget.renderUnknownVariant() = when (this) { - CodegenTarget.SERVER -> false - CodegenTarget.CLIENT -> true -} +fun CodegenTarget.renderUnknownVariant() = + when (this) { + CodegenTarget.SERVER -> false + CodegenTarget.CLIENT -> true + } /** * Generate an `enum` for a Smithy Union Shape @@ -177,7 +178,11 @@ fun unknownVariantError(union: String) = "The `Unknown` variant is intended for responses only. " + "It occurs when an outdated client is used after a new enum variant was added on the server side." -private fun RustWriter.renderVariant(symbolProvider: SymbolProvider, member: MemberShape, memberSymbol: Symbol) { +private fun RustWriter.renderVariant( + symbolProvider: SymbolProvider, + member: MemberShape, + memberSymbol: Symbol, +) { if (member.isTargetUnit()) { write("${symbolProvider.toMemberName(member)},") } else { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/ErrorImplGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/ErrorImplGenerator.kt index 049933bc459..bc6881521bf 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/ErrorImplGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/error/ErrorImplGenerator.kt @@ -108,21 +108,22 @@ class ErrorImplGenerator( val messageSymbol = symbolProvider.toSymbol(messageShape).mapRustType { t -> t.asDeref() } val messageType = messageSymbol.rustType() val memberName = symbolProvider.toMemberName(messageShape) - val (returnType, message) = if (messageType.stripOuter() is RustType.Opaque) { - // The string shape has a constraint trait that makes its symbol be a wrapper tuple struct. - if (messageSymbol.isOptional()) { - "Option<&${messageType.stripOuter().render()}>" to - "self.$memberName.as_ref()" - } else { - "&${messageType.render()}" to "&self.$memberName" - } - } else { - if (messageSymbol.isOptional()) { - messageType.render() to "self.$memberName.as_deref()" + val (returnType, message) = + if (messageType.stripOuter() is RustType.Opaque) { + // The string shape has a constraint trait that makes its symbol be a wrapper tuple struct. + if (messageSymbol.isOptional()) { + "Option<&${messageType.stripOuter().render()}>" to + "self.$memberName.as_ref()" + } else { + "&${messageType.render()}" to "&self.$memberName" + } } else { - messageType.render() to "self.$memberName.as_ref()" + if (messageSymbol.isOptional()) { + messageType.render() to "self.$memberName.as_deref()" + } else { + messageType.render() to "self.$memberName.as_ref()" + } } - } rust( """ @@ -153,9 +154,10 @@ class ErrorImplGenerator( rustBlock("fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result") { // If the error id and the Rust name don't match, print the actual error id for easy debugging // Note: Exceptions cannot be renamed so it is OK to not call `getName(service)` here - val errorDesc = symbol.name.letIf(symbol.name != shape.id.name) { symbolName -> - "$symbolName [${shape.id.name}]" - } + val errorDesc = + symbol.name.letIf(symbol.name != shape.id.name) { symbolName -> + "$symbolName [${shape.id.name}]" + } write("::std::write!(f, ${errorDesc.dq()})?;") messageShape?.let { if (it.shouldRedact(model)) { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/http/HttpBindingGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/http/HttpBindingGenerator.kt index 8ebf6082c86..9687bb2492a 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/http/HttpBindingGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/http/HttpBindingGenerator.kt @@ -55,6 +55,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.protocols.HttpLocation import software.amazon.smithy.rust.codegen.core.smithy.protocols.Protocol import software.amazon.smithy.rust.codegen.core.smithy.protocols.ProtocolFunctions import software.amazon.smithy.rust.codegen.core.smithy.protocols.parse.EventStreamUnmarshallerGenerator +import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.SerializerUtil import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.ValueExpression import software.amazon.smithy.rust.codegen.core.smithy.rustType import software.amazon.smithy.rust.codegen.core.util.UNREACHABLE @@ -75,7 +76,8 @@ import software.amazon.smithy.rust.codegen.core.util.redactIfNecessary * - serializing data to an HTTP response (we are a server), */ enum class HttpMessageType { - REQUEST, RESPONSE + REQUEST, + RESPONSE, } /** @@ -129,6 +131,7 @@ class HttpBindingGenerator( private val headerUtil = RuntimeType.smithyHttp(runtimeConfig).resolve("header") private val defaultTimestampFormat = TimestampFormatTrait.Format.EPOCH_SECONDS private val protocolFunctions = ProtocolFunctions(codegenContext) + private val serializerUtil = SerializerUtil(model, symbolProvider) /** * Generate a function to deserialize [binding] from HTTP headers. @@ -164,16 +167,17 @@ class HttpBindingGenerator( val outputSymbol = symbolProvider.toSymbol(binding.member) val target = model.expectShape(binding.member.target) check(target is MapShape) - val inner = protocolFunctions.deserializeFn(binding.member, fnNameSuffix = "inner") { fnName -> - rustBlockTemplate( - "pub fn $fnName<'a>(headers: impl #{Iterator}) -> std::result::Result, #{header_util}::ParseError>", - *preludeScope, - "Value" to symbolProvider.toSymbol(model.expectShape(target.value.target)), - "header_util" to headerUtil, - ) { - deserializeFromHeader(model.expectShape(target.value.target), binding.member) + val inner = + protocolFunctions.deserializeFn(binding.member, fnNameSuffix = "inner") { fnName -> + rustBlockTemplate( + "pub fn $fnName<'a>(headers: impl #{Iterator}) -> std::result::Result, #{header_util}::ParseError>", + *preludeScope, + "Value" to symbolProvider.toSymbol(model.expectShape(target.value.target)), + "header_util" to headerUtil, + ) { + deserializeFromHeader(model.expectShape(target.value.target), binding.member) + } } - } val returnTypeSymbol = outputSymbol.mapRustType { it.asOptional() } return protocolFunctions.deserializeFn(binding.member, fnNameSuffix = "prefix_header") { fnName -> rustBlockTemplate( @@ -252,13 +256,18 @@ class HttpBindingGenerator( } } - private fun RustWriter.bindEventStreamOutput(operationShape: OperationShape, outputT: Symbol, targetShape: UnionShape) { - val unmarshallerConstructorFn = EventStreamUnmarshallerGenerator( - protocol, - codegenContext, - operationShape, - targetShape, - ).render() + private fun RustWriter.bindEventStreamOutput( + operationShape: OperationShape, + outputT: Symbol, + targetShape: UnionShape, + ) { + val unmarshallerConstructorFn = + EventStreamUnmarshallerGenerator( + protocol, + codegenContext, + operationShape, + targetShape, + ).render() rustTemplate( """ let unmarshaller = #{unmarshallerConstructorFn}(); @@ -267,17 +276,18 @@ class HttpBindingGenerator( """, "SdkBody" to RuntimeType.sdkBody(runtimeConfig), "unmarshallerConstructorFn" to unmarshallerConstructorFn, - "receiver" to writable { - if (codegenTarget == CodegenTarget.SERVER) { - rust("${outputT.rustType().qualifiedName()}::new(unmarshaller, body)") - } else { - rustTemplate( - "#{EventReceiver}::new(#{Receiver}::new(unmarshaller, body))", - "EventReceiver" to RuntimeType.eventReceiver(runtimeConfig), - "Receiver" to RuntimeType.eventStreamReceiver(runtimeConfig), - ) - } - }, + "receiver" to + writable { + if (codegenTarget == CodegenTarget.SERVER) { + rust("${outputT.rustType().qualifiedName()}::new(unmarshaller, body)") + } else { + rustTemplate( + "#{EventReceiver}::new(#{Receiver}::new(unmarshaller, body))", + "EventReceiver" to RuntimeType.eventReceiver(runtimeConfig), + "Receiver" to RuntimeType.eventStreamReceiver(runtimeConfig), + ) + } + }, ) } @@ -338,10 +348,11 @@ class HttpBindingGenerator( } } - is BlobShape -> rust( - "Ok(#T::new(body))", - symbolProvider.toSymbol(targetShape), - ) + is BlobShape -> + rust( + "Ok(#T::new(body))", + symbolProvider.toSymbol(targetShape), + ) // `httpPayload` can be applied to set/map/list shapes. // However, none of the AWS protocols support it. // Smithy CLI will refuse to build the model if you apply the trait to these shapes, so this branch @@ -355,7 +366,10 @@ class HttpBindingGenerator( * Parse a value from a header. * This function produces an expression which produces the precise type required by the target shape. */ - private fun RustWriter.deserializeFromHeader(targetShape: Shape, memberShape: MemberShape) { + private fun RustWriter.deserializeFromHeader( + targetShape: Shape, + memberShape: MemberShape, + ) { val rustType = symbolProvider.toSymbol(targetShape).rustType().stripOuter() // Normally, we go through a flow that looks for `,`s but that's wrong if the output // is just a single string (which might include `,`s.). @@ -364,12 +378,13 @@ class HttpBindingGenerator( rust("#T::one_or_none(headers)", headerUtil) return } - val (coreType, coreShape) = if (targetShape is CollectionShape) { - val coreShape = model.expectShape(targetShape.member.target) - symbolProvider.toSymbol(coreShape).rustType() to coreShape - } else { - rustType to targetShape - } + val (coreType, coreShape) = + if (targetShape is CollectionShape) { + val coreShape = model.expectShape(targetShape.member.target) + symbolProvider.toSymbol(coreShape).rustType() to coreShape + } else { + rustType to targetShape + } val parsedValue = safeName() if (coreShape.isTimestampShape()) { val timestampFormat = @@ -481,14 +496,17 @@ class HttpBindingGenerator( shape: Shape, httpMessageType: HttpMessageType = HttpMessageType.REQUEST, ): RuntimeType? { - val (headerBindings, prefixHeaderBinding) = when (httpMessageType) { - // Only a single structure member can be bound by `httpPrefixHeaders`, hence the `getOrNull(0)`. - HttpMessageType.REQUEST -> index.getRequestBindings(shape, HttpLocation.HEADER) to - index.getRequestBindings(shape, HttpLocation.PREFIX_HEADERS).getOrNull(0) - - HttpMessageType.RESPONSE -> index.getResponseBindings(shape, HttpLocation.HEADER) to - index.getResponseBindings(shape, HttpLocation.PREFIX_HEADERS).getOrNull(0) - } + val (headerBindings, prefixHeaderBinding) = + when (httpMessageType) { + // Only a single structure member can be bound by `httpPrefixHeaders`, hence the `getOrNull(0)`. + HttpMessageType.REQUEST -> + index.getRequestBindings(shape, HttpLocation.HEADER) to + index.getRequestBindings(shape, HttpLocation.PREFIX_HEADERS).getOrNull(0) + + HttpMessageType.RESPONSE -> + index.getResponseBindings(shape, HttpLocation.HEADER) to + index.getResponseBindings(shape, HttpLocation.PREFIX_HEADERS).getOrNull(0) + } if (headerBindings.isEmpty() && prefixHeaderBinding == null) { return null @@ -497,22 +515,24 @@ class HttpBindingGenerator( return protocolFunctions.serializeFn(shape, fnNameSuffix = "headers") { fnName -> // If the shape is an operation shape, the input symbol of the generated function is the input or output // shape, which is the shape holding the header-bound data. - val shapeSymbol = symbolProvider.toSymbol( - if (shape is OperationShape) { - when (httpMessageType) { - HttpMessageType.REQUEST -> shape.inputShape(model) - HttpMessageType.RESPONSE -> shape.outputShape(model) - } - } else { - shape - }, - ) - val codegenScope = arrayOf( - "BuildError" to runtimeConfig.operationBuildError(), - HttpMessageType.REQUEST.name to RuntimeType.HttpRequestBuilder, - HttpMessageType.RESPONSE.name to RuntimeType.HttpResponseBuilder, - "Shape" to shapeSymbol, - ) + val shapeSymbol = + symbolProvider.toSymbol( + if (shape is OperationShape) { + when (httpMessageType) { + HttpMessageType.REQUEST -> shape.inputShape(model) + HttpMessageType.RESPONSE -> shape.outputShape(model) + } + } else { + shape + }, + ) + val codegenScope = + arrayOf( + "BuildError" to runtimeConfig.operationBuildError(), + HttpMessageType.REQUEST.name to RuntimeType.HttpRequestBuilder, + HttpMessageType.RESPONSE.name to RuntimeType.HttpResponseBuilder, + "Shape" to shapeSymbol, + ) rustBlockTemplate( """ pub fn $fnName( @@ -560,7 +580,6 @@ class HttpBindingGenerator( // default value for that primitive type (e.g. `Some(false)` for an `Option` header). // If a header is multivalued, we always want to serialize its primitive members, regardless of their // values. - val serializePrimitiveValuesIfDefault = memberSymbol.isOptional() || (targetShape is CollectionShape) ifSome(memberSymbol, ValueExpression.Reference("&input.$memberName")) { variableName -> if (targetShape is CollectionShape) { renderMultiValuedHeader( @@ -579,7 +598,8 @@ class HttpBindingGenerator( false, timestampFormat, renderErrorMessage, - serializePrimitiveValuesIfDefault, + serializeIfDefault = memberSymbol.isOptional(), + memberShape, ) } } @@ -610,6 +630,7 @@ class HttpBindingGenerator( timestampFormat, renderErrorMessage, serializeIfDefault = true, + shape.member, ) } } @@ -629,6 +650,7 @@ class HttpBindingGenerator( timestampFormat: TimestampFormatTrait.Format, renderErrorMessage: (String) -> Writable, serializeIfDefault: Boolean, + memberShape: MemberShape, ) { val context = HeaderValueSerializationContext(value, shape) for (customization in customizations) { @@ -642,13 +664,14 @@ class HttpBindingGenerator( val encoder = RuntimeType.smithyTypes(runtimeConfig).resolve("primitive::Encoder") rust("let mut encoder = #T::from(${variableName.asValue()});", encoder) } - val formatted = headerFmtFun( - this, - shape, - timestampFormat, - context.valueExpression.name, - isMultiValuedHeader = isMultiValuedHeader, - ) + val formatted = + headerFmtFun( + this, + shape, + timestampFormat, + context.valueExpression.name, + isMultiValuedHeader = isMultiValuedHeader, + ) val safeName = safeName("formatted") rustTemplate( """ @@ -668,7 +691,11 @@ class HttpBindingGenerator( if (serializeIfDefault) { block(context.valueExpression) } else { - ifNotDefault(context.shape, context.valueExpression, block) + with(serializerUtil) { + ignoreDefaultsForNumbersAndBools(memberShape, context.valueExpression) { + block(context.valueExpression) + } + } } } @@ -712,20 +739,22 @@ class HttpBindingGenerator( """, "HeaderValue" to RuntimeType.Http.resolve("HeaderValue"), - "invalid_header_name" to OperationBuildError(runtimeConfig).invalidField(memberName) { - rust("""format!("`{k}` cannot be used as a header name: {err}")""") - }, - "invalid_header_value" to OperationBuildError(runtimeConfig).invalidField(memberName) { - rust( - """ - format!( - "`{}` cannot be used as a header value: {}", - ${memberShape.redactIfNecessary(model, "v")}, - err + "invalid_header_name" to + OperationBuildError(runtimeConfig).invalidField(memberName) { + rust("""format!("`{k}` cannot be used as a header name: {err}")""") + }, + "invalid_header_value" to + OperationBuildError(runtimeConfig).invalidField(memberName) { + rust( + """ + format!( + "`{}` cannot be used as a header value: {}", + ${memberShape.redactIfNecessary(model, "v")}, + err + ) + """, ) - """, - ) - }, + }, ) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/protocol/ProtocolSupport.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/protocol/ProtocolSupport.kt index c66dae4ce5b..b32b9c893c9 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/protocol/ProtocolSupport.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/protocol/ProtocolSupport.kt @@ -6,12 +6,12 @@ package software.amazon.smithy.rust.codegen.core.smithy.generators.protocol data class ProtocolSupport( - /* Client support */ + // Client support val requestSerialization: Boolean, val requestBodySerialization: Boolean, val responseDeserialization: Boolean, val errorDeserialization: Boolean, - /* Server support */ + // Server support val requestDeserialization: Boolean, val requestBodyDeserialization: Boolean, val responseSerialization: Boolean, diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/AwsJson.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/AwsJson.kt index 06b479506c1..1b54f4289f9 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/AwsJson.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/AwsJson.kt @@ -42,11 +42,12 @@ class AwsJsonHttpBindingResolver( private val model: Model, private val awsJsonVersion: AwsJsonVersion, ) : HttpBindingResolver { - private val httpTrait = HttpTrait.builder() - .code(200) - .method("POST") - .uri(UriPattern.parse("/")) - .build() + private val httpTrait = + HttpTrait.builder() + .code(200) + .method("POST") + .uri(UriPattern.parse("/")) + .build() private fun bindings(shape: ToShapeId): List { val members = shape.let { model.expectShape(it.toShapeId()) }.members() @@ -76,8 +77,7 @@ class AwsJsonHttpBindingResolver( override fun responseBindings(operationShape: OperationShape): List = bindings(operationShape.outputShape) - override fun errorResponseBindings(errorShape: ToShapeId): List = - bindings(errorShape) + override fun errorResponseBindings(errorShape: ToShapeId): List = bindings(errorShape) override fun requestContentType(operationShape: OperationShape): String = "application/x-amz-json-${awsJsonVersion.value}" @@ -96,24 +96,26 @@ class AwsJsonSerializerGenerator( JsonSerializerGenerator(codegenContext, httpBindingResolver, ::awsJsonFieldName), ) : StructuredDataSerializerGenerator by jsonSerializerGenerator { private val runtimeConfig = codegenContext.runtimeConfig - private val codegenScope = arrayOf( - "Error" to runtimeConfig.serializationError(), - "SdkBody" to RuntimeType.sdkBody(runtimeConfig), - ) + private val codegenScope = + arrayOf( + "Error" to runtimeConfig.serializationError(), + "SdkBody" to RuntimeType.sdkBody(runtimeConfig), + ) private val protocolFunctions = ProtocolFunctions(codegenContext) override fun operationInputSerializer(operationShape: OperationShape): RuntimeType { var serializer = jsonSerializerGenerator.operationInputSerializer(operationShape) if (serializer == null) { val inputShape = operationShape.inputShape(codegenContext.model) - serializer = protocolFunctions.serializeFn(operationShape, fnNameSuffix = "input") { fnName -> - rustBlockTemplate( - "pub fn $fnName(_input: &#{target}) -> Result<#{SdkBody}, #{Error}>", - *codegenScope, "target" to codegenContext.symbolProvider.toSymbol(inputShape), - ) { - rustTemplate("""Ok(#{SdkBody}::from("{}"))""", *codegenScope) + serializer = + protocolFunctions.serializeFn(operationShape, fnNameSuffix = "input") { fnName -> + rustBlockTemplate( + "pub fn $fnName(_input: &#{target}) -> Result<#{SdkBody}, #{Error}>", + *codegenScope, "target" to codegenContext.symbolProvider.toSymbol(inputShape), + ) { + rustTemplate("""Ok(#{SdkBody}::from("{}"))""", *codegenScope) + } } - } } return serializer } @@ -124,14 +126,16 @@ open class AwsJson( val awsJsonVersion: AwsJsonVersion, ) : Protocol { private val runtimeConfig = codegenContext.runtimeConfig - private val errorScope = arrayOf( - "Bytes" to RuntimeType.Bytes, - "ErrorMetadataBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), - "Headers" to RuntimeType.headers(runtimeConfig), - "JsonError" to CargoDependency.smithyJson(runtimeConfig).toType() - .resolve("deserialize::error::DeserializeError"), - "json_errors" to RuntimeType.jsonErrors(runtimeConfig), - ) + private val errorScope = + arrayOf( + "Bytes" to RuntimeType.Bytes, + "ErrorMetadataBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), + "Headers" to RuntimeType.headers(runtimeConfig), + "JsonError" to + CargoDependency.smithyJson(runtimeConfig).toType() + .resolve("deserialize::error::DeserializeError"), + "json_errors" to RuntimeType.jsonErrors(runtimeConfig), + ) val version: AwsJsonVersion get() = awsJsonVersion diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/AwsQuery.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/AwsQuery.kt index da7ccd1ad12..7f62cd9f8af 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/AwsQuery.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/AwsQuery.kt @@ -22,11 +22,12 @@ import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.AwsQu import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.StructuredDataSerializerGenerator import software.amazon.smithy.rust.codegen.core.util.getTrait -private val awsQueryHttpTrait = HttpTrait.builder() - .code(200) - .method("POST") - .uri(UriPattern.parse("/")) - .build() +private val awsQueryHttpTrait = + HttpTrait.builder() + .code(200) + .method("POST") + .uri(UriPattern.parse("/")) + .build() class AwsQueryBindingResolver(private val model: Model) : StaticHttpBindingResolver(model, awsQueryHttpTrait, "application/x-www-form-urlencoded", "text/xml") { @@ -39,12 +40,13 @@ class AwsQueryBindingResolver(private val model: Model) : class AwsQueryProtocol(private val codegenContext: CodegenContext) : Protocol { private val runtimeConfig = codegenContext.runtimeConfig private val awsQueryErrors: RuntimeType = RuntimeType.wrappedXmlErrors(runtimeConfig) - private val errorScope = arrayOf( - "Bytes" to RuntimeType.Bytes, - "ErrorMetadataBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), - "Headers" to RuntimeType.headers(runtimeConfig), - "XmlDecodeError" to RuntimeType.smithyXml(runtimeConfig).resolve("decode::XmlDecodeError"), - ) + private val errorScope = + arrayOf( + "Bytes" to RuntimeType.Bytes, + "ErrorMetadataBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), + "Headers" to RuntimeType.headers(runtimeConfig), + "XmlDecodeError" to RuntimeType.smithyXml(runtimeConfig).resolve("decode::XmlDecodeError"), + ) override val httpBindingResolver: HttpBindingResolver = AwsQueryBindingResolver(codegenContext.model) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/AwsQueryCompatible.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/AwsQueryCompatible.kt index 61861a369a7..7b15e81051d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/AwsQueryCompatible.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/AwsQueryCompatible.kt @@ -31,8 +31,7 @@ class AwsQueryCompatibleHttpBindingResolver( override fun errorResponseBindings(errorShape: ToShapeId): List = awsJsonHttpBindingResolver.errorResponseBindings(errorShape) - override fun errorCode(errorShape: ToShapeId): String = - awsQueryBindingResolver.errorCode(errorShape) + override fun errorCode(errorShape: ToShapeId): String = awsQueryBindingResolver.errorCode(errorShape) override fun requestContentType(operationShape: OperationShape): String = awsJsonHttpBindingResolver.requestContentType(operationShape) @@ -46,15 +45,17 @@ class AwsQueryCompatible( private val awsJson: AwsJson, ) : Protocol { private val runtimeConfig = codegenContext.runtimeConfig - private val errorScope = arrayOf( - "Bytes" to RuntimeType.Bytes, - "ErrorMetadataBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), - "Headers" to RuntimeType.headers(runtimeConfig), - "JsonError" to CargoDependency.smithyJson(runtimeConfig).toType() - .resolve("deserialize::error::DeserializeError"), - "aws_query_compatible_errors" to RuntimeType.awsQueryCompatibleErrors(runtimeConfig), - "json_errors" to RuntimeType.jsonErrors(runtimeConfig), - ) + private val errorScope = + arrayOf( + "Bytes" to RuntimeType.Bytes, + "ErrorMetadataBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), + "Headers" to RuntimeType.headers(runtimeConfig), + "JsonError" to + CargoDependency.smithyJson(runtimeConfig).toType() + .resolve("deserialize::error::DeserializeError"), + "aws_query_compatible_errors" to RuntimeType.awsQueryCompatibleErrors(runtimeConfig), + "json_errors" to RuntimeType.jsonErrors(runtimeConfig), + ) override val httpBindingResolver: HttpBindingResolver = AwsQueryCompatibleHttpBindingResolver( @@ -64,11 +65,9 @@ class AwsQueryCompatible( override val defaultTimestampFormat = awsJson.defaultTimestampFormat - override fun structuredDataParser(): StructuredDataParserGenerator = - awsJson.structuredDataParser() + override fun structuredDataParser(): StructuredDataParserGenerator = awsJson.structuredDataParser() - override fun structuredDataSerializer(): StructuredDataSerializerGenerator = - awsJson.structuredDataSerializer() + override fun structuredDataSerializer(): StructuredDataSerializerGenerator = awsJson.structuredDataSerializer() override fun parseHttpErrorMetadata(operationShape: OperationShape): RuntimeType = ProtocolFunctions.crossOperationFn("parse_http_error_metadata") { fnName -> diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/Ec2Query.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/Ec2Query.kt index 691736780b9..439cf35f031 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/Ec2Query.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/Ec2Query.kt @@ -21,23 +21,25 @@ import software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize.Struc class Ec2QueryProtocol(private val codegenContext: CodegenContext) : Protocol { private val runtimeConfig = codegenContext.runtimeConfig private val ec2QueryErrors: RuntimeType = RuntimeType.ec2QueryErrors(runtimeConfig) - private val errorScope = arrayOf( - "Bytes" to RuntimeType.Bytes, - "ErrorMetadataBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), - "Headers" to RuntimeType.headers(runtimeConfig), - "XmlDecodeError" to RuntimeType.smithyXml(runtimeConfig).resolve("decode::XmlDecodeError"), - ) + private val errorScope = + arrayOf( + "Bytes" to RuntimeType.Bytes, + "ErrorMetadataBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), + "Headers" to RuntimeType.headers(runtimeConfig), + "XmlDecodeError" to RuntimeType.smithyXml(runtimeConfig).resolve("decode::XmlDecodeError"), + ) - override val httpBindingResolver: HttpBindingResolver = StaticHttpBindingResolver( - codegenContext.model, - HttpTrait.builder() - .code(200) - .method("POST") - .uri(UriPattern.parse("/")) - .build(), - "application/x-www-form-urlencoded", - "text/xml", - ) + override val httpBindingResolver: HttpBindingResolver = + StaticHttpBindingResolver( + codegenContext.model, + HttpTrait.builder() + .code(200) + .method("POST") + .uri(UriPattern.parse("/")) + .build(), + "application/x-www-form-urlencoded", + "text/xml", + ) override val defaultTimestampFormat: TimestampFormatTrait.Format = TimestampFormatTrait.Format.DATE_TIME diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBindingResolver.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBindingResolver.kt index dbfe3de6103..8eb693c41fb 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBindingResolver.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBindingResolver.kt @@ -62,14 +62,18 @@ interface HttpBindingResolver { /** * Returns a list of member shapes bound to a given request [location] for a given [operationShape] */ - fun requestMembers(operationShape: OperationShape, location: HttpLocation): List = - requestBindings(operationShape).filter { it.location == location }.map { it.member } + fun requestMembers( + operationShape: OperationShape, + location: HttpLocation, + ): List = requestBindings(operationShape).filter { it.location == location }.map { it.member } /** * Returns a list of member shapes bound to a given response [location] for a given [operationShape] */ - fun responseMembers(operationShape: OperationShape, location: HttpLocation): List = - responseBindings(operationShape).filter { it.location == location }.map { it.member } + fun responseMembers( + operationShape: OperationShape, + location: HttpLocation, + ): List = responseBindings(operationShape).filter { it.location == location }.map { it.member } /** * Determine the timestamp format based on the input parameters. @@ -138,8 +142,7 @@ open class HttpTraitHttpBindingResolver( location: HttpLocation, defaultTimestampFormat: TimestampFormatTrait.Format, model: Model, - ): TimestampFormatTrait.Format = - httpIndex.determineTimestampFormat(memberShape, location, defaultTimestampFormat) + ): TimestampFormatTrait.Format = httpIndex.determineTimestampFormat(memberShape, location, defaultTimestampFormat) override fun requestContentType(operationShape: OperationShape): String? = httpIndex.determineRequestContentType( @@ -184,8 +187,7 @@ open class StaticHttpBindingResolver( override fun responseBindings(operationShape: OperationShape): List = bindings(operationShape.output.orNull()) - override fun errorResponseBindings(errorShape: ToShapeId): List = - bindings(errorShape) + override fun errorResponseBindings(errorShape: ToShapeId): List = bindings(errorShape) override fun requestContentType(operationShape: OperationShape): String = requestContentType diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBoundProtocolPayloadGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBoundProtocolPayloadGenerator.kt index 5b1d9df988a..a8fa69a6c27 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBoundProtocolPayloadGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBoundProtocolPayloadGenerator.kt @@ -62,26 +62,30 @@ class HttpBoundProtocolPayloadGenerator( private val target = codegenContext.target private val httpBindingResolver = protocol.httpBindingResolver private val smithyEventStream = RuntimeType.smithyEventStream(runtimeConfig) - private val codegenScope = arrayOf( - "hyper" to CargoDependency.HyperWithStream.toType(), - "SdkBody" to RuntimeType.sdkBody(runtimeConfig), - "BuildError" to runtimeConfig.operationBuildError(), - "SmithyHttp" to RuntimeType.smithyHttp(runtimeConfig), - "NoOpSigner" to smithyEventStream.resolve("frame::NoOpSigner"), - ) + private val codegenScope = + arrayOf( + "hyper" to CargoDependency.HyperWithStream.toType(), + "SdkBody" to RuntimeType.sdkBody(runtimeConfig), + "BuildError" to runtimeConfig.operationBuildError(), + "SmithyHttp" to RuntimeType.smithyHttp(runtimeConfig), + "NoOpSigner" to smithyEventStream.resolve("frame::NoOpSigner"), + ) private val protocolFunctions = ProtocolFunctions(codegenContext) override fun payloadMetadata( operationShape: OperationShape, additionalPayloadContext: AdditionalPayloadContext, ): ProtocolPayloadGenerator.PayloadMetadata { - val (shape, payloadMemberName) = when (httpMessageType) { - HttpMessageType.RESPONSE -> operationShape.outputShape(model) to - httpBindingResolver.responseMembers(operationShape, HttpLocation.PAYLOAD).firstOrNull()?.memberName + val (shape, payloadMemberName) = + when (httpMessageType) { + HttpMessageType.RESPONSE -> + operationShape.outputShape(model) to + httpBindingResolver.responseMembers(operationShape, HttpLocation.PAYLOAD).firstOrNull()?.memberName - HttpMessageType.REQUEST -> operationShape.inputShape(model) to - httpBindingResolver.requestMembers(operationShape, HttpLocation.PAYLOAD).firstOrNull()?.memberName - } + HttpMessageType.REQUEST -> + operationShape.inputShape(model) to + httpBindingResolver.requestMembers(operationShape, HttpLocation.PAYLOAD).firstOrNull()?.memberName + } // Only: // - streaming operations (blob streaming and event streams), @@ -95,9 +99,10 @@ class HttpBoundProtocolPayloadGenerator( } else { val member = shape.expectMember(payloadMemberName) when (val type = model.expectShape(member.target)) { - is DocumentShape, is StructureShape, is UnionShape -> ProtocolPayloadGenerator.PayloadMetadata( - takesOwnership = false, - ) + is DocumentShape, is StructureShape, is UnionShape -> + ProtocolPayloadGenerator.PayloadMetadata( + takesOwnership = false, + ) is StringShape, is BlobShape -> ProtocolPayloadGenerator.PayloadMetadata(takesOwnership = true) else -> UNREACHABLE("Unexpected payload target type: $type") @@ -112,24 +117,28 @@ class HttpBoundProtocolPayloadGenerator( additionalPayloadContext: AdditionalPayloadContext, ) { when (httpMessageType) { - HttpMessageType.RESPONSE -> generateResponsePayload( - writer, - shapeName, - operationShape, - additionalPayloadContext, - ) + HttpMessageType.RESPONSE -> + generateResponsePayload( + writer, + shapeName, + operationShape, + additionalPayloadContext, + ) - HttpMessageType.REQUEST -> generateRequestPayload( - writer, - shapeName, - operationShape, - additionalPayloadContext, - ) + HttpMessageType.REQUEST -> + generateRequestPayload( + writer, + shapeName, + operationShape, + additionalPayloadContext, + ) } } private fun generateRequestPayload( - writer: RustWriter, shapeName: String, operationShape: OperationShape, + writer: RustWriter, + shapeName: String, + operationShape: OperationShape, additionalPayloadContext: AdditionalPayloadContext, ) { val payloadMemberName = @@ -150,7 +159,9 @@ class HttpBoundProtocolPayloadGenerator( } private fun generateResponsePayload( - writer: RustWriter, shapeName: String, operationShape: OperationShape, + writer: RustWriter, + shapeName: String, + operationShape: OperationShape, additionalPayloadContext: AdditionalPayloadContext, ) { val payloadMemberName = @@ -203,15 +214,20 @@ class HttpBoundProtocolPayloadGenerator( ) } else { val bodyMetadata = payloadMetadata(operationShape) - val payloadMember = when (httpMessageType) { - HttpMessageType.RESPONSE -> operationShape.outputShape(model).expectMember(payloadMemberName) - HttpMessageType.REQUEST -> operationShape.inputShape(model).expectMember(payloadMemberName) - } + val payloadMember = + when (httpMessageType) { + HttpMessageType.RESPONSE -> operationShape.outputShape(model).expectMember(payloadMemberName) + HttpMessageType.REQUEST -> operationShape.inputShape(model).expectMember(payloadMemberName) + } writer.serializeViaPayload(bodyMetadata, shapeName, payloadMember, serializerGenerator) } } - private fun generateStructureSerializer(writer: RustWriter, shapeName: String, serializer: RuntimeType?) { + private fun generateStructureSerializer( + writer: RustWriter, + shapeName: String, + serializer: RuntimeType?, + ) { if (serializer == null) { writer.rust("\"\"") } else { @@ -232,28 +248,31 @@ class HttpBoundProtocolPayloadGenerator( val memberName = symbolProvider.toMemberName(memberShape) val unionShape = model.expectShape(memberShape.target, UnionShape::class.java) - val contentType = when (target) { - CodegenTarget.CLIENT -> httpBindingResolver.requestContentType(operationShape) - CodegenTarget.SERVER -> httpBindingResolver.responseContentType(operationShape) - } - val errorMarshallerConstructorFn = EventStreamErrorMarshallerGenerator( - model, - target, - runtimeConfig, - symbolProvider, - unionShape, - serializerGenerator, - contentType ?: throw CodegenException("event streams must set a content type"), - ).render() - val marshallerConstructorFn = EventStreamMarshallerGenerator( - model, - target, - runtimeConfig, - symbolProvider, - unionShape, - serializerGenerator, - contentType, - ).render() + val contentType = + when (target) { + CodegenTarget.CLIENT -> httpBindingResolver.requestContentType(operationShape) + CodegenTarget.SERVER -> httpBindingResolver.responseContentType(operationShape) + } + val errorMarshallerConstructorFn = + EventStreamErrorMarshallerGenerator( + model, + target, + runtimeConfig, + symbolProvider, + unionShape, + serializerGenerator, + contentType ?: throw CodegenException("event streams must set a content type"), + ).render() + val marshallerConstructorFn = + EventStreamMarshallerGenerator( + model, + target, + runtimeConfig, + symbolProvider, + unionShape, + serializerGenerator, + contentType, + ).render() // TODO(EventStream): [RPC] RPC protocols need to send an initial message with the // parameters that are not `@eventHeader` or `@eventPayload`. @@ -276,50 +295,53 @@ class HttpBoundProtocolPayloadGenerator( serializerGenerator: StructuredDataSerializerGenerator, ) { val ref = if (payloadMetadata.takesOwnership) "" else "&" - val serializer = protocolFunctions.serializeFn(member, fnNameSuffix = "http_payload") { fnName -> - val outputT = if (member.isStreaming(model)) { - symbolProvider.toSymbol(member) - } else { - RuntimeType.ByteSlab.toSymbol() - } - rustBlockTemplate( - "pub fn $fnName(payload: $ref#{Member}) -> Result<#{outputT}, #{BuildError}>", - "Member" to symbolProvider.toSymbol(member), - "outputT" to outputT, - *codegenScope, - ) { - val asRef = if (payloadMetadata.takesOwnership) "" else ".as_ref()" + val serializer = + protocolFunctions.serializeFn(member, fnNameSuffix = "http_payload") { fnName -> + val outputT = + if (member.isStreaming(model)) { + symbolProvider.toSymbol(member) + } else { + RuntimeType.ByteSlab.toSymbol() + } + rustBlockTemplate( + "pub fn $fnName(payload: $ref#{Member}) -> Result<#{outputT}, #{BuildError}>", + "Member" to symbolProvider.toSymbol(member), + "outputT" to outputT, + *codegenScope, + ) { + val asRef = if (payloadMetadata.takesOwnership) "" else ".as_ref()" - if (symbolProvider.toSymbol(member).isOptional()) { - withBlockTemplate( - """ - let payload = match payload$asRef { - Some(t) => t, - None => return Ok( - """, - ")};", - *codegenScope, - ) { - when (val targetShape = model.expectShape(member.target)) { - // Return an empty `Vec`. - is StringShape, is BlobShape, is DocumentShape -> rust( - """ - Vec::new() - """, - ) + if (symbolProvider.toSymbol(member).isOptional()) { + withBlockTemplate( + """ + let payload = match payload$asRef { + Some(t) => t, + None => return Ok( + """, + ")};", + *codegenScope, + ) { + when (val targetShape = model.expectShape(member.target)) { + // Return an empty `Vec`. + is StringShape, is BlobShape, is DocumentShape -> + rust( + """ + Vec::new() + """, + ) - is StructureShape -> rust("#T()", serializerGenerator.unsetStructure(targetShape)) - is UnionShape -> rust("#T()", serializerGenerator.unsetUnion(targetShape)) - else -> throw CodegenException("`httpPayload` on member shapes targeting shapes of type ${targetShape.type} is unsupported") + is StructureShape -> rust("#T()", serializerGenerator.unsetStructure(targetShape)) + is UnionShape -> rust("#T()", serializerGenerator.unsetUnion(targetShape)) + else -> throw CodegenException("`httpPayload` on member shapes targeting shapes of type ${targetShape.type} is unsupported") + } } } - } - withBlock("Ok(", ")") { - renderPayload(member, "payload", serializerGenerator) + withBlock("Ok(", ")") { + renderPayload(member, "payload", serializerGenerator) + } } } - } rust("#T($ref $shapeName.${symbolProvider.toMemberName(member)})?", serializer) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/Protocol.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/Protocol.kt index 4a1339ca9aa..236c297db92 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/Protocol.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/Protocol.kt @@ -67,6 +67,8 @@ typealias ProtocolMap = Map> interface ProtocolGeneratorFactory { fun protocol(codegenContext: C): Protocol + fun buildProtocolGenerator(codegenContext: C): T + fun support(): ProtocolSupport } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/ProtocolFunctions.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/ProtocolFunctions.kt index c468fdca0bc..e40046f1d84 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/ProtocolFunctions.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/ProtocolFunctions.kt @@ -41,7 +41,10 @@ class ProtocolFunctions( companion object { private val serDeModule = RustModule.pubCrate("protocol_serde") - fun crossOperationFn(fnName: String, block: ProtocolFnWritable): RuntimeType = + fun crossOperationFn( + fnName: String, + block: ProtocolFnWritable, + ): RuntimeType = RuntimeType.forInlineFun(fnName, serDeModule) { block(fnName) } @@ -100,12 +103,13 @@ class ProtocolFunctions( val moduleName = codegenContext.symbolProvider.shapeModuleName(codegenContext.serviceShape, shape) val fnBaseName = codegenContext.symbolProvider.shapeFunctionName(codegenContext.serviceShape, shape) val suffix = fnNameSuffix?.let { "_$it" } ?: "" - val fnName = RustReservedWords.escapeIfNeeded( - when (fnType) { - FnType.Deserialize -> "de_$fnBaseName$suffix" - FnType.Serialize -> "ser_$fnBaseName$suffix" - }, - ) + val fnName = + RustReservedWords.escapeIfNeeded( + when (fnType) { + FnType.Deserialize -> "de_$fnBaseName$suffix" + FnType.Serialize -> "ser_$fnBaseName$suffix" + }, + ) return serDeFn(moduleName, fnName, parentModule, block) } @@ -115,12 +119,13 @@ class ProtocolFunctions( parentModule: RustModule.LeafModule, block: ProtocolFnWritable, ): RuntimeType { - val additionalAttributes = when { - // Some SDK models have maps with names prefixed with `__mapOf__`, which become `__map_of__`, - // and the Rust compiler warning doesn't like multiple adjacent underscores. - moduleName.contains("__") || fnName.contains("__") -> listOf(Attribute.AllowNonSnakeCase) - else -> emptyList() - } + val additionalAttributes = + when { + // Some SDK models have maps with names prefixed with `__mapOf__`, which become `__map_of__`, + // and the Rust compiler warning doesn't like multiple adjacent underscores. + moduleName.contains("__") || fnName.contains("__") -> listOf(Attribute.AllowNonSnakeCase) + else -> emptyList() + } return RuntimeType.forInlineFun( fnName, RustModule.pubCrate(moduleName, parent = parentModule, additionalAttributes = additionalAttributes), @@ -131,7 +136,10 @@ class ProtocolFunctions( } /** Creates a module name for a ser/de function. */ -internal fun RustSymbolProvider.shapeModuleName(serviceShape: ServiceShape?, shape: Shape): String = +internal fun RustSymbolProvider.shapeModuleName( + serviceShape: ServiceShape?, + shape: Shape, +): String = RustReservedWords.escapeIfNeeded( "shape_" + when (shape) { @@ -142,14 +150,19 @@ internal fun RustSymbolProvider.shapeModuleName(serviceShape: ServiceShape?, sha ) /** Creates a unique name for a ser/de function. */ -fun RustSymbolProvider.shapeFunctionName(serviceShape: ServiceShape?, shape: Shape): String { - val extras = "".letIf(shape.hasTrait()) { - it + "_output" - }.letIf(shape.hasTrait()) { it + "_input" } - val containerName = when (shape) { - is MemberShape -> model.expectShape(shape.container).contextName(serviceShape).toSnakeCase() - else -> shape.contextName(serviceShape).toSnakeCase() - } + extras +fun RustSymbolProvider.shapeFunctionName( + serviceShape: ServiceShape?, + shape: Shape, +): String { + val extras = + "".letIf(shape.hasTrait()) { + it + "_output" + }.letIf(shape.hasTrait()) { it + "_input" } + val containerName = + when (shape) { + is MemberShape -> model.expectShape(shape.container).contextName(serviceShape).toSnakeCase() + else -> shape.contextName(serviceShape).toSnakeCase() + } + extras return when (shape) { is MemberShape -> shape.memberName.toSnakeCase() is DocumentShape -> "document" diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/RestJson.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/RestJson.kt index 3e08ceca8e2..d839bac3c8d 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/RestJson.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/RestJson.kt @@ -42,9 +42,10 @@ class RestJsonHttpBindingResolver( * overridden by a specific mechanism e.g. an output shape member is targeted with `httpPayload` or `mediaType` traits. */ override fun responseContentType(operationShape: OperationShape): String? { - val members = operationShape - .outputShape(model) - .members() + val members = + operationShape + .outputShape(model) + .members() // TODO(https://github.com/awslabs/smithy/issues/1259) // Temporary fix for https://github.com/awslabs/smithy/blob/df456a514f72f4e35f0fb07c7e26006ff03b2071/smithy-model/src/main/java/software/amazon/smithy/model/knowledge/HttpBindingIndex.java#L352 for (member in members) { @@ -61,14 +62,16 @@ class RestJsonHttpBindingResolver( open class RestJson(val codegenContext: CodegenContext) : Protocol { private val runtimeConfig = codegenContext.runtimeConfig - private val errorScope = arrayOf( - "Bytes" to RuntimeType.Bytes, - "ErrorMetadataBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), - "Headers" to RuntimeType.headers(runtimeConfig), - "JsonError" to CargoDependency.smithyJson(runtimeConfig).toType() - .resolve("deserialize::error::DeserializeError"), - "json_errors" to RuntimeType.jsonErrors(runtimeConfig), - ) + private val errorScope = + arrayOf( + "Bytes" to RuntimeType.Bytes, + "ErrorMetadataBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), + "Headers" to RuntimeType.headers(runtimeConfig), + "JsonError" to + CargoDependency.smithyJson(runtimeConfig).toType() + .resolve("deserialize::error::DeserializeError"), + "json_errors" to RuntimeType.jsonErrors(runtimeConfig), + ) override val httpBindingResolver: HttpBindingResolver = RestJsonHttpBindingResolver(codegenContext.model, ProtocolContentTypes("application/json", "application/json", "application/vnd.amazon.eventstream")) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/RestXml.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/RestXml.kt index 15d294c0356..700fe60775c 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/RestXml.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/RestXml.kt @@ -21,17 +21,19 @@ import software.amazon.smithy.rust.codegen.core.util.expectTrait open class RestXml(val codegenContext: CodegenContext) : Protocol { private val restXml = codegenContext.serviceShape.expectTrait() private val runtimeConfig = codegenContext.runtimeConfig - private val errorScope = arrayOf( - "Bytes" to RuntimeType.Bytes, - "ErrorMetadataBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), - "Headers" to RuntimeType.headers(runtimeConfig), - "XmlDecodeError" to RuntimeType.smithyXml(runtimeConfig).resolve("decode::XmlDecodeError"), - ) + private val errorScope = + arrayOf( + "Bytes" to RuntimeType.Bytes, + "ErrorMetadataBuilder" to RuntimeType.errorMetadataBuilder(runtimeConfig), + "Headers" to RuntimeType.headers(runtimeConfig), + "XmlDecodeError" to RuntimeType.smithyXml(runtimeConfig).resolve("decode::XmlDecodeError"), + ) - protected val restXmlErrors: RuntimeType = when (restXml.isNoErrorWrapping) { - true -> RuntimeType.unwrappedXmlErrors(runtimeConfig) - false -> RuntimeType.wrappedXmlErrors(runtimeConfig) - } + protected val restXmlErrors: RuntimeType = + when (restXml.isNoErrorWrapping) { + true -> RuntimeType.unwrappedXmlErrors(runtimeConfig) + false -> RuntimeType.wrappedXmlErrors(runtimeConfig) + } override val httpBindingResolver: HttpBindingResolver = HttpTraitHttpBindingResolver(codegenContext.model, ProtocolContentTypes("application/xml", "application/xml", "application/vnd.amazon.eventstream")) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/XmlNameIndex.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/XmlNameIndex.kt index e3f1be1ff7e..4495f6f92de 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/XmlNameIndex.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/XmlNameIndex.kt @@ -67,5 +67,6 @@ data class XmlMemberIndex(val dataMembers: List, val attributeMembe } fun isEmpty() = dataMembers.isEmpty() && attributeMembers.isEmpty() + fun isNotEmpty() = !isEmpty() } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/EventStreamUnmarshallerGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/EventStreamUnmarshallerGenerator.kt index 47aadd368d3..b114911d926 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/EventStreamUnmarshallerGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/EventStreamUnmarshallerGenerator.kt @@ -43,8 +43,7 @@ import software.amazon.smithy.rust.codegen.core.util.expectTrait import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.toPascalCase -fun RustModule.Companion.eventStreamSerdeModule(): RustModule.LeafModule = - private("event_stream_serde") +fun RustModule.Companion.eventStreamSerdeModule(): RustModule.LeafModule = private("event_stream_serde") class EventStreamUnmarshallerGenerator( private val protocol: Protocol, @@ -58,28 +57,30 @@ class EventStreamUnmarshallerGenerator( private val codegenTarget = codegenContext.target private val runtimeConfig = codegenContext.runtimeConfig private val unionSymbol = symbolProvider.toSymbol(unionShape) - private val errorSymbol = if (codegenTarget == CodegenTarget.SERVER && unionShape.eventStreamErrors().isEmpty()) { - RuntimeType.smithyHttp(runtimeConfig).resolve("event_stream::MessageStreamError").toSymbol() - } else { - symbolProvider.symbolForEventStreamError(unionShape) - } + private val errorSymbol = + if (codegenTarget == CodegenTarget.SERVER && unionShape.eventStreamErrors().isEmpty()) { + RuntimeType.smithyHttp(runtimeConfig).resolve("event_stream::MessageStreamError").toSymbol() + } else { + symbolProvider.symbolForEventStreamError(unionShape) + } private val smithyEventStream = RuntimeType.smithyEventStream(runtimeConfig) private val smithyTypes = RuntimeType.smithyTypes(runtimeConfig) private val eventStreamSerdeModule = RustModule.eventStreamSerdeModule() - private val codegenScope = arrayOf( - "Blob" to RuntimeType.blob(runtimeConfig), - "expect_fns" to smithyEventStream.resolve("smithy"), - "MarshallMessage" to smithyEventStream.resolve("frame::MarshallMessage"), - "Message" to smithyTypes.resolve("event_stream::Message"), - "Header" to smithyTypes.resolve("event_stream::Header"), - "HeaderValue" to smithyTypes.resolve("event_stream::HeaderValue"), - "Error" to smithyEventStream.resolve("error::Error"), - "OpError" to errorSymbol, - "SmithyError" to RuntimeType.smithyTypes(runtimeConfig).resolve("Error"), - "tracing" to RuntimeType.Tracing, - "UnmarshalledMessage" to smithyEventStream.resolve("frame::UnmarshalledMessage"), - "UnmarshallMessage" to smithyEventStream.resolve("frame::UnmarshallMessage"), - ) + private val codegenScope = + arrayOf( + "Blob" to RuntimeType.blob(runtimeConfig), + "expect_fns" to smithyEventStream.resolve("smithy"), + "MarshallMessage" to smithyEventStream.resolve("frame::MarshallMessage"), + "Message" to smithyTypes.resolve("event_stream::Message"), + "Header" to smithyTypes.resolve("event_stream::Header"), + "HeaderValue" to smithyTypes.resolve("event_stream::HeaderValue"), + "Error" to smithyEventStream.resolve("error::Error"), + "OpError" to errorSymbol, + "SmithyError" to RuntimeType.smithyTypes(runtimeConfig).resolve("Error"), + "tracing" to RuntimeType.Tracing, + "UnmarshalledMessage" to smithyEventStream.resolve("frame::UnmarshalledMessage"), + "UnmarshallMessage" to smithyEventStream.resolve("frame::UnmarshallMessage"), + ) fun render(): RuntimeType { val unmarshallerType = unionShape.eventStreamUnmarshallerType() @@ -88,7 +89,10 @@ class EventStreamUnmarshallerGenerator( } } - private fun RustWriter.renderUnmarshaller(unmarshallerType: RuntimeType, unionSymbol: Symbol) { + private fun RustWriter.renderUnmarshaller( + unmarshallerType: RuntimeType, + unionSymbol: Symbol, + ) { val unmarshallerTypeName = unmarshallerType.name rust( """ @@ -139,11 +143,12 @@ class EventStreamUnmarshallerGenerator( } } - private fun expectedContentType(payloadTarget: Shape): String? = when (payloadTarget) { - is BlobShape -> "application/octet-stream" - is StringShape -> "text/plain" - else -> null - } + private fun expectedContentType(payloadTarget: Shape): String? = + when (payloadTarget) { + is BlobShape -> "application/octet-stream" + is StringShape -> "text/plain" + else -> null + } private fun RustWriter.renderUnmarshallEvent() { rustBlock("match response_headers.smithy_type.as_str()") { @@ -155,22 +160,27 @@ class EventStreamUnmarshallerGenerator( } rustBlock("_unknown_variant => ") { when (codegenTarget.renderUnknownVariant()) { - true -> rustTemplate( - "Ok(#{UnmarshalledMessage}::Event(#{Output}::${UnionGenerator.UnknownVariantName}))", - "Output" to unionSymbol, - *codegenScope, - ) + true -> + rustTemplate( + "Ok(#{UnmarshalledMessage}::Event(#{Output}::${UnionGenerator.UnknownVariantName}))", + "Output" to unionSymbol, + *codegenScope, + ) - false -> rustTemplate( - "return Err(#{Error}::unmarshalling(format!(\"unrecognized :event-type: {}\", _unknown_variant)));", - *codegenScope, - ) + false -> + rustTemplate( + "return Err(#{Error}::unmarshalling(format!(\"unrecognized :event-type: {}\", _unknown_variant)));", + *codegenScope, + ) } } } } - private fun RustWriter.renderUnmarshallUnionMember(unionMember: MemberShape, unionStruct: StructureShape) { + private fun RustWriter.renderUnmarshallUnionMember( + unionMember: MemberShape, + unionStruct: StructureShape, + ) { val unionMemberName = symbolProvider.toMemberName(unionMember) val empty = unionStruct.members().isEmpty() val payloadOnly = @@ -330,11 +340,12 @@ class EventStreamUnmarshallerGenerator( val syntheticUnion = unionShape.expectTrait() if (syntheticUnion.errorMembers.isNotEmpty()) { // clippy::single-match implied, using if when there's only one error - val (header, matchOperator) = if (syntheticUnion.errorMembers.size > 1) { - listOf("match response_headers.smithy_type.as_str() {", "=>") - } else { - listOf("if response_headers.smithy_type.as_str() == ", "") - } + val (header, matchOperator) = + if (syntheticUnion.errorMembers.size > 1) { + listOf("match response_headers.smithy_type.as_str() {", "=>") + } else { + listOf("if response_headers.smithy_type.as_str() == ", "") + } rust(header) for (member in syntheticUnion.errorMembers) { rustBlock("${member.memberName.dq()} $matchOperator ") { @@ -360,14 +371,15 @@ class EventStreamUnmarshallerGenerator( ) )) """, - "build" to builderInstantiator.finalizeBuilder( - "builder", target, - mapErr = { - rustTemplate( - """|err|#{Error}::unmarshalling(format!("{}", err))""", *codegenScope, - ) - }, - ), + "build" to + builderInstantiator.finalizeBuilder( + "builder", target, + mapErr = { + rustTemplate( + """|err|#{Error}::unmarshalling(format!("{}", err))""", *codegenScope, + ) + }, + ), "parser" to parser, *codegenScope, ) @@ -377,7 +389,12 @@ class EventStreamUnmarshallerGenerator( CodegenTarget.SERVER -> { val target = model.expectShape(member.target, StructureShape::class.java) val parser = protocol.structuredDataParser().errorParser(target) - val mut = if (parser != null) { " mut" } else { "" } + val mut = + if (parser != null) { + " mut" + } else { + "" + } rust("let$mut builder = #T::default();", symbolProvider.symbolForBuilder(target)) if (parser != null) { rustTemplate( diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGenerator.kt index 6b0a7b507bd..31a1b0c7b54 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGenerator.kt @@ -104,23 +104,24 @@ class JsonParserGenerator( private val smithyJson = CargoDependency.smithyJson(runtimeConfig).toType() private val protocolFunctions = ProtocolFunctions(codegenContext) private val builderInstantiator = codegenContext.builderInstantiator() - private val codegenScope = arrayOf( - "Error" to smithyJson.resolve("deserialize::error::DeserializeError"), - "expect_blob_or_null" to smithyJson.resolve("deserialize::token::expect_blob_or_null"), - "expect_bool_or_null" to smithyJson.resolve("deserialize::token::expect_bool_or_null"), - "expect_document" to smithyJson.resolve("deserialize::token::expect_document"), - "expect_number_or_null" to smithyJson.resolve("deserialize::token::expect_number_or_null"), - "expect_start_array" to smithyJson.resolve("deserialize::token::expect_start_array"), - "expect_start_object" to smithyJson.resolve("deserialize::token::expect_start_object"), - "expect_string_or_null" to smithyJson.resolve("deserialize::token::expect_string_or_null"), - "expect_timestamp_or_null" to smithyJson.resolve("deserialize::token::expect_timestamp_or_null"), - "json_token_iter" to smithyJson.resolve("deserialize::json_token_iter"), - "Peekable" to RuntimeType.std.resolve("iter::Peekable"), - "skip_value" to smithyJson.resolve("deserialize::token::skip_value"), - "skip_to_end" to smithyJson.resolve("deserialize::token::skip_to_end"), - "Token" to smithyJson.resolve("deserialize::Token"), - "or_empty" to orEmptyJson(), - ) + private val codegenScope = + arrayOf( + "Error" to smithyJson.resolve("deserialize::error::DeserializeError"), + "expect_blob_or_null" to smithyJson.resolve("deserialize::token::expect_blob_or_null"), + "expect_bool_or_null" to smithyJson.resolve("deserialize::token::expect_bool_or_null"), + "expect_document" to smithyJson.resolve("deserialize::token::expect_document"), + "expect_number_or_null" to smithyJson.resolve("deserialize::token::expect_number_or_null"), + "expect_start_array" to smithyJson.resolve("deserialize::token::expect_start_array"), + "expect_start_object" to smithyJson.resolve("deserialize::token::expect_start_object"), + "expect_string_or_null" to smithyJson.resolve("deserialize::token::expect_string_or_null"), + "expect_timestamp_or_null" to smithyJson.resolve("deserialize::token::expect_timestamp_or_null"), + "json_token_iter" to smithyJson.resolve("deserialize::json_token_iter"), + "Peekable" to RuntimeType.std.resolve("iter::Peekable"), + "skip_value" to smithyJson.resolve("deserialize::token::skip_value"), + "skip_to_end" to smithyJson.resolve("deserialize::token::skip_to_end"), + "Token" to smithyJson.resolve("deserialize::Token"), + "or_empty" to orEmptyJson(), + ) /** * Reusable structure parser implementation that can be used to generate parsing code for @@ -168,11 +169,12 @@ class JsonParserGenerator( *codegenScope, "ReturnType" to returnSymbolToParse.symbol, ) { - val input = if (shape is DocumentShape) { - "input" - } else { - "#{or_empty}(input)" - } + val input = + if (shape is DocumentShape) { + "input" + } else { + "#{or_empty}(input)" + } rustTemplate( """ @@ -212,19 +214,20 @@ class JsonParserGenerator( ) } - private fun orEmptyJson(): RuntimeType = ProtocolFunctions.crossOperationFn("or_empty_doc") { - rust( - """ - pub(crate) fn or_empty_doc(data: &[u8]) -> &[u8] { - if data.is_empty() { - b"{}" - } else { - data + private fun orEmptyJson(): RuntimeType = + ProtocolFunctions.crossOperationFn("or_empty_doc") { + rust( + """ + pub(crate) fn or_empty_doc(data: &[u8]) -> &[u8] { + if data.is_empty() { + b"{}" + } else { + data + } } - } - """, - ) - } + """, + ) + } override fun serverInputParser(operationShape: OperationShape): RuntimeType? { val includedMembers = httpBindingResolver.requestMembers(operationShape, HttpLocation.DOCUMENT) @@ -321,7 +324,10 @@ class JsonParserGenerator( } } - private fun RustWriter.deserializeStringInner(target: StringShape, escapedStrName: String) { + private fun RustWriter.deserializeStringInner( + target: StringShape, + escapedStrName: String, + ) { withBlock("$escapedStrName.to_unescaped().map(|u|", ")") { when (target.hasTrait()) { true -> { @@ -380,60 +386,61 @@ class JsonParserGenerator( private fun RustWriter.deserializeCollection(shape: CollectionShape) { val isSparse = shape.hasTrait() val (returnSymbol, returnUnconstrainedType) = returnSymbolToParse(shape) - val parser = protocolFunctions.deserializeFn(shape) { fnName -> - rustBlockTemplate( - """ - pub(crate) fn $fnName<'a, I>(tokens: &mut #{Peekable}) -> Result, #{Error}> - where I: Iterator, #{Error}>> - """, - "ReturnType" to returnSymbol, - *codegenScope, - ) { - startArrayOrNull { - rust("let mut items = Vec::new();") - rustBlock("loop") { - rustBlock("match tokens.peek()") { - rustBlockTemplate("Some(Ok(#{Token}::EndArray { .. })) =>", *codegenScope) { - rust("tokens.next().transpose().unwrap(); break;") - } - rustBlock("_ => ") { - if (isSparse) { - withBlock("items.push(", ");") { - deserializeMember(shape.member) - } - } else { - withBlock("let value =", ";") { - deserializeMember(shape.member) - } - rust( - """ - if let Some(value) = value { - items.push(value); + val parser = + protocolFunctions.deserializeFn(shape) { fnName -> + rustBlockTemplate( + """ + pub(crate) fn $fnName<'a, I>(tokens: &mut #{Peekable}) -> Result, #{Error}> + where I: Iterator, #{Error}>> + """, + "ReturnType" to returnSymbol, + *codegenScope, + ) { + startArrayOrNull { + rust("let mut items = Vec::new();") + rustBlock("loop") { + rustBlock("match tokens.peek()") { + rustBlockTemplate("Some(Ok(#{Token}::EndArray { .. })) =>", *codegenScope) { + rust("tokens.next().transpose().unwrap(); break;") + } + rustBlock("_ => ") { + if (isSparse) { + withBlock("items.push(", ");") { + deserializeMember(shape.member) } - """, - ) - codegenTarget.ifServer { - rustTemplate( + } else { + withBlock("let value =", ";") { + deserializeMember(shape.member) + } + rust( """ - else { - return Err(#{Error}::custom("dense list cannot contain null values")); + if let Some(value) = value { + items.push(value); } """, - *codegenScope, ) + codegenTarget.ifServer { + rustTemplate( + """ + else { + return Err(#{Error}::custom("dense list cannot contain null values")); + } + """, + *codegenScope, + ) + } } } } } - } - if (returnUnconstrainedType) { - rust("Ok(Some(#{T}(items)))", returnSymbol) - } else { - rust("Ok(Some(items))") + if (returnUnconstrainedType) { + rust("Ok(Some(#{T}(items)))", returnSymbol) + } else { + rust("Ok(Some(items))") + } } } } - } rust("#T(tokens)?", parser) } @@ -441,181 +448,190 @@ class JsonParserGenerator( val keyTarget = model.expectShape(shape.key.target) as StringShape val isSparse = shape.hasTrait() val returnSymbolToParse = returnSymbolToParse(shape) - val parser = protocolFunctions.deserializeFn(shape) { fnName -> - rustBlockTemplate( - """ - pub(crate) fn $fnName<'a, I>(tokens: &mut #{Peekable}) -> Result, #{Error}> - where I: Iterator, #{Error}>> - """, - "ReturnType" to returnSymbolToParse.symbol, - *codegenScope, - ) { - startObjectOrNull { - rust("let mut map = #T::new();", RuntimeType.HashMap) - objectKeyLoop(hasMembers = true) { - withBlock("let key =", "?;") { - deserializeStringInner(keyTarget, "key") - } - withBlock("let value =", ";") { - deserializeMember(shape.value) - } - if (isSparse) { - rust("map.insert(key, value);") - } else { - codegenTarget.ifServer { - rustTemplate( - """ - match value { - Some(value) => { map.insert(key, value); } - None => return Err(#{Error}::custom("dense map cannot contain null values")) - }""", - *codegenScope, - ) + val parser = + protocolFunctions.deserializeFn(shape) { fnName -> + rustBlockTemplate( + """ + pub(crate) fn $fnName<'a, I>(tokens: &mut #{Peekable}) -> Result, #{Error}> + where I: Iterator, #{Error}>> + """, + "ReturnType" to returnSymbolToParse.symbol, + *codegenScope, + ) { + startObjectOrNull { + rust("let mut map = #T::new();", RuntimeType.HashMap) + objectKeyLoop(hasMembers = true) { + withBlock("let key =", "?;") { + deserializeStringInner(keyTarget, "key") } - codegenTarget.ifClient { - rustTemplate( - """ - if let Some(value) = value { - map.insert(key, value); - } - """, - ) + withBlock("let value =", ";") { + deserializeMember(shape.value) + } + if (isSparse) { + rust("map.insert(key, value);") + } else { + codegenTarget.ifServer { + rustTemplate( + """ + match value { + Some(value) => { map.insert(key, value); } + None => return Err(#{Error}::custom("dense map cannot contain null values")) + }""", + *codegenScope, + ) + } + codegenTarget.ifClient { + rustTemplate( + """ + if let Some(value) = value { + map.insert(key, value); + } + """, + ) + } } } - } - if (returnSymbolToParse.isUnconstrained) { - rust("Ok(Some(#{T}(map)))", returnSymbolToParse.symbol) - } else { - rust("Ok(Some(map))") + if (returnSymbolToParse.isUnconstrained) { + rust("Ok(Some(#{T}(map)))", returnSymbolToParse.symbol) + } else { + rust("Ok(Some(map))") + } } } } - } rust("#T(tokens)?", parser) } private fun RustWriter.deserializeStruct(shape: StructureShape) { val returnSymbolToParse = returnSymbolToParse(shape) - val nestedParser = protocolFunctions.deserializeFn(shape) { fnName -> - rustBlockTemplate( - """ - pub(crate) fn $fnName<'a, I>(tokens: &mut #{Peekable}) -> Result, #{Error}> - where I: Iterator, #{Error}>> - """, - "ReturnType" to returnSymbolToParse.symbol, - *codegenScope, - ) { - startObjectOrNull { - Attribute.AllowUnusedMut.render(this) - rustTemplate( - "let mut builder = #{Builder}::default();", - *codegenScope, - "Builder" to symbolProvider.symbolForBuilder(shape), - ) - deserializeStructInner(shape.members()) - val builder = builderInstantiator.finalizeBuilder( - "builder", shape, - ) { + val nestedParser = + protocolFunctions.deserializeFn(shape) { fnName -> + rustBlockTemplate( + """ + pub(crate) fn $fnName<'a, I>(tokens: &mut #{Peekable}) -> Result, #{Error}> + where I: Iterator, #{Error}>> + """, + "ReturnType" to returnSymbolToParse.symbol, + *codegenScope, + ) { + startObjectOrNull { + Attribute.AllowUnusedMut.render(this) rustTemplate( - """|err|#{Error}::custom_source("Response was invalid", err)""", *codegenScope, + "let mut builder = #{Builder}::default();", + *codegenScope, + "Builder" to symbolProvider.symbolForBuilder(shape), ) + deserializeStructInner(shape.members()) + val builder = + builderInstantiator.finalizeBuilder( + "builder", shape, + ) { + rustTemplate( + """|err|#{Error}::custom_source("Response was invalid", err)""", *codegenScope, + ) + } + rust("Ok(Some(#T))", builder) } - rust("Ok(Some(#T))", builder) } } - } rust("#T(tokens)?", nestedParser) } private fun RustWriter.deserializeUnion(shape: UnionShape) { val returnSymbolToParse = returnSymbolToParse(shape) - val nestedParser = protocolFunctions.deserializeFn(shape) { fnName -> - rustBlockTemplate( - """ - pub(crate) fn $fnName<'a, I>(tokens: &mut #{Peekable}) -> Result, #{Error}> - where I: Iterator, #{Error}>> - """, - *codegenScope, - "Shape" to returnSymbolToParse.symbol, - ) { - rust("let mut variant = None;") - val checkValueSet = !shape.members().all { it.isTargetUnit() } && !codegenTarget.renderUnknownVariant() - rustBlock("match tokens.next().transpose()?") { - rustBlockTemplate( - """ - Some(#{Token}::ValueNull { .. }) => return Ok(None), - Some(#{Token}::StartObject { .. }) => - """, - *codegenScope, - ) { - objectKeyLoop(hasMembers = shape.members().isNotEmpty()) { - rustTemplate( - """ - let key = key.to_unescaped()?; - if key == "__type" { - #{skip_value}(tokens)?; - continue - } - if variant.is_some() { - return Err(#{Error}::custom("encountered mixed variants in union")); - } - """, - *codegenScope, - ) - withBlock("variant = match key.as_ref() {", "};") { - for (member in shape.members()) { - val variantName = symbolProvider.toMemberName(member) - rustBlock("${jsonName(member).dq()} =>") { - if (member.isTargetUnit()) { + val nestedParser = + protocolFunctions.deserializeFn(shape) { fnName -> + rustBlockTemplate( + """ + pub(crate) fn $fnName<'a, I>(tokens: &mut #{Peekable}) -> Result, #{Error}> + where I: Iterator, #{Error}>> + """, + *codegenScope, + "Shape" to returnSymbolToParse.symbol, + ) { + rust("let mut variant = None;") + val checkValueSet = !shape.members().all { it.isTargetUnit() } && !codegenTarget.renderUnknownVariant() + rustBlock("match tokens.next().transpose()?") { + rustBlockTemplate( + """ + Some(#{Token}::ValueNull { .. }) => return Ok(None), + Some(#{Token}::StartObject { .. }) => + """, + *codegenScope, + ) { + objectKeyLoop(hasMembers = shape.members().isNotEmpty()) { + rustTemplate( + """ + let key = key.to_unescaped()?; + if key == "__type" { + #{skip_value}(tokens)?; + continue + } + if variant.is_some() { + return Err(#{Error}::custom("encountered mixed variants in union")); + } + """, + *codegenScope, + ) + withBlock("variant = match key.as_ref() {", "};") { + for (member in shape.members()) { + val variantName = symbolProvider.toMemberName(member) + rustBlock("${jsonName(member).dq()} =>") { + if (member.isTargetUnit()) { + rustTemplate( + """ + #{skip_value}(tokens)?; + Some(#{Union}::$variantName) + """, + "Union" to returnSymbolToParse.symbol, *codegenScope, + ) + } else { + withBlock("Some(#T::$variantName(", "))", returnSymbolToParse.symbol) { + deserializeMember(member) + unwrapOrDefaultOrError(member, checkValueSet) + } + } + } + } + when (codegenTarget.renderUnknownVariant()) { + // In client mode, resolve an unknown union variant to the unknown variant. + true -> rustTemplate( """ - #{skip_value}(tokens)?; - Some(#{Union}::$variantName) + _ => { + #{skip_value}(tokens)?; + Some(#{Union}::${UnionGenerator.UnknownVariantName}) + } """, - "Union" to returnSymbolToParse.symbol, *codegenScope, + "Union" to returnSymbolToParse.symbol, + *codegenScope, + ) + // In server mode, use strict parsing. + // Consultation: https://github.com/awslabs/smithy/issues/1222 + false -> + rustTemplate( + """variant => return Err(#{Error}::custom(format!("unexpected union variant: {}", variant)))""", + *codegenScope, ) - } else { - withBlock("Some(#T::$variantName(", "))", returnSymbolToParse.symbol) { - deserializeMember(member) - unwrapOrDefaultOrError(member, checkValueSet) - } - } } } - when (codegenTarget.renderUnknownVariant()) { - // In client mode, resolve an unknown union variant to the unknown variant. - true -> rustTemplate( - """ - _ => { - #{skip_value}(tokens)?; - Some(#{Union}::${UnionGenerator.UnknownVariantName}) - } - """, - "Union" to returnSymbolToParse.symbol, - *codegenScope, - ) - // In server mode, use strict parsing. - // Consultation: https://github.com/awslabs/smithy/issues/1222 - false -> rustTemplate( - """variant => return Err(#{Error}::custom(format!("unexpected union variant: {}", variant)))""", - *codegenScope, - ) - } } } + rustTemplate( + """_ => return Err(#{Error}::custom("expected start object or null"))""", + *codegenScope, + ) } - rustTemplate( - """_ => return Err(#{Error}::custom("expected start object or null"))""", - *codegenScope, - ) + rust("Ok(variant)") } - rust("Ok(variant)") } - } rust("#T(tokens)?", nestedParser) } - private fun RustWriter.unwrapOrDefaultOrError(member: MemberShape, checkValueSet: Boolean) { + private fun RustWriter.unwrapOrDefaultOrError( + member: MemberShape, + checkValueSet: Boolean, + ) { if (symbolProvider.toSymbol(member).canUseDefault() && !checkValueSet) { rust(".unwrap_or_default()") } else { @@ -626,7 +642,10 @@ class JsonParserGenerator( } } - private fun RustWriter.objectKeyLoop(hasMembers: Boolean, inner: Writable) { + private fun RustWriter.objectKeyLoop( + hasMembers: Boolean, + inner: Writable, + ) { if (!hasMembers) { rustTemplate("#{skip_to_end}(tokens)?;", *codegenScope) } else { @@ -651,8 +670,13 @@ class JsonParserGenerator( } private fun RustWriter.startArrayOrNull(inner: Writable) = startOrNull("array", inner) + private fun RustWriter.startObjectOrNull(inner: Writable) = startOrNull("object", inner) - private fun RustWriter.startOrNull(objectOrArray: String, inner: Writable) { + + private fun RustWriter.startOrNull( + objectOrArray: String, + inner: Writable, + ) { rustBlockTemplate("match tokens.next().transpose()?", *codegenScope) { rustBlockTemplate( """ diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/RestXmlParserGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/RestXmlParserGenerator.kt index d37413f29f2..cea67a46c2b 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/RestXmlParserGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/RestXmlParserGenerator.kt @@ -24,11 +24,12 @@ class RestXmlParserGenerator( ) { context, inner -> val shapeName = context.outputShapeName // Get the non-synthetic version of the outputShape and check to see if it has the `AllowInvalidXmlRoot` trait - val allowInvalidRoot = context.model.getShape(context.shape.outputShape).orNull().let { shape -> - shape?.getTrait()?.originalId.let { shapeId -> - context.model.getShape(shapeId).orNull()?.hasTrait() ?: false + val allowInvalidRoot = + context.model.getShape(context.shape.outputShape).orNull().let { shape -> + shape?.getTrait()?.originalId.let { shapeId -> + context.model.getShape(shapeId).orNull()?.hasTrait() ?: false + } } - } // If we DON'T allow the XML root to be invalid, insert code to check for and report a mismatch if (!allowInvalidRoot) { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGenerator.kt index 03caf527a89..a93981df211 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGenerator.kt @@ -70,7 +70,6 @@ class XmlBindingTraitParserGenerator( private val xmlErrors: RuntimeType, private val writeOperationWrapper: RustWriter.(OperationWrapperContext, OperationInnerWriteable) -> Unit, ) : StructuredDataParserGenerator { - /** Abstraction to represent an XML element name */ data class XmlName(val name: String) { /** Generates an expression to match a given element against this XML tag name */ @@ -103,15 +102,16 @@ class XmlBindingTraitParserGenerator( private val builderInstantiator = codegenContext.builderInstantiator() // The symbols we want all the time - private val codegenScope = arrayOf( - "Blob" to RuntimeType.blob(runtimeConfig), - "Document" to smithyXml.resolve("decode::Document"), - "XmlDecodeError" to xmlDecodeError, - "next_start_element" to smithyXml.resolve("decode::next_start_element"), - "try_data" to smithyXml.resolve("decode::try_data"), - "ScopedDecoder" to scopedDecoder, - "aws_smithy_types" to CargoDependency.smithyTypes(runtimeConfig).toType(), - ) + private val codegenScope = + arrayOf( + "Blob" to RuntimeType.blob(runtimeConfig), + "Document" to smithyXml.resolve("decode::Document"), + "XmlDecodeError" to xmlDecodeError, + "next_start_element" to smithyXml.resolve("decode::next_start_element"), + "try_data" to smithyXml.resolve("decode::try_data"), + "ScopedDecoder" to scopedDecoder, + "aws_smithy_types" to CargoDependency.smithyTypes(runtimeConfig).toType(), + ) private val model = codegenContext.model private val index = HttpBindingIndex.of(model) private val xmlIndex = XmlNameIndex.of(model) @@ -305,7 +305,11 @@ class XmlBindingTraitParserGenerator( /** * Update a structure builder based on the [members], specifying where to find each member (document vs. attributes) */ - private fun RustWriter.parseStructureInner(members: XmlMemberIndex, builder: String, outerCtx: Ctx) { + private fun RustWriter.parseStructureInner( + members: XmlMemberIndex, + builder: String, + outerCtx: Ctx, + ) { members.attributeMembers.forEach { member -> val temp = safeName("attrib") withBlock("let $temp =", ";") { @@ -339,7 +343,11 @@ class XmlBindingTraitParserGenerator( * generates a match expression * When [ignoreUnexpected] is true, unexpected tags are ignored */ - private fun RustWriter.parseLoop(ctx: Ctx, ignoreUnexpected: Boolean = true, inner: RustWriter.(Ctx) -> Unit) { + private fun RustWriter.parseLoop( + ctx: Ctx, + ignoreUnexpected: Boolean = true, + inner: RustWriter.(Ctx) -> Unit, + ) { rustBlock("while let Some(mut tag) = ${ctx.tag}.next_tag()") { rustBlock("match tag.start_el()") { inner(ctx.copy(tag = "tag")) @@ -353,7 +361,11 @@ class XmlBindingTraitParserGenerator( /** * Generate an XML parser for a given member */ - private fun RustWriter.parseMember(memberShape: MemberShape, ctx: Ctx, forceOptional: Boolean = false) { + private fun RustWriter.parseMember( + memberShape: MemberShape, + ctx: Ctx, + forceOptional: Boolean = false, + ) { val target = model.expectShape(memberShape.target) val symbol = symbolProvider.toSymbol(memberShape) conditionalBlock("Some(", ")", forceOptional || symbol.isOptional()) { @@ -364,17 +376,19 @@ class XmlBindingTraitParserGenerator( rustTemplate("#{try_data}(&mut ${ctx.tag})?.as_ref()", *codegenScope) } - is MapShape -> if (memberShape.isFlattened()) { - parseFlatMap(target, ctx) - } else { - parseMap(target, ctx) - } + is MapShape -> + if (memberShape.isFlattened()) { + parseFlatMap(target, ctx) + } else { + parseMap(target, ctx) + } - is CollectionShape -> if (memberShape.isFlattened()) { - parseFlatList(target, ctx) - } else { - parseList(target, ctx) - } + is CollectionShape -> + if (memberShape.isFlattened()) { + parseFlatList(target, ctx) + } else { + parseList(target, ctx) + } is StructureShape -> { parseStructure(target, ctx) @@ -389,7 +403,10 @@ class XmlBindingTraitParserGenerator( } } - private fun RustWriter.parseAttributeMember(memberShape: MemberShape, ctx: Ctx) { + private fun RustWriter.parseAttributeMember( + memberShape: MemberShape, + ctx: Ctx, + ) { rustBlock("") { rustTemplate( """ @@ -411,58 +428,66 @@ class XmlBindingTraitParserGenerator( } } - private fun RustWriter.parseUnion(shape: UnionShape, ctx: Ctx) { + private fun RustWriter.parseUnion( + shape: UnionShape, + ctx: Ctx, + ) { val symbol = symbolProvider.toSymbol(shape) - val nestedParser = protocolFunctions.deserializeFn(shape) { fnName -> - rustBlockTemplate( - "pub fn $fnName(decoder: &mut #{ScopedDecoder}) -> Result<#{Shape}, #{XmlDecodeError}>", - *codegenScope, "Shape" to symbol, - ) { - val members = shape.members() - rustTemplate("let mut base: Option<#{Shape}> = None;", *codegenScope, "Shape" to symbol) - parseLoop(Ctx(tag = "decoder", accum = null), ignoreUnexpected = false) { ctx -> - members.forEach { member -> - val variantName = symbolProvider.toMemberName(member) - case(member) { - if (member.isTargetUnit()) { - rust("base = Some(#T::$variantName);", symbol) - } else { - val current = - """ - (match base.take() { - None => None, - Some(${format(symbol)}::$variantName(inner)) => Some(inner), - Some(_) => return Err(#{XmlDecodeError}::custom("mixed variants")) - }) - """ - withBlock("let tmp =", ";") { - parseMember(member, ctx.copy(accum = current.trim())) + val nestedParser = + protocolFunctions.deserializeFn(shape) { fnName -> + rustBlockTemplate( + "pub fn $fnName(decoder: &mut #{ScopedDecoder}) -> Result<#{Shape}, #{XmlDecodeError}>", + *codegenScope, "Shape" to symbol, + ) { + val members = shape.members() + rustTemplate("let mut base: Option<#{Shape}> = None;", *codegenScope, "Shape" to symbol) + parseLoop(Ctx(tag = "decoder", accum = null), ignoreUnexpected = false) { ctx -> + members.forEach { member -> + val variantName = symbolProvider.toMemberName(member) + case(member) { + if (member.isTargetUnit()) { + rust("base = Some(#T::$variantName);", symbol) + } else { + val current = + """ + (match base.take() { + None => None, + Some(${format(symbol)}::$variantName(inner)) => Some(inner), + Some(_) => return Err(#{XmlDecodeError}::custom("mixed variants")) + }) + """ + withBlock("let tmp =", ";") { + parseMember(member, ctx.copy(accum = current.trim())) + } + rust("base = Some(#T::$variantName(tmp));", symbol) } - rust("base = Some(#T::$variantName(tmp));", symbol) } } + when (target.renderUnknownVariant()) { + true -> rust("_unknown => base = Some(#T::${UnionGenerator.UnknownVariantName}),", symbol) + false -> + rustTemplate( + """variant => return Err(#{XmlDecodeError}::custom(format!("unexpected union variant: {:?}", variant)))""", + *codegenScope, + ) + } } - when (target.renderUnknownVariant()) { - true -> rust("_unknown => base = Some(#T::${UnionGenerator.UnknownVariantName}),", symbol) - false -> rustTemplate( - """variant => return Err(#{XmlDecodeError}::custom(format!("unexpected union variant: {:?}", variant)))""", - *codegenScope, - ) - } + rustTemplate( + """base.ok_or_else(||#{XmlDecodeError}::custom("expected union, got nothing"))""", + *codegenScope, + ) } - rustTemplate( - """base.ok_or_else(||#{XmlDecodeError}::custom("expected union, got nothing"))""", - *codegenScope, - ) } - } rust("#T(&mut ${ctx.tag})", nestedParser) } /** * The match clause to check if the tag matches a given member */ - private fun RustWriter.case(member: MemberShape, inner: Writable) { + private fun RustWriter.case( + member: MemberShape, + inner: Writable, + ) { rustBlock( "s if ${ member.xmlName().matchExpression("s") @@ -473,61 +498,73 @@ class XmlBindingTraitParserGenerator( rust(",") } - private fun RustWriter.parseStructure(shape: StructureShape, ctx: Ctx) { + private fun RustWriter.parseStructure( + shape: StructureShape, + ctx: Ctx, + ) { val symbol = symbolProvider.toSymbol(shape) - val nestedParser = protocolFunctions.deserializeFn(shape) { fnName -> - Attribute.AllowNeedlessQuestionMark.render(this) - rustBlockTemplate( - "pub fn $fnName(decoder: &mut #{ScopedDecoder}) -> Result<#{Shape}, #{XmlDecodeError}>", - *codegenScope, "Shape" to symbol, - ) { - Attribute.AllowUnusedMut.render(this) - rustTemplate("let mut builder = #{Shape}::builder();", *codegenScope, "Shape" to symbol) - val members = shape.xmlMembers() - if (members.isNotEmpty()) { - parseStructureInner(members, "builder", Ctx(tag = "decoder", accum = null)) - } else { - rust("let _ = decoder;") - } - val builder = builderInstantiator.finalizeBuilder( - "builder", - shape, - mapErr = { - rustTemplate( - """|_|#{XmlDecodeError}::custom("missing field")""", - *codegenScope, + val nestedParser = + protocolFunctions.deserializeFn(shape) { fnName -> + Attribute.AllowNeedlessQuestionMark.render(this) + rustBlockTemplate( + "pub fn $fnName(decoder: &mut #{ScopedDecoder}) -> Result<#{Shape}, #{XmlDecodeError}>", + *codegenScope, "Shape" to symbol, + ) { + Attribute.AllowUnusedMut.render(this) + rustTemplate("let mut builder = #{Shape}::builder();", *codegenScope, "Shape" to symbol) + val members = shape.xmlMembers() + if (members.isNotEmpty()) { + parseStructureInner(members, "builder", Ctx(tag = "decoder", accum = null)) + } else { + rust("let _ = decoder;") + } + val builder = + builderInstantiator.finalizeBuilder( + "builder", + shape, + mapErr = { + rustTemplate( + """|_|#{XmlDecodeError}::custom("missing field")""", + *codegenScope, + ) + }, ) - }, - ) - rust("Ok(#T)", builder) + rust("Ok(#T)", builder) + } } - } rust("#T(&mut ${ctx.tag})", nestedParser) } - private fun RustWriter.parseList(target: CollectionShape, ctx: Ctx) { + private fun RustWriter.parseList( + target: CollectionShape, + ctx: Ctx, + ) { val member = target.member - val listParser = protocolFunctions.deserializeFn(target) { fnName -> - rustBlockTemplate( - "pub fn $fnName(decoder: &mut #{ScopedDecoder}) -> Result<#{List}, #{XmlDecodeError}>", - *codegenScope, - "List" to symbolProvider.toSymbol(target), - ) { - rust("let mut out = std::vec::Vec::new();") - parseLoop(Ctx(tag = "decoder", accum = null)) { ctx -> - case(member) { - withBlock("out.push(", ");") { - parseMember(member, ctx) + val listParser = + protocolFunctions.deserializeFn(target) { fnName -> + rustBlockTemplate( + "pub fn $fnName(decoder: &mut #{ScopedDecoder}) -> Result<#{List}, #{XmlDecodeError}>", + *codegenScope, + "List" to symbolProvider.toSymbol(target), + ) { + rust("let mut out = std::vec::Vec::new();") + parseLoop(Ctx(tag = "decoder", accum = null)) { ctx -> + case(member) { + withBlock("out.push(", ");") { + parseMember(member, ctx) + } } } + rust("Ok(out)") } - rust("Ok(out)") } - } rust("#T(&mut ${ctx.tag})", listParser) } - private fun RustWriter.parseFlatList(target: CollectionShape, ctx: Ctx) { + private fun RustWriter.parseFlatList( + target: CollectionShape, + ctx: Ctx, + ) { val list = safeName("list") withBlock("Result::<#T, #T>::Ok({", "})", symbolProvider.toSymbol(target), xmlDecodeError) { val accum = ctx.accum ?: throw CodegenException("Need accum to parse flat list") @@ -539,26 +576,33 @@ class XmlBindingTraitParserGenerator( } } - private fun RustWriter.parseMap(target: MapShape, ctx: Ctx) { - val mapParser = protocolFunctions.deserializeFn(target) { fnName -> - rustBlockTemplate( - "pub fn $fnName(decoder: &mut #{ScopedDecoder}) -> Result<#{Map}, #{XmlDecodeError}>", - *codegenScope, - "Map" to symbolProvider.toSymbol(target), - ) { - rust("let mut out = #T::new();", RuntimeType.HashMap) - parseLoop(Ctx(tag = "decoder", accum = null)) { ctx -> - rustBlock("s if ${XmlName("entry").matchExpression("s")} => ") { - rust("#T(&mut ${ctx.tag}, &mut out)?;", mapEntryParser(target, ctx)) + private fun RustWriter.parseMap( + target: MapShape, + ctx: Ctx, + ) { + val mapParser = + protocolFunctions.deserializeFn(target) { fnName -> + rustBlockTemplate( + "pub fn $fnName(decoder: &mut #{ScopedDecoder}) -> Result<#{Map}, #{XmlDecodeError}>", + *codegenScope, + "Map" to symbolProvider.toSymbol(target), + ) { + rust("let mut out = #T::new();", RuntimeType.HashMap) + parseLoop(Ctx(tag = "decoder", accum = null)) { ctx -> + rustBlock("s if ${XmlName("entry").matchExpression("s")} => ") { + rust("#T(&mut ${ctx.tag}, &mut out)?;", mapEntryParser(target, ctx)) + } } + rust("Ok(out)") } - rust("Ok(out)") } - } rust("#T(&mut ${ctx.tag})", mapParser) } - private fun RustWriter.parseFlatMap(target: MapShape, ctx: Ctx) { + private fun RustWriter.parseFlatMap( + target: MapShape, + ctx: Ctx, + ) { val map = safeName("map") val entryDecoder = mapEntryParser(target, ctx) withBlock("Result::<#T, #T>::Ok({", "})", symbolProvider.toSymbol(target), xmlDecodeError) { @@ -575,7 +619,10 @@ class XmlBindingTraitParserGenerator( } } - private fun mapEntryParser(target: MapShape, ctx: Ctx): RuntimeType { + private fun mapEntryParser( + target: MapShape, + ctx: Ctx, + ): RuntimeType { return protocolFunctions.deserializeFn(target, "entry") { fnName -> rustBlockTemplate( "pub fn $fnName(decoder: &mut #{ScopedDecoder}, out: &mut #{Map}) -> Result<(), #{XmlDecodeError}>", @@ -618,7 +665,10 @@ class XmlBindingTraitParserGenerator( * Parse a simple member from a data field * [provider] generates code for the inner data field */ - private fun RustWriter.parsePrimitiveInner(member: MemberShape, provider: Writable) { + private fun RustWriter.parsePrimitiveInner( + member: MemberShape, + provider: Writable, + ) { when (val shape = model.expectShape(member.target)) { is StringShape -> parseStringInner(shape, provider) is NumberShape, is BooleanShape -> { @@ -671,7 +721,10 @@ class XmlBindingTraitParserGenerator( } } - private fun RustWriter.parseStringInner(shape: StringShape, provider: Writable) { + private fun RustWriter.parseStringInner( + shape: StringShape, + provider: Writable, + ) { withBlock("Result::<#T, #T>::Ok(", ")", symbolProvider.toSymbol(shape), xmlDecodeError) { if (shape.hasTrait()) { val enumSymbol = symbolProvider.toSymbol(shape) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/EventStreamErrorMarshallerGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/EventStreamErrorMarshallerGenerator.kt index b9491f29e8c..97c8adb48a3 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/EventStreamErrorMarshallerGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/EventStreamErrorMarshallerGenerator.kt @@ -46,20 +46,22 @@ class EventStreamErrorMarshallerGenerator( private val smithyEventStream = RuntimeType.smithyEventStream(runtimeConfig) private val smithyTypes = RuntimeType.smithyTypes(runtimeConfig) - private val operationErrorSymbol = if (target == CodegenTarget.SERVER && unionShape.eventStreamErrors().isEmpty()) { - RuntimeType.smithyHttp(runtimeConfig).resolve("event_stream::MessageStreamError").toSymbol() - } else { - symbolProvider.symbolForEventStreamError(unionShape) - } + private val operationErrorSymbol = + if (target == CodegenTarget.SERVER && unionShape.eventStreamErrors().isEmpty()) { + RuntimeType.smithyHttp(runtimeConfig).resolve("event_stream::MessageStreamError").toSymbol() + } else { + symbolProvider.symbolForEventStreamError(unionShape) + } private val eventStreamSerdeModule = RustModule.eventStreamSerdeModule() private val errorsShape = unionShape.expectTrait() - private val codegenScope = arrayOf( - "MarshallMessage" to smithyEventStream.resolve("frame::MarshallMessage"), - "Message" to smithyTypes.resolve("event_stream::Message"), - "Header" to smithyTypes.resolve("event_stream::Header"), - "HeaderValue" to smithyTypes.resolve("event_stream::HeaderValue"), - "Error" to smithyEventStream.resolve("error::Error"), - ) + private val codegenScope = + arrayOf( + "MarshallMessage" to smithyEventStream.resolve("frame::MarshallMessage"), + "Message" to smithyTypes.resolve("event_stream::Message"), + "Header" to smithyTypes.resolve("event_stream::Header"), + "HeaderValue" to smithyTypes.resolve("event_stream::HeaderValue"), + "Error" to smithyEventStream.resolve("error::Error"), + ) override fun render(): RuntimeType { val marshallerType = unionShape.eventStreamMarshallerType() @@ -70,7 +72,10 @@ class EventStreamErrorMarshallerGenerator( } } - private fun RustWriter.renderMarshaller(marshallerType: RuntimeType, unionSymbol: Symbol) { + private fun RustWriter.renderMarshaller( + marshallerType: RuntimeType, + unionSymbol: Symbol, + ) { rust( """ ##[non_exhaustive] @@ -128,7 +133,10 @@ class EventStreamErrorMarshallerGenerator( } } - private fun RustWriter.renderMarshallEvent(unionMember: MemberShape, eventStruct: StructureShape) { + private fun RustWriter.renderMarshallEvent( + unionMember: MemberShape, + eventStruct: StructureShape, + ) { val headerMembers = eventStruct.members().filter { it.hasTrait() } val payloadMember = eventStruct.members().firstOrNull { it.hasTrait() } for (member in headerMembers) { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/EventStreamMarshallerGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/EventStreamMarshallerGenerator.kt index ac6cf88ccc2..84e31a6173c 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/EventStreamMarshallerGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/EventStreamMarshallerGenerator.kt @@ -56,13 +56,14 @@ open class EventStreamMarshallerGenerator( private val smithyEventStream = RuntimeType.smithyEventStream(runtimeConfig) private val smithyTypes = RuntimeType.smithyTypes(runtimeConfig) private val eventStreamSerdeModule = RustModule.eventStreamSerdeModule() - private val codegenScope = arrayOf( - "MarshallMessage" to smithyEventStream.resolve("frame::MarshallMessage"), - "Message" to smithyTypes.resolve("event_stream::Message"), - "Header" to smithyTypes.resolve("event_stream::Header"), - "HeaderValue" to smithyTypes.resolve("event_stream::HeaderValue"), - "Error" to smithyEventStream.resolve("error::Error"), - ) + private val codegenScope = + arrayOf( + "MarshallMessage" to smithyEventStream.resolve("frame::MarshallMessage"), + "Message" to smithyTypes.resolve("event_stream::Message"), + "Header" to smithyTypes.resolve("event_stream::Header"), + "HeaderValue" to smithyTypes.resolve("event_stream::HeaderValue"), + "Error" to smithyEventStream.resolve("error::Error"), + ) open fun render(): RuntimeType { val marshallerType = unionShape.eventStreamMarshallerType() @@ -73,7 +74,10 @@ open class EventStreamMarshallerGenerator( } } - private fun RustWriter.renderMarshaller(marshallerType: RuntimeType, unionSymbol: Symbol) { + private fun RustWriter.renderMarshaller( + marshallerType: RuntimeType, + unionSymbol: Symbol, + ) { rust( """ ##[non_exhaustive] @@ -125,7 +129,10 @@ open class EventStreamMarshallerGenerator( } } - private fun RustWriter.renderMarshallEvent(unionMember: MemberShape, eventStruct: StructureShape) { + private fun RustWriter.renderMarshallEvent( + unionMember: MemberShape, + eventStruct: StructureShape, + ) { val headerMembers = eventStruct.members().filter { it.hasTrait() } val payloadMember = eventStruct.members().firstOrNull { it.hasTrait() } for (member in headerMembers) { @@ -146,7 +153,11 @@ open class EventStreamMarshallerGenerator( } } - protected fun RustWriter.renderMarshallEventHeader(memberName: String, member: MemberShape, target: Shape) { + protected fun RustWriter.renderMarshallEventHeader( + memberName: String, + member: MemberShape, + target: Shape, + ) { val headerName = member.memberName handleOptional( symbolProvider.toSymbol(member).isOptional(), @@ -156,7 +167,11 @@ open class EventStreamMarshallerGenerator( ) } - private fun RustWriter.renderAddHeader(headerName: String, inputName: String, target: Shape) { + private fun RustWriter.renderAddHeader( + headerName: String, + inputName: String, + target: Shape, + ) { withBlock("headers.push(", ");") { rustTemplate( "#{Header}::new(${headerName.dq()}, #{HeaderValue}::${headerValue(inputName, target)})", @@ -167,17 +182,21 @@ open class EventStreamMarshallerGenerator( // Event stream header types: https://awslabs.github.io/smithy/1.0/spec/core/stream-traits.html#eventheader-trait // Note: there are no floating point header types for Event Stream. - private fun headerValue(inputName: String, target: Shape): String = when (target) { - is BooleanShape -> "Bool($inputName)" - is ByteShape -> "Byte($inputName)" - is ShortShape -> "Int16($inputName)" - is IntegerShape -> "Int32($inputName)" - is LongShape -> "Int64($inputName)" - is BlobShape -> "ByteArray($inputName.into_inner().into())" - is StringShape -> "String($inputName.into())" - is TimestampShape -> "Timestamp($inputName)" - else -> throw IllegalStateException("unsupported event stream header shape type: $target") - } + private fun headerValue( + inputName: String, + target: Shape, + ): String = + when (target) { + is BooleanShape -> "Bool($inputName)" + is ByteShape -> "Byte($inputName)" + is ShortShape -> "Int16($inputName)" + is IntegerShape -> "Int32($inputName)" + is LongShape -> "Int64($inputName)" + is BlobShape -> "ByteArray($inputName.into_inner().into())" + is StringShape -> "String($inputName.into())" + is TimestampShape -> "Timestamp($inputName)" + else -> throw IllegalStateException("unsupported event stream header shape type: $target") + } protected fun RustWriter.renderMarshallEventPayload( inputExpr: String, @@ -189,11 +208,12 @@ open class EventStreamMarshallerGenerator( if (target is BlobShape || target is StringShape) { data class PayloadContext(val conversionFn: String, val contentType: String) - val ctx = when (target) { - is BlobShape -> PayloadContext("into_inner", "application/octet-stream") - is StringShape -> PayloadContext("into_bytes", "text/plain") - else -> throw IllegalStateException("unreachable") - } + val ctx = + when (target) { + is BlobShape -> PayloadContext("into_inner", "application/octet-stream") + is StringShape -> PayloadContext("into_bytes", "text/plain") + else -> throw IllegalStateException("unreachable") + } addStringHeader(":content-type", "${ctx.contentType.dq()}.into()") handleOptional( optional, @@ -245,7 +265,10 @@ open class EventStreamMarshallerGenerator( } } - protected fun RustWriter.addStringHeader(name: String, valueExpr: String) { + protected fun RustWriter.addStringHeader( + name: String, + valueExpr: String, + ) { rustTemplate("headers.push(#{Header}::new(${name.dq()}, #{HeaderValue}::String($valueExpr)));", *codegenScope) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/JsonSerializerGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/JsonSerializerGenerator.kt index 981706b5665..0a95ab26524 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/JsonSerializerGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/JsonSerializerGenerator.kt @@ -110,7 +110,10 @@ class JsonSerializerGenerator( val writeNulls: Boolean = false, ) { companion object { - fun collectionMember(context: Context, itemName: String): MemberContext = + fun collectionMember( + context: Context, + itemName: String, + ): MemberContext = MemberContext( "${context.writerExpression}.value()", ValueExpression.Reference(itemName), @@ -118,7 +121,11 @@ class JsonSerializerGenerator( writeNulls = true, ) - fun mapMember(context: Context, key: String, value: String): MemberContext = + fun mapMember( + context: Context, + key: String, + value: String, + ): MemberContext = MemberContext( "${context.writerExpression}.key($key)", ValueExpression.Reference(value), @@ -151,8 +158,10 @@ class JsonSerializerGenerator( ) /** Returns an expression to get a JsonValueWriter from a JsonObjectWriter */ - private fun objectValueWriterExpression(objectWriterName: String, jsonName: String): String = - "$objectWriterName.key(${jsonName.dq()})" + private fun objectValueWriterExpression( + objectWriterName: String, + jsonName: String, + ): String = "$objectWriterName.key(${jsonName.dq()})" } } @@ -170,15 +179,16 @@ class JsonSerializerGenerator( private val codegenTarget = codegenContext.target private val runtimeConfig = codegenContext.runtimeConfig private val protocolFunctions = ProtocolFunctions(codegenContext) - private val codegenScope = arrayOf( - *preludeScope, - "Error" to runtimeConfig.serializationError(), - "SdkBody" to RuntimeType.sdkBody(runtimeConfig), - "JsonObjectWriter" to RuntimeType.smithyJson(runtimeConfig).resolve("serialize::JsonObjectWriter"), - "JsonValueWriter" to RuntimeType.smithyJson(runtimeConfig).resolve("serialize::JsonValueWriter"), - "ByteSlab" to RuntimeType.ByteSlab, - ) - private val serializerUtil = SerializerUtil(model) + private val codegenScope = + arrayOf( + *preludeScope, + "Error" to runtimeConfig.serializationError(), + "SdkBody" to RuntimeType.sdkBody(runtimeConfig), + "JsonObjectWriter" to RuntimeType.smithyJson(runtimeConfig).resolve("serialize::JsonObjectWriter"), + "JsonValueWriter" to RuntimeType.smithyJson(runtimeConfig).resolve("serialize::JsonValueWriter"), + "ByteSlab" to RuntimeType.ByteSlab, + ) + private val serializerUtil = SerializerUtil(model, symbolProvider) /** * Reusable structure serializer implementation that can be used to generate serializing code for @@ -191,10 +201,11 @@ class JsonSerializerGenerator( makeSection: (StructureShape, String) -> JsonSerializerSection, error: Boolean, ): RuntimeType { - val suffix = when (error) { - true -> "error" - else -> "output" - } + val suffix = + when (error) { + true -> "error" + else -> "output" + } return protocolFunctions.serializeFn(structureShape, fnNameSuffix = suffix) { fnName -> rustBlockTemplate( "pub fn $fnName(value: &#{target}) -> Result", @@ -323,29 +334,33 @@ class JsonSerializerGenerator( context: StructContext, includedMembers: List? = null, ) { - val structureSerializer = protocolFunctions.serializeFn(context.shape) { fnName -> - val inner = context.copy(objectName = "object", localName = "input") - val members = includedMembers ?: inner.shape.members() - val allowUnusedVariables = writable { - if (members.isEmpty()) { Attribute.AllowUnusedVariables.render(this) } - } - rustBlockTemplate( - """ - pub fn $fnName( - #{AllowUnusedVariables:W} object: &mut #{JsonObjectWriter}, - #{AllowUnusedVariables:W} input: &#{StructureSymbol}, - ) -> Result<(), #{Error}> - """, - "StructureSymbol" to symbolProvider.toSymbol(context.shape), - "AllowUnusedVariables" to allowUnusedVariables, - *codegenScope, - ) { - for (member in members) { - serializeMember(MemberContext.structMember(inner, member, symbolProvider, jsonName)) + val structureSerializer = + protocolFunctions.serializeFn(context.shape) { fnName -> + val inner = context.copy(objectName = "object", localName = "input") + val members = includedMembers ?: inner.shape.members() + val allowUnusedVariables = + writable { + if (members.isEmpty()) { + Attribute.AllowUnusedVariables.render(this) + } + } + rustBlockTemplate( + """ + pub fn $fnName( + #{AllowUnusedVariables:W} object: &mut #{JsonObjectWriter}, + #{AllowUnusedVariables:W} input: &#{StructureSymbol}, + ) -> Result<(), #{Error}> + """, + "StructureSymbol" to symbolProvider.toSymbol(context.shape), + "AllowUnusedVariables" to allowUnusedVariables, + *codegenScope, + ) { + for (member in members) { + serializeMember(MemberContext.structMember(inner, member, symbolProvider, jsonName)) + } + rust("Ok(())") } - rust("Ok(())") } - } rust("#T(&mut ${context.objectName}, ${context.localName})?;", structureSerializer) } @@ -379,14 +394,17 @@ class JsonSerializerGenerator( } with(serializerUtil) { - ignoreZeroValues(context.shape, context.valueExpression) { + ignoreDefaultsForNumbersAndBools(context.shape, context.valueExpression) { serializeMemberValue(context, targetShape) } } } } - private fun RustWriter.serializeMemberValue(context: MemberContext, target: Shape) { + private fun RustWriter.serializeMemberValue( + context: MemberContext, + target: Shape, + ) { val writer = context.writerExpression val value = context.valueExpression @@ -394,21 +412,23 @@ class JsonSerializerGenerator( is StringShape -> rust("$writer.string(${value.name}.as_str());") is BooleanShape -> rust("$writer.boolean(${value.asValue()});") is NumberShape -> { - val numberType = when (target) { - is IntegerShape, is ByteShape, is LongShape, is ShortShape -> "NegInt" - is DoubleShape, is FloatShape -> "Float" - else -> throw IllegalStateException("unreachable") - } + val numberType = + when (target) { + is IntegerShape, is ByteShape, is LongShape, is ShortShape -> "NegInt" + is DoubleShape, is FloatShape -> "Float" + else -> throw IllegalStateException("unreachable") + } rust( "$writer.number(##[allow(clippy::useless_conversion)]#T::$numberType((${value.asValue()}).into()));", RuntimeType.smithyTypes(runtimeConfig).resolve("Number"), ) } - is BlobShape -> rust( - "$writer.string_unchecked(&#T(${value.asRef()}));", - RuntimeType.base64Encode(runtimeConfig), - ) + is BlobShape -> + rust( + "$writer.string_unchecked(&#T(${value.asRef()}));", + RuntimeType.base64Encode(runtimeConfig), + ) is TimestampShape -> { val timestampFormat = @@ -420,28 +440,35 @@ class JsonSerializerGenerator( ) } - is CollectionShape -> jsonArrayWriter(context) { arrayName -> - serializeCollection(Context(arrayName, value, target)) - } + is CollectionShape -> + jsonArrayWriter(context) { arrayName -> + serializeCollection(Context(arrayName, value, target)) + } - is MapShape -> jsonObjectWriter(context) { objectName -> - serializeMap(Context(objectName, value, target)) - } + is MapShape -> + jsonObjectWriter(context) { objectName -> + serializeMap(Context(objectName, value, target)) + } - is StructureShape -> jsonObjectWriter(context) { objectName -> - serializeStructure(StructContext(objectName, value.asRef(), target)) - } + is StructureShape -> + jsonObjectWriter(context) { objectName -> + serializeStructure(StructContext(objectName, value.asRef(), target)) + } - is UnionShape -> jsonObjectWriter(context) { objectName -> - serializeUnion(Context(objectName, value, target)) - } + is UnionShape -> + jsonObjectWriter(context) { objectName -> + serializeUnion(Context(objectName, value, target)) + } is DocumentShape -> rust("$writer.document(${value.asRef()});") else -> TODO(target.toString()) } } - private fun RustWriter.jsonArrayWriter(context: MemberContext, inner: RustWriter.(String) -> Unit) { + private fun RustWriter.jsonArrayWriter( + context: MemberContext, + inner: RustWriter.(String) -> Unit, + ) { safeName("array").also { arrayName -> rust("let mut $arrayName = ${context.writerExpression}.start_array();") inner(arrayName) @@ -449,7 +476,10 @@ class JsonSerializerGenerator( } } - private fun RustWriter.jsonObjectWriter(context: MemberContext, inner: RustWriter.(String) -> Unit) { + private fun RustWriter.jsonObjectWriter( + context: MemberContext, + inner: RustWriter.(String) -> Unit, + ) { safeName("object").also { objectName -> rust("##[allow(unused_mut)]") rust("let mut $objectName = ${context.writerExpression}.start_object();") @@ -497,34 +527,36 @@ class JsonSerializerGenerator( private fun RustWriter.serializeUnion(context: Context) { val unionSymbol = symbolProvider.toSymbol(context.shape) - val unionSerializer = protocolFunctions.serializeFn(context.shape) { fnName -> - rustBlockTemplate( - "pub fn $fnName(${context.writerExpression}: &mut #{JsonObjectWriter}, input: &#{Input}) -> Result<(), #{Error}>", - "Input" to unionSymbol, - *codegenScope, - ) { - rustBlock("match input") { - for (member in context.shape.members()) { - val variantName = if (member.isTargetUnit()) { - "${symbolProvider.toMemberName(member)}" - } else { - "${symbolProvider.toMemberName(member)}(inner)" + val unionSerializer = + protocolFunctions.serializeFn(context.shape) { fnName -> + rustBlockTemplate( + "pub fn $fnName(${context.writerExpression}: &mut #{JsonObjectWriter}, input: &#{Input}) -> Result<(), #{Error}>", + "Input" to unionSymbol, + *codegenScope, + ) { + rustBlock("match input") { + for (member in context.shape.members()) { + val variantName = + if (member.isTargetUnit()) { + "${symbolProvider.toMemberName(member)}" + } else { + "${symbolProvider.toMemberName(member)}(inner)" + } + withBlock("#T::$variantName => {", "},", unionSymbol) { + serializeMember(MemberContext.unionMember(context, "inner", member, jsonName)) + } } - withBlock("#T::$variantName => {", "},", unionSymbol) { - serializeMember(MemberContext.unionMember(context, "inner", member, jsonName)) + if (codegenTarget.renderUnknownVariant()) { + rustTemplate( + "#{Union}::${UnionGenerator.UnknownVariantName} => return Err(#{Error}::unknown_variant(${unionSymbol.name.dq()}))", + "Union" to unionSymbol, + *codegenScope, + ) } } - if (codegenTarget.renderUnknownVariant()) { - rustTemplate( - "#{Union}::${UnionGenerator.UnknownVariantName} => return Err(#{Error}::unknown_variant(${unionSymbol.name.dq()}))", - "Union" to unionSymbol, - *codegenScope, - ) - } + rust("Ok(())") } - rust("Ok(())") } - } rust("#T(&mut ${context.writerExpression}, ${context.valueExpression.asRef()})?;", unionSerializer) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/QuerySerializerGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/QuerySerializerGenerator.kt index 23c8bbb4fb8..1686950a09a 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/QuerySerializerGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/QuerySerializerGenerator.kt @@ -5,7 +5,6 @@ package software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize -import software.amazon.smithy.model.knowledge.NullableIndex import software.amazon.smithy.model.shapes.BlobShape import software.amazon.smithy.model.shapes.BooleanShape import software.amazon.smithy.model.shapes.CollectionShape @@ -90,24 +89,26 @@ abstract class QuerySerializerGenerator(private val codegenContext: CodegenConte protected val model = codegenContext.model protected val symbolProvider = codegenContext.symbolProvider protected val runtimeConfig = codegenContext.runtimeConfig - private val nullableIndex = NullableIndex(model) private val target = codegenContext.target private val serviceShape = codegenContext.serviceShape private val serializerError = runtimeConfig.serializationError() private val smithyTypes = RuntimeType.smithyTypes(runtimeConfig) private val smithyQuery = RuntimeType.smithyQuery(runtimeConfig) - private val serdeUtil = SerializerUtil(model) + private val serdeUtil = SerializerUtil(model, symbolProvider) private val protocolFunctions = ProtocolFunctions(codegenContext) - private val codegenScope = arrayOf( - "String" to RuntimeType.String, - "Error" to serializerError, - "SdkBody" to RuntimeType.sdkBody(runtimeConfig), - "QueryWriter" to smithyQuery.resolve("QueryWriter"), - "QueryValueWriter" to smithyQuery.resolve("QueryValueWriter"), - ) + private val codegenScope = + arrayOf( + "String" to RuntimeType.String, + "Error" to serializerError, + "SdkBody" to RuntimeType.sdkBody(runtimeConfig), + "QueryWriter" to smithyQuery.resolve("QueryWriter"), + "QueryValueWriter" to smithyQuery.resolve("QueryValueWriter"), + ) abstract val protocolName: String + abstract fun MemberShape.queryKeyName(prioritizedFallback: String? = null): String + abstract fun MemberShape.isFlattened(): Boolean override fun documentSerializer(): RuntimeType { @@ -171,17 +172,18 @@ abstract class QuerySerializerGenerator(private val codegenContext: CodegenConte return } val structureSymbol = symbolProvider.toSymbol(context.shape) - val structureSerializer = protocolFunctions.serializeFn(context.shape) { fnName -> - Attribute.AllowUnusedMut.render(this) - rustBlockTemplate( - "pub fn $fnName(mut writer: #{QueryValueWriter}, input: &#{Input}) -> Result<(), #{Error}>", - "Input" to structureSymbol, - *codegenScope, - ) { - serializeStructureInner(context) - rust("Ok(())") + val structureSerializer = + protocolFunctions.serializeFn(context.shape) { fnName -> + Attribute.AllowUnusedMut.render(this) + rustBlockTemplate( + "pub fn $fnName(mut writer: #{QueryValueWriter}, input: &#{Input}) -> Result<(), #{Error}>", + "Input" to structureSymbol, + *codegenScope, + ) { + serializeStructureInner(context) + rust("Ok(())") + } } - } rust("#T(${context.writerExpression}, ${context.valueExpression.asRef()})?;", structureSerializer) } @@ -209,14 +211,17 @@ abstract class QuerySerializerGenerator(private val codegenContext: CodegenConte } } else { with(serdeUtil) { - ignoreZeroValues(context.shape, context.valueExpression) { + ignoreDefaultsForNumbersAndBools(context.shape, context.valueExpression) { serializeMemberValue(context, targetShape) } } } } - private fun RustWriter.serializeMemberValue(context: MemberContext, target: Shape) { + private fun RustWriter.serializeMemberValue( + context: MemberContext, + target: Shape, + ) { val writer = context.writerExpression val value = context.valueExpression when (target) { @@ -228,21 +233,23 @@ abstract class QuerySerializerGenerator(private val codegenContext: CodegenConte } is BooleanShape -> rust("$writer.boolean(${value.asValue()});") is NumberShape -> { - val numberType = when (symbolProvider.toSymbol(target).rustType()) { - is RustType.Float -> "Float" - // NegInt takes an i64 while PosInt takes u64. We need this to be signed here - is RustType.Integer -> "NegInt" - else -> throw IllegalStateException("unreachable") - } + val numberType = + when (symbolProvider.toSymbol(target).rustType()) { + is RustType.Float -> "Float" + // NegInt takes an i64 while PosInt takes u64. We need this to be signed here + is RustType.Integer -> "NegInt" + else -> throw IllegalStateException("unreachable") + } rust( "$writer.number(##[allow(clippy::useless_conversion)]#T::$numberType((${value.asValue()}).into()));", smithyTypes.resolve("Number"), ) } - is BlobShape -> rust( - "$writer.string(&#T(${value.asRef()}));", - RuntimeType.base64Encode(runtimeConfig), - ) + is BlobShape -> + rust( + "$writer.string(&#T(${value.asRef()}));", + RuntimeType.base64Encode(runtimeConfig), + ) is TimestampShape -> { val timestampFormat = determineTimestampFormat(context.shape) val timestampFormatType = RuntimeType.serializeTimestampFormat(runtimeConfig, timestampFormat) @@ -251,9 +258,10 @@ abstract class QuerySerializerGenerator(private val codegenContext: CodegenConte is CollectionShape -> serializeCollection(context, Context(writer, context.valueExpression, target)) is MapShape -> serializeMap(context, Context(writer, context.valueExpression, target)) is StructureShape -> serializeStructure(Context(writer, context.valueExpression, target)) - is UnionShape -> structWriter(context) { writerExpression -> - serializeUnion(Context(writerExpression, context.valueExpression, target)) - } + is UnionShape -> + structWriter(context) { writerExpression -> + serializeUnion(Context(writerExpression, context.valueExpression, target)) + } else -> TODO(target.toString()) } } @@ -262,7 +270,10 @@ abstract class QuerySerializerGenerator(private val codegenContext: CodegenConte shape.getMemberTrait(model, TimestampFormatTrait::class.java).orNull()?.format ?: TimestampFormatTrait.Format.DATE_TIME - private fun RustWriter.structWriter(context: MemberContext, inner: RustWriter.(String) -> Unit) { + private fun RustWriter.structWriter( + context: MemberContext, + inner: RustWriter.(String) -> Unit, + ) { val prefix = context.shape.queryKeyName() safeName("scope").also { scopeName -> Attribute.AllowUnusedMut.render(this) @@ -271,12 +282,16 @@ abstract class QuerySerializerGenerator(private val codegenContext: CodegenConte } } - private fun RustWriter.serializeCollection(memberContext: MemberContext, context: Context) { + private fun RustWriter.serializeCollection( + memberContext: MemberContext, + context: Context, + ) { val flat = memberContext.shape.isFlattened() - val memberOverride = when (val override = context.shape.member.getTrait()?.value) { - null -> "None" - else -> "Some(${override.dq()})" - } + val memberOverride = + when (val override = context.shape.member.getTrait()?.value) { + null -> "None" + else -> "Some(${override.dq()})" + } val itemName = safeName("item") safeName("list").also { listName -> rust("let mut $listName = ${context.writerExpression}.start_list($flat, $memberOverride);") @@ -294,7 +309,10 @@ abstract class QuerySerializerGenerator(private val codegenContext: CodegenConte } } - private fun RustWriter.serializeMap(memberContext: MemberContext, context: Context) { + private fun RustWriter.serializeMap( + memberContext: MemberContext, + context: Context, + ) { val flat = memberContext.shape.isFlattened() val entryKeyName = context.shape.key.queryKeyName("key").dq() val entryValueName = context.shape.value.queryKeyName("value").dq() @@ -304,10 +322,11 @@ abstract class QuerySerializerGenerator(private val codegenContext: CodegenConte rust("let mut $mapName = ${context.writerExpression}.start_map($flat, $entryKeyName, $entryValueName);") rustBlock("for ($keyName, $valueName) in ${context.valueExpression.asRef()}") { val keyTarget = model.expectShape(context.shape.key.target) - val keyExpression = when (keyTarget.hasTrait()) { - true -> "$keyName.as_str()" - else -> keyName - } + val keyExpression = + when (keyTarget.hasTrait()) { + true -> "$keyName.as_str()" + else -> keyName + } val entryName = safeName("entry") Attribute.AllowUnusedMut.render(this) rust("let mut $entryName = $mapName.entry($keyExpression);") @@ -319,41 +338,43 @@ abstract class QuerySerializerGenerator(private val codegenContext: CodegenConte private fun RustWriter.serializeUnion(context: Context) { val unionSymbol = symbolProvider.toSymbol(context.shape) - val unionSerializer = protocolFunctions.serializeFn(context.shape) { fnName -> - Attribute.AllowUnusedMut.render(this) - rustBlockTemplate( - "pub fn $fnName(mut writer: #{QueryValueWriter}, input: &#{Input}) -> Result<(), #{Error}>", - "Input" to unionSymbol, - *codegenScope, - ) { - rustBlock("match input") { - for (member in context.shape.members()) { - val variantName = if (member.isTargetUnit()) { - "${symbolProvider.toMemberName(member)}" - } else { - "${symbolProvider.toMemberName(member)}(inner)" + val unionSerializer = + protocolFunctions.serializeFn(context.shape) { fnName -> + Attribute.AllowUnusedMut.render(this) + rustBlockTemplate( + "pub fn $fnName(mut writer: #{QueryValueWriter}, input: &#{Input}) -> Result<(), #{Error}>", + "Input" to unionSymbol, + *codegenScope, + ) { + rustBlock("match input") { + for (member in context.shape.members()) { + val variantName = + if (member.isTargetUnit()) { + "${symbolProvider.toMemberName(member)}" + } else { + "${symbolProvider.toMemberName(member)}(inner)" + } + withBlock("#T::$variantName => {", "},", unionSymbol) { + serializeMember( + MemberContext.unionMember( + context.copy(writerExpression = "writer"), + "inner", + member, + ), + ) + } } - withBlock("#T::$variantName => {", "},", unionSymbol) { - serializeMember( - MemberContext.unionMember( - context.copy(writerExpression = "writer"), - "inner", - member, - ), + if (target.renderUnknownVariant()) { + rustTemplate( + "#{Union}::${UnionGenerator.UnknownVariantName} => return Err(#{Error}::unknown_variant(${unionSymbol.name.dq()}))", + "Union" to unionSymbol, + *codegenScope, ) } } - if (target.renderUnknownVariant()) { - rustTemplate( - "#{Union}::${UnionGenerator.UnknownVariantName} => return Err(#{Error}::unknown_variant(${unionSymbol.name.dq()}))", - "Union" to unionSymbol, - *codegenScope, - ) - } + rust("Ok(())") } - rust("Ok(())") } - } rust("#T(${context.writerExpression}, ${context.valueExpression.asRef()})?;", unionSerializer) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/SerializerUtil.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/SerializerUtil.kt index 27293e43039..55b65063b56 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/SerializerUtil.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/SerializerUtil.kt @@ -5,27 +5,42 @@ package software.amazon.smithy.rust.codegen.core.smithy.protocols.serialize +import software.amazon.smithy.codegen.core.SymbolProvider import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.StructureShape +import software.amazon.smithy.model.traits.ClientOptionalTrait +import software.amazon.smithy.model.traits.InputTrait import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.rustBlock +import software.amazon.smithy.rust.codegen.core.util.hasTrait -class SerializerUtil(private val model: Model) { - fun RustWriter.ignoreZeroValues(shape: MemberShape, value: ValueExpression, inner: Writable) { - // Required shapes should always be serialized +class SerializerUtil(private val model: Model, private val symbolProvider: SymbolProvider) { + fun RustWriter.ignoreDefaultsForNumbersAndBools( + shape: MemberShape, + value: ValueExpression, + inner: Writable, + ) { + // @required shapes should always be serialized, and members with @clientOptional or part of @input structures + // should ignore default values. If we have an Option, it won't have a default anyway, so we don't need to + // ignore it. // See https://github.com/smithy-lang/smithy-rs/issues/230 and https://github.com/aws/aws-sdk-go-v2/pull/1129 + val container = model.expectShape(shape.container) if ( shape.isRequired || + shape.hasTrait() || // Zero values are always serialized in lists and collections, this only applies to structures - model.expectShape(shape.container) !is StructureShape + container !is StructureShape || + container.hasTrait() ) { rustBlock("") { inner(this) } } else { - this.ifNotDefault(model.expectShape(shape.target), value) { inner(this) } + this.ifNotNumberOrBoolDefault(model.expectShape(shape.target), symbolProvider.toSymbol(shape), value) { + inner(this) + } } } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/ValueExpression.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/ValueExpression.kt index 00bc8ba74c7..fe21e20b081 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/ValueExpression.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/ValueExpression.kt @@ -11,17 +11,20 @@ sealed class ValueExpression { abstract val name: String data class Reference(override val name: String) : ValueExpression() + data class Value(override val name: String) : ValueExpression() - fun asValue(): String = when (this) { - is Reference -> autoDeref(name) - is Value -> name - } + fun asValue(): String = + when (this) { + is Reference -> autoDeref(name) + is Value -> name + } - fun asRef(): String = when (this) { - is Reference -> name - is Value -> "&$name" - } + fun asRef(): String = + when (this) { + is Reference -> name + is Value -> "&$name" + } override fun toString(): String = this.name } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/XmlBindingTraitSerializerGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/XmlBindingTraitSerializerGenerator.kt index fc4f0198387..ebb5f6aa678 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/XmlBindingTraitSerializerGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/XmlBindingTraitSerializerGenerator.kt @@ -73,7 +73,7 @@ class XmlBindingTraitSerializerGenerator( private val xmlIndex = XmlNameIndex.of(model) private val rootNamespace = codegenContext.serviceShape.getTrait() - private val util = SerializerUtil(model) + private val util = SerializerUtil(model, symbolProvider) sealed class Ctx { abstract val input: String @@ -85,11 +85,15 @@ class XmlBindingTraitSerializerGenerator( companion object { // Kotlin doesn't have a "This" type @Suppress("UNCHECKED_CAST") - fun updateInput(input: T, newInput: String): T = when (input) { - is Element -> input.copy(input = newInput) as T - is Scope -> input.copy(input = newInput) as T - else -> TODO() - } + fun updateInput( + input: T, + newInput: String, + ): T = + when (input) { + is Element -> input.copy(input = newInput) as T + is Scope -> input.copy(input = newInput) as T + else -> TODO() + } } } @@ -105,8 +109,9 @@ class XmlBindingTraitSerializerGenerator( if (xmlMembers.isEmpty()) { return null } - val operationXmlName = xmlIndex.operationInputShapeName(operationShape) - ?: throw CodegenException("operation must have a name if it has members") + val operationXmlName = + xmlIndex.operationInputShapeName(operationShape) + ?: throw CodegenException("operation must have a name if it has members") return protocolFunctions.serializeFn(operationShape, fnNameSuffix = "op_input") { fnName -> rustBlockTemplate( "pub fn $fnName(input: &#{target}) -> Result<#{SdkBody}, #{Error}>", @@ -162,11 +167,12 @@ class XmlBindingTraitSerializerGenerator( *codegenScope, ) when (target) { - is StructureShape -> serializeStructure( - target, - XmlMemberIndex.fromMembers(target.members().toList()), - Ctx.Element("root", "input"), - ) + is StructureShape -> + serializeStructure( + target, + XmlMemberIndex.fromMembers(target.members().toList()), + Ctx.Element("root", "input"), + ) is UnionShape -> serializeUnion(target, Ctx.Element("root", "input")) else -> throw IllegalStateException("xml payloadSerializer only supports structs and unions") @@ -204,8 +210,9 @@ class XmlBindingTraitSerializerGenerator( if (xmlMembers.isEmpty()) { return null } - val operationXmlName = xmlIndex.operationOutputShapeName(operationShape) - ?: throw CodegenException("operation must have a name if it has members") + val operationXmlName = + xmlIndex.operationOutputShapeName(operationShape) + ?: throw CodegenException("operation must have a name if it has members") return protocolFunctions.serializeFn(operationShape, fnNameSuffix = "output") { fnName -> rustBlockTemplate( "pub fn $fnName(output: &#{target}) -> Result", @@ -235,9 +242,10 @@ class XmlBindingTraitSerializerGenerator( override fun serverErrorSerializer(shape: ShapeId): RuntimeType { val errorShape = model.expectShape(shape, StructureShape::class.java) - val xmlMembers = httpBindingResolver.errorResponseBindings(shape) - .filter { it.location == HttpLocation.DOCUMENT } - .map { it.member } + val xmlMembers = + httpBindingResolver.errorResponseBindings(shape) + .filter { it.location == HttpLocation.DOCUMENT } + .map { it.member } return protocolFunctions.serializeFn(errorShape, fnNameSuffix = "error") { fnName -> rustBlockTemplate( "pub fn $fnName(error: &#{target}) -> Result", @@ -273,7 +281,10 @@ class XmlBindingTraitSerializerGenerator( return ".write_ns(${uri.dq()}, $prefix)" } - private fun RustWriter.structureInner(members: XmlMemberIndex, ctx: Ctx.Element) { + private fun RustWriter.structureInner( + members: XmlMemberIndex, + ctx: Ctx.Element, + ) { if (members.attributeMembers.isNotEmpty()) { rust("let mut ${ctx.elementWriter} = ${ctx.elementWriter};") } @@ -293,16 +304,20 @@ class XmlBindingTraitSerializerGenerator( rust("scope.finish();") } - private fun RustWriter.serializeRawMember(member: MemberShape, input: String) { + private fun RustWriter.serializeRawMember( + member: MemberShape, + input: String, + ) { when (model.expectShape(member.target)) { is StringShape -> { // The `input` expression always evaluates to a reference type at this point, but if it does so because // it's preceded by the `&` operator, calling `as_str()` on it will upset Clippy. - val dereferenced = if (input.startsWith("&")) { - autoDeref(input) - } else { - input - } + val dereferenced = + if (input.startsWith("&")) { + autoDeref(input) + } else { + input + } rust("$dereferenced.as_str()") } @@ -330,7 +345,11 @@ class XmlBindingTraitSerializerGenerator( } @Suppress("NAME_SHADOWING") - private fun RustWriter.serializeMember(memberShape: MemberShape, ctx: Ctx.Scope, rootNameOverride: String? = null) { + private fun RustWriter.serializeMember( + memberShape: MemberShape, + ctx: Ctx.Scope, + rootNameOverride: String? = null, + ) { val target = model.expectShape(memberShape.target) val xmlName = rootNameOverride ?: xmlIndex.memberName(memberShape) val ns = memberShape.xmlNamespace(root = false).apply() @@ -343,19 +362,21 @@ class XmlBindingTraitSerializerGenerator( } } - is CollectionShape -> if (memberShape.hasTrait()) { - serializeFlatList(memberShape, target, ctx) - } else { - rust("let mut inner_writer = ${ctx.scopeWriter}.start_el(${xmlName.dq()})$ns.finish();") - serializeList(target, Ctx.Scope("inner_writer", ctx.input)) - } + is CollectionShape -> + if (memberShape.hasTrait()) { + serializeFlatList(memberShape, target, ctx) + } else { + rust("let mut inner_writer = ${ctx.scopeWriter}.start_el(${xmlName.dq()})$ns.finish();") + serializeList(target, Ctx.Scope("inner_writer", ctx.input)) + } - is MapShape -> if (memberShape.hasTrait()) { - serializeMap(target, xmlIndex.memberName(memberShape), ctx) - } else { - rust("let mut inner_writer = ${ctx.scopeWriter}.start_el(${xmlName.dq()})$ns.finish();") - serializeMap(target, "entry", Ctx.Scope("inner_writer", ctx.input)) - } + is MapShape -> + if (memberShape.hasTrait()) { + serializeMap(target, xmlIndex.memberName(memberShape), ctx) + } else { + rust("let mut inner_writer = ${ctx.scopeWriter}.start_el(${xmlName.dq()})$ns.finish();") + serializeMap(target, "entry", Ctx.Scope("inner_writer", ctx.input)) + } is StructureShape -> { // We call serializeStructure only when target.members() is nonempty. @@ -401,74 +422,91 @@ class XmlBindingTraitSerializerGenerator( fnNameSuffix: String? = null, ) { val structureSymbol = symbolProvider.toSymbol(structureShape) - val structureSerializer = protocolFunctions.serializeFn(structureShape, fnNameSuffix = fnNameSuffix) { fnName -> - rustBlockTemplate( - "pub fn $fnName(input: &#{Input}, writer: #{ElementWriter}) -> Result<(), #{Error}>", - "Input" to structureSymbol, - *codegenScope, - ) { - if (!members.isNotEmpty()) { - // removed unused warning if there are no fields we're going to read - rust("let _ = input;") + val structureSerializer = + protocolFunctions.serializeFn(structureShape, fnNameSuffix = fnNameSuffix) { fnName -> + rustBlockTemplate( + "pub fn $fnName(input: &#{Input}, writer: #{ElementWriter}) -> Result<(), #{Error}>", + "Input" to structureSymbol, + *codegenScope, + ) { + if (!members.isNotEmpty()) { + // removed unused warning if there are no fields we're going to read + rust("let _ = input;") + } + structureInner(members, Ctx.Element("writer", "&input")) + rust("Ok(())") } - structureInner(members, Ctx.Element("writer", "&input")) - rust("Ok(())") } - } rust("#T(${ctx.input}, ${ctx.elementWriter})?", structureSerializer) } - private fun RustWriter.serializeUnion(unionShape: UnionShape, ctx: Ctx.Element) { + private fun RustWriter.serializeUnion( + unionShape: UnionShape, + ctx: Ctx.Element, + ) { val unionSymbol = symbolProvider.toSymbol(unionShape) - val structureSerializer = protocolFunctions.serializeFn(unionShape) { fnName -> - rustBlockTemplate( - "pub fn $fnName(input: &#{Input}, writer: #{ElementWriter}) -> Result<(), #{Error}>", - "Input" to unionSymbol, - *codegenScope, - ) { - rust("let mut scope_writer = writer.finish();") - rustBlock("match input") { - val members = unionShape.members() - members.forEach { member -> - val variantName = if (member.isTargetUnit()) { - "${symbolProvider.toMemberName(member)}" - } else { - "${symbolProvider.toMemberName(member)}(inner)" - } - withBlock("#T::$variantName =>", ",", unionSymbol) { - serializeMember(member, Ctx.Scope("scope_writer", "inner")) + val structureSerializer = + protocolFunctions.serializeFn(unionShape) { fnName -> + rustBlockTemplate( + "pub fn $fnName(input: &#{Input}, writer: #{ElementWriter}) -> Result<(), #{Error}>", + "Input" to unionSymbol, + *codegenScope, + ) { + rust("let mut scope_writer = writer.finish();") + rustBlock("match input") { + val members = unionShape.members() + members.forEach { member -> + val variantName = + if (member.isTargetUnit()) { + "${symbolProvider.toMemberName(member)}" + } else { + "${symbolProvider.toMemberName(member)}(inner)" + } + withBlock("#T::$variantName =>", ",", unionSymbol) { + serializeMember(member, Ctx.Scope("scope_writer", "inner")) + } } - } - if (codegenTarget.renderUnknownVariant()) { - rustTemplate( - "#{Union}::${UnionGenerator.UnknownVariantName} => return Err(#{Error}::unknown_variant(${unionSymbol.name.dq()}))", - "Union" to unionSymbol, - *codegenScope, - ) + if (codegenTarget.renderUnknownVariant()) { + rustTemplate( + "#{Union}::${UnionGenerator.UnknownVariantName} => return Err(#{Error}::unknown_variant(${unionSymbol.name.dq()}))", + "Union" to unionSymbol, + *codegenScope, + ) + } } + rust("Ok(())") } - rust("Ok(())") } - } rust("#T(${ctx.input}, ${ctx.elementWriter})?", structureSerializer) } - private fun RustWriter.serializeList(listShape: CollectionShape, ctx: Ctx.Scope) { + private fun RustWriter.serializeList( + listShape: CollectionShape, + ctx: Ctx.Scope, + ) { val itemName = safeName("list_item") rustBlock("for $itemName in ${ctx.input}") { serializeMember(listShape.member, ctx.copy(input = itemName)) } } - private fun RustWriter.serializeFlatList(member: MemberShape, listShape: CollectionShape, ctx: Ctx.Scope) { + private fun RustWriter.serializeFlatList( + member: MemberShape, + listShape: CollectionShape, + ctx: Ctx.Scope, + ) { val itemName = safeName("list_item") rustBlock("for $itemName in ${ctx.input}") { serializeMember(listShape.member, ctx.copy(input = itemName), xmlIndex.memberName(member)) } } - private fun RustWriter.serializeMap(mapShape: MapShape, entryName: String, ctx: Ctx.Scope) { + private fun RustWriter.serializeMap( + mapShape: MapShape, + entryName: String, + ctx: Ctx.Scope, + ) { val key = safeName("key") val value = safeName("value") rustBlock("for ($key, $value) in ${ctx.input}") { @@ -501,29 +539,31 @@ class XmlBindingTraitSerializerGenerator( if (memberSymbol.isOptional()) { val tmp = safeName() val target = model.expectShape(member.target) - val pattern = if (target.isStructureShape && target.members().isEmpty()) { - // In this case, we mark a variable captured in the if-let - // expression as unused to prevent the warning coming - // from the following code generated by handleOptional: - // if let Some(var_2) = &input.input { - // scope.start_el("input").finish(); - // } - // where var_2 above is unused. - "Some(_$tmp)" - } else { - "Some($tmp)" - } + val pattern = + if (target.isStructureShape && target.members().isEmpty()) { + // In this case, we mark a variable captured in the if-let + // expression as unused to prevent the warning coming + // from the following code generated by handleOptional: + // if let Some(var_2) = &input.input { + // scope.start_el("input").finish(); + // } + // where var_2 above is unused. + "Some(_$tmp)" + } else { + "Some($tmp)" + } rustBlock("if let $pattern = ${ctx.input}") { inner(Ctx.updateInput(ctx, tmp)) } } else { with(util) { - val valueExpression = if (ctx.input.startsWith("&")) { - ValueExpression.Reference(ctx.input) - } else { - ValueExpression.Value(ctx.input) - } - ignoreZeroValues(member, valueExpression) { + val valueExpression = + if (ctx.input.startsWith("&")) { + ValueExpression.Reference(ctx.input) + } else { + ValueExpression.Value(ctx.input) + } + ignoreDefaultsForNumbersAndBools(member, valueExpression) { inner(ctx) } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/traits/RustBoxTrait.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/traits/RustBoxTrait.kt index 41144d5945c..86e341062cf 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/traits/RustBoxTrait.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/traits/RustBoxTrait.kt @@ -19,6 +19,7 @@ import software.amazon.smithy.model.traits.Trait */ class RustBoxTrait : Trait { val ID = ShapeId.from("software.amazon.smithy.rust.codegen.smithy.rust.synthetic#box") + override fun toNode(): Node = Node.objectNode() override fun toShapeId(): ShapeId = ID diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/traits/SyntheticOutputTrait.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/traits/SyntheticOutputTrait.kt index ba086f9cb6a..d34ca0e39da 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/traits/SyntheticOutputTrait.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/traits/SyntheticOutputTrait.kt @@ -17,7 +17,7 @@ import software.amazon.smithy.model.traits.AnnotationTrait */ class SyntheticOutputTrait constructor(val operation: ShapeId, val originalId: ShapeId?) : AnnotationTrait(ID, Node.objectNode()) { - companion object { - val ID: ShapeId = ShapeId.from("smithy.api.internal#syntheticOutput") + companion object { + val ID: ShapeId = ShapeId.from("smithy.api.internal#syntheticOutput") + } } -} diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/EventStreamNormalizer.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/EventStreamNormalizer.kt index e46323ce19c..236ce443383 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/EventStreamNormalizer.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/EventStreamNormalizer.kt @@ -28,17 +28,21 @@ import software.amazon.smithy.rust.codegen.core.util.outputShape * place that does codegen with the unions. */ object EventStreamNormalizer { - fun transform(model: Model): Model = ModelTransformer.create().mapShapes(model) { shape -> - if (shape is OperationShape && shape.isEventStream(model)) { - addStreamErrorsToOperationErrors(model, shape) - } else if (shape is UnionShape && shape.isEventStream()) { - syntheticEquivalentEventStreamUnion(model, shape) - } else { - shape + fun transform(model: Model): Model = + ModelTransformer.create().mapShapes(model) { shape -> + if (shape is OperationShape && shape.isEventStream(model)) { + addStreamErrorsToOperationErrors(model, shape) + } else if (shape is UnionShape && shape.isEventStream()) { + syntheticEquivalentEventStreamUnion(model, shape) + } else { + shape + } } - } - private fun addStreamErrorsToOperationErrors(model: Model, operation: OperationShape): OperationShape { + private fun addStreamErrorsToOperationErrors( + model: Model, + operation: OperationShape, + ): OperationShape { if (!operation.isEventStream(model)) { return operation } @@ -57,10 +61,14 @@ object EventStreamNormalizer { .build() } - private fun syntheticEquivalentEventStreamUnion(model: Model, union: UnionShape): UnionShape { - val (errorMembers, eventMembers) = union.members().partition { member -> - model.expectShape(member.target).hasTrait() - } + private fun syntheticEquivalentEventStreamUnion( + model: Model, + union: UnionShape, + ): UnionShape { + val (errorMembers, eventMembers) = + union.members().partition { member -> + model.expectShape(member.target).hasTrait() + } return union.toBuilder() .members(eventMembers) .addTrait(SyntheticEventStreamUnionTrait(errorMembers)) @@ -73,7 +81,10 @@ fun OperationShape.operationErrors(model: Model): List { return operationIndex.getErrors(this) } -fun eventStreamErrors(model: Model, shape: Shape): Map> { +fun eventStreamErrors( + model: Model, + shape: Shape, +): Map> { return DirectedWalker(model) .walkShapes(shape) .filter { it is UnionShape && it.isEventStream() } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/OperationNormalizer.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/OperationNormalizer.kt index 241e0d44d14..4092174b55e 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/OperationNormalizer.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/OperationNormalizer.kt @@ -54,10 +54,11 @@ object OperationNormalizer { fun transform(model: Model): Model { val transformer = ModelTransformer.create() val operations = model.shapes(OperationShape::class.java).toList() - val newShapes = operations.flatMap { operation -> - // Generate or modify the input and output of the given `Operation` to be a unique shape - listOf(syntheticInputShape(model, operation), syntheticOutputShape(model, operation)) - } + val newShapes = + operations.flatMap { operation -> + // Generate or modify the input and output of the given `Operation` to be a unique shape + listOf(syntheticInputShape(model, operation), syntheticOutputShape(model, operation)) + } val shapeConflict = newShapes.firstOrNull { shape -> model.getShape(shape.id).isPresent } check( shapeConflict == null, @@ -67,13 +68,14 @@ object OperationNormalizer { val modelWithOperationInputs = model.toBuilder().addShapes(newShapes).build() return transformer.mapShapes(modelWithOperationInputs) { // Update all operations to point to their new input/output shapes - val transformed: Optional = it.asOperationShape().map { operation -> - modelWithOperationInputs.expectShape(operation.syntheticInputId()) - operation.toBuilder() - .input(operation.syntheticInputId()) - .output(operation.syntheticOutputId()) - .build() - } + val transformed: Optional = + it.asOperationShape().map { operation -> + modelWithOperationInputs.expectShape(operation.syntheticInputId()) + operation.toBuilder() + .input(operation.syntheticInputId()) + .output(operation.syntheticOutputId()) + .build() + } transformed.orElse(it) } } @@ -84,11 +86,15 @@ object OperationNormalizer { * * If the operation does not have an output, an empty shape is generated */ - private fun syntheticOutputShape(model: Model, operation: OperationShape): StructureShape { + private fun syntheticOutputShape( + model: Model, + operation: OperationShape, + ): StructureShape { val outputId = operation.syntheticOutputId() - val outputShapeBuilder = operation.output.map { shapeId -> - model.expectShape(shapeId, StructureShape::class.java).toBuilder().rename(outputId) - }.orElse(empty(outputId)) + val outputShapeBuilder = + operation.output.map { shapeId -> + model.expectShape(shapeId, StructureShape::class.java).toBuilder().rename(outputId) + }.orElse(empty(outputId)) return outputShapeBuilder.addTrait( SyntheticOutputTrait( operation = operation.id, @@ -103,11 +109,15 @@ object OperationNormalizer { * * If the input operation does not have an input, an empty shape is generated */ - private fun syntheticInputShape(model: Model, operation: OperationShape): StructureShape { + private fun syntheticInputShape( + model: Model, + operation: OperationShape, + ): StructureShape { val inputId = operation.syntheticInputId() - val inputShapeBuilder = operation.input.map { shapeId -> - model.expectShape(shapeId, StructureShape::class.java).toBuilder().rename(inputId) - }.orElse(empty(inputId)) + val inputShapeBuilder = + operation.input.map { shapeId -> + model.expectShape(shapeId, StructureShape::class.java).toBuilder().rename(inputId) + }.orElse(empty(inputId)) // There are still shapes missing the input trait. If we don't apply this, we'll get bad results from the // nullability index if (!inputShapeBuilder.build().hasTrait()) { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/RecursiveShapeBoxer.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/RecursiveShapeBoxer.kt index d53751829fb..f9c4d2d17c8 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/RecursiveShapeBoxer.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/RecursiveShapeBoxer.kt @@ -77,13 +77,14 @@ class RecursiveShapeBoxer( // (External to this function) Go back to 1. val index = TopologicalIndex.of(model) val recursiveShapes = index.recursiveShapes - val loops = recursiveShapes.map { shapeId -> - // Get all the shapes in the closure (represented as `Path`s). - index.getRecursiveClosure(shapeId) - }.flatMap { loops -> - // Flatten the connections into shapes. - loops.map { it.shapes } - } + val loops = + recursiveShapes.map { shapeId -> + // Get all the shapes in the closure (represented as `Path`s). + index.getRecursiveClosure(shapeId) + }.flatMap { loops -> + // Flatten the connections into shapes. + loops.map { it.shapes } + } val loopToFix = loops.firstOrNull { !containsIndirectionPredicate(it) } return loopToFix?.let { loop: List -> @@ -111,11 +112,12 @@ class RecursiveShapeBoxer( * indirection artificially ourselves using `Box`. * */ -private fun containsIndirection(loop: Collection): Boolean = loop.find { - when (it) { - is CollectionShape, is MapShape -> true - else -> it.hasTrait() - } -} != null +private fun containsIndirection(loop: Collection): Boolean = + loop.find { + when (it) { + is CollectionShape, is MapShape -> true + else -> it.hasTrait() + } + } != null private fun addRustBoxTrait(shape: MemberShape): MemberShape = shape.toBuilder().addTrait(RustBoxTrait()).build() diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/BasicTestModels.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/BasicTestModels.kt index eb4829702ee..c138a599bf5 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/BasicTestModels.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/BasicTestModels.kt @@ -6,7 +6,8 @@ package software.amazon.smithy.rust.codegen.core.testutil object BasicTestModels { - val AwsJson10TestModel = """ + val AwsJson10TestModel = + """ namespace com.example use aws.protocols#awsJson1_0 @awsJson1_0 @@ -19,5 +20,5 @@ object BasicTestModels { structure TestInput { foo: String, } - """.asSmithyModel() + """.asSmithyModel() } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/CodegenIntegrationTest.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/CodegenIntegrationTest.kt index 19bd7ddf580..9790b080b65 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/CodegenIntegrationTest.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/CodegenIntegrationTest.kt @@ -32,16 +32,21 @@ data class IntegrationTestParams( /** * Run cargo test on a true, end-to-end, codegen product of a given model. */ -fun codegenIntegrationTest(model: Model, params: IntegrationTestParams, invokePlugin: (PluginContext) -> Unit): Path { - val (ctx, testDir) = generatePluginContext( - model, - params.additionalSettings, - params.addModuleToEventStreamAllowList, - params.moduleVersion, - params.service, - params.runtimeConfig, - params.overrideTestDir, - ) +fun codegenIntegrationTest( + model: Model, + params: IntegrationTestParams, + invokePlugin: (PluginContext) -> Unit, +): Path { + val (ctx, testDir) = + generatePluginContext( + model, + params.additionalSettings, + params.addModuleToEventStreamAllowList, + params.moduleVersion, + params.service, + params.runtimeConfig, + params.overrideTestDir, + ) testDir.writeDotCargoConfigToml(listOf("--deny", "warnings")) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/DefaultBuilderInstantiator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/DefaultBuilderInstantiator.kt index 96af195c764..aa11d70edb7 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/DefaultBuilderInstantiator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/DefaultBuilderInstantiator.kt @@ -19,11 +19,19 @@ import software.amazon.smithy.rust.codegen.core.smithy.generators.BuilderInstant * and to serve as the base behavior for client and server instantiators. */ class DefaultBuilderInstantiator(private val checkFallibleBuilder: Boolean, private val symbolProvider: RustSymbolProvider) : BuilderInstantiator { - override fun setField(builder: String, value: Writable, field: MemberShape): Writable { + override fun setField( + builder: String, + value: Writable, + field: MemberShape, + ): Writable { return setFieldWithSetter(builder, value, field) } - override fun finalizeBuilder(builder: String, shape: StructureShape, mapErr: Writable?): Writable { + override fun finalizeBuilder( + builder: String, + shape: StructureShape, + mapErr: Writable?, + ): Writable { return writable { rust("builder.build()") if (checkFallibleBuilder && BuilderGenerator.hasFallibleBuilder(shape, symbolProvider)) { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamMarshallTestCases.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamMarshallTestCases.kt index 2850f51c721..65ae5019cb5 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamMarshallTestCases.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamMarshallTestCases.kt @@ -23,8 +23,9 @@ object EventStreamMarshallTestCases { ) { val generator = "crate::event_stream_serde::TestStreamMarshaller" - val protocolTestHelpers = CargoDependency.smithyProtocolTestHelpers(TestRuntimeConfig) - .copy(scope = DependencyScope.Compile) + val protocolTestHelpers = + CargoDependency.smithyProtocolTestHelpers(TestRuntimeConfig) + .copy(scope = DependencyScope.Compile) fun builderInput( @Language("Rust", prefix = "macro_rules! foo { () => {{\n", suffix = "\n}}}") diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestModels.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestModels.kt index e944a552a08..c0f61e07dbe 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestModels.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamTestModels.kt @@ -16,7 +16,8 @@ import software.amazon.smithy.rust.codegen.core.smithy.protocols.RestXml private fun fillInBaseModel( protocolName: String, extraServiceAnnotations: String = "", -): String = """ +): String = + """ namespace test use smithy.framework#ValidationException @@ -87,14 +88,18 @@ private fun fillInBaseModel( $extraServiceAnnotations @$protocolName service TestService { version: "123", operations: [TestStreamOp] } -""" + """ object EventStreamTestModels { private fun restJson1(): Model = fillInBaseModel("restJson1").asSmithyModel() + private fun restXml(): Model = fillInBaseModel("restXml").asSmithyModel() + private fun awsJson11(): Model = fillInBaseModel("awsJson1_1").asSmithyModel() + private fun awsQuery(): Model = fillInBaseModel("awsQuery", "@xmlNamespace(uri: \"https://example.com\")").asSmithyModel() + private fun ec2Query(): Model = fillInBaseModel("ec2Query", "@xmlNamespace(uri: \"https://example.com\")").asSmithyModel() @@ -114,79 +119,82 @@ object EventStreamTestModels { override fun toString(): String = protocolShapeId } - val TEST_CASES = listOf( - // - // restJson1 - // - TestCase( - protocolShapeId = "aws.protocols#restJson1", - model = restJson1(), - mediaType = "application/json", - requestContentType = "application/vnd.amazon.eventstream", - responseContentType = "application/json", - validTestStruct = """{"someString":"hello","someInt":5}""", - validMessageWithNoHeaderPayloadTraits = """{"someString":"hello","someInt":5}""", - validTestUnion = """{"Foo":"hello"}""", - validSomeError = """{"Message":"some error"}""", - validUnmodeledError = """{"Message":"unmodeled error"}""", - ) { RestJson(it) }, - - // - // awsJson1_1 - // - TestCase( - protocolShapeId = "aws.protocols#awsJson1_1", - model = awsJson11(), - mediaType = "application/x-amz-json-1.1", - requestContentType = "application/x-amz-json-1.1", - responseContentType = "application/x-amz-json-1.1", - validTestStruct = """{"someString":"hello","someInt":5}""", - validMessageWithNoHeaderPayloadTraits = """{"someString":"hello","someInt":5}""", - validTestUnion = """{"Foo":"hello"}""", - validSomeError = """{"Message":"some error"}""", - validUnmodeledError = """{"Message":"unmodeled error"}""", - ) { AwsJson(it, AwsJsonVersion.Json11) }, - - // - // restXml - // - TestCase( - protocolShapeId = "aws.protocols#restXml", - model = restXml(), - mediaType = "application/xml", - requestContentType = "application/vnd.amazon.eventstream", - responseContentType = "application/xml", - validTestStruct = """ - - hello - 5 - - """.trimIndent(), - validMessageWithNoHeaderPayloadTraits = """ - - hello - 5 - - """.trimIndent(), - validTestUnion = "hello", - validSomeError = """ - - - SomeError - SomeError - some error - - - """.trimIndent(), - validUnmodeledError = """ - - - UnmodeledError - UnmodeledError - unmodeled error - - - """.trimIndent(), - ) { RestXml(it) }, - ) + val TEST_CASES = + listOf( + // + // restJson1 + // + TestCase( + protocolShapeId = "aws.protocols#restJson1", + model = restJson1(), + mediaType = "application/json", + requestContentType = "application/vnd.amazon.eventstream", + responseContentType = "application/json", + validTestStruct = """{"someString":"hello","someInt":5}""", + validMessageWithNoHeaderPayloadTraits = """{"someString":"hello","someInt":5}""", + validTestUnion = """{"Foo":"hello"}""", + validSomeError = """{"Message":"some error"}""", + validUnmodeledError = """{"Message":"unmodeled error"}""", + ) { RestJson(it) }, + // + // awsJson1_1 + // + TestCase( + protocolShapeId = "aws.protocols#awsJson1_1", + model = awsJson11(), + mediaType = "application/x-amz-json-1.1", + requestContentType = "application/x-amz-json-1.1", + responseContentType = "application/x-amz-json-1.1", + validTestStruct = """{"someString":"hello","someInt":5}""", + validMessageWithNoHeaderPayloadTraits = """{"someString":"hello","someInt":5}""", + validTestUnion = """{"Foo":"hello"}""", + validSomeError = """{"Message":"some error"}""", + validUnmodeledError = """{"Message":"unmodeled error"}""", + ) { AwsJson(it, AwsJsonVersion.Json11) }, + // + // restXml + // + TestCase( + protocolShapeId = "aws.protocols#restXml", + model = restXml(), + mediaType = "application/xml", + requestContentType = "application/vnd.amazon.eventstream", + responseContentType = "application/xml", + validTestStruct = + """ + + hello + 5 + + """.trimIndent(), + validMessageWithNoHeaderPayloadTraits = + """ + + hello + 5 + + """.trimIndent(), + validTestUnion = "hello", + validSomeError = + """ + + + SomeError + SomeError + some error + + + """.trimIndent(), + validUnmodeledError = + """ + + + UnmodeledError + UnmodeledError + unmodeled error + + + """.trimIndent(), + ) { RestXml(it) }, + ) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamUnmarshallTestCases.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamUnmarshallTestCases.kt index 3adc813546a..4a94d0af3ae 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamUnmarshallTestCases.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/EventStreamUnmarshallTestCases.kt @@ -77,13 +77,13 @@ object EventStreamUnmarshallTestCases { expect_event(result.unwrap()) ); """, - "DataInput" to conditionalBuilderInput( - """ - Blob::new(&b"hello, world!"[..]) - """, - conditional = optionalBuilderInputs, - ), - + "DataInput" to + conditionalBuilderInput( + """ + Blob::new(&b"hello, world!"[..]) + """, + conditional = optionalBuilderInputs, + ), ) } @@ -118,18 +118,18 @@ object EventStreamUnmarshallTestCases { expect_event(result.unwrap()) ); """, - "StructInput" to conditionalBuilderInput( - """ - TestStruct::builder() - .some_string(#{StringInput}) - .some_int(#{IntInput}) - .build() - """, - conditional = optionalBuilderInputs, - "StringInput" to conditionalBuilderInput("\"hello\"", conditional = optionalBuilderInputs), - "IntInput" to conditionalBuilderInput("5", conditional = optionalBuilderInputs), - ), - + "StructInput" to + conditionalBuilderInput( + """ + TestStruct::builder() + .some_string(#{StringInput}) + .some_int(#{IntInput}) + .build() + """, + conditional = optionalBuilderInputs, + "StringInput" to conditionalBuilderInput("\"hello\"", conditional = optionalBuilderInputs), + "IntInput" to conditionalBuilderInput("5", conditional = optionalBuilderInputs), + ), ) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/NamingObstacleCourseTestModels.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/NamingObstacleCourseTestModels.kt index 72979545b94..5508611972e 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/NamingObstacleCourseTestModels.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/NamingObstacleCourseTestModels.kt @@ -16,167 +16,172 @@ object NamingObstacleCourseTestModels { * Test model that confounds the generation machinery by using operations named after every item * in the Rust prelude. */ - fun rustPreludeOperationsModel(): Model = StringBuilder().apply { - append( - """ - ${"$"}version: "2.0" - namespace crate - - use smithy.test#httpRequestTests - use smithy.test#httpResponseTests - use aws.protocols#awsJson1_1 - use aws.api#service - use smithy.framework#ValidationException - - structure InputAndOutput {} - - @awsJson1_1 - @service(sdkId: "Config") - service Config { - version: "2006-03-01", - rename: { "smithy.api#String": "PreludeString" }, - operations: [ - """, - ) - for (item in rustPrelude) { - append("$item,\n") - } - append( - """ - ] + fun rustPreludeOperationsModel(): Model = + StringBuilder().apply { + append( + """ + ${"$"}version: "2.0" + namespace crate + + use smithy.test#httpRequestTests + use smithy.test#httpResponseTests + use aws.protocols#awsJson1_1 + use aws.api#service + use smithy.framework#ValidationException + + structure InputAndOutput {} + + @awsJson1_1 + @service(sdkId: "Config") + service Config { + version: "2006-03-01", + rename: { "smithy.api#String": "PreludeString" }, + operations: [ + """, + ) + for (item in rustPrelude) { + append("$item,\n") } - """, - ) - for (item in rustPrelude) { - append("operation $item { input: InputAndOutput, output: InputAndOutput, errors: [ValidationException] }\n") - } - }.toString().asSmithyModel() - - fun rustPreludeStructsModel(): Model = StringBuilder().apply { - append( - """ - ${"$"}version: "2.0" - namespace crate - - use smithy.test#httpRequestTests - use smithy.test#httpResponseTests - use aws.protocols#awsJson1_1 - use aws.api#service - use smithy.framework#ValidationException - - structure InputAndOutput {} - - @awsJson1_1 - @service(sdkId: "Config") - service Config { - version: "2006-03-01", - rename: { "smithy.api#String": "PreludeString" }, - operations: [ - """, - ) - for (item in rustPrelude) { - append("Use$item,\n") - } - append( - """ - ] + append( + """ + ] + } + """, + ) + for (item in rustPrelude) { + append("operation $item { input: InputAndOutput, output: InputAndOutput, errors: [ValidationException] }\n") } - """, - ) - for (item in rustPrelude) { - append("structure $item { $item: smithy.api#String }\n") - append("operation Use$item { input: $item, output: $item, errors: [ValidationException] }\n") - } - println(toString()) - }.toString().asSmithyModel() - - fun rustPreludeEnumsModel(): Model = StringBuilder().apply { - append( - """ - ${"$"}version: "2.0" - namespace crate - - use smithy.test#httpRequestTests - use smithy.test#httpResponseTests - use aws.protocols#awsJson1_1 - use aws.api#service - use smithy.framework#ValidationException - - structure InputAndOutput {} - - @awsJson1_1 - @service(sdkId: "Config") - service Config { - version: "2006-03-01", - rename: { "smithy.api#String": "PreludeString" }, - operations: [ - """, - ) - for (item in rustPrelude) { - append("Use$item,\n") - } - append( - """ - ] + }.toString().asSmithyModel() + + fun rustPreludeStructsModel(): Model = + StringBuilder().apply { + append( + """ + ${"$"}version: "2.0" + namespace crate + + use smithy.test#httpRequestTests + use smithy.test#httpResponseTests + use aws.protocols#awsJson1_1 + use aws.api#service + use smithy.framework#ValidationException + + structure InputAndOutput {} + + @awsJson1_1 + @service(sdkId: "Config") + service Config { + version: "2006-03-01", + rename: { "smithy.api#String": "PreludeString" }, + operations: [ + """, + ) + for (item in rustPrelude) { + append("Use$item,\n") } - """, - ) - for (item in rustPrelude) { - append("enum $item { $item }\n") - append("structure Struct$item { $item: $item }\n") - append("operation Use$item { input: Struct$item, output: Struct$item, errors: [ValidationException] }\n") - } - }.toString().asSmithyModel() - - fun rustPreludeEnumVariantsModel(): Model = StringBuilder().apply { - append( - """ - ${"$"}version: "2.0" - namespace crate - - use smithy.test#httpRequestTests - use smithy.test#httpResponseTests - use aws.protocols#awsJson1_1 - use aws.api#service - use smithy.framework#ValidationException - - @awsJson1_1 - @service(sdkId: "Config") - service Config { - version: "2006-03-01", - rename: { "smithy.api#String": "PreludeString" }, - operations: [EnumOp] + append( + """ + ] + } + """, + ) + for (item in rustPrelude) { + append("structure $item { $item: smithy.api#String }\n") + append("operation Use$item { input: $item, output: $item, errors: [ValidationException] }\n") } - - operation EnumOp { - input: InputAndOutput, - output: InputAndOutput, - errors: [ValidationException], + println(toString()) + }.toString().asSmithyModel() + + fun rustPreludeEnumsModel(): Model = + StringBuilder().apply { + append( + """ + ${"$"}version: "2.0" + namespace crate + + use smithy.test#httpRequestTests + use smithy.test#httpResponseTests + use aws.protocols#awsJson1_1 + use aws.api#service + use smithy.framework#ValidationException + + structure InputAndOutput {} + + @awsJson1_1 + @service(sdkId: "Config") + service Config { + version: "2006-03-01", + rename: { "smithy.api#String": "PreludeString" }, + operations: [ + """, + ) + for (item in rustPrelude) { + append("Use$item,\n") } - - structure InputAndOutput { - the_enum: TheEnum, + append( + """ + ] + } + """, + ) + for (item in rustPrelude) { + append("enum $item { $item }\n") + append("structure Struct$item { $item: $item }\n") + append("operation Use$item { input: Struct$item, output: Struct$item, errors: [ValidationException] }\n") } - - enum TheEnum { - """, - ) - for (item in rustPrelude) { - append("$item,\n") - } - append( - """ + }.toString().asSmithyModel() + + fun rustPreludeEnumVariantsModel(): Model = + StringBuilder().apply { + append( + """ + ${"$"}version: "2.0" + namespace crate + + use smithy.test#httpRequestTests + use smithy.test#httpResponseTests + use aws.protocols#awsJson1_1 + use aws.api#service + use smithy.framework#ValidationException + + @awsJson1_1 + @service(sdkId: "Config") + service Config { + version: "2006-03-01", + rename: { "smithy.api#String": "PreludeString" }, + operations: [EnumOp] + } + + operation EnumOp { + input: InputAndOutput, + output: InputAndOutput, + errors: [ValidationException], + } + + structure InputAndOutput { + the_enum: TheEnum, + } + + enum TheEnum { + """, + ) + for (item in rustPrelude) { + append("$item,\n") } - """, - ) - }.toString().asSmithyModel() + append( + """ + } + """, + ) + }.toString().asSmithyModel() /** * This targets two bug classes: * - operation inputs used as nested outputs * - operation outputs used as nested outputs */ - fun reusedInputOutputShapesModel(protocol: Trait) = """ + fun reusedInputOutputShapesModel(protocol: Trait) = + """ namespace test use ${protocol.toShapeId()} use aws.api#service @@ -226,5 +231,5 @@ object NamingObstacleCourseTestModels { list GetThingInputList { member: GetThingInput } - """.asSmithyModel() + """.asSmithyModel() } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt index 8fc7b1cc4b6..8db16eac2c9 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/Rust.kt @@ -122,8 +122,13 @@ private object Commands { // ``` fun cargoCheck(variation: TestVariation): String { return decorateCmd("cargo check", variation) +val TestModuleDocProvider = + object : ModuleDocProvider { + override fun docsWriter(module: RustModule.LeafModule): Writable = + writable { + docs("Some test documentation\n\nSome more details...") + } } -} val TestModuleDocProvider = object : ModuleDocProvider { @@ -170,39 +175,33 @@ object TestWorkspace { private fun generate() { val cargoToml = baseDir.resolve("Cargo.toml") val workspaceToml = - TomlWriter() - .write( - mapOf( - "workspace" to - mapOf( - "members" to subprojects, - ), - ), - ) + TomlWriter().write( + mapOf( + "workspace" to + mapOf( + "members" to subprojects, + ), + ), + ) cargoToml.writeText(workspaceToml) } fun subproject(): File { synchronized(subprojects) { val newProject = tempDir(directory = baseDir) - newProject - .resolve("Cargo.toml") - .writeText( - """ - [package] - name = "stub-${newProject.name}" - version = "0.0.1" - """.trimIndent(), - ) - newProject - .resolve("rust-toolchain.toml") - .writeText( - // help rust select the right version when we run cargo test - // TODO(https://github.com/smithy-lang/smithy-rs/issues/2048): load this - // from the msrv property using a - // method as we do for runtime crate versions - "[toolchain]\nchannel = \"1.70.0\"\n", - ) + newProject.resolve("Cargo.toml").writeText( + """ + [package] + name = "stub-${newProject.name}" + version = "0.0.1" + """.trimIndent(), + ) + newProject.resolve("rust-toolchain.toml").writeText( + // help rust select the right version when we run cargo test + // TODO(https://github.com/smithy-lang/smithy-rs/issues/2048): load this from the msrv property using a + // method as we do for runtime crate versions + "[toolchain]\nchannel = \"1.72.1\"\n", + ) // ensure there at least an empty lib.rs file to avoid broken crates newProject.resolve("src").mkdirs() newProject.resolve("src/lib.rs").writeText("") @@ -275,30 +274,20 @@ fun generatePluginContext( .letIf(service != null) { it.withMember("service", service) } .withMember( "runtimeConfig", - Node.objectNodeBuilder() - .withMember( - "relativePath", - Node.from( - ( - (runtimeConfig ?: TestRuntimeConfig) - .runtimeCrateLocation - ) - .path, - ), - ) - .build(), + Node.objectNodeBuilder().withMember( + "relativePath", + Node.from(((runtimeConfig ?: TestRuntimeConfig).runtimeCrateLocation).path), + ).build(), ) if (addModuleToEventStreamAllowList) { settingsBuilder = settingsBuilder.withMember( "codegen", - Node.objectNodeBuilder() - .withMember( - "eventStreamAllowList", - Node.fromStrings(moduleName), - ) - .build(), + Node.objectNodeBuilder().withMember( + "eventStreamAllowList", + Node.fromStrings(moduleName), + ).build(), ) } @@ -337,10 +326,8 @@ fun RustWriter.unitTest( } fun RustWriter.cargoDependencies() = - dependencies - .map { RustDependency.fromSymbolDependency(it) } - .filterIsInstance() - .distinct() + dependencies.map { RustDependency.fromSymbolDependency(it) } + .filterIsInstance().distinct() fun RustWriter.assertNoNewDependencies( block: Writable, @@ -381,9 +368,16 @@ fun RustWriter.testDependenciesOnly(block: Writable) = } } -fun testDependenciesOnly(block: Writable): Writable = { testDependenciesOnly(block) } +fun testDependenciesOnly(block: Writable): Writable = + { + testDependenciesOnly(block) + } -fun RustWriter.tokioTest(name: String, vararg args: Any, block: Writable) { +fun RustWriter.tokioTest( + name: String, + vararg args: Any, + block: Writable, +) { unitTest(name, attribute = Attribute.TokioTest, async = true, block = block, args = args) } @@ -413,13 +407,14 @@ class TestWriterDelegator( * This should only be used in test code—the generated module name will be something like * `tests_123` */ -fun RustCrate.testModule(block: Writable) = lib { - withInlineModule( - RustModule.inlineTests(safeName("tests")), - TestModuleDocProvider, - block, - ) -} +fun RustCrate.testModule(block: Writable) = + lib { + withInlineModule( + RustModule.inlineTests(safeName("tests")), + TestModuleDocProvider, + block, + ) + } fun FileManifest.printGeneratedFiles() { this.files.forEach { path -> println("file:///$path") } @@ -563,21 +558,18 @@ private fun String.intoCrate( this.shouldParseAsRust() val tempDir = TestWorkspace.subproject() val cargoToml = - RustWriter.toml("Cargo.toml") - .apply { - CargoTomlGenerator( - moduleName = tempDir.nameWithoutExtension, - moduleVersion = "0.0.1", - moduleAuthors = listOf("Testy McTesterson"), - moduleDescription = null, - moduleLicense = null, - moduleRepository = null, - writer = this, - dependencies = deps, - ) - .render() - } - .toString() + RustWriter.toml("Cargo.toml").apply { + CargoTomlGenerator( + moduleName = tempDir.nameWithoutExtension, + moduleVersion = "0.0.1", + moduleAuthors = listOf("Testy McTesterson"), + moduleDescription = null, + moduleLicense = null, + moduleRepository = null, + writer = this, + dependencies = deps, + ).render() + }.toString() tempDir.resolve("Cargo.toml").writeText(cargoToml) tempDir.resolve("src").mkdirs() val mainRs = tempDir.resolve("src/main.rs") @@ -639,8 +631,10 @@ fun String.compileAndRun(vararg strings: String) { binary.absolutePath.runCommand() } -fun RustCrate.integrationTest(name: String, writable: Writable) = - this.withFile("tests/$name.rs", writable) +fun RustCrate.integrationTest( + name: String, + writable: Writable, +) = this.withFile("tests/$name.rs", writable) fun TestWriterDelegator.unitTest(test: Writable): TestWriterDelegator { lib { diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt index cbd29d33d46..f5797ba9b6e 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/testutil/TestHelpers.kt @@ -50,7 +50,7 @@ import software.amazon.smithy.rust.codegen.core.util.toSnakeCase import java.io.File val TestRuntimeConfig = - RuntimeConfig(runtimeCrateLocation = RuntimeCrateLocation.Path(File("../rust-runtime/").absolutePath)) + RuntimeConfig(runtimeCrateLocation = RuntimeCrateLocation.path(File("../rust-runtime/").absolutePath)) /** * IMPORTANT: You shouldn't need to refer to these directly in code or tests. They are private for a reason. @@ -68,15 +68,19 @@ private object CodegenCoreTestModules { val OperationsTestModule = RustModule.public("test_operation") object TestModuleProvider : ModuleProvider { - override fun moduleForShape(context: ModuleProviderContext, shape: Shape): RustModule.LeafModule = + override fun moduleForShape( + context: ModuleProviderContext, + shape: Shape, + ): RustModule.LeafModule = when (shape) { is OperationShape -> OperationsTestModule - is StructureShape -> when { - shape.hasTrait() -> ErrorsTestModule - shape.hasTrait() -> InputsTestModule - shape.hasTrait() -> OutputsTestModule - else -> ModelsTestModule - } + is StructureShape -> + when { + shape.hasTrait() -> ErrorsTestModule + shape.hasTrait() -> InputsTestModule + shape.hasTrait() -> OutputsTestModule + else -> ModelsTestModule + } else -> ModelsTestModule } @@ -107,12 +111,13 @@ private object CodegenCoreTestModules { } } -fun testRustSymbolProviderConfig(nullabilityCheckMode: NullableIndex.CheckMode) = RustSymbolProviderConfig( - runtimeConfig = TestRuntimeConfig, - renameExceptions = true, - nullabilityCheckMode = nullabilityCheckMode, - moduleProvider = CodegenCoreTestModules.TestModuleProvider, -) +fun testRustSymbolProviderConfig(nullabilityCheckMode: NullableIndex.CheckMode) = + RustSymbolProviderConfig( + runtimeConfig = TestRuntimeConfig, + renameExceptions = true, + nullabilityCheckMode = nullabilityCheckMode, + moduleProvider = CodegenCoreTestModules.TestModuleProvider, + ) fun testRustSettings( service: ShapeId = ShapeId.from("notrelevant#notrelevant"), @@ -139,6 +144,7 @@ fun testRustSettings( ) private const val SmithyVersion = "1.0" + fun String.asSmithyModel( sourceLocation: String? = null, smithyVersion: String = SmithyVersion, @@ -158,18 +164,19 @@ internal fun testSymbolProvider( model: Model, rustReservedWordConfig: RustReservedWordConfig? = null, nullabilityCheckMode: NullableIndex.CheckMode = NullableIndex.CheckMode.CLIENT, -): RustSymbolProvider = SymbolVisitor( - testRustSettings(), - model, - ServiceShape.builder().version("test").id("test#Service").build(), - testRustSymbolProviderConfig(nullabilityCheckMode), -).let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf(Attribute.NonExhaustive)) } - .let { - RustReservedWordSymbolProvider( - it, - rustReservedWordConfig ?: RustReservedWordConfig(emptyMap(), emptyMap(), emptyMap()), - ) - } +): RustSymbolProvider = + SymbolVisitor( + testRustSettings(), + model, + ServiceShape.builder().version("test").id("test#Service").build(), + testRustSymbolProviderConfig(nullabilityCheckMode), + ).let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf(Attribute.NonExhaustive)) } + .let { + RustReservedWordSymbolProvider( + it, + rustReservedWordConfig ?: RustReservedWordConfig(emptyMap(), emptyMap(), emptyMap()), + ) + } // Intentionally only visible to codegen-core since the other modules have their own contexts internal fun testCodegenContext( @@ -178,21 +185,22 @@ internal fun testCodegenContext( settings: CoreRustSettings = testRustSettings(), codegenTarget: CodegenTarget = CodegenTarget.CLIENT, nullabilityCheckMode: NullableIndex.CheckMode = NullableIndex.CheckMode.CLIENT, -): CodegenContext = object : CodegenContext( - model, - testSymbolProvider(model, nullabilityCheckMode = nullabilityCheckMode), - TestModuleDocProvider, - serviceShape - ?: model.serviceShapes.firstOrNull() - ?: ServiceShape.builder().version("test").id("test#Service").build(), - ShapeId.from("test#Protocol"), - settings, - codegenTarget, -) { - override fun builderInstantiator(): BuilderInstantiator { - return DefaultBuilderInstantiator(codegenTarget == CodegenTarget.CLIENT, symbolProvider) +): CodegenContext = + object : CodegenContext( + model, + testSymbolProvider(model, nullabilityCheckMode = nullabilityCheckMode), + TestModuleDocProvider, + serviceShape + ?: model.serviceShapes.firstOrNull() + ?: ServiceShape.builder().version("test").id("test#Service").build(), + ShapeId.from("test#Protocol"), + settings, + codegenTarget, + ) { + override fun builderInstantiator(): BuilderInstantiator { + return DefaultBuilderInstantiator(codegenTarget == CodegenTarget.CLIENT, symbolProvider) + } } -} /** * In tests, we frequently need to generate a struct, a builder, and an impl block to access said builder. @@ -214,7 +222,10 @@ fun StructureShape.renderWithModelBuilder( } } -fun RustCrate.unitTest(name: String? = null, test: Writable) { +fun RustCrate.unitTest( + name: String? = null, + test: Writable, +) { lib { val testName = name ?: safeName("test") unitTest(testName, block = test) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Exec.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Exec.kt index 64223fe5500..296d7bc39f2 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Exec.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Exec.kt @@ -12,17 +12,22 @@ import java.util.logging.Logger data class CommandError(val output: String) : Exception("Command Error\n$output") -fun String.runCommand(workdir: Path? = null, environment: Map = mapOf(), timeout: Long = 3600): String { +fun String.runCommand( + workdir: Path? = null, + environment: Map = mapOf(), + timeout: Long = 3600, +): String { val logger = Logger.getLogger("RunCommand") logger.fine("Invoking comment $this in `$workdir` with env $environment") val start = System.currentTimeMillis() val parts = this.split("\\s".toRegex()) - val builder = ProcessBuilder(*parts.toTypedArray()) - .redirectOutput(ProcessBuilder.Redirect.PIPE) - .redirectError(ProcessBuilder.Redirect.PIPE) - .letIf(workdir != null) { - it.directory(workdir?.toFile()) - } + val builder = + ProcessBuilder(*parts.toTypedArray()) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectError(ProcessBuilder.Redirect.PIPE) + .letIf(workdir != null) { + it.directory(workdir?.toFile()) + } val env = builder.environment() environment.forEach { (k, v) -> env[k] = v } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/LetIf.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/LetIf.kt index 89868f7a005..4c6a70535a2 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/LetIf.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/LetIf.kt @@ -7,7 +7,10 @@ package software.amazon.smithy.rust.codegen.core.util /** * Utility function similar to `let` that conditionally applies [f] only if [cond] is true. */ -fun T.letIf(cond: Boolean, f: (T) -> T): T { +fun T.letIf( + cond: Boolean, + f: (T) -> T, +): T { return if (cond) { f(this) } else { @@ -15,19 +18,23 @@ fun T.letIf(cond: Boolean, f: (T) -> T): T { } } -fun List.extendIf(condition: Boolean, f: () -> T) = if (condition) { +fun List.extendIf( + condition: Boolean, + f: () -> T, +) = if (condition) { this + listOf(f()) } else { this } -fun Boolean.thenSingletonListOf(f: () -> T): List = if (this) { - listOf(f()) -} else { - listOf() -} +fun Boolean.thenSingletonListOf(f: () -> T): List = + if (this) { + listOf(f()) + } else { + listOf() + } /** * Returns this list if it is non-empty otherwise, it returns null */ -fun List.orNullIfEmpty(): List? = this.ifEmpty { null } +fun List.orNullIfEmpty(): List? = this.ifEmpty { null } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Map.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Map.kt index 00c4450a55a..0a214c6f825 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Map.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Map.kt @@ -8,11 +8,13 @@ package software.amazon.smithy.rust.codegen.core.util /** * Deep merges two maps, with the properties of `other` taking priority over the properties of `this`. */ -fun Map.deepMergeWith(other: Map): Map = - deepMergeMaps(this, other) +fun Map.deepMergeWith(other: Map): Map = deepMergeMaps(this, other) @Suppress("UNCHECKED_CAST") -private fun deepMergeMaps(left: Map, right: Map): Map { +private fun deepMergeMaps( + left: Map, + right: Map, +): Map { val result = mutableMapOf() for (leftEntry in left.entries) { val rightValue = right[leftEntry.key] diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Panic.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Panic.kt index 7d24a179883..ea7fe0724a2 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Panic.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Panic.kt @@ -6,7 +6,9 @@ package software.amazon.smithy.rust.codegen.core.util /** Something has gone horribly wrong due to a coding error */ +@Suppress("ktlint:standard:function-naming") fun PANIC(reason: String = ""): Nothing = throw RuntimeException(reason) /** This code should never be executed (but Kotlin cannot prove that) */ +@Suppress("ktlint:standard:function-naming") fun UNREACHABLE(reason: String): Nothing = throw IllegalStateException("This should be unreachable: $reason") diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Smithy.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Smithy.kt index bde5c4b3389..b167f05d2d3 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Smithy.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Smithy.kt @@ -44,12 +44,15 @@ fun StructureShape.expectMember(member: String): MemberShape = fun UnionShape.expectMember(member: String): MemberShape = this.getMember(member).orElseThrow { CodegenException("$member did not exist on $this") } -fun StructureShape.errorMessageMember(): MemberShape? = this.getMember("message").or { - this.getMember("Message") -}.orNull() +fun StructureShape.errorMessageMember(): MemberShape? = + this.getMember("message").or { + this.getMember("Message") + }.orNull() fun StructureShape.hasStreamingMember(model: Model) = this.findStreamingMember(model) != null + fun UnionShape.hasStreamingMember(model: Model) = this.findMemberWithTrait(model) != null + fun MemberShape.isStreaming(model: Model) = this.getMemberTrait(model, StreamingTrait::class.java).isPresent fun UnionShape.isEventStream(): Boolean { @@ -90,9 +93,10 @@ fun OperationShape.isEventStream(model: Model): Boolean { return isInputEventStream(model) || isOutputEventStream(model) } -fun ServiceShape.hasEventStreamOperations(model: Model): Boolean = operations.any { id -> - model.expectShape(id, OperationShape::class.java).isEventStream(model) -} +fun ServiceShape.hasEventStreamOperations(model: Model): Boolean = + operations.any { id -> + model.expectShape(id, OperationShape::class.java).isEventStream(model) + } fun Shape.shouldRedact(model: Model): Boolean = when (this) { @@ -102,7 +106,10 @@ fun Shape.shouldRedact(model: Model): Boolean = const val REDACTION = "\"*** Sensitive Data Redacted ***\"" -fun Shape.redactIfNecessary(model: Model, safeToPrint: String): String = +fun Shape.redactIfNecessary( + model: Model, + safeToPrint: String, +): String = if (this.shouldRedact(model)) { REDACTION } else { @@ -149,5 +156,4 @@ fun String.shapeId() = ShapeId.from(this) fun ServiceShape.serviceNameOrDefault(default: String) = getTrait()?.value ?: default /** Returns the SDK ID of the given service shape */ -fun ServiceShape.sdkId(): String = - getTrait()?.sdkId?.lowercase()?.replace(" ", "") ?: id.getName(this) +fun ServiceShape.sdkId(): String = getTrait()?.sdkId?.lowercase()?.replace(" ", "") ?: id.getName(this) diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Strings.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Strings.kt index d6668500280..a6e15baccb2 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Strings.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Strings.kt @@ -32,21 +32,25 @@ private fun String.splitOnWordBoundaries(): List { if (currentWord.isNotEmpty()) { out += currentWord.lowercase() } - currentWord = if (next.isLetterOrDigit()) { - next.toString() - } else { - "" - } + currentWord = + if (next.isLetterOrDigit()) { + next.toString() + } else { + "" + } } val allLowerCase = this.lowercase() == this this.forEachIndexed { index, nextCharacter -> val computeWordInProgress = { - val result = completeWordInProgress && currentWord.isNotEmpty() && completeWords.any { - it.startsWith(currentWord, ignoreCase = true) && (currentWord + this.substring(index)).startsWith( - it, - ignoreCase = true, - ) && !it.equals(currentWord, ignoreCase = true) - } + val result = + completeWordInProgress && currentWord.isNotEmpty() && + completeWords.any { + it.startsWith(currentWord, ignoreCase = true) && + (currentWord + this.substring(index)).startsWith( + it, + ignoreCase = true, + ) && !it.equals(currentWord, ignoreCase = true) + } completeWordInProgress = result result @@ -63,9 +67,10 @@ private fun String.splitOnWordBoundaries(): List { !computeWordInProgress() && loweredFollowedByUpper(currentWord, nextCharacter) -> emit(nextCharacter) // s3[k]ey - !computeWordInProgress() && allLowerCase && digitFollowedByLower(currentWord, nextCharacter) -> emit( - nextCharacter, - ) + !computeWordInProgress() && allLowerCase && digitFollowedByLower(currentWord, nextCharacter) -> + emit( + nextCharacter, + ) // DB[P]roxy, or `IAM[U]ser` but not AC[L]s endOfAcronym(currentWord, nextCharacter, this.getOrNull(index + 1), this.getOrNull(index + 2)) -> emit(nextCharacter) @@ -83,7 +88,12 @@ private fun String.splitOnWordBoundaries(): List { /** * Handle cases like `DB[P]roxy`, `ARN[S]upport`, `AC[L]s` */ -private fun endOfAcronym(current: String, nextChar: Char, peek: Char?, doublePeek: Char?): Boolean { +private fun endOfAcronym( + current: String, + nextChar: Char, + peek: Char?, + doublePeek: Char?, +): Boolean { if (!current.last().isUpperCase()) { // Not an acronym in progress return false @@ -109,14 +119,20 @@ private fun endOfAcronym(current: String, nextChar: Char, peek: Char?, doublePee return true } -private fun loweredFollowedByUpper(current: String, nextChar: Char): Boolean { +private fun loweredFollowedByUpper( + current: String, + nextChar: Char, +): Boolean { if (!nextChar.isUpperCase()) { return false } return current.last().isLowerCase() || current.last().isDigit() } -private fun digitFollowedByLower(current: String, nextChar: Char): Boolean { +private fun digitFollowedByLower( + current: String, + nextChar: Char, +): Boolean { return (current.last().isDigit() && nextChar.isLowerCase()) } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Synthetics.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Synthetics.kt index f0746701e3f..4ecc62361d4 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Synthetics.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/util/Synthetics.kt @@ -20,18 +20,20 @@ fun Model.Builder.cloneOperation( idTransform: (ShapeId) -> ShapeId, ): Model.Builder { val operationShape = model.expectShape(oldOperation.toShapeId(), OperationShape::class.java) - val inputShape = model.expectShape( - checkNotNull(operationShape.input.orNull()) { - "cloneOperation expects OperationNormalizer to be run first to add input shapes to all operations" - }, - StructureShape::class.java, - ) - val outputShape = model.expectShape( - checkNotNull(operationShape.output.orNull()) { - "cloneOperation expects OperationNormalizer to be run first to add output shapes to all operations" - }, - StructureShape::class.java, - ) + val inputShape = + model.expectShape( + checkNotNull(operationShape.input.orNull()) { + "cloneOperation expects OperationNormalizer to be run first to add input shapes to all operations" + }, + StructureShape::class.java, + ) + val outputShape = + model.expectShape( + checkNotNull(operationShape.output.orNull()) { + "cloneOperation expects OperationNormalizer to be run first to add output shapes to all operations" + }, + StructureShape::class.java, + ) val inputId = idTransform(inputShape.id) addShape(inputShape.toBuilder().rename(inputId).build()) @@ -54,8 +56,9 @@ fun Model.Builder.cloneOperation( * Renames a StructureShape builder and automatically fixes all the members. */ fun StructureShape.Builder.rename(newId: ShapeId): StructureShape.Builder { - val renamedMembers = this.build().members().map { - it.toBuilder().id(newId.withMember(it.memberName)).build() - } + val renamedMembers = + this.build().members().map { + it.toBuilder().id(newId.withMember(it.memberName)).build() + } return this.id(newId).members(renamedMembers) } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/VersionTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/VersionTest.kt index 2147dc857ce..030ee2ea160 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/VersionTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/VersionTest.kt @@ -5,49 +5,50 @@ package software.amazon.smithy.rust.codegen.core -import io.kotest.assertions.throwables.shouldThrowAny import io.kotest.matchers.shouldBe -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.Arguments -import org.junit.jupiter.params.provider.MethodSource +import org.junit.jupiter.api.Test class VersionTest { - @ParameterizedTest() - @MethodSource("versionProvider") - fun `parses version`( - content: String, - fullVersion: String, - crateVersion: String, - ) { - val version = Version.parse(content) - version.fullVersion shouldBe fullVersion - version.stableCrateVersion shouldBe crateVersion - } - - @ParameterizedTest() - @MethodSource("invalidVersionProvider") - fun `fails to parse version`( - content: String, - ) { - shouldThrowAny { Version.parse(content) } - } - - companion object { - @JvmStatic - fun versionProvider() = listOf( - Arguments.of( - """{ "stableVersion": "1.0.1", "unstableVersion": "0.60.1","githash": "0198d26096eb1af510ce24766c921ffc5e4c191e", "runtimeCrates": {} }""", - "1.0.1-0198d26096eb1af510ce24766c921ffc5e4c191e", - "1.0.1", - ), - Arguments.of( - """{ "unstableVersion": "0.60.1", "stableVersion": "release-2022-08-04", "githash": "db48039065bec890ef387385773b37154b555b14", "runtimeCrates": {} }""", - "release-2022-08-04-db48039065bec890ef387385773b37154b555b14", - "release-2022-08-04", - ), - ) - - @JvmStatic - fun invalidVersionProvider() = listOf("0.0.0", "") + @Test + fun `parse versions json`() { + val version = + Version.parse( + """ + { + "gitHash": "30205973b951256c4c37b998e7a6e94fee2f6ecc", + "runtimeCrates": { + "aws-smithy-http-server": "0.60.1", + "aws-smithy-runtime-api": "1.1.1", + "aws-smithy-protocol-test": "0.60.1", + "aws-smithy-eventstream": "0.60.1", + "aws-smithy-async": "1.1.1", + "aws-smithy-http-server-python": "0.60.1", + "aws-smithy-types": "1.1.1", + "aws-smithy-types-convert": "0.60.1", + "aws-smithy-http-auth": "0.60.1", + "aws-smithy-checksums": "0.60.1", + "aws-smithy-runtime": "1.1.1", + "aws-smithy-query": "0.60.1", + "aws-smithy-xml": "0.60.1", + "aws-smithy-json": "0.60.1", + "aws-smithy-http-tower": "0.60.1", + "aws-smithy-http": "0.60.1", + "aws-smithy-client": "0.60.1", + "aws-sig-auth": "0.60.1", + "aws-credential-types": "1.1.1", + "aws-runtime-api": "1.1.1", + "aws-types": "1.1.1", + "aws-sigv4": "1.1.1", + "aws-runtime": "1.1.1", + "aws-http": "0.60.1", + "aws-endpoint": "0.60.1", + "aws-config": "1.1.1", + "aws-hyper": "0.60.1" } + } + """, + ) + version.gitHash shouldBe "30205973b951256c4c37b998e7a6e94fee2f6ecc" + version.crates["aws-smithy-http-server"] shouldBe "0.60.1" + version.crates["aws-config"] shouldBe "1.1.1" } } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/InlineDependencyTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/InlineDependencyTest.kt index 4e341c769f8..af54e494ee8 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/InlineDependencyTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/InlineDependencyTest.kt @@ -17,9 +17,10 @@ import software.amazon.smithy.rust.codegen.core.testutil.unitTest import kotlin.io.path.pathString internal class InlineDependencyTest { - private fun makeDep(name: String) = InlineDependency(name, RustModule.private("module")) { - rustBlock("fn foo()") {} - } + private fun makeDep(name: String) = + InlineDependency(name, RustModule.private("module")) { + rustBlock("fn foo()") {} + } @Test fun `equal dependencies should be equal`() { @@ -60,13 +61,14 @@ internal class InlineDependencyTest { val a = RustModule.public("a") val b = RustModule.public("b", parent = a) val c = RustModule.public("c", parent = b) - val type = RuntimeType.forInlineFun("forty2", c) { - rust( - """ - pub fn forty2() -> usize { 42 } - """, - ) - } + val type = + RuntimeType.forInlineFun("forty2", c) { + rust( + """ + pub fn forty2() -> usize { 42 } + """, + ) + } val crate = TestWorkspace.testProject() crate.lib { unitTest("use_nested_module") { diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustGenericsTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustGenericsTest.kt index a8eb41353f5..6d0e70d1268 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustGenericsTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustGenericsTest.kt @@ -57,44 +57,49 @@ class RustGenericsTest { @Test fun `bounds is correct for several args`() { - val gg = RustGenerics( - GenericTypeArg("A", testRT("Apple")), - GenericTypeArg("PL", testRT("Plum")), - GenericTypeArg("PE", testRT("Pear")), - ) + val gg = + RustGenerics( + GenericTypeArg("A", testRT("Apple")), + GenericTypeArg("PL", testRT("Plum")), + GenericTypeArg("PE", testRT("Pear")), + ) val writer = RustWriter.forModule("model") writer.rustTemplate("#{bounds:W}", "bounds" to gg.bounds()) - writer.toString() shouldContain """ + writer.toString() shouldContain + """ A: test::Apple, PL: test::Plum, PE: test::Pear, - """.trimIndent() + """.trimIndent() } @Test fun `bounds skips arg with no bounds`() { - val gg = RustGenerics( - GenericTypeArg("A", testRT("Apple")), - GenericTypeArg("PL"), - GenericTypeArg("PE", testRT("Pear")), - ) + val gg = + RustGenerics( + GenericTypeArg("A", testRT("Apple")), + GenericTypeArg("PL"), + GenericTypeArg("PE", testRT("Pear")), + ) val writer = RustWriter.forModule("model") writer.rustTemplate("#{bounds:W}", "bounds" to gg.bounds()) - writer.toString() shouldContain """ + writer.toString() shouldContain + """ A: test::Apple, PE: test::Pear, - """.trimIndent() + """.trimIndent() } @Test fun `bounds generates nothing if all args are skipped`() { - val gg = RustGenerics( - GenericTypeArg("A"), - GenericTypeArg("PL"), - GenericTypeArg("PE"), - ) + val gg = + RustGenerics( + GenericTypeArg("A"), + GenericTypeArg("PL"), + GenericTypeArg("PE"), + ) val writer = RustWriter.forModule("model") writer.rustTemplate("A#{bounds:W}B", "bounds" to gg.bounds()) @@ -103,19 +108,22 @@ class RustGenericsTest { @Test fun `Adding GenericGenerators works`() { - val ggA = RustGenerics( - GenericTypeArg("A", testRT("Apple")), - ) - val ggB = RustGenerics( - GenericTypeArg("B", testRT("Banana")), - ) + val ggA = + RustGenerics( + GenericTypeArg("A", testRT("Apple")), + ) + val ggB = + RustGenerics( + GenericTypeArg("B", testRT("Banana")), + ) RustWriter.forModule("model").let { it.rustTemplate("#{bounds:W}", "bounds" to (ggA + ggB).bounds()) - it.toString() shouldContain """ + it.toString() shouldContain + """ A: test::Apple, B: test::Banana, - """.trimIndent() + """.trimIndent() } RustWriter.forModule("model").let { diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt index ec97799af42..99b0217eb9a 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustReservedWordsTest.kt @@ -23,20 +23,28 @@ import software.amazon.smithy.rust.codegen.core.util.lookup internal class RustReservedWordSymbolProviderTest { private class TestSymbolProvider(model: Model, nullabilityCheckMode: NullableIndex.CheckMode) : WrappingSymbolProvider(SymbolVisitor(testRustSettings(), model, null, testRustSymbolProviderConfig(nullabilityCheckMode))) + private val emptyConfig = RustReservedWordConfig(emptyMap(), emptyMap(), emptyMap()) @Test fun `structs are escaped`() { - val model = """ + val model = + """ namespace test structure Self {} - """.asSmithyModel() - val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model, NullableIndex.CheckMode.CLIENT), emptyConfig) + """.asSmithyModel() + val provider = + RustReservedWordSymbolProvider(TestSymbolProvider(model, NullableIndex.CheckMode.CLIENT), emptyConfig) val symbol = provider.toSymbol(model.lookup("test#Self")) symbol.name shouldBe "SelfValue" } - private fun mappingTest(config: RustReservedWordConfig, model: Model, id: String, test: (String) -> Unit) { + private fun mappingTest( + config: RustReservedWordConfig, + model: Model, + id: String, + test: (String) -> Unit, + ) { val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model, NullableIndex.CheckMode.CLIENT), config) val symbol = provider.toMemberName(model.lookup("test#Container\$$id")) test(symbol) @@ -44,39 +52,44 @@ internal class RustReservedWordSymbolProviderTest { @Test fun `structs member names are mapped via config`() { - val config = emptyConfig.copy( - structureMemberMap = mapOf( - "name_to_map" to "mapped_name", - "NameToMap" to "MappedName", - ), - ) - var model = """ + val config = + emptyConfig.copy( + structureMemberMap = + mapOf( + "name_to_map" to "mapped_name", + "NameToMap" to "MappedName", + ), + ) + var model = + """ namespace test structure Container { name_to_map: String } - """.asSmithyModel() + """.asSmithyModel() mappingTest(config, model, "name_to_map") { memberName -> memberName shouldBe "mapped_name" } - model = """ + model = + """ namespace test enum Container { NameToMap = "NameToMap" } - """.asSmithyModel(smithyVersion = "2.0") + """.asSmithyModel(smithyVersion = "2.0") mappingTest(config, model, "NameToMap") { memberName -> // Container was not a struct, so the field keeps its old name memberName shouldBe "NameToMap" } - model = """ + model = + """ namespace test union Container { NameToMap: String } - """.asSmithyModel() + """.asSmithyModel() mappingTest(config, model, "NameToMap") { memberName -> // Container was not a struct, so the field keeps its old name memberName shouldBe "NameToMap" @@ -85,40 +98,45 @@ internal class RustReservedWordSymbolProviderTest { @Test fun `union member names are mapped via config`() { - val config = emptyConfig.copy( - unionMemberMap = mapOf( - "name_to_map" to "mapped_name", - "NameToMap" to "MappedName", - ), - ) - - var model = """ + val config = + emptyConfig.copy( + unionMemberMap = + mapOf( + "name_to_map" to "mapped_name", + "NameToMap" to "MappedName", + ), + ) + + var model = + """ namespace test union Container { NameToMap: String } - """.asSmithyModel() + """.asSmithyModel() mappingTest(config, model, "NameToMap") { memberName -> memberName shouldBe "MappedName" } - model = """ + model = + """ namespace test structure Container { name_to_map: String } - """.asSmithyModel() + """.asSmithyModel() mappingTest(config, model, "name_to_map") { memberName -> // Container was not a union, so the field keeps its old name memberName shouldBe "name_to_map" } - model = """ + model = + """ namespace test enum Container { NameToMap = "NameToMap" } - """.asSmithyModel(smithyVersion = "2.0") + """.asSmithyModel(smithyVersion = "2.0") mappingTest(config, model, "NameToMap") { memberName -> // Container was not a union, so the field keeps its old name memberName shouldBe "NameToMap" @@ -127,13 +145,15 @@ internal class RustReservedWordSymbolProviderTest { @Test fun `member names are escaped`() { - val model = """ + val model = + """ namespace namespace structure container { async: String } - """.asSmithyModel() - val provider = RustReservedWordSymbolProvider(TestSymbolProvider(model, NullableIndex.CheckMode.CLIENT), emptyConfig) + """.asSmithyModel() + val provider = + RustReservedWordSymbolProvider(TestSymbolProvider(model, NullableIndex.CheckMode.CLIENT), emptyConfig) provider.toMemberName( MemberShape.builder().id("namespace#container\$async").target("namespace#Integer").build(), ) shouldBe "r##async" @@ -145,27 +165,35 @@ internal class RustReservedWordSymbolProviderTest { @Test fun `enum variant names are updated to avoid conflicts`() { - val model = """ + val model = + """ namespace foo @enum([{ name: "dontcare", value: "dontcare" }]) string Container - """.asSmithyModel() - val provider = RustReservedWordSymbolProvider( - TestSymbolProvider(model, NullableIndex.CheckMode.CLIENT), - reservedWordConfig = emptyConfig.copy( - enumMemberMap = mapOf( - "Unknown" to "UnknownValue", - "UnknownValue" to "UnknownValue_", - ), - ), - ) - - fun expectEnumRename(original: String, expected: MaybeRenamed) { - val symbol = provider.toSymbol( - MemberShape.builder() - .id(ShapeId.fromParts("foo", "Container").withMember(original)) - .target("smithy.api#String") - .build(), + """.asSmithyModel() + val provider = + RustReservedWordSymbolProvider( + TestSymbolProvider(model, NullableIndex.CheckMode.CLIENT), + reservedWordConfig = + emptyConfig.copy( + enumMemberMap = + mapOf( + "Unknown" to "UnknownValue", + "UnknownValue" to "UnknownValue_", + ), + ), ) + + fun expectEnumRename( + original: String, + expected: MaybeRenamed, + ) { + val symbol = + provider.toSymbol( + MemberShape.builder() + .id(ShapeId.fromParts("foo", "Container").withMember(original)) + .target("smithy.api#String") + .build(), + ) symbol.name shouldBe expected.name symbol.renamedFrom() shouldBe expected.renamedFrom } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustTypeTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustTypeTest.kt index fcd9583d497..c0a81cd90cd 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustTypeTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustTypeTest.kt @@ -19,7 +19,10 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.util.dq internal class RustTypesTest { - private fun forInputExpectOutput(t: Writable, expectedOutput: String) { + private fun forInputExpectOutput( + t: Writable, + expectedOutput: String, + ) { val writer = RustWriter.forModule("rust_types") writer.rustInlineTemplate("'") t.invoke(writer) @@ -152,17 +155,18 @@ internal class RustTypesTest { @Test fun `attribute macros from strings render properly`() { - val attributeMacro = Attribute( - Attribute.cfg( - Attribute.all( - Attribute.pair("feature" to "unstable".dq()), - Attribute.any( - Attribute.pair("feature" to "serialize".dq()), - Attribute.pair("feature" to "deserialize".dq()), + val attributeMacro = + Attribute( + Attribute.cfg( + Attribute.all( + Attribute.pair("feature" to "unstable".dq()), + Attribute.any( + Attribute.pair("feature" to "serialize".dq()), + Attribute.pair("feature" to "deserialize".dq()), + ), ), ), - ), - ) + ) forInputExpectOutput( writable { attributeMacro.render(this) @@ -173,16 +177,17 @@ internal class RustTypesTest { @Test fun `attribute macros render writers properly`() { - val attributeMacro = Attribute( - cfg( - all( - // Normally we'd use the `pair` fn to define these but this is a test - writable { rustInline("""feature = "unstable"""") }, - writable { rustInline("""feature = "serialize"""") }, - writable { rustInline("""feature = "deserialize"""") }, + val attributeMacro = + Attribute( + cfg( + all( + // Normally we'd use the `pair` fn to define these but this is a test + writable { rustInline("""feature = "unstable"""") }, + writable { rustInline("""feature = "serialize"""") }, + writable { rustInline("""feature = "deserialize"""") }, + ), ), - ), - ) + ) forInputExpectOutput( writable { attributeMacro.render(this) @@ -200,13 +205,14 @@ internal class RustTypesTest { @Test fun `derive attribute macros render properly`() { - val attributeMacro = Attribute( - derive( - RuntimeType.Clone, - RuntimeType.Debug, - RuntimeType.StdError, - ), - ) + val attributeMacro = + Attribute( + derive( + RuntimeType.Clone, + RuntimeType.Debug, + RuntimeType.StdError, + ), + ) forInputExpectOutput( writable { attributeMacro.render(this) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt index 2bd5269cc25..18f8cbfadc3 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/RustWriterTest.kt @@ -46,14 +46,16 @@ class RustWriterTest { @Test fun `manually created struct`() { val stringShape = StringShape.builder().id("test#Hello").build() - val set = SetShape.builder() - .id("foo.bar#Records") - .member(stringShape.id) - .build() - val model = Model.assembler() - .addShapes(set, stringShape) - .assemble() - .unwrap() + val set = + SetShape.builder() + .id("foo.bar#Records") + .member(stringShape.id) + .build() + val model = + Model.assembler() + .addShapes(set, stringShape) + .assemble() + .unwrap() val provider = testSymbolProvider(model) val setSymbol = provider.toSymbol(set) @@ -99,10 +101,11 @@ class RustWriterTest { @Test fun `generate doc links`() { - val model = """ + val model = + """ namespace test structure Foo {} - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#Foo") val symbol = testSymbolProvider(model).toSymbol(shape) val writer = RustWriter.root() @@ -136,11 +139,12 @@ class RustWriterTest { @Test fun `attributes with derive helpers must come after derives`() { val attr = Attribute("foo", isDeriveHelper = true) - val metadata = RustMetadata( - derives = setOf(RuntimeType.Debug), - additionalAttributes = listOf(Attribute.AllowDeprecated, attr), - visibility = Visibility.PUBLIC, - ) + val metadata = + RustMetadata( + derives = setOf(RuntimeType.Debug), + additionalAttributes = listOf(Attribute.AllowDeprecated, attr), + visibility = Visibility.PUBLIC, + ) val sut = RustWriter.root() metadata.render(sut) sut.toString().shouldContain("#[allow(deprecated)]\n#[derive(::std::fmt::Debug)]\n#[foo]") @@ -189,13 +193,14 @@ class RustWriterTest { @Test fun `missing template parameters are enclosed in backticks in the exception message`() { val sut = RustWriter.root() - val exception = assertThrows { - sut.rustTemplate( - "#{Foo} #{Bar}", - "Foo Bar" to CargoDependency.Http.toType().resolve("foo"), - "Baz" to CargoDependency.Http.toType().resolve("foo"), - ) - } + val exception = + assertThrows { + sut.rustTemplate( + "#{Foo} #{Bar}", + "Foo Bar" to CargoDependency.Http.toType().resolve("foo"), + "Baz" to CargoDependency.Http.toType().resolve("foo"), + ) + } exception.message shouldBe """ Rust block template expected `Foo` but was not present in template. diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/WritableTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/WritableTest.kt index a9b45582ef5..b847768c55a 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/WritableTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/rustlang/WritableTest.kt @@ -11,7 +11,10 @@ import org.junit.jupiter.api.Test import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType internal class RustTypeParametersTest { - private fun forInputExpectOutput(input: Any, expectedOutput: String) { + private fun forInputExpectOutput( + input: Any, + expectedOutput: String, + ) { val writer = RustWriter.forModule("model") writer.rustInlineTemplate("'") writer.rustInlineTemplate("#{typeParameters:W}", "typeParameters" to rustTypeParameters(input)) @@ -50,13 +53,14 @@ internal class RustTypeParametersTest { @Test fun `rustTypeParameters accepts heterogeneous inputs`() { val writer = RustWriter.forModule("model") - val tps = rustTypeParameters( - RuntimeType("crate::operation::Operation").toSymbol(), - RustType.Unit, - RuntimeType.String, - "T", - RustGenerics(GenericTypeArg("A"), GenericTypeArg("B")), - ) + val tps = + rustTypeParameters( + RuntimeType("crate::operation::Operation").toSymbol(), + RustType.Unit, + RuntimeType.String, + "T", + RustGenerics(GenericTypeArg("A"), GenericTypeArg("B")), + ) writer.rustInlineTemplate("'") writer.rustInlineTemplate("#{tps:W}", "tps" to tps) writer.rustInlineTemplate("'") diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegatorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegatorTest.kt index 6ed2fc5ed32..e1d6074bdcb 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegatorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/CodegenDelegatorTest.kt @@ -22,53 +22,56 @@ class CodegenDelegatorTest { CargoDependency("A", CratesIo("1"), Compile, optional = false, features = setOf("f1")), CargoDependency("A", CratesIo("1"), Compile, optional = false, features = setOf("f2")), CargoDependency("A", CratesIo("1"), Compile, optional = false, features = setOf("f1", "f2")), - CargoDependency("B", CratesIo("2"), Compile, optional = false, features = setOf()), CargoDependency("B", CratesIo("2"), Compile, optional = true, features = setOf()), - CargoDependency("C", CratesIo("3"), Compile, optional = true, features = setOf()), CargoDependency("C", CratesIo("3"), Compile, optional = true, features = setOf()), ).shuffled().mergeDependencyFeatures() - merged shouldBe setOf( - CargoDependency("A", CratesIo("1"), Compile, optional = false, features = setOf("f1", "f2")), - CargoDependency("B", CratesIo("2"), Compile, optional = false, features = setOf()), - CargoDependency("C", CratesIo("3"), Compile, optional = true, features = setOf()), - ) + merged shouldBe + setOf( + CargoDependency("A", CratesIo("1"), Compile, optional = false, features = setOf("f1", "f2")), + CargoDependency("B", CratesIo("2"), Compile, optional = false, features = setOf()), + CargoDependency("C", CratesIo("3"), Compile, optional = true, features = setOf()), + ) } @RepeatedTest(10) // Test it several times since the shuffle adds in some randomness fun testMergeDependencyFeaturesDontMergeDevOnlyFeatures() { - val merged = listOf( - CargoDependency("A", CratesIo("1"), Compile, features = setOf("a")), - CargoDependency("A", CratesIo("1"), Compile, features = setOf("b")), - CargoDependency("A", CratesIo("1"), Dev, features = setOf("c")), - CargoDependency("A", CratesIo("1"), Dev, features = setOf("test-util")), - ).shuffled().mergeDependencyFeatures() - .sortedBy { it.scope } + val merged = + listOf( + CargoDependency("A", CratesIo("1"), Compile, features = setOf("a")), + CargoDependency("A", CratesIo("1"), Compile, features = setOf("b")), + CargoDependency("A", CratesIo("1"), Dev, features = setOf("c")), + CargoDependency("A", CratesIo("1"), Dev, features = setOf("test-util")), + ).shuffled().mergeDependencyFeatures() + .sortedBy { it.scope } - merged shouldBe setOf( - CargoDependency("A", CratesIo("1"), Compile, features = setOf("a", "b")), - CargoDependency("A", CratesIo("1"), Dev, features = setOf("c", "test-util")), - ) + merged shouldBe + setOf( + CargoDependency("A", CratesIo("1"), Compile, features = setOf("a", "b")), + CargoDependency("A", CratesIo("1"), Dev, features = setOf("c", "test-util")), + ) } @Test fun testMergeIdenticalFeatures() { - val merged = listOf( - CargoDependency("A", CratesIo("1"), Compile), - CargoDependency("A", CratesIo("1"), Dev), - CargoDependency("B", CratesIo("1"), Compile), - CargoDependency("B", CratesIo("1"), Dev, features = setOf("a", "b")), - CargoDependency("C", CratesIo("1"), Compile), - CargoDependency("C", CratesIo("1"), Dev, features = setOf("test-util")), - ).mergeIdenticalTestDependencies() - merged shouldBe setOf( - CargoDependency("A", CratesIo("1"), Compile), - CargoDependency("B", CratesIo("1"), Compile), - CargoDependency("B", CratesIo("1"), Dev, features = setOf("a", "b")), - CargoDependency("C", CratesIo("1"), Compile), - CargoDependency("C", CratesIo("1"), Dev, features = setOf("test-util")), - ) + val merged = + listOf( + CargoDependency("A", CratesIo("1"), Compile), + CargoDependency("A", CratesIo("1"), Dev), + CargoDependency("B", CratesIo("1"), Compile), + CargoDependency("B", CratesIo("1"), Dev, features = setOf("a", "b")), + CargoDependency("C", CratesIo("1"), Compile), + CargoDependency("C", CratesIo("1"), Dev, features = setOf("test-util")), + ).mergeIdenticalTestDependencies() + merged shouldBe + setOf( + CargoDependency("A", CratesIo("1"), Compile), + CargoDependency("B", CratesIo("1"), Compile), + CargoDependency("B", CratesIo("1"), Dev, features = setOf("a", "b")), + CargoDependency("C", CratesIo("1"), Compile), + CargoDependency("C", CratesIo("1"), Dev, features = setOf("test-util")), + ) } } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeTypeTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeTypeTest.kt index b3dec08b7c4..285ec032154 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeTypeTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/RuntimeTypeTest.kt @@ -42,51 +42,52 @@ class RuntimeTypesTest { crateLoc.crateLocation("aws-smithy-runtime-api") shouldBe Local("/foo", null) crateLoc.crateLocation("aws-smithy-http") shouldBe Local("/foo", null) - val crateLocVersioned = RuntimeCrateLocation(null, CrateVersionMap(mapOf("aws-smithy-runtime-api" to "999.999"))) - crateLocVersioned.crateLocation("aws-smithy-runtime") shouldBe CratesIo(Version.stableCrateVersion()) + val crateLocVersioned = + RuntimeCrateLocation(null, CrateVersionMap(mapOf("aws-smithy-runtime-api" to "999.999"))) + crateLocVersioned.crateLocation("aws-smithy-runtime") shouldBe CratesIo(Version.crateVersion("aws-smithy-runtime")) crateLocVersioned.crateLocation("aws-smithy-runtime-api") shouldBe CratesIo("999.999") - crateLocVersioned.crateLocation("aws-smithy-http") shouldBe CratesIo(Version.unstableCrateVersion()) + crateLocVersioned.crateLocation("aws-smithy-http") shouldBe CratesIo(Version.crateVersion("aws-smithy-http")) } companion object { - @JvmStatic - fun runtimeConfigProvider() = listOf( - Arguments.of( - "{}", - RuntimeCrateLocation(null, CrateVersionMap(mapOf())), - ), - Arguments.of( - """ - { - "relativePath": "/path" - } - """, - RuntimeCrateLocation("/path", CrateVersionMap(mapOf())), - ), - Arguments.of( - """ - { - "versions": { - "a": "1.0", - "b": "2.0" + fun runtimeConfigProvider() = + listOf( + Arguments.of( + "{}", + RuntimeCrateLocation(null, CrateVersionMap(mapOf())), + ), + Arguments.of( + """ + { + "relativePath": "/path" + } + """, + RuntimeCrateLocation("/path", CrateVersionMap(mapOf())), + ), + Arguments.of( + """ + { + "versions": { + "a": "1.0", + "b": "2.0" + } } - } - """, - RuntimeCrateLocation(null, CrateVersionMap(mapOf("a" to "1.0", "b" to "2.0"))), - ), - Arguments.of( - """ - { - "relativePath": "/path", - "versions": { - "a": "1.0", - "b": "2.0" + """, + RuntimeCrateLocation(null, CrateVersionMap(mapOf("a" to "1.0", "b" to "2.0"))), + ), + Arguments.of( + """ + { + "relativePath": "/path", + "versions": { + "a": "1.0", + "b": "2.0" + } } - } - """, - RuntimeCrateLocation("/path", CrateVersionMap(mapOf("a" to "1.0", "b" to "2.0"))), - ), - ) + """, + RuntimeCrateLocation("/path", CrateVersionMap(mapOf("a" to "1.0", "b" to "2.0"))), + ), + ) } } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitorTest.kt index 06485823c69..4821ecaf0c6 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/SymbolVisitorTest.kt @@ -40,14 +40,16 @@ class SymbolVisitorTest { fun `creates structures`() { val memberBuilder = MemberShape.builder().id("foo.bar#MyStruct\$someField").target("smithy.api#String") val member = memberBuilder.build() - val struct = StructureShape.builder() - .id("foo.bar#MyStruct") - .addMember(member) - .build() - val model = Model.assembler() - .addShapes(struct, member) - .assemble() - .unwrap() + val struct = + StructureShape.builder() + .id("foo.bar#MyStruct") + .addMember(member) + .build() + val model = + Model.assembler() + .addShapes(struct, member) + .assemble() + .unwrap() val provider: SymbolProvider = testSymbolProvider(model) val sym = provider.toSymbol(struct) sym.rustType().render(false) shouldBe "MyStruct" @@ -59,15 +61,17 @@ class SymbolVisitorTest { fun `renames errors`() { val memberBuilder = MemberShape.builder().id("foo.bar#TerribleException\$someField").target("smithy.api#String") val member = memberBuilder.build() - val struct = StructureShape.builder() - .id("foo.bar#TerribleException") - .addMember(member) - .addTrait(ErrorTrait("server")) - .build() - val model = Model.assembler() - .addShapes(struct, member) - .assemble() - .unwrap() + val struct = + StructureShape.builder() + .id("foo.bar#TerribleException") + .addMember(member) + .addTrait(ErrorTrait("server")) + .build() + val model = + Model.assembler() + .addShapes(struct, member) + .assemble() + .unwrap() val provider: SymbolProvider = testSymbolProvider(model) val sym = provider.toSymbol(struct) sym.rustType().render(false) shouldBe "TerribleError" @@ -76,7 +80,8 @@ class SymbolVisitorTest { @Test fun `creates enums`() { - val model = """ + val model = + """ namespace test @enum([ @@ -90,7 +95,7 @@ class SymbolVisitorTest { } ]) string StandardUnit - """.asSmithyModel() + """.asSmithyModel() val shape = model.expectShape(ShapeId.from("test#StandardUnit")) val provider: SymbolProvider = testSymbolProvider(model) val sym = provider.toSymbol(shape) @@ -118,13 +123,18 @@ class SymbolVisitorTest { "Boolean, true, bool", "PrimitiveBoolean, false, bool", ) - fun `creates primitives`(primitiveType: String, optional: Boolean, rustName: String) { - val model = """ + fun `creates primitives`( + primitiveType: String, + optional: Boolean, + rustName: String, + ) { + val model = + """ namespace foo.bar structure MyStruct { quux: $primitiveType } - """.asSmithyModel() + """.asSmithyModel() val member = model.expectShape(ShapeId.from("foo.bar#MyStruct\$quux")) val provider: SymbolProvider = testSymbolProvider(model) val memberSymbol = provider.toSymbol(member) @@ -142,14 +152,16 @@ class SymbolVisitorTest { @Test fun `creates sets of strings`() { val stringShape = StringShape.builder().id("test#Hello").build() - val set = SetShape.builder() - .id("foo.bar#Records") - .member(stringShape.id) - .build() - val model = Model.assembler() - .addShapes(set, stringShape) - .assemble() - .unwrap() + val set = + SetShape.builder() + .id("foo.bar#Records") + .member(stringShape.id) + .build() + val model = + Model.assembler() + .addShapes(set, stringShape) + .assemble() + .unwrap() val provider: SymbolProvider = testSymbolProvider(model) val setSymbol = provider.toSymbol(set) @@ -161,14 +173,16 @@ class SymbolVisitorTest { fun `create vec instead for non-strings`() { val struct = StructureShape.builder().id("foo.bar#Record").build() val setMember = MemberShape.builder().id("foo.bar#Records\$member").target(struct).build() - val set = SetShape.builder() - .id("foo.bar#Records") - .member(setMember) - .build() - val model = Model.assembler() - .addShapes(set, setMember, struct) - .assemble() - .unwrap() + val set = + SetShape.builder() + .id("foo.bar#Records") + .member(setMember) + .build() + val model = + Model.assembler() + .addShapes(set, setMember, struct) + .assemble() + .unwrap() val provider: SymbolProvider = testSymbolProvider(model) val setSymbol = provider.toSymbol(set) @@ -180,16 +194,18 @@ class SymbolVisitorTest { fun `create sparse collections`() { val struct = StructureShape.builder().id("foo.bar#Record").build() val setMember = MemberShape.builder().id("foo.bar#Records\$member").target(struct).build() - val set = ListShape.builder() - .id("foo.bar#Records") - .member(setMember) - .addTrait(SparseTrait()) - .build() - val model = Model.assembler() - .putProperty(ModelAssembler.ALLOW_UNKNOWN_TRAITS, true) - .addShapes(set, setMember, struct) - .assemble() - .unwrap() + val set = + ListShape.builder() + .id("foo.bar#Records") + .member(setMember) + .addTrait(SparseTrait()) + .build() + val model = + Model.assembler() + .putProperty(ModelAssembler.ALLOW_UNKNOWN_TRAITS, true) + .addShapes(set, setMember, struct) + .assemble() + .unwrap() val provider: SymbolProvider = testSymbolProvider(model) val setSymbol = provider.toSymbol(set) @@ -201,14 +217,16 @@ class SymbolVisitorTest { fun `create timestamps`() { val memberBuilder = MemberShape.builder().id("foo.bar#MyStruct\$someField").target("smithy.api#Timestamp") val member = memberBuilder.build() - val struct = StructureShape.builder() - .id("foo.bar#MyStruct") - .addMember(member) - .build() - val model = Model.assembler() - .addShapes(struct, member) - .assemble() - .unwrap() + val struct = + StructureShape.builder() + .id("foo.bar#MyStruct") + .addMember(member) + .build() + val model = + Model.assembler() + .addShapes(struct, member) + .assemble() + .unwrap() val provider: SymbolProvider = testSymbolProvider(model) val sym = provider.toSymbol(member) sym.rustType().render(false) shouldBe "Option" @@ -218,7 +236,8 @@ class SymbolVisitorTest { @Test fun `creates operations`() { - val model = """ + val model = + """ namespace smithy.example @idempotent @@ -252,7 +271,7 @@ class SymbolVisitorTest { // Sent in the body additional: String, } - """.asSmithyModel() + """.asSmithyModel() val symbol = testSymbolProvider(model).toSymbol(model.expectShape(ShapeId.from("smithy.example#PutObject"))) symbol.definitionFile shouldBe "src/test_operation.rs" symbol.name shouldBe "PutObject" diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtraTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtraTest.kt index f9eda03a43f..e320b9745a0 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtraTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/customizations/SmithyTypesPubUseExtraTest.kt @@ -10,7 +10,6 @@ import software.amazon.smithy.model.Model import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext import software.amazon.smithy.rust.codegen.core.smithy.RustCrate -import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureGeneratorTest.Companion.model import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.core.testutil.generatePluginContext import software.amazon.smithy.rust.codegen.core.testutil.testCodegenContext @@ -25,6 +24,11 @@ class SmithyTypesPubUseExtraTest { return """ namespace test + service TestService { + version: "123" + operations: [SomeOperation] + } + $additionalShape structure SomeStruct { } @@ -46,50 +50,65 @@ class SmithyTypesPubUseExtraTest { """.asSmithyModel() } - private val rustCrate: RustCrate - private val codegenContext: CodegenContext = testCodegenContext(model) - - init { - val (context, _) = generatePluginContext( - model, - runtimeConfig = codegenContext.runtimeConfig, - ) - rustCrate = RustCrate( - context.fileManifest, - codegenContext.symbolProvider, - codegenContext.settings.codegenConfig, - codegenContext.expectModuleDocProvider(), - ) + private fun initialize(model: Model): Pair { + val codegenContext = testCodegenContext(model) + + val (context, _) = + generatePluginContext( + model, + runtimeConfig = codegenContext.runtimeConfig, + ) + val rustCrate = + RustCrate( + context.fileManifest, + codegenContext.symbolProvider, + codegenContext.settings.codegenConfig, + codegenContext.expectModuleDocProvider(), + ) + + return Pair(codegenContext, rustCrate) } private fun reexportsWithEmptyModel() = reexportsWithMember() + private fun reexportsWithMember( inputMember: String = "", outputMember: String = "", unionMember: String = "", additionalShape: String = "", ) = RustWriter.root().let { writer -> - pubUseSmithyPrimitives( - codegenContext, - modelWithMember(inputMember, outputMember, unionMember, additionalShape), - rustCrate, - )(writer) + val model = modelWithMember(inputMember, outputMember, unionMember, additionalShape) + val props = initialize(model) + val context = props.first + val rustCrate = props.second + pubUseSmithyPrimitives(context, model, rustCrate)(writer) + pubUseSmithyPrimitivesEventStream(context, model)(writer) writer.toString() } - private fun assertDoesntHaveReexports(reexports: String, expectedTypes: List) = - expectedTypes.forEach { assertDoesntHaveReexports(reexports, it) } + private fun assertDoesntHaveReexports( + reexports: String, + expectedTypes: List, + ) = expectedTypes.forEach { assertDoesntHaveReexports(reexports, it) } - private fun assertDoesntHaveReexports(reexports: String, type: String) { + private fun assertDoesntHaveReexports( + reexports: String, + type: String, + ) { if (reexports.contains(type)) { throw AssertionError("Expected $type to NOT be re-exported, but it was.") } } - private fun assertHasReexports(reexports: String, expectedTypes: List) = - expectedTypes.forEach { assertHasReexport(reexports, it) } + private fun assertHasReexports( + reexports: String, + expectedTypes: List, + ) = expectedTypes.forEach { assertHasReexport(reexports, it) } - private fun assertHasReexport(reexports: String, type: String) { + private fun assertHasReexport( + reexports: String, + type: String, + ) { if (!reexports.contains(type)) { throw AssertionError("Expected $type to be re-exported. Re-exported types:\n$reexports") } @@ -151,4 +170,26 @@ class SmithyTypesPubUseExtraTest { streamingTypes, ) } + + @Test + fun `it re-exports when a model has event stream`() { + val eventStreamTypes = + listOf( + "crate::event_receiver::EventReceiver", + "::aws_smithy_types::event_stream::Header", + "::aws_smithy_types::event_stream::HeaderValue", + "::aws_smithy_types::event_stream::Message", + "::aws_smithy_types::str_bytes::StrBytes", + ) + val eventStreamShape = "@streaming union EventStream { foo: SomeStruct }" + + assertHasReexports( + reexportsWithMember(additionalShape = eventStreamShape, inputMember = "m: EventStream"), + eventStreamTypes, + ) + assertHasReexports( + reexportsWithMember(additionalShape = eventStreamShape, outputMember = "m: EventStream"), + eventStreamTypes, + ) + } } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index a7c1342a443..179b89512dc 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -71,11 +71,12 @@ internal class BuilderGeneratorTest { @Test fun `generate fallible builders`() { val baseProvider = testSymbolProvider(StructureGeneratorTest.model) - val provider = object : WrappingSymbolProvider(baseProvider) { - override fun toSymbol(shape: Shape): Symbol { - return baseProvider.toSymbol(shape).toBuilder().setDefault(Default.NoDefault).build() + val provider = + object : WrappingSymbolProvider(baseProvider) { + override fun toSymbol(shape: Shape): Symbol { + return baseProvider.toSymbol(shape).toBuilder().setDefault(Default.NoDefault).build() + } } - } val project = TestWorkspace.testProject(provider) project.moduleFor(StructureGeneratorTest.struct) { @@ -101,7 +102,12 @@ internal class BuilderGeneratorTest { project.compileAndTest() } - private fun generator(model: Model, provider: RustSymbolProvider, writer: RustWriter, shape: StructureShape) = StructureGenerator(model, provider, writer, shape, emptyList(), StructSettings(flattenVecAccessors = true)) + private fun generator( + model: Model, + provider: RustSymbolProvider, + writer: RustWriter, + shape: StructureShape, + ) = StructureGenerator(model, provider, writer, shape, emptyList(), StructSettings(flattenVecAccessors = true)) @Test fun `builder for a struct with sensitive fields should implement the debug trait as such`() { @@ -181,7 +187,8 @@ internal class BuilderGeneratorTest { @Test fun `it supports nonzero defaults`() { - val model = """ + val model = + """ namespace com.test structure MyStruct { @default(0) @@ -225,13 +232,14 @@ internal class BuilderGeneratorTest { @default(1) integer OneDefault - """.asSmithyModel(smithyVersion = "2.0") + """.asSmithyModel(smithyVersion = "2.0") - val provider = testSymbolProvider( - model, - rustReservedWordConfig = StructureGeneratorTest.rustReservedWordConfig, - nullabilityCheckMode = NullableIndex.CheckMode.CLIENT_CAREFUL, - ) + val provider = + testSymbolProvider( + model, + rustReservedWordConfig = StructureGeneratorTest.rustReservedWordConfig, + nullabilityCheckMode = NullableIndex.CheckMode.CLIENT_CAREFUL, + ) val project = TestWorkspace.testProject(provider) val shape: StructureShape = model.lookup("com.test#MyStruct") project.useShapeWriter(shape) { diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/CargoTomlGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/CargoTomlGeneratorTest.kt index c57ebdc727f..dc115e5db91 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/CargoTomlGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/CargoTomlGeneratorTest.kt @@ -36,7 +36,7 @@ class CargoTomlGeneratorTest { .expect("missing `smithy.codegen-version` field") .as_str() .expect("`smithy.codegen-version` is not str"); - assert_eq!(codegen_version, "${Version.fullVersion()}"); + assert_eq!(codegen_version, "${Version.fromDefaultResource().gitHash}"); """, ) } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt index b233a763bd7..b0fa42ef0fc 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/EnumGeneratorTest.kt @@ -31,15 +31,17 @@ import software.amazon.smithy.rust.codegen.core.util.lookup import software.amazon.smithy.rust.codegen.core.util.orNull class EnumGeneratorTest { - private val rustReservedWordConfig = RustReservedWordConfig( - enumMemberMap = mapOf("Unknown" to "UnknownValue"), - structureMemberMap = emptyMap(), - unionMemberMap = emptyMap(), - ) + private val rustReservedWordConfig = + RustReservedWordConfig( + enumMemberMap = mapOf("Unknown" to "UnknownValue"), + structureMemberMap = emptyMap(), + unionMemberMap = emptyMap(), + ) @Nested inner class EnumMemberModelTests { - private val testModel = """ + private val testModel = + """ namespace test @enum([ { value: "some-value-1", @@ -53,16 +55,17 @@ class EnumGeneratorTest { documentation: "It has some docs that #need to be escaped" } ]) string EnumWithUnknown - """.asSmithyModel() + """.asSmithyModel() private val symbolProvider = testSymbolProvider(testModel, rustReservedWordConfig = rustReservedWordConfig) private val enumTrait = testModel.lookup("test#EnumWithUnknown").expectTrait() - private fun model(name: String): EnumMemberModel = EnumMemberModel( - testModel.lookup("test#EnumWithUnknown"), - enumTrait.values.first { it.name.orNull() == name }, - symbolProvider, - ) + private fun model(name: String): EnumMemberModel = + EnumMemberModel( + testModel.lookup("test#EnumWithUnknown"), + enumTrait.values.first { it.name.orNull() == name }, + symbolProvider, + ) @Test fun `it converts enum names to PascalCase and renames any named Unknown to UnknownValue`() { @@ -114,7 +117,8 @@ class EnumGeneratorTest { @Test fun `it generates named enums`() { - val model = """ + val model = + """ namespace test @enum([ { @@ -133,7 +137,7 @@ class EnumGeneratorTest { ]) @deprecated(since: "1.2.3") string InstanceType - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#InstanceType") val provider = testSymbolProvider(model) @@ -162,7 +166,8 @@ class EnumGeneratorTest { @Test fun `named enums implement eq and hash`() { - val model = """ + val model = + """ namespace test @enum([ { @@ -174,7 +179,7 @@ class EnumGeneratorTest { name: "Bar" }]) string FooEnum - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#FooEnum") val provider = testSymbolProvider(model) @@ -196,7 +201,8 @@ class EnumGeneratorTest { @Test fun `unnamed enums implement eq and hash`() { - val model = """ + val model = + """ namespace test @enum([ { @@ -207,7 +213,7 @@ class EnumGeneratorTest { }]) @deprecated string FooEnum - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#FooEnum") val provider = testSymbolProvider(model) @@ -230,7 +236,8 @@ class EnumGeneratorTest { @Test fun `it generates unnamed enums`() { - val model = """ + val model = + """ namespace test @enum([ { @@ -250,7 +257,7 @@ class EnumGeneratorTest { }, ]) string FooEnum - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#FooEnum") val provider = testSymbolProvider(model) @@ -271,7 +278,8 @@ class EnumGeneratorTest { @Test fun `it should generate documentation for enums`() { - val model = """ + val model = + """ namespace test /// Some top-level documentation. @@ -280,7 +288,7 @@ class EnumGeneratorTest { { name: "Unknown", value: "Unknown" }, ]) string SomeEnum - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#SomeEnum") val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) @@ -300,7 +308,8 @@ class EnumGeneratorTest { @Test fun `it should generate documentation for unnamed enums`() { - val model = """ + val model = + """ namespace test /// Some top-level documentation. @@ -309,7 +318,7 @@ class EnumGeneratorTest { { value: "Two" }, ]) string SomeEnum - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#SomeEnum") val provider = testSymbolProvider(model) @@ -327,14 +336,15 @@ class EnumGeneratorTest { @Test fun `it handles variants that clash with Rust reserved words`() { - val model = """ + val model = + """ namespace test @enum([ { name: "Known", value: "Known" }, { name: "Self", value: "other" }, ]) string SomeEnum - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#SomeEnum") val provider = testSymbolProvider(model) @@ -351,14 +361,15 @@ class EnumGeneratorTest { @Test fun `impl debug for non-sensitive enum should implement the derived debug trait`() { - val model = """ + val model = + """ namespace test @enum([ { name: "Foo", value: "Foo" }, { name: "Bar", value: "Bar" }, ]) string SomeEnum - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#SomeEnum") val provider = testSymbolProvider(model) @@ -378,7 +389,8 @@ class EnumGeneratorTest { @Test fun `impl debug for sensitive enum should redact text`() { - val model = """ + val model = + """ namespace test @sensitive @enum([ @@ -386,7 +398,7 @@ class EnumGeneratorTest { { name: "Bar", value: "Bar" }, ]) string SomeEnum - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#SomeEnum") val provider = testSymbolProvider(model) @@ -406,14 +418,15 @@ class EnumGeneratorTest { @Test fun `impl debug for non-sensitive unnamed enum should implement the derived debug trait`() { - val model = """ + val model = + """ namespace test @enum([ { value: "Foo" }, { value: "Bar" }, ]) string SomeEnum - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#SomeEnum") val provider = testSymbolProvider(model) @@ -437,7 +450,8 @@ class EnumGeneratorTest { @Test fun `impl debug for sensitive unnamed enum should redact text`() { - val model = """ + val model = + """ namespace test @sensitive @enum([ @@ -445,7 +459,7 @@ class EnumGeneratorTest { { value: "Bar" }, ]) string SomeEnum - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#SomeEnum") val provider = testSymbolProvider(model) @@ -470,41 +484,48 @@ class EnumGeneratorTest { @Test fun `it supports other enum types`() { class CustomizingEnumType : EnumType() { - override fun implFromForStr(context: EnumGeneratorContext): Writable = writable { - // intentional no-op - } + override fun implFromForStr(context: EnumGeneratorContext): Writable = + writable { + // intentional no-op + } - override fun implFromStr(context: EnumGeneratorContext): Writable = writable { - // intentional no-op - } + override fun implFromStr(context: EnumGeneratorContext): Writable = + writable { + // intentional no-op + } - override fun additionalEnumMembers(context: EnumGeneratorContext): Writable = writable { - rust("// additional enum members") - } + override fun additionalEnumMembers(context: EnumGeneratorContext): Writable = + writable { + rust("// additional enum members") + } - override fun additionalAsStrMatchArms(context: EnumGeneratorContext): Writable = writable { - rust("// additional as_str match arm") - } + override fun additionalAsStrMatchArms(context: EnumGeneratorContext): Writable = + writable { + rust("// additional as_str match arm") + } - override fun additionalDocs(context: EnumGeneratorContext): Writable = writable { - rust("// additional docs") - } + override fun additionalDocs(context: EnumGeneratorContext): Writable = + writable { + rust("// additional docs") + } } - val model = """ + val model = + """ namespace test @enum([ { name: "Known", value: "Known" }, { name: "Self", value: "other" }, ]) string SomeEnum - """.asSmithyModel() + """.asSmithyModel() val shape = model.lookup("test#SomeEnum") val provider = testSymbolProvider(model) - val output = RustWriter.root().apply { - renderEnum(model, provider, shape, CustomizingEnumType()) - }.toString() + val output = + RustWriter.root().apply { + renderEnum(model, provider, shape, CustomizingEnumType()) + }.toString() // Since we didn't use the Infallible EnumType, there should be no Unknown variant output shouldNotContain "Unknown" diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/InstantiatorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/InstantiatorTest.kt index aa89acbb2bf..346eaf103c7 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/InstantiatorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/InstantiatorTest.kt @@ -10,6 +10,8 @@ import software.amazon.smithy.model.node.Node import software.amazon.smithy.model.node.NumberNode import software.amazon.smithy.model.node.StringNode import software.amazon.smithy.model.shapes.BlobShape +import software.amazon.smithy.model.shapes.DoubleShape +import software.amazon.smithy.model.shapes.FloatShape import software.amazon.smithy.model.shapes.MemberShape import software.amazon.smithy.model.shapes.ShapeId import software.amazon.smithy.model.shapes.StructureShape @@ -32,7 +34,8 @@ import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.lookup class InstantiatorTest { - private val model = """ + private val model = + """ namespace com.test @documentation("this documents the shape") @@ -84,7 +87,9 @@ class InstantiatorTest { @required num: Integer } - """.asSmithyModel().let { RecursiveShapeBoxer().transform(it) } + """.asSmithyModel().let { + RecursiveShapeBoxer().transform(it) + } private val codegenContext = testCodegenContext(model) private val symbolProvider = codegenContext.symbolProvider @@ -150,16 +155,17 @@ class InstantiatorTest { val structure = model.lookup("com.test#WithBox") val sut = Instantiator(symbolProvider, model, runtimeConfig, BuilderKindBehavior(codegenContext)) - val data = Node.parse( - """ - { - "member": { - "member": { } - }, - "value": 10 - } - """, - ) + val data = + Node.parse( + """ + { + "member": { + "member": { } + }, + "value": 10 + } + """, + ) val project = TestWorkspace.testProject(model) structure.renderWithModelBuilder(model, symbolProvider, project) @@ -204,12 +210,13 @@ class InstantiatorTest { @Test fun `generate sparse lists`() { val data = Node.parse(""" [ "bar", "foo", null ] """) - val sut = Instantiator( - symbolProvider, - model, - runtimeConfig, - BuilderKindBehavior(codegenContext), - ) + val sut = + Instantiator( + symbolProvider, + model, + runtimeConfig, + BuilderKindBehavior(codegenContext), + ) val project = TestWorkspace.testProject(model) project.lib { @@ -225,21 +232,23 @@ class InstantiatorTest { @Test fun `generate maps of maps`() { - val data = Node.parse( - """ - { - "k1": { "map": {} }, - "k2": { "map": { "k3": {} } }, - "k3": { } - } - """, - ) - val sut = Instantiator( - symbolProvider, - model, - runtimeConfig, - BuilderKindBehavior(codegenContext), - ) + val data = + Node.parse( + """ + { + "k1": { "map": {} }, + "k2": { "map": { "k3": {} } }, + "k3": { } + } + """, + ) + val sut = + Instantiator( + symbolProvider, + model, + runtimeConfig, + BuilderKindBehavior(codegenContext), + ) val inner = model.lookup("com.test#Inner") val project = TestWorkspace.testProject(model) @@ -266,12 +275,13 @@ class InstantiatorTest { fun `blob inputs are binary data`() { // "Parameter values that contain binary data MUST be defined using values // that can be represented in plain text (for example, use "foo" and not "Zm9vCg==")." - val sut = Instantiator( - symbolProvider, - model, - runtimeConfig, - BuilderKindBehavior(codegenContext), - ) + val sut = + Instantiator( + symbolProvider, + model, + runtimeConfig, + BuilderKindBehavior(codegenContext), + ) val project = TestWorkspace.testProject(model) project.testModule { @@ -293,12 +303,13 @@ class InstantiatorTest { fun `integer and fractional timestamps`() { // "Parameter values that contain binary data MUST be defined using values // that can be represented in plain text (for example, use "foo" and not "Zm9vCg==")." - val sut = Instantiator( - symbolProvider, - model, - runtimeConfig, - BuilderKindBehavior(codegenContext), - ) + val sut = + Instantiator( + symbolProvider, + model, + runtimeConfig, + BuilderKindBehavior(codegenContext), + ) val project = TestWorkspace.testProject(model) project.testModule { unitTest("timestamps") { @@ -328,4 +339,45 @@ class InstantiatorTest { } project.compileAndTest() } + + @Test + fun `floating-point number instantiation`() { + val sut = + Instantiator( + symbolProvider, + model, + runtimeConfig, + BuilderKindBehavior(codegenContext), + ) + val project = TestWorkspace.testProject(model) + project.testModule { + unitTest("default_number_instantiation") { + for ((value, node) in arrayOf( + "1.0" to NumberNode.from(1), + "1.5" to NumberNode.from(1.5), + "1.0" to StringNode.from("1"), + "1.5" to StringNode.from("1.5"), + )) { + withBlock("let value: f32 = ", ";") { + sut.render( + this, + FloatShape.builder().id(ShapeId.from("com.example#FloatShape")).build(), + node, + ) + } + rustTemplate("assert_eq!($value, value);") + + withBlock("let value: f64 = ", ";") { + sut.render( + this, + DoubleShape.builder().id(ShapeId.from("com.example#DoubleShape")).build(), + node, + ) + } + rustTemplate("assert_eq!($value, value);") + } + } + } + project.compileAndTest() + } } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGeneratorTest.kt index f31fd538e83..c197a7cb4c0 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/StructureGeneratorTest.kt @@ -87,14 +87,20 @@ class StructureGeneratorTest { val secretStructure = model.lookup("com.test#SecretStructure") val structWithInnerSecretStructure = model.lookup("com.test#StructWithInnerSecretStructure") - val rustReservedWordConfig: RustReservedWordConfig = RustReservedWordConfig( - structureMemberMap = StructureGenerator.structureMemberNameMap, - enumMemberMap = emptyMap(), - unionMemberMap = emptyMap(), - ) + val rustReservedWordConfig: RustReservedWordConfig = + RustReservedWordConfig( + structureMemberMap = StructureGenerator.structureMemberNameMap, + enumMemberMap = emptyMap(), + unionMemberMap = emptyMap(), + ) } - private fun structureGenerator(model: Model, provider: RustSymbolProvider, writer: RustWriter, shape: StructureShape) = StructureGenerator(model, provider, writer, shape, emptyList(), StructSettings(flattenVecAccessors = true)) + private fun structureGenerator( + model: Model, + provider: RustSymbolProvider, + writer: RustWriter, + shape: StructureShape, + ) = StructureGenerator(model, provider, writer, shape, emptyList(), StructSettings(flattenVecAccessors = true)) @Test fun `generate basic structures`() { @@ -213,7 +219,8 @@ class StructureGeneratorTest { @Test fun `attach docs to everything`() { - val model = """ + val model = + """ namespace com.test @documentation("inner doc") structure Inner { } @@ -259,7 +266,8 @@ class StructureGeneratorTest { @Test fun `deprecated trait with message and since`() { - val model = """ + val model = + """ namespace test @deprecated @@ -273,7 +281,7 @@ class StructureGeneratorTest { @deprecated(message: "Fly, you fools!", since: "1.2.3") structure Qux {} - """.asSmithyModel() + """.asSmithyModel() val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) val project = TestWorkspace.testProject(provider) project.lib { rust("##![allow(deprecated)]") } @@ -290,7 +298,8 @@ class StructureGeneratorTest { @Test fun `nested deprecated trait`() { - val model = """ + val model = + """ namespace test structure Nested { @@ -306,7 +315,7 @@ class StructureGeneratorTest { @deprecated structure Bar {} - """.asSmithyModel() + """.asSmithyModel() val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) val project = TestWorkspace.testProject(provider) project.lib { rust("##![allow(deprecated)]") } @@ -404,7 +413,8 @@ class StructureGeneratorTest { @Test fun `fields are NOT doc-hidden`() { - val model = """ + val model = + """ namespace com.test structure MyStruct { foo: String, @@ -413,7 +423,7 @@ class StructureGeneratorTest { ts: Timestamp, byteValue: Byte, } - """.asSmithyModel() + """.asSmithyModel() val struct = model.lookup("com.test#MyStruct") val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) @@ -425,11 +435,12 @@ class StructureGeneratorTest { @Test fun `streaming fields are NOT doc-hidden`() { - val model = """ + val model = + """ namespace com.test @streaming blob SomeStreamingThing structure MyStruct { foo: SomeStreamingThing } - """.asSmithyModel() + """.asSmithyModel() val struct = model.lookup("com.test#MyStruct") val provider = testSymbolProvider(model, rustReservedWordConfig = rustReservedWordConfig) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/TestEnumType.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/TestEnumType.kt index e8ea12c0dbc..5699c9e5cad 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/TestEnumType.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/TestEnumType.kt @@ -13,37 +13,40 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.util.dq object TestEnumType : EnumType() { - override fun implFromForStr(context: EnumGeneratorContext): Writable = writable { - rustTemplate( - """ - impl #{From}<&str> for ${context.enumName} { - fn from(s: &str) -> Self { - match s { - #{matchArms} + override fun implFromForStr(context: EnumGeneratorContext): Writable = + writable { + rustTemplate( + """ + impl #{From}<&str> for ${context.enumName} { + fn from(s: &str) -> Self { + match s { + #{matchArms} + } } } - } - """, - "From" to RuntimeType.From, - "matchArms" to writable { - context.sortedMembers.forEach { member -> - rust("${member.value.dq()} => ${context.enumName}::${member.derivedName()},") - } - rust("_ => panic!()") - }, - ) - } + """, + "From" to RuntimeType.From, + "matchArms" to + writable { + context.sortedMembers.forEach { member -> + rust("${member.value.dq()} => ${context.enumName}::${member.derivedName()},") + } + rust("_ => panic!()") + }, + ) + } - override fun implFromStr(context: EnumGeneratorContext): Writable = writable { - rust( - """ - impl std::str::FromStr for ${context.enumName} { - type Err = std::convert::Infallible; - fn from_str(s: &str) -> std::result::Result { - Ok(${context.enumName}::from(s)) + override fun implFromStr(context: EnumGeneratorContext): Writable = + writable { + rust( + """ + impl std::str::FromStr for ${context.enumName} { + type Err = std::convert::Infallible; + fn from_str(s: &str) -> std::result::Result { + Ok(${context.enumName}::from(s)) + } } - } - """, - ) - } + """, + ) + } } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGeneratorTest.kt index 8b6778890f0..6513ce0952b 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/UnionGeneratorTest.kt @@ -20,15 +20,16 @@ import software.amazon.smithy.rust.codegen.core.util.lookup class UnionGeneratorTest { @Test fun `generate basic unions`() { - val writer = generateUnion( - """ - union MyUnion { - stringConfig: String, - @documentation("This *is* documentation about the member") - intConfig: PrimitiveInteger - } - """, - ) + val writer = + generateUnion( + """ + union MyUnion { + stringConfig: String, + @documentation("This *is* documentation about the member") + intConfig: PrimitiveInteger + } + """, + ) writer.compileAndTest( """ @@ -43,14 +44,15 @@ class UnionGeneratorTest { @Test fun `generate conversion helper methods`() { - val writer = generateUnion( - """ - union MyUnion { - stringValue: String, - intValue: PrimitiveInteger - } - """, - ) + val writer = + generateUnion( + """ + union MyUnion { + stringValue: String, + intValue: PrimitiveInteger + } + """, + ) writer.compileAndTest( """ @@ -99,7 +101,8 @@ class UnionGeneratorTest { @Test fun `generate deprecated unions`() { - val model = """namespace test + val model = + """namespace test union Nested { foo: Foo, @deprecated @@ -112,7 +115,7 @@ class UnionGeneratorTest { @deprecated union Bar { x: Integer } - """.asSmithyModel() + """.asSmithyModel() val provider = testSymbolProvider(model) val project = TestWorkspace.testProject(provider) project.lib { rust("##![allow(deprecated)]") } @@ -127,14 +130,15 @@ class UnionGeneratorTest { @Test fun `impl debug for non-sensitive union should implement the derived debug trait`() { - val writer = generateUnion( - """ - union MyUnion { - foo: PrimitiveInteger - bar: String, - } - """, - ) + val writer = + generateUnion( + """ + union MyUnion { + foo: PrimitiveInteger + bar: String, + } + """, + ) writer.compileAndTest( """ @@ -146,15 +150,16 @@ class UnionGeneratorTest { @Test fun `impl debug for sensitive union should redact text`() { - val writer = generateUnion( - """ - @sensitive - union MyUnion { - foo: PrimitiveInteger, - bar: String, - } - """, - ) + val writer = + generateUnion( + """ + @sensitive + union MyUnion { + foo: PrimitiveInteger, + bar: String, + } + """, + ) writer.compileAndTest( """ @@ -166,17 +171,18 @@ class UnionGeneratorTest { @Test fun `impl debug for union should redact text for sensitive member target`() { - val writer = generateUnion( - """ - @sensitive - string Bar - - union MyUnion { - foo: PrimitiveInteger, - bar: Bar, - } - """, - ) + val writer = + generateUnion( + """ + @sensitive + string Bar + + union MyUnion { + foo: PrimitiveInteger, + bar: Bar, + } + """, + ) writer.compileAndTest( """ @@ -188,17 +194,18 @@ class UnionGeneratorTest { @Test fun `impl debug for union with unit target should redact text for sensitive member target`() { - val writer = generateUnion( - """ - @sensitive - string Bar - - union MyUnion { - foo: Unit, - bar: Bar, - } - """, - ) + val writer = + generateUnion( + """ + @sensitive + string Bar + + union MyUnion { + foo: Unit, + bar: Bar, + } + """, + ) writer.compileAndTest( """ @@ -219,7 +226,11 @@ class UnionGeneratorTest { ) } - private fun generateUnion(modelSmithy: String, unionName: String = "MyUnion", unknownVariant: Boolean = true): RustWriter { + private fun generateUnion( + modelSmithy: String, + unionName: String = "MyUnion", + unknownVariant: Boolean = true, + ): RustWriter { val model = "namespace test\n$modelSmithy".asSmithyModel() val provider: SymbolProvider = testSymbolProvider(model) val writer = RustWriter.forModule("model") diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/ProtocolFunctionsTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/ProtocolFunctionsTest.kt index cbc08421f5f..06a5e9f42aa 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/ProtocolFunctionsTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/ProtocolFunctionsTest.kt @@ -12,7 +12,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.testSymbolProvider import software.amazon.smithy.rust.codegen.core.util.lookup class ProtocolFunctionsTest { - private val testModel = """ + private val testModel = + """ namespace test structure SomeStruct1 { @@ -79,13 +80,16 @@ class ProtocolFunctionsTest { operation Op2 { input: Op1Input, } - """.asSmithyModel() + """.asSmithyModel() @Test fun `generates function names for shapes`() { val symbolProvider = testSymbolProvider(testModel) - fun test(shapeId: String, expected: String) { + fun test( + shapeId: String, + expected: String, + ) { symbolProvider.shapeFunctionName(null, testModel.lookup(shapeId)) shouldBe expected } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/AwsQueryParserGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/AwsQueryParserGeneratorTest.kt index 38beea1e1be..bc239f10215 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/AwsQueryParserGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/AwsQueryParserGeneratorTest.kt @@ -23,7 +23,8 @@ import software.amazon.smithy.rust.codegen.core.util.lookup import software.amazon.smithy.rust.codegen.core.util.outputShape class AwsQueryParserGeneratorTest { - private val baseModel = """ + private val baseModel = + """ namespace test use aws.protocols#awsQuery @@ -37,17 +38,18 @@ class AwsQueryParserGeneratorTest { operation SomeOperation { output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() @Test fun `it modifies operation parsing to include Response and Result tags`() { val model = RecursiveShapeBoxer().transform(OperationNormalizer.transform(baseModel)) val codegenContext = testCodegenContext(model) val symbolProvider = codegenContext.symbolProvider - val parserGenerator = AwsQueryParserGenerator( - codegenContext, - RuntimeType.wrappedXmlErrors(TestRuntimeConfig), - ) + val parserGenerator = + AwsQueryParserGenerator( + codegenContext, + RuntimeType.wrappedXmlErrors(TestRuntimeConfig), + ) val operationParser = parserGenerator.operationParser(model.lookup("test#SomeOperation"))!! val project = TestWorkspace.testProject(testSymbolProvider(model)) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/Ec2QueryParserGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/Ec2QueryParserGeneratorTest.kt index 9a51b072538..aaac54b7399 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/Ec2QueryParserGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/Ec2QueryParserGeneratorTest.kt @@ -23,7 +23,8 @@ import software.amazon.smithy.rust.codegen.core.util.lookup import software.amazon.smithy.rust.codegen.core.util.outputShape class Ec2QueryParserGeneratorTest { - private val baseModel = """ + private val baseModel = + """ namespace test use aws.protocols#awsQuery @@ -37,17 +38,18 @@ class Ec2QueryParserGeneratorTest { operation SomeOperation { output: SomeOutput } - """.asSmithyModel() + """.asSmithyModel() @Test fun `it modifies operation parsing to include Response and Result tags`() { val model = RecursiveShapeBoxer().transform(OperationNormalizer.transform(baseModel)) val codegenContext = testCodegenContext(model) val symbolProvider = codegenContext.symbolProvider - val parserGenerator = Ec2QueryParserGenerator( - codegenContext, - RuntimeType.wrappedXmlErrors(TestRuntimeConfig), - ) + val parserGenerator = + Ec2QueryParserGenerator( + codegenContext, + RuntimeType.wrappedXmlErrors(TestRuntimeConfig), + ) val operationParser = parserGenerator.operationParser(model.lookup("test#SomeOperation"))!! val project = TestWorkspace.testProject(testSymbolProvider(model)) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGeneratorTest.kt index e5ca4d19aee..ed416545b1f 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGeneratorTest.kt @@ -28,7 +28,8 @@ import software.amazon.smithy.rust.codegen.core.util.lookup import software.amazon.smithy.rust.codegen.core.util.outputShape class JsonParserGeneratorTest { - private val baseModel = """ + private val baseModel = + """ namespace test use aws.protocols#restJson1 @@ -108,7 +109,7 @@ class JsonParserGeneratorTest { output: OpOutput, errors: [Error] } - """.asSmithyModel() + """.asSmithyModel() @Test fun `generates valid deserializers`() { @@ -116,11 +117,12 @@ class JsonParserGeneratorTest { val codegenContext = testCodegenContext(model) val symbolProvider = codegenContext.symbolProvider - val parserGenerator = JsonParserGenerator( - codegenContext, - HttpTraitHttpBindingResolver(model, ProtocolContentTypes.consistent("application/json")), - ::restJsonFieldName, - ) + val parserGenerator = + JsonParserGenerator( + codegenContext, + HttpTraitHttpBindingResolver(model, ProtocolContentTypes.consistent("application/json")), + ::restJsonFieldName, + ) val operationGenerator = parserGenerator.operationParser(model.lookup("test#Op")) val payloadGenerator = parserGenerator.payloadParser(model.lookup("test#OpOutput\$top")) val errorParser = parserGenerator.errorParser(model.lookup("test#Error")) diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGeneratorTest.kt index 0d78af182ea..0ec685f15a6 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/XmlBindingTraitParserGeneratorTest.kt @@ -29,7 +29,8 @@ import software.amazon.smithy.rust.codegen.core.util.lookup import software.amazon.smithy.rust.codegen.core.util.outputShape internal class XmlBindingTraitParserGeneratorTest { - private val baseModel = """ + private val baseModel = + """ namespace test use aws.protocols#restXml union Choice { @@ -89,17 +90,18 @@ internal class XmlBindingTraitParserGeneratorTest { input: Top, output: Top } - """.asSmithyModel() + """.asSmithyModel() @Test fun `generates valid parsers`() { val model = RecursiveShapeBoxer().transform(OperationNormalizer.transform(baseModel)) val codegenContext = testCodegenContext(model) val symbolProvider = codegenContext.symbolProvider - val parserGenerator = XmlBindingTraitParserGenerator( - codegenContext, - RuntimeType.wrappedXmlErrors(TestRuntimeConfig), - ) { _, inner -> inner("decoder") } + val parserGenerator = + XmlBindingTraitParserGenerator( + codegenContext, + RuntimeType.wrappedXmlErrors(TestRuntimeConfig), + ) { _, inner -> inner("decoder") } val operationParser = parserGenerator.operationParser(model.lookup("test#Op"))!! val choiceShape = model.lookup("test#Choice") diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/AwsQuerySerializerGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/AwsQuerySerializerGeneratorTest.kt index 2203b05dc1f..a0fd7fffe8c 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/AwsQuerySerializerGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/AwsQuerySerializerGeneratorTest.kt @@ -28,7 +28,8 @@ import software.amazon.smithy.rust.codegen.core.util.inputShape import software.amazon.smithy.rust.codegen.core.util.lookup class AwsQuerySerializerGeneratorTest { - private val baseModel = """ + private val baseModel = + """ namespace test use aws.protocols#restJson1 @@ -85,15 +86,16 @@ class AwsQuerySerializerGeneratorTest { operation Op { input: OpInput, } - """.asSmithyModel() + """.asSmithyModel() @ParameterizedTest @CsvSource("true", "false") fun `generates valid serializers`(generateUnknownVariant: Boolean) { - val codegenTarget = when (generateUnknownVariant) { - true -> CodegenTarget.CLIENT - false -> CodegenTarget.SERVER - } + val codegenTarget = + when (generateUnknownVariant) { + true -> CodegenTarget.CLIENT + false -> CodegenTarget.SERVER + } val model = RecursiveShapeBoxer().transform(OperationNormalizer.transform(baseModel)) val codegenContext = testCodegenContext(model, codegenTarget = codegenTarget) val symbolProvider = codegenContext.symbolProvider @@ -155,7 +157,8 @@ class AwsQuerySerializerGeneratorTest { project.compileAndTest() } - private val baseModelWithRequiredTypes = """ + private val baseModelWithRequiredTypes = + """ namespace test use aws.protocols#restJson1 @@ -219,7 +222,7 @@ class AwsQuerySerializerGeneratorTest { operation Op { input: OpInput, } - """.asSmithyModel() + """.asSmithyModel() @ParameterizedTest @CsvSource( @@ -229,13 +232,18 @@ class AwsQuerySerializerGeneratorTest { "true, CLIENT_ZERO_VALUE_V1_NO_INPUT", "false, SERVER", ) - fun `generates valid serializers for required types`(generateUnknownVariant: Boolean, nullabilityCheckMode: NullableIndex.CheckMode) { - val codegenTarget = when (generateUnknownVariant) { - true -> CodegenTarget.CLIENT - false -> CodegenTarget.SERVER - } + fun `generates valid serializers for required types`( + generateUnknownVariant: Boolean, + nullabilityCheckMode: NullableIndex.CheckMode, + ) { + val codegenTarget = + when (generateUnknownVariant) { + true -> CodegenTarget.CLIENT + false -> CodegenTarget.SERVER + } val model = RecursiveShapeBoxer().transform(OperationNormalizer.transform(baseModelWithRequiredTypes)) - val codegenContext = testCodegenContext(model, codegenTarget = codegenTarget, nullabilityCheckMode = nullabilityCheckMode) + val codegenContext = + testCodegenContext(model, codegenTarget = codegenTarget, nullabilityCheckMode = nullabilityCheckMode) val symbolProvider = codegenContext.symbolProvider val parserGenerator = AwsQuerySerializerGenerator(codegenContext) val operationGenerator = parserGenerator.operationInputSerializer(model.lookup("test#Op")) @@ -245,7 +253,12 @@ class AwsQuerySerializerGeneratorTest { // Depending on the nullability check mode, the builder can be fallible or not. When it's fallible, we need to // add unwrap calls. val builderIsFallible = hasFallibleBuilder(model.lookup("test#Top"), symbolProvider) - val maybeUnwrap = if (builderIsFallible) { ".unwrap()" } else { "" } + val maybeUnwrap = + if (builderIsFallible) { + ".unwrap()" + } else { + "" + } project.lib { unitTest( "query_serializer", diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/Ec2QuerySerializerGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/Ec2QuerySerializerGeneratorTest.kt index 4b5f490e13a..d0a33e1f5d9 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/Ec2QuerySerializerGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/Ec2QuerySerializerGeneratorTest.kt @@ -29,7 +29,8 @@ import software.amazon.smithy.rust.codegen.core.util.inputShape import software.amazon.smithy.rust.codegen.core.util.lookup class Ec2QuerySerializerGeneratorTest { - private val baseModel = """ + private val baseModel = + """ namespace test union Choice { @@ -85,7 +86,7 @@ class Ec2QuerySerializerGeneratorTest { operation Op { input: OpInput, } - """.asSmithyModel() + """.asSmithyModel() @ParameterizedTest @CsvSource( @@ -152,7 +153,8 @@ class Ec2QuerySerializerGeneratorTest { project.compileAndTest() } - private val baseModelWithRequiredTypes = """ + private val baseModelWithRequiredTypes = + """ namespace test union Choice { @@ -215,7 +217,7 @@ class Ec2QuerySerializerGeneratorTest { operation Op { input: OpInput, } - """.asSmithyModel() + """.asSmithyModel() @ParameterizedTest @CsvSource( @@ -239,7 +241,12 @@ class Ec2QuerySerializerGeneratorTest { // add unwrap calls. val builderIsFallible = BuilderGenerator.hasFallibleBuilder(model.lookup("test#Top"), symbolProvider) - val maybeUnwrap = if (builderIsFallible) { ".unwrap()" } else { "" } + val maybeUnwrap = + if (builderIsFallible) { + ".unwrap()" + } else { + "" + } project.lib { unitTest( "ec2query_serializer", diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/JsonSerializerGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/JsonSerializerGeneratorTest.kt index 61140ecd420..922f2b7ae8d 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/JsonSerializerGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/JsonSerializerGeneratorTest.kt @@ -31,7 +31,8 @@ import software.amazon.smithy.rust.codegen.core.util.inputShape import software.amazon.smithy.rust.codegen.core.util.lookup class JsonSerializerGeneratorTest { - private val baseModel = """ + private val baseModel = + """ namespace test use aws.protocols#restJson1 @@ -100,7 +101,7 @@ class JsonSerializerGeneratorTest { operation Op { input: OpInput, } - """.asSmithyModel() + """.asSmithyModel() @ParameterizedTest @CsvSource( @@ -114,11 +115,12 @@ class JsonSerializerGeneratorTest { val model = RecursiveShapeBoxer().transform(OperationNormalizer.transform(baseModel)) val codegenContext = testCodegenContext(model, nullabilityCheckMode = nullabilityCheckMode) val symbolProvider = codegenContext.symbolProvider - val parserSerializer = JsonSerializerGenerator( - codegenContext, - HttpTraitHttpBindingResolver(model, ProtocolContentTypes.consistent("application/json")), - ::restJsonFieldName, - ) + val parserSerializer = + JsonSerializerGenerator( + codegenContext, + HttpTraitHttpBindingResolver(model, ProtocolContentTypes.consistent("application/json")), + ::restJsonFieldName, + ) val operationGenerator = parserSerializer.operationInputSerializer(model.lookup("test#Op")) val documentGenerator = parserSerializer.documentSerializer() @@ -167,7 +169,8 @@ class JsonSerializerGeneratorTest { project.compileAndTest() } - private val baseModelWithRequiredTypes = """ + private val baseModelWithRequiredTypes = + """ namespace test use aws.protocols#restJson1 @@ -245,7 +248,7 @@ class JsonSerializerGeneratorTest { operation Op { input: OpInput, } - """.asSmithyModel() + """.asSmithyModel() @ParameterizedTest @CsvSource( @@ -259,11 +262,12 @@ class JsonSerializerGeneratorTest { val model = RecursiveShapeBoxer().transform(OperationNormalizer.transform(baseModelWithRequiredTypes)) val codegenContext = testCodegenContext(model, nullabilityCheckMode = nullabilityCheckMode) val symbolProvider = codegenContext.symbolProvider - val parserSerializer = JsonSerializerGenerator( - codegenContext, - HttpTraitHttpBindingResolver(model, ProtocolContentTypes.consistent("application/json")), - ::restJsonFieldName, - ) + val parserSerializer = + JsonSerializerGenerator( + codegenContext, + HttpTraitHttpBindingResolver(model, ProtocolContentTypes.consistent("application/json")), + ::restJsonFieldName, + ) val operationGenerator = parserSerializer.operationInputSerializer(model.lookup("test#Op")) val documentGenerator = parserSerializer.documentSerializer() @@ -273,7 +277,12 @@ class JsonSerializerGeneratorTest { // add unwrap calls. val builderIsFallible = BuilderGenerator.hasFallibleBuilder(model.lookup("test#Top"), symbolProvider) - val maybeUnwrap = if (builderIsFallible) { ".unwrap()" } else { "" } + val maybeUnwrap = + if (builderIsFallible) { + ".unwrap()" + } else { + "" + } project.lib { unitTest( "json_serializers", diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/XmlBindingTraitSerializerGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/XmlBindingTraitSerializerGeneratorTest.kt index 2aa24581b55..58f482e2769 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/XmlBindingTraitSerializerGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/serialize/XmlBindingTraitSerializerGeneratorTest.kt @@ -32,7 +32,8 @@ import software.amazon.smithy.rust.codegen.core.util.inputShape import software.amazon.smithy.rust.codegen.core.util.lookup internal class XmlBindingTraitSerializerGeneratorTest { - private val baseModel = """ + private val baseModel = + """ namespace test use aws.protocols#restXml union Choice { @@ -106,7 +107,7 @@ internal class XmlBindingTraitSerializerGeneratorTest { operation Op { input: OpInput, } - """.asSmithyModel() + """.asSmithyModel() @ParameterizedTest @CsvSource( @@ -120,10 +121,11 @@ internal class XmlBindingTraitSerializerGeneratorTest { val model = RecursiveShapeBoxer().transform(OperationNormalizer.transform(baseModel)) val codegenContext = testCodegenContext(model, nullabilityCheckMode = nullabilityCheckMode) val symbolProvider = codegenContext.symbolProvider - val parserGenerator = XmlBindingTraitSerializerGenerator( - codegenContext, - HttpTraitHttpBindingResolver(model, ProtocolContentTypes.consistent("application/xml")), - ) + val parserGenerator = + XmlBindingTraitSerializerGenerator( + codegenContext, + HttpTraitHttpBindingResolver(model, ProtocolContentTypes.consistent("application/xml")), + ) val operationSerializer = parserGenerator.payloadSerializer(model.lookup("test#OpInput\$payload")) val project = TestWorkspace.testProject(testSymbolProvider(model)) @@ -171,7 +173,8 @@ internal class XmlBindingTraitSerializerGeneratorTest { project.compileAndTest() } - private val baseModelWithRequiredTypes = """ + private val baseModelWithRequiredTypes = + """ namespace test use aws.protocols#restXml union Choice { @@ -237,7 +240,7 @@ internal class XmlBindingTraitSerializerGeneratorTest { operation Op { input: OpInput, } - """.asSmithyModel() + """.asSmithyModel() @ParameterizedTest @CsvSource( @@ -251,10 +254,11 @@ internal class XmlBindingTraitSerializerGeneratorTest { val model = RecursiveShapeBoxer().transform(OperationNormalizer.transform(baseModelWithRequiredTypes)) val codegenContext = testCodegenContext(model, nullabilityCheckMode = nullabilityCheckMode) val symbolProvider = codegenContext.symbolProvider - val parserGenerator = XmlBindingTraitSerializerGenerator( - codegenContext, - HttpTraitHttpBindingResolver(model, ProtocolContentTypes.consistent("application/xml")), - ) + val parserGenerator = + XmlBindingTraitSerializerGenerator( + codegenContext, + HttpTraitHttpBindingResolver(model, ProtocolContentTypes.consistent("application/xml")), + ) val operationSerializer = parserGenerator.payloadSerializer(model.lookup("test#OpInput\$payload")) val project = TestWorkspace.testProject(symbolProvider) @@ -263,11 +267,22 @@ internal class XmlBindingTraitSerializerGeneratorTest { // add unwrap calls. val builderIsFallible = BuilderGenerator.hasFallibleBuilder(model.lookup("test#Top"), symbolProvider) - val maybeUnwrap = if (builderIsFallible) { ".unwrap()" } else { "" } - val payloadIsOptional = model.lookup("test#OpInput\$payload").let { - symbolProvider.toSymbol(it).isOptional() - } - val maybeUnwrapPayload = if (payloadIsOptional) { ".unwrap()" } else { "" } + val maybeUnwrap = + if (builderIsFallible) { + ".unwrap()" + } else { + "" + } + val payloadIsOptional = + model.lookup("test#OpInput\$payload").let { + symbolProvider.toSymbol(it).isOptional() + } + val maybeUnwrapPayload = + if (payloadIsOptional) { + ".unwrap()" + } else { + "" + } project.lib { unitTest( "serialize_xml", diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/EventStreamNormalizerTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/EventStreamNormalizerTest.kt index 0398180b8d6..6c964fc3a01 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/EventStreamNormalizerTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/EventStreamNormalizerTest.kt @@ -17,15 +17,16 @@ import software.amazon.smithy.rust.codegen.core.util.hasTrait class EventStreamNormalizerTest { @Test fun `it should leave normal unions alone`() { - val transformed = EventStreamNormalizer.transform( - """ - namespace test - union SomeNormalUnion { - Foo: String, - Bar: Long, - } - """.asSmithyModel(), - ) + val transformed = + EventStreamNormalizer.transform( + """ + namespace test + union SomeNormalUnion { + Foo: String, + Bar: Long, + } + """.asSmithyModel(), + ) val shape = transformed.expectShape(ShapeId.from("test#SomeNormalUnion"), UnionShape::class.java) shape.hasTrait() shouldBe false @@ -34,24 +35,25 @@ class EventStreamNormalizerTest { @Test fun `it should transform event stream unions`() { - val transformed = EventStreamNormalizer.transform( - """ - namespace test - - structure SomeMember { - } - - @error("client") - structure SomeError { - } - - @streaming - union SomeEventStream { - SomeMember: SomeMember, - SomeError: SomeError, - } - """.asSmithyModel(), - ) + val transformed = + EventStreamNormalizer.transform( + """ + namespace test + + structure SomeMember { + } + + @error("client") + structure SomeError { + } + + @streaming + union SomeEventStream { + SomeMember: SomeMember, + SomeError: SomeError, + } + """.asSmithyModel(), + ) val shape = transformed.expectShape(ShapeId.from("test#SomeEventStream"), UnionShape::class.java) shape.hasTrait() shouldBe true diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/OperationNormalizerTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/OperationNormalizerTest.kt index 8e1d922820d..39553dd8802 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/OperationNormalizerTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/OperationNormalizerTest.kt @@ -20,10 +20,11 @@ import software.amazon.smithy.rust.codegen.core.util.orNull internal class OperationNormalizerTest { @Test fun `add inputs and outputs to empty operations`() { - val model = """ + val model = + """ namespace smithy.test operation Empty {} - """.asSmithyModel() + """.asSmithyModel() val operationId = ShapeId.from("smithy.test#Empty") model.expectShape(operationId, OperationShape::class.java).input.isPresent shouldBe false val modified = OperationNormalizer.transform(model) @@ -43,7 +44,8 @@ internal class OperationNormalizerTest { @Test fun `create cloned inputs for operations`() { - val model = """ + val model = + """ namespace smithy.test structure RenameMe { v: String @@ -51,7 +53,7 @@ internal class OperationNormalizerTest { operation MyOp { input: RenameMe } - """.asSmithyModel() + """.asSmithyModel() val operationId = ShapeId.from("smithy.test#MyOp") model.expectShape(operationId, OperationShape::class.java).input.isPresent shouldBe true val modified = OperationNormalizer.transform(model) @@ -66,7 +68,8 @@ internal class OperationNormalizerTest { @Test fun `create cloned outputs for operations`() { - val model = """ + val model = + """ namespace smithy.test structure RenameMe { v: String @@ -74,7 +77,7 @@ internal class OperationNormalizerTest { operation MyOp { output: RenameMe } - """.asSmithyModel() + """.asSmithyModel() val operationId = ShapeId.from("smithy.test#MyOp") model.expectShape(operationId, OperationShape::class.java).output.isPresent shouldBe true val modified = OperationNormalizer.transform(model) @@ -89,7 +92,8 @@ internal class OperationNormalizerTest { @Test fun `synthetics should not collide with other operations`() { - val model = """ + val model = + """ namespace test structure DeleteApplicationRequest {} @@ -107,7 +111,7 @@ internal class OperationNormalizerTest { input: DeleteApplicationOutputRequest, output: DeleteApplicationOutputResponse, } - """.asSmithyModel() + """.asSmithyModel() (model.expectShape(ShapeId.from("test#DeleteApplicationOutput")) is OperationShape) shouldBe true diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/RecursiveShapeBoxerTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/RecursiveShapeBoxerTest.kt index 293e2217131..f6f8dc2a4b7 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/RecursiveShapeBoxerTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/RecursiveShapeBoxerTest.kt @@ -18,7 +18,8 @@ import kotlin.streams.toList internal class RecursiveShapeBoxerTest { @Test fun `leave non-recursive models unchanged`() { - val model = """ + val model = + """ namespace com.example list BarList { member: Bar @@ -30,19 +31,20 @@ internal class RecursiveShapeBoxerTest { structure Bar { hello: Hello } - """.asSmithyModel() + """.asSmithyModel() RecursiveShapeBoxer().transform(model) shouldBe model } @Test fun `add the box trait to simple recursive shapes`() { - val model = """ + val model = + """ namespace com.example structure Recursive { RecursiveStruct: Recursive, anotherField: Boolean } - """.asSmithyModel() + """.asSmithyModel() val transformed = RecursiveShapeBoxer().transform(model) val member: MemberShape = transformed.lookup("com.example#Recursive\$RecursiveStruct") member.expectTrait() @@ -50,7 +52,8 @@ internal class RecursiveShapeBoxerTest { @Test fun `add the box trait to complex structures`() { - val model = """ + val model = + """ namespace com.example structure Expr { left: Atom, @@ -69,14 +72,15 @@ internal class RecursiveShapeBoxerTest { otherMember: Atom, third: SecondTree } - """.asSmithyModel() + """.asSmithyModel() val transformed = RecursiveShapeBoxer().transform(model) val boxed = transformed.shapes().filter { it.hasTrait() }.toList() - boxed.map { it.id.toString().removePrefix("com.example#") }.toSet() shouldBe setOf( - "Atom\$add", - "Atom\$sub", - "SecondTree\$third", - "Atom\$more", - ) + boxed.map { it.id.toString().removePrefix("com.example#") }.toSet() shouldBe + setOf( + "Atom\$add", + "Atom\$sub", + "SecondTree\$third", + "Atom\$more", + ) } } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/RecursiveShapesIntegrationTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/RecursiveShapesIntegrationTest.kt index 110836fdadd..1f8917c35f6 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/RecursiveShapesIntegrationTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/transformers/RecursiveShapesIntegrationTest.kt @@ -24,7 +24,8 @@ import software.amazon.smithy.rust.codegen.core.util.lookup class RecursiveShapesIntegrationTest { @Test fun `recursive shapes are properly boxed`() { - val model = """ + val model = + """ namespace com.example structure Expr { left: Atom, @@ -43,7 +44,7 @@ class RecursiveShapesIntegrationTest { otherMember: Atom, third: SecondTree } - """.asSmithyModel() + """.asSmithyModel() val check = { input: Model -> val symbolProvider = testSymbolProvider(model) @@ -62,9 +63,10 @@ class RecursiveShapesIntegrationTest { project } val unmodifiedProject = check(model) - val output = assertThrows { - unmodifiedProject.compileAndTest(expectFailure = true) - } + val output = + assertThrows { + unmodifiedProject.compileAndTest(expectFailure = true) + } // THIS IS A LOAD-BEARING shouldContain! If the compiler error changes then this will break! output.message shouldContain "have infinite size" diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/util/MapTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/util/MapTest.kt index a38499de36b..1ed9bd77064 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/util/MapTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/util/MapTest.kt @@ -13,58 +13,68 @@ class MapTest { fun `it should deep merge maps`() { mapOf().deepMergeWith(mapOf()) shouldBe emptyMap() - mapOf("foo" to 1, "bar" to "baz").deepMergeWith(mapOf()) shouldBe mapOf( - "foo" to 1, - "bar" to "baz", - ) + mapOf("foo" to 1, "bar" to "baz").deepMergeWith(mapOf()) shouldBe + mapOf( + "foo" to 1, + "bar" to "baz", + ) - mapOf().deepMergeWith(mapOf("foo" to 1, "bar" to "baz")) shouldBe mapOf( - "foo" to 1, - "bar" to "baz", - ) + mapOf().deepMergeWith(mapOf("foo" to 1, "bar" to "baz")) shouldBe + mapOf( + "foo" to 1, + "bar" to "baz", + ) mapOf( - "package" to mapOf( - "name" to "foo", - "version" to "1.0.0", - ), + "package" to + mapOf( + "name" to "foo", + "version" to "1.0.0", + ), ).deepMergeWith( mapOf( - "package" to mapOf( - "readme" to "README.md", - ), + "package" to + mapOf( + "readme" to "README.md", + ), ), - ) shouldBe mapOf( - "package" to mapOf( - "name" to "foo", - "version" to "1.0.0", - "readme" to "README.md", - ), - ) + ) shouldBe + mapOf( + "package" to + mapOf( + "name" to "foo", + "version" to "1.0.0", + "readme" to "README.md", + ), + ) mapOf( - "package" to mapOf( - "name" to "foo", - "version" to "1.0.0", - "overwrite-me" to "wrong", - ), + "package" to + mapOf( + "name" to "foo", + "version" to "1.0.0", + "overwrite-me" to "wrong", + ), "make-me-not-a-map" to mapOf("foo" to "bar"), ).deepMergeWith( mapOf( - "package" to mapOf( - "readme" to "README.md", - "overwrite-me" to "correct", - ), + "package" to + mapOf( + "readme" to "README.md", + "overwrite-me" to "correct", + ), "make-me-not-a-map" to 5, ), - ) shouldBe mapOf( - "package" to mapOf( - "name" to "foo", - "version" to "1.0.0", - "readme" to "README.md", - "overwrite-me" to "correct", - ), - "make-me-not-a-map" to 5, - ) + ) shouldBe + mapOf( + "package" to + mapOf( + "name" to "foo", + "version" to "1.0.0", + "readme" to "README.md", + "overwrite-me" to "correct", + ), + "make-me-not-a-map" to 5, + ) } } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/util/StringsTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/util/StringsTest.kt index af4e65d450e..ab46172348d 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/util/StringsTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/util/StringsTest.kt @@ -17,14 +17,14 @@ import java.io.File import java.util.stream.Stream internal class StringsTest { - @Test fun doubleQuote() { "abc".doubleQuote() shouldBe "\"abc\"" """{"some": "json"}""".doubleQuote() shouldBe """"{\"some\": \"json\"}"""" - """{"nested": "{\"nested\": 5}"}"}""".doubleQuote() shouldBe """ - "{\"nested\": \"{\\\"nested\\\": 5}\"}\"}" - """.trimIndent().trim() + """{"nested": "{\"nested\": 5}"}"}""".doubleQuote() shouldBe + """ + "{\"nested\": \"{\\\"nested\\\": 5}\"}\"}" + """.trimIndent().trim() } @Test @@ -59,7 +59,10 @@ internal class StringsTest { @ParameterizedTest @ArgumentsSource(TestCasesProvider::class) - fun testSnakeCase(input: String, output: String) { + fun testSnakeCase( + input: String, + output: String, + ) { input.toSnakeCase() shouldBe output } } diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/util/SyntheticsTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/util/SyntheticsTest.kt index 270183d05e8..a21479c697d 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/util/SyntheticsTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/util/SyntheticsTest.kt @@ -15,7 +15,8 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel class SyntheticsTest { @Test fun `it should clone operations`() { - val model = """ + val model = + """ namespace test service TestService { @@ -33,11 +34,12 @@ class SyntheticsTest { } operation SomeOperation { input: TestInput, output: TestOutput } - """.asSmithyModel() + """.asSmithyModel() - val transformed = model.toBuilder().cloneOperation(model, ShapeId.from("test#SomeOperation")) { shapeId -> - ShapeId.fromParts(shapeId.namespace + ".cloned", shapeId.name + "Foo") - }.build() + val transformed = + model.toBuilder().cloneOperation(model, ShapeId.from("test#SomeOperation")) { shapeId -> + ShapeId.fromParts(shapeId.namespace + ".cloned", shapeId.name + "Foo") + }.build() val newOp = transformed.expectShape(ShapeId.from("test.cloned#SomeOperationFoo"), OperationShape::class.java) newOp.input.orNull() shouldBe ShapeId.from("test.cloned#TestInputFoo") @@ -56,14 +58,15 @@ class SyntheticsTest { @Test fun `it should rename structs`() { - val model = """ + val model = + """ namespace test structure SomeInput { one: String, two: String, } - """.asSmithyModel() + """.asSmithyModel() val original = model.expectShape(ShapeId.from("test#SomeInput"), StructureShape::class.java) val new = original.toBuilder().rename(ShapeId.from("new#SomeOtherInput")).build() diff --git a/codegen-server/build.gradle.kts b/codegen-server/build.gradle.kts index be9709471ed..0ba262225d1 100644 --- a/codegen-server/build.gradle.kts +++ b/codegen-server/build.gradle.kts @@ -32,7 +32,12 @@ dependencies { testImplementation("software.amazon.smithy:smithy-validation-model:$smithyVersion") } -tasks.compileKotlin { kotlinOptions.jvmTarget = "1.8" } +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +tasks.compileKotlin { kotlinOptions.jvmTarget = "11" } // Reusable license copySpec val licenseSpec = copySpec { @@ -63,7 +68,7 @@ if (isTestingEnabled.toBoolean()) { testImplementation("io.kotest:kotest-assertions-core-jvm:$kotestVersion") } - tasks.compileTestKotlin { kotlinOptions.jvmTarget = "1.8" } + tasks.compileTestKotlin { kotlinOptions.jvmTarget = "11" } tasks.test { useJUnitPlatform() diff --git a/codegen-server/python/build.gradle.kts b/codegen-server/python/build.gradle.kts index 337d099bccb..f23a955bd5c 100644 --- a/codegen-server/python/build.gradle.kts +++ b/codegen-server/python/build.gradle.kts @@ -32,7 +32,12 @@ dependencies { testImplementation("software.amazon.smithy:smithy-validation-model:$smithyVersion") } -tasks.compileKotlin { kotlinOptions.jvmTarget = "1.8" } +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +tasks.compileKotlin { kotlinOptions.jvmTarget = "11" } // Reusable license copySpec val licenseSpec = copySpec { @@ -63,7 +68,7 @@ if (isTestingEnabled.toBoolean()) { testImplementation("io.kotest:kotest-assertions-core-jvm:$kotestVersion") } - tasks.compileTestKotlin { kotlinOptions.jvmTarget = "1.8" } + tasks.compileTestKotlin { kotlinOptions.jvmTarget = "11" } tasks.test { useJUnitPlatform() diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonEventStreamSymbolProvider.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonEventStreamSymbolProvider.kt index 38d3830bace..fe642c7cc9c 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonEventStreamSymbolProvider.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonEventStreamSymbolProvider.kt @@ -58,25 +58,28 @@ class PythonEventStreamSymbolProvider( // We can only wrap the type if it's either an input or an output that used in an operation model.expectShape(shape.container).let { maybeInputOutput -> - val operationId = maybeInputOutput.getTrait()?.operation - ?: maybeInputOutput.getTrait()?.operation + val operationId = + maybeInputOutput.getTrait()?.operation + ?: maybeInputOutput.getTrait()?.operation operationId?.let { model.expectShape(it, OperationShape::class.java) } } ?: return initial val unionShape = model.expectShape(shape.target).asUnionShape().get() - val error = if (unionShape.eventStreamErrors().isEmpty()) { - RuntimeType.smithyHttp(runtimeConfig).resolve("event_stream::MessageStreamError").toSymbol() - } else { - symbolForEventStreamError(unionShape) - } + val error = + if (unionShape.eventStreamErrors().isEmpty()) { + RuntimeType.smithyHttp(runtimeConfig).resolve("event_stream::MessageStreamError").toSymbol() + } else { + symbolForEventStreamError(unionShape) + } val inner = initial.rustType().stripOuter() val innerSymbol = Symbol.builder().name(inner.name).rustType(inner).build() val containerName = shape.container.name val memberName = shape.memberName.toPascalCase() - val outer = when (shape.isOutputEventStream(model)) { - true -> "${containerName}${memberName}EventStreamSender" - else -> "${containerName}${memberName}Receiver" - } + val outer = + when (shape.isOutputEventStream(model)) { + true -> "${containerName}${memberName}EventStreamSender" + else -> "${containerName}${memberName}Receiver" + } val rustType = RustType.Opaque(outer, PythonServerRustModule.PythonEventStream.fullyQualifiedPath()) return Symbol.builder() .name(rustType.name) diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCargoDependency.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCargoDependency.kt index 2782e44b94c..2e8070d15e3 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCargoDependency.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCargoDependency.kt @@ -16,16 +16,20 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig */ object PythonServerCargoDependency { val PyO3: CargoDependency = CargoDependency("pyo3", CratesIo("0.18")) - val PyO3Asyncio: CargoDependency = CargoDependency("pyo3-asyncio", CratesIo("0.18"), features = setOf("attributes", "tokio-runtime")) + val PyO3Asyncio: CargoDependency = + CargoDependency("pyo3-asyncio", CratesIo("0.18"), features = setOf("attributes", "tokio-runtime")) val Tokio: CargoDependency = CargoDependency("tokio", CratesIo("1.20.1"), features = setOf("full")) val TokioStream: CargoDependency = CargoDependency("tokio-stream", CratesIo("0.1.12")) val Tracing: CargoDependency = CargoDependency("tracing", CratesIo("0.1")) val Tower: CargoDependency = CargoDependency("tower", CratesIo("0.4")) val TowerHttp: CargoDependency = CargoDependency("tower-http", CratesIo("0.3"), features = setOf("trace")) - val Hyper: CargoDependency = CargoDependency("hyper", CratesIo("0.14.12"), features = setOf("server", "http1", "http2", "tcp", "stream")) + val Hyper: CargoDependency = + CargoDependency("hyper", CratesIo("0.14.12"), features = setOf("server", "http1", "http2", "tcp", "stream")) val NumCpus: CargoDependency = CargoDependency("num_cpus", CratesIo("1.13")) val ParkingLot: CargoDependency = CargoDependency("parking_lot", CratesIo("0.12")) fun smithyHttpServer(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-http-server") - fun smithyHttpServerPython(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-http-server-python") + + fun smithyHttpServerPython(runtimeConfig: RuntimeConfig) = + runtimeConfig.smithyRuntimeCrate("smithy-http-server-python") } diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt index 3bb954bfc22..19ea83426ac 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerCodegenVisitor.kt @@ -60,7 +60,6 @@ class PythonServerCodegenVisitor( context: PluginContext, private val codegenDecorator: ServerCodegenDecorator, ) : ServerCodegenVisitor(context, codegenDecorator) { - init { val rustSymbolProviderConfig = RustSymbolProviderConfig( @@ -95,23 +94,26 @@ class PythonServerCodegenVisitor( publicConstrainedTypes: Boolean, includeConstraintShapeProvider: Boolean, codegenDecorator: ServerCodegenDecorator, - ) = RustServerCodegenPythonPlugin.baseSymbolProvider(settings, model, serviceShape, rustSymbolProviderConfig, publicConstrainedTypes, includeConstraintShapeProvider, codegenDecorator) + ) = + RustServerCodegenPythonPlugin.baseSymbolProvider(settings, model, serviceShape, rustSymbolProviderConfig, publicConstrainedTypes, includeConstraintShapeProvider, codegenDecorator) - val serverSymbolProviders = ServerSymbolProviders.from( - settings, - model, - service, - rustSymbolProviderConfig, - settings.codegenConfig.publicConstrainedTypes, - codegenDecorator, - ::baseSymbolProviderFactory, - ) + val serverSymbolProviders = + ServerSymbolProviders.from( + settings, + model, + service, + rustSymbolProviderConfig, + settings.codegenConfig.publicConstrainedTypes, + codegenDecorator, + ::baseSymbolProviderFactory, + ) // Override `codegenContext` which carries the various symbol providers. - val moduleDocProvider = codegenDecorator.moduleDocumentationCustomization( - codegenContext, - PythonServerModuleDocProvider(ServerModuleDocProvider(codegenContext)), - ) + val moduleDocProvider = + codegenDecorator.moduleDocumentationCustomization( + codegenContext, + PythonServerModuleDocProvider(ServerModuleDocProvider(codegenContext)), + ) codegenContext = ServerCodegenContext( model, @@ -127,12 +129,13 @@ class PythonServerCodegenVisitor( ) // Override `rustCrate` which carries the symbolProvider. - rustCrate = RustCrate( - context.fileManifest, - codegenContext.symbolProvider, - settings.codegenConfig, - codegenContext.expectModuleDocProvider(), - ) + rustCrate = + RustCrate( + context.fileManifest, + codegenContext.symbolProvider, + settings.codegenConfig, + codegenContext.expectModuleDocProvider(), + ) // Override `protocolGenerator` which carries the symbolProvider. protocolGenerator = protocolGeneratorFactory.buildProtocolGenerator(codegenContext) } @@ -175,8 +178,10 @@ class PythonServerCodegenVisitor( * Although raw strings require no code generation, enums are actually [EnumTrait] applied to string shapes. */ override fun stringShape(shape: StringShape) { - fun pythonServerEnumGeneratorFactory(codegenContext: ServerCodegenContext, shape: StringShape) = - PythonServerEnumGenerator(codegenContext, shape, validationExceptionConversionGenerator) + fun pythonServerEnumGeneratorFactory( + codegenContext: ServerCodegenContext, + shape: StringShape, + ) = PythonServerEnumGenerator(codegenContext, shape, validationExceptionConversionGenerator) stringShape(shape, ::pythonServerEnumGeneratorFactory) } @@ -193,7 +198,8 @@ class PythonServerCodegenVisitor( PythonServerUnionGenerator(model, codegenContext, this, shape, renderUnknownVariant = false).render() } - if (shape.isReachableFromOperationInput() && shape.canReachConstrainedShape( + if (shape.isReachableFromOperationInput() && + shape.canReachConstrainedShape( model, codegenContext.symbolProvider, ) diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerSymbolProvider.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerSymbolProvider.kt index f01e9a41c4a..70e055e23f8 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerSymbolProvider.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonServerSymbolProvider.kt @@ -35,8 +35,13 @@ import software.amazon.smithy.rust.codegen.server.smithy.ConstrainedShapeSymbolP import software.amazon.smithy.rust.codegen.server.smithy.ServerRustSettings import java.util.logging.Logger -/* Returns the Python implementation of the ByteStream shape or the original symbol that is provided in input. */ -private fun toPythonByteStreamSymbolOrOriginal(model: Model, config: RustSymbolProviderConfig, initial: Symbol, shape: Shape): Symbol { +// Returns the Python implementation of the ByteStream shape or the original symbol that is provided in input. +private fun toPythonByteStreamSymbolOrOriginal( + model: Model, + config: RustSymbolProviderConfig, + initial: Symbol, + shape: Shape, +): Symbol { if (shape !is MemberShape) { return initial } @@ -75,7 +80,6 @@ class PythonServerSymbolVisitor( serviceShape: ServiceShape?, config: RustSymbolProviderConfig, ) : SymbolVisitor(settings, model, serviceShape, config) { - private val runtimeConfig = config.runtimeConfig private val logger = Logger.getLogger(javaClass.name) @@ -111,7 +115,6 @@ class PythonConstrainedShapeSymbolProvider( serviceShape: ServiceShape, publicConstrainedTypes: Boolean, ) : ConstrainedShapeSymbolProvider(base, serviceShape, publicConstrainedTypes) { - override fun toSymbol(shape: Shape): Symbol { val initial = super.toSymbol(shape) return toPythonByteStreamSymbolOrOriginal(model, config, initial, shape) @@ -127,7 +130,6 @@ class PythonConstrainedShapeSymbolProvider( * Note that since streaming members can only be used on the root shape, this can only impact input and output shapes. */ class PythonStreamingShapeMetadataProvider(private val base: RustSymbolProvider) : SymbolMetadataProvider(base) { - override fun structureMeta(structureShape: StructureShape): RustMetadata { val baseMetadata = base.toSymbol(structureShape).expectRustMetadata() return if (structureShape.hasStreamingMember(model)) { @@ -147,10 +149,16 @@ class PythonStreamingShapeMetadataProvider(private val base: RustSymbolProvider) } override fun memberMeta(memberShape: MemberShape) = base.toSymbol(memberShape).expectRustMetadata() + override fun enumMeta(stringShape: StringShape) = base.toSymbol(stringShape).expectRustMetadata() + override fun listMeta(listShape: ListShape) = base.toSymbol(listShape).expectRustMetadata() + override fun mapMeta(mapShape: MapShape) = base.toSymbol(mapShape).expectRustMetadata() + override fun stringMeta(stringShape: StringShape) = base.toSymbol(stringShape).expectRustMetadata() + override fun numberMeta(numberShape: NumberShape) = base.toSymbol(numberShape).expectRustMetadata() + override fun blobMeta(blobShape: BlobShape) = base.toSymbol(blobShape).expectRustMetadata() } diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonType.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonType.kt index 8cdc481b395..e22786dd5f0 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonType.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/PythonType.kt @@ -101,23 +101,23 @@ sealed class PythonType { } data class Opaque(override val name: String, val pythonRootModuleName: String, val rustNamespace: String? = null) : PythonType() { - - override val namespace: String? = rustNamespace?.split("::")?.joinToString(".") { - when (it) { - "crate" -> pythonRootModuleName - // In Python, we expose submodules from `aws_smithy_http_server_python` - // like `types`, `middleware`, `tls` etc. from Python root module - "aws_smithy_http_server_python" -> pythonRootModuleName - else -> it - } - } - // Most opaque types have a leading `::`, so strip that for Python as needed - .let { - when (it?.startsWith(".")) { - true -> it.substring(1) + override val namespace: String? = + rustNamespace?.split("::")?.joinToString(".") { + when (it) { + "crate" -> pythonRootModuleName + // In Python, we expose submodules from `aws_smithy_http_server_python` + // like `types`, `middleware`, `tls` etc. from Python root module + "aws_smithy_http_server_python" -> pythonRootModuleName else -> it } } + // Most opaque types have a leading `::`, so strip that for Python as needed + .let { + when (it?.startsWith(".")) { + true -> it.substring(1) + else -> it + } + } } } @@ -139,12 +139,13 @@ fun RustType.pythonType(pythonRootModuleName: String): PythonType = is RustType.Option -> PythonType.Optional(this.member.pythonType(pythonRootModuleName)) is RustType.Box -> this.member.pythonType(pythonRootModuleName) is RustType.Dyn -> this.member.pythonType(pythonRootModuleName) - is RustType.Application -> PythonType.Application( - this.type.pythonType(pythonRootModuleName), - this.args.map { - it.pythonType(pythonRootModuleName) - }, - ) + is RustType.Application -> + PythonType.Application( + this.type.pythonType(pythonRootModuleName), + this.args.map { + it.pythonType(pythonRootModuleName) + }, + ) is RustType.Opaque -> PythonType.Opaque(this.name, pythonRootModuleName, rustNamespace = this.namespace) is RustType.MaybeConstrained -> this.member.pythonType(pythonRootModuleName) } @@ -154,39 +155,41 @@ fun RustType.pythonType(pythonRootModuleName: String): PythonType = * It generates something like `typing.Dict[String, String]`. */ fun PythonType.render(fullyQualified: Boolean = true): String { - val namespace = if (fullyQualified) { - this.namespace?.let { "$it." } ?: "" - } else { - "" - } - val base = when (this) { - is PythonType.None -> this.name - is PythonType.Bool -> this.name - is PythonType.Float -> this.name - is PythonType.Int -> this.name - is PythonType.Str -> this.name - is PythonType.Any -> this.name - is PythonType.Opaque -> this.name - is PythonType.List -> "${this.name}[${this.member.render(fullyQualified)}]" - is PythonType.Dict -> "${this.name}[${this.key.render(fullyQualified)}, ${this.member.render(fullyQualified)}]" - is PythonType.Set -> "${this.name}[${this.member.render(fullyQualified)}]" - is PythonType.Awaitable -> "${this.name}[${this.member.render(fullyQualified)}]" - is PythonType.Optional -> "${this.name}[${this.member.render(fullyQualified)}]" - is PythonType.AsyncIterator -> "${this.name}[${this.member.render(fullyQualified)}]" - is PythonType.Application -> { - val args = this.args.joinToString(", ") { it.render(fullyQualified) } - "${this.name}[$args]" - } - is PythonType.Callable -> { - val args = this.args.joinToString(", ") { it.render(fullyQualified) } - val rtype = this.rtype.render(fullyQualified) - "${this.name}[[$args], $rtype]" + val namespace = + if (fullyQualified) { + this.namespace?.let { "$it." } ?: "" + } else { + "" } - is PythonType.Union -> { - val args = this.args.joinToString(", ") { it.render(fullyQualified) } - "${this.name}[$args]" + val base = + when (this) { + is PythonType.None -> this.name + is PythonType.Bool -> this.name + is PythonType.Float -> this.name + is PythonType.Int -> this.name + is PythonType.Str -> this.name + is PythonType.Any -> this.name + is PythonType.Opaque -> this.name + is PythonType.List -> "${this.name}[${this.member.render(fullyQualified)}]" + is PythonType.Dict -> "${this.name}[${this.key.render(fullyQualified)}, ${this.member.render(fullyQualified)}]" + is PythonType.Set -> "${this.name}[${this.member.render(fullyQualified)}]" + is PythonType.Awaitable -> "${this.name}[${this.member.render(fullyQualified)}]" + is PythonType.Optional -> "${this.name}[${this.member.render(fullyQualified)}]" + is PythonType.AsyncIterator -> "${this.name}[${this.member.render(fullyQualified)}]" + is PythonType.Application -> { + val args = this.args.joinToString(", ") { it.render(fullyQualified) } + "${this.name}[$args]" + } + is PythonType.Callable -> { + val args = this.args.joinToString(", ") { it.render(fullyQualified) } + val rtype = this.rtype.render(fullyQualified) + "${this.name}[[$args], $rtype]" + } + is PythonType.Union -> { + val args = this.args.joinToString(", ") { it.render(fullyQualified) } + "${this.name}[$args]" + } } - } return "$namespace$base" } diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/RustServerCodegenPythonPlugin.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/RustServerCodegenPythonPlugin.kt index a2c9ab45de6..735d6901571 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/RustServerCodegenPythonPlugin.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/RustServerCodegenPythonPlugin.kt @@ -75,8 +75,7 @@ class RustServerCodegenPythonPlugin : SmithyBuildPlugin { constrainedTypes: Boolean = true, includeConstrainedShapeProvider: Boolean = true, codegenDecorator: ServerCodegenDecorator, - ) = - // Rename a set of symbols that do not implement `PyClass` and have been wrapped in + ) = // Rename a set of symbols that do not implement `PyClass` and have been wrapped in // `aws_smithy_http_server_python::types`. PythonServerSymbolVisitor(settings, model, serviceShape = serviceShape, config = rustSymbolProviderConfig) // Generate public constrained types for directly constrained shapes. diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/customizations/PythonServerCodegenDecorator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/customizations/PythonServerCodegenDecorator.kt index daa4a7b4dd4..ab103ff6394 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/customizations/PythonServerCodegenDecorator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/customizations/PythonServerCodegenDecorator.kt @@ -35,15 +35,14 @@ class CdylibManifestDecorator : ServerCodegenDecorator { override val name: String = "CdylibDecorator" override val order: Byte = 0 - override fun crateManifestCustomizations( - codegenContext: ServerCodegenContext, - ): ManifestCustomizations = + override fun crateManifestCustomizations(codegenContext: ServerCodegenContext): ManifestCustomizations = mapOf( - "lib" to mapOf( - // Library target names cannot contain hyphen names. - "name" to codegenContext.settings.moduleName.toSnakeCase(), - "crate-type" to listOf("cdylib"), - ), + "lib" to + mapOf( + // Library target names cannot contain hyphen names. + "name" to codegenContext.settings.moduleName.toSnakeCase(), + "crate-type" to listOf("cdylib"), + ), ) } @@ -53,14 +52,15 @@ class CdylibManifestDecorator : ServerCodegenDecorator { class PubUsePythonTypes(private val codegenContext: ServerCodegenContext) : LibRsCustomization() { override fun section(section: LibRsSection): Writable { return when (section) { - is LibRsSection.Body -> writable { - docs("Re-exported Python types from supporting crates.") - rustBlock("pub mod python_types") { - rust("pub use #T;", PythonServerRuntimeType.blob(codegenContext.runtimeConfig).toSymbol()) - rust("pub use #T;", PythonServerRuntimeType.dateTime(codegenContext.runtimeConfig).toSymbol()) - rust("pub use #T;", PythonServerRuntimeType.document(codegenContext.runtimeConfig).toSymbol()) + is LibRsSection.Body -> + writable { + docs("Re-exported Python types from supporting crates.") + rustBlock("pub mod python_types") { + rust("pub use #T;", PythonServerRuntimeType.blob(codegenContext.runtimeConfig).toSymbol()) + rust("pub use #T;", PythonServerRuntimeType.dateTime(codegenContext.runtimeConfig).toSymbol()) + rust("pub use #T;", PythonServerRuntimeType.document(codegenContext.runtimeConfig).toSymbol()) + } } - } else -> emptySection } } @@ -73,7 +73,10 @@ class PythonExportModuleDecorator : ServerCodegenDecorator { override val name: String = "PythonExportModuleDecorator" override val order: Byte = 0 - override fun extras(codegenContext: ServerCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ServerCodegenContext, + rustCrate: RustCrate, + ) { val service = codegenContext.settings.getService(codegenContext.model) val serviceShapes = DirectedWalker(codegenContext.model).walkShapes(service) PythonServerModuleGenerator(codegenContext, rustCrate, serviceShapes).render() @@ -104,19 +107,26 @@ class PyProjectTomlDecorator : ServerCodegenDecorator { override val name: String = "PyProjectTomlDecorator" override val order: Byte = 0 - override fun extras(codegenContext: ServerCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ServerCodegenContext, + rustCrate: RustCrate, + ) { rustCrate.withFile("pyproject.toml") { - val config = mapOf( - "build-system" to listOfNotNull( - "requires" to listOfNotNull("maturin>=0.14,<0.15"), - "build-backend" to "maturin", - ).toMap(), - "tool" to listOfNotNull( - "maturin" to listOfNotNull( - "python-source" to "python", - ).toMap(), - ).toMap(), - ) + val config = + mapOf( + "build-system" to + listOfNotNull( + "requires" to listOfNotNull("maturin>=0.14,<0.15"), + "build-backend" to "maturin", + ).toMap(), + "tool" to + listOfNotNull( + "maturin" to + listOfNotNull( + "python-source" to "python", + ).toMap(), + ).toMap(), + ) writeWithNoFormatting(TomlWriter().write(config)) } } @@ -134,7 +144,10 @@ class PyO3ExtensionModuleDecorator : ServerCodegenDecorator { override val name: String = "PyO3ExtensionModuleDecorator" override val order: Byte = 0 - override fun extras(codegenContext: ServerCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ServerCodegenContext, + rustCrate: RustCrate, + ) { // Add `pyo3/extension-module` to default features. rustCrate.mergeFeature(Feature("extension-module", true, listOf("pyo3/extension-module"))) } @@ -157,7 +170,10 @@ class InitPyDecorator : ServerCodegenDecorator { override val name: String = "InitPyDecorator" override val order: Byte = 0 - override fun extras(codegenContext: ServerCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ServerCodegenContext, + rustCrate: RustCrate, + ) { val libName = codegenContext.settings.moduleName.toSnakeCase() rustCrate.withFile("python/$libName/__init__.py") { @@ -185,7 +201,10 @@ class PyTypedMarkerDecorator : ServerCodegenDecorator { override val name: String = "PyTypedMarkerDecorator" override val order: Byte = 0 - override fun extras(codegenContext: ServerCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ServerCodegenContext, + rustCrate: RustCrate, + ) { val libName = codegenContext.settings.moduleName.toSnakeCase() rustCrate.withFile("python/$libName/py.typed") { @@ -204,7 +223,10 @@ class AddStubgenScriptDecorator : ServerCodegenDecorator { override val name: String = "AddStubgenScriptDecorator" override val order: Byte = 0 - override fun extras(codegenContext: ServerCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ServerCodegenContext, + rustCrate: RustCrate, + ) { val stubgenPythonContent = this::class.java.getResource("/stubgen.py").readText() rustCrate.withFile("stubgen.py") { writeWithNoFormatting("$stubgenPythonContent") @@ -216,26 +238,27 @@ class AddStubgenScriptDecorator : ServerCodegenDecorator { } } -val DECORATORS = arrayOf( - /** - * Add the [InternalServerError] error to all operations. - * This is done because the Python interpreter can raise exceptions during execution. - */ - AddInternalServerErrorToAllOperationsDecorator(), - // Add the [lib] section to Cargo.toml to configure the generation of the shared library. - CdylibManifestDecorator(), - // Add `pub use` of `aws_smithy_http_server_python::types`. - PubUsePythonTypesDecorator(), - // Render the Python shared library export. - PythonExportModuleDecorator(), - // Generate `pyproject.toml` for the crate. - PyProjectTomlDecorator(), - // Add PyO3 extension module feature. - PyO3ExtensionModuleDecorator(), - // Generate `__init__.py` for the Python source. - InitPyDecorator(), - // Generate `py.typed` for the Python source. - PyTypedMarkerDecorator(), - // Generate scripts for stub generation. - AddStubgenScriptDecorator(), -) +val DECORATORS = + arrayOf( + /* + * Add the [InternalServerError] error to all operations. + * This is done because the Python interpreter can raise exceptions during execution. + */ + AddInternalServerErrorToAllOperationsDecorator(), + // Add the [lib] section to Cargo.toml to configure the generation of the shared library. + CdylibManifestDecorator(), + // Add `pub use` of `aws_smithy_http_server_python::types`. + PubUsePythonTypesDecorator(), + // Render the Python shared library export. + PythonExportModuleDecorator(), + // Generate `pyproject.toml` for the crate. + PyProjectTomlDecorator(), + // Add PyO3 extension module feature. + PyO3ExtensionModuleDecorator(), + // Generate `__init__.py` for the Python source. + InitPyDecorator(), + // Generate `py.typed` for the Python source. + PyTypedMarkerDecorator(), + // Generate scripts for stub generation. + AddStubgenScriptDecorator(), + ) diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/ConstrainedPythonBlobGenerator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/ConstrainedPythonBlobGenerator.kt index a9c2021520e..d25c1103592 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/ConstrainedPythonBlobGenerator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/ConstrainedPythonBlobGenerator.kt @@ -45,9 +45,10 @@ class ConstrainedPythonBlobGenerator( } } val constraintViolation = constraintViolationSymbolProvider.toSymbol(shape) - private val blobConstraintsInfo: List = listOf(LengthTrait::class.java) - .mapNotNull { shape.getTrait(it).orNull() } - .map { BlobLength(it) } + private val blobConstraintsInfo: List = + listOf(LengthTrait::class.java) + .mapNotNull { shape.getTrait(it).orNull() } + .map { BlobLength(it) } private val constraintsInfo: List = blobConstraintsInfo.map { it.toTraitInfo() } fun render() { @@ -57,7 +58,10 @@ class ConstrainedPythonBlobGenerator( renderTryFrom(symbol, blobType) } - fun renderFrom(symbol: Symbol, blobType: RustType) { + fun renderFrom( + symbol: Symbol, + blobType: RustType, + ) { val name = symbol.name val inner = blobType.render() writer.rustTemplate( @@ -79,7 +83,10 @@ class ConstrainedPythonBlobGenerator( ) } - fun renderTryFrom(symbol: Symbol, blobType: RustType) { + fun renderTryFrom( + symbol: Symbol, + blobType: RustType, + ) { val name = symbol.name val inner = blobType.render() writer.rustTemplate( diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonApplicationGenerator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonApplicationGenerator.kt index 9b05d22434a..84ef0bdbc55 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonApplicationGenerator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonApplicationGenerator.kt @@ -70,11 +70,12 @@ class PythonApplicationGenerator( private val protocol: ServerProtocol, ) { private val index = TopDownIndex.of(codegenContext.model) - private val operations = index.getContainedOperations(codegenContext.serviceShape).toSortedSet( - compareBy { - it.id - }, - ).toList() + private val operations = + index.getContainedOperations(codegenContext.serviceShape).toSortedSet( + compareBy { + it.id + }, + ).toList() private val symbolProvider = codegenContext.symbolProvider private val libName = codegenContext.settings.moduleName.toSnakeCase() private val runtimeConfig = codegenContext.runtimeConfig @@ -348,18 +349,19 @@ class PythonApplicationGenerator( val output = PythonType.Opaque("${operationName}Output", libName, rustNamespace = "crate::output") val context = PythonType.Opaque("Ctx", libName) val returnType = PythonType.Union(listOf(output, PythonType.Awaitable(output))) - val handler = PythonType.Union( - listOf( - PythonType.Callable( - listOf(input, context), - returnType, + val handler = + PythonType.Union( + listOf( + PythonType.Callable( + listOf(input, context), + returnType, + ), + PythonType.Callable( + listOf(input), + returnType, + ), ), - PythonType.Callable( - listOf(input), - returnType, - ), - ), - ) + ) rustTemplate( """ @@ -435,21 +437,23 @@ class PythonApplicationGenerator( ) } - private fun RustWriter.operationImplementationStubs(operations: List) = rust( - operations.joinToString("\n///\n") { - val operationDocumentation = it.getTrait()?.value - val ret = if (!operationDocumentation.isNullOrBlank()) { - operationDocumentation.replace("#", "##").prependIndent("/// ## ") + "\n" - } else { - "" - } - ret + - """ - /// ${it.signature()}: - /// raise NotImplementedError - """.trimIndent() - }, - ) + private fun RustWriter.operationImplementationStubs(operations: List) = + rust( + operations.joinToString("\n///\n") { + val operationDocumentation = it.getTrait()?.value + val ret = + if (!operationDocumentation.isNullOrBlank()) { + operationDocumentation.replace("#", "##").prependIndent("/// ## ") + "\n" + } else { + "" + } + ret + + """ + /// ${it.signature()}: + /// raise NotImplementedError + """.trimIndent() + }, + ) /** * Returns the function signature for an operation handler implementation. Used in the documentation. diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEnumGenerator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEnumGenerator.kt index ac12cc0df37..a7bcdd56d5e 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEnumGenerator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEnumGenerator.kt @@ -35,27 +35,28 @@ class PythonConstrainedEnum( override fun additionalEnumAttributes(context: EnumGeneratorContext): List = listOf(Attribute(pyO3.resolve("pyclass"))) - override fun additionalEnumImpls(context: EnumGeneratorContext): Writable = writable { - Attribute(pyO3.resolve("pymethods")).render(this) - rustTemplate( - """ - impl ${context.enumName} { - #{name_method:W} - ##[getter] - pub fn value(&self) -> &str { - self.as_str() - } - fn __repr__(&self) -> String { - self.as_str().to_owned() - } - fn __str__(&self) -> String { - self.as_str().to_owned() + override fun additionalEnumImpls(context: EnumGeneratorContext): Writable = + writable { + Attribute(pyO3.resolve("pymethods")).render(this) + rustTemplate( + """ + impl ${context.enumName} { + #{name_method:W} + ##[getter] + pub fn value(&self) -> &str { + self.as_str() + } + fn __repr__(&self) -> String { + self.as_str().to_owned() + } + fn __str__(&self) -> String { + self.as_str().to_owned() + } } - } - """, - "name_method" to pyEnumName(context), - ) - } + """, + "name_method" to pyEnumName(context), + ) + } private fun pyEnumName(context: EnumGeneratorContext): Writable = writable { @@ -80,8 +81,8 @@ class PythonServerEnumGenerator( shape: StringShape, validationExceptionConversionGenerator: ValidationExceptionConversionGenerator, ) : EnumGenerator( - codegenContext.model, - codegenContext.symbolProvider, - shape, - PythonConstrainedEnum(codegenContext, shape, validationExceptionConversionGenerator), -) + codegenContext.model, + codegenContext.symbolProvider, + shape, + PythonConstrainedEnum(codegenContext, shape, validationExceptionConversionGenerator), + ) diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEventStreamErrorGenerator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEventStreamErrorGenerator.kt index b915e953cd9..118aa8a76c8 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEventStreamErrorGenerator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerEventStreamErrorGenerator.kt @@ -34,14 +34,15 @@ class PythonServerEventStreamErrorGenerator( private val symbolProvider: RustSymbolProvider, val shape: UnionShape, ) : ServerOperationErrorGenerator( - model, - symbolProvider, - shape, -) { + model, + symbolProvider, + shape, + ) { private val errorSymbol = symbolProvider.symbolForEventStreamError(shape) - private val errors = shape.eventStreamErrors().map { - model.expectShape(it.asMemberShape().get().target, StructureShape::class.java) - } + private val errors = + shape.eventStreamErrors().map { + model.expectShape(it.asMemberShape().get().target, StructureShape::class.java) + } private val pyO3 = PythonServerCargoDependency.PyO3.toType() diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerModuleGenerator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerModuleGenerator.kt index cbec0b8551c..d8dc07f0e1f 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerModuleGenerator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerModuleGenerator.kt @@ -28,10 +28,11 @@ class PythonServerModuleGenerator( private val rustCrate: RustCrate, private val serviceShapes: Set, ) { - private val codegenScope = arrayOf( - "SmithyPython" to PythonServerCargoDependency.smithyHttpServerPython(codegenContext.runtimeConfig).toType(), - "pyo3" to PythonServerCargoDependency.PyO3.toType(), - ) + private val codegenScope = + arrayOf( + "SmithyPython" to PythonServerCargoDependency.smithyHttpServerPython(codegenContext.runtimeConfig).toType(), + "pyo3" to PythonServerCargoDependency.PyO3.toType(), + ) private val symbolProvider = codegenContext.symbolProvider private val libName = codegenContext.settings.moduleName.toSnakeCase() @@ -84,18 +85,20 @@ class PythonServerModuleGenerator( visitedModelType = true } when (shape) { - is UnionShape -> rustTemplate( - """ - $moduleType.add_class::()?; - """, - *codegenScope, - ) - else -> rustTemplate( - """ - $moduleType.add_class::()?; - """, - *codegenScope, - ) + is UnionShape -> + rustTemplate( + """ + $moduleType.add_class::()?; + """, + *codegenScope, + ) + else -> + rustTemplate( + """ + $moduleType.add_class::()?; + """, + *codegenScope, + ) } } } @@ -237,7 +240,7 @@ class PythonServerModuleGenerator( // Render the codegeneration version as module attribute. private fun RustWriter.renderCodegenVersion() { - rust("""m.add("CODEGEN_VERSION", "${Version.stableCrateVersion()}")?;""") + rust("""m.add("CODEGEN_VERSION", "${Version.fromDefaultResource().gitHash}")?;""") } // Convert to symbol and check the namespace to figure out where they should be imported from. diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerOperationHandlerGenerator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerOperationHandlerGenerator.kt index 53b82c2d293..c77798f88bf 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerOperationHandlerGenerator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerOperationHandlerGenerator.kt @@ -82,7 +82,10 @@ class PythonServerOperationHandlerGenerator( ) } - private fun renderPyFunction(name: String, output: String): Writable = + private fun renderPyFunction( + name: String, + output: String, + ): Writable = writable { rustTemplate( """ @@ -101,7 +104,10 @@ class PythonServerOperationHandlerGenerator( ) } - private fun renderPyCoroutine(name: String, output: String): Writable = + private fun renderPyCoroutine( + name: String, + output: String, + ): Writable = writable { rustTemplate( """ diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerStructureGenerator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerStructureGenerator.kt index 9357383e6b2..3a78b0ddd05 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerStructureGenerator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerStructureGenerator.kt @@ -41,7 +41,6 @@ class PythonServerStructureGenerator( private val writer: RustWriter, private val shape: StructureShape, ) : StructureGenerator(model, codegenContext.symbolProvider, writer, shape, emptyList(), codegenContext.structSettings()) { - private val symbolProvider = codegenContext.symbolProvider private val libName = codegenContext.settings.moduleName.toSnakeCase() private val pyO3 = PythonServerCargoDependency.PyO3.toType() @@ -151,13 +150,19 @@ class PythonServerStructureGenerator( rust("/// :rtype ${PythonType.None.renderAsDocstring()}:") } - private fun renderMemberSignature(shape: MemberShape, symbol: Symbol): Writable = + private fun renderMemberSignature( + shape: MemberShape, + symbol: Symbol, + ): Writable = writable { val pythonType = memberPythonType(shape, symbol) rust("/// :type ${pythonType.renderAsDocstring()}:") } - private fun memberPythonType(shape: MemberShape, symbol: Symbol): PythonType = + private fun memberPythonType( + shape: MemberShape, + symbol: Symbol, + ): PythonType = if (shape.isEventStream(model)) { val eventStreamSymbol = PythonEventStreamSymbolProvider.parseSymbol(symbol) val innerT = eventStreamSymbol.innerT.pythonType(libName) diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerUnionGenerator.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerUnionGenerator.kt index 01a2a833afe..ef5a043a505 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerUnionGenerator.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerUnionGenerator.kt @@ -179,11 +179,12 @@ class PythonServerUnionGenerator( ) writer.rust("/// :rtype ${pythonType.renderAsDocstring()}:") writer.rustBlockTemplate("pub fn as_$funcNamePart(&self) -> #{pyo3}::PyResult<${rustType.render()}>", "pyo3" to pyo3) { - val variantType = if (rustType.isCopy()) { - "*variant" - } else { - "variant.clone()" - } + val variantType = + if (rustType.isCopy()) { + "*variant" + } else { + "variant.clone()" + } val errorVariant = memberSymbol.rustType().pythonType(libName).renderAsDocstring() rustTemplate( """ diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/protocols/PythonServerProtocolLoader.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/protocols/PythonServerProtocolLoader.kt index dbfa9e029dc..4e41cc8ed37 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/protocols/PythonServerProtocolLoader.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/protocols/PythonServerProtocolLoader.kt @@ -37,18 +37,22 @@ import software.amazon.smithy.rust.codegen.server.smithy.protocols.ServerRestJso */ class PythonServerAfterDeserializedMemberJsonParserCustomization(private val runtimeConfig: RuntimeConfig) : JsonParserCustomization() { - override fun section(section: JsonParserSection): Writable = when (section) { - is JsonParserSection.AfterTimestampDeserializedMember -> writable { - rust(".map(#T::from)", PythonServerRuntimeType.dateTime(runtimeConfig).toSymbol()) + override fun section(section: JsonParserSection): Writable = + when (section) { + is JsonParserSection.AfterTimestampDeserializedMember -> + writable { + rust(".map(#T::from)", PythonServerRuntimeType.dateTime(runtimeConfig).toSymbol()) + } + is JsonParserSection.AfterBlobDeserializedMember -> + writable { + rust(".map(#T::from)", PythonServerRuntimeType.blob(runtimeConfig).toSymbol()) + } + is JsonParserSection.AfterDocumentDeserializedMember -> + writable { + rust(".map(#T::from)", PythonServerRuntimeType.document(runtimeConfig).toSymbol()) + } + else -> emptySection } - is JsonParserSection.AfterBlobDeserializedMember -> writable { - rust(".map(#T::from)", PythonServerRuntimeType.blob(runtimeConfig).toSymbol()) - } - is JsonParserSection.AfterDocumentDeserializedMember -> writable { - rust(".map(#T::from)", PythonServerRuntimeType.document(runtimeConfig).toSymbol()) - } - else -> emptySection - } } /** @@ -57,13 +61,15 @@ class PythonServerAfterDeserializedMemberJsonParserCustomization(private val run */ class PythonServerAfterDeserializedMemberServerHttpBoundCustomization() : ServerHttpBoundProtocolCustomization() { - override fun section(section: ServerHttpBoundProtocolSection): Writable = when (section) { - is ServerHttpBoundProtocolSection.AfterTimestampDeserializedMember -> writable { - rust(".into()") - } + override fun section(section: ServerHttpBoundProtocolSection): Writable = + when (section) { + is ServerHttpBoundProtocolSection.AfterTimestampDeserializedMember -> + writable { + rust(".into()") + } - else -> emptySection - } + else -> emptySection + } } /** @@ -71,12 +77,14 @@ class PythonServerAfterDeserializedMemberServerHttpBoundCustomization() : */ class PythonServerAfterDeserializedMemberHttpBindingCustomization(private val runtimeConfig: RuntimeConfig) : HttpBindingCustomization() { - override fun section(section: HttpBindingSection): Writable = when (section) { - is HttpBindingSection.AfterDeserializingIntoADateTimeOfHttpHeaders -> writable { - rust(".into_iter().map(#T::from).collect()", PythonServerRuntimeType.dateTime(runtimeConfig).toSymbol()) + override fun section(section: HttpBindingSection): Writable = + when (section) { + is HttpBindingSection.AfterDeserializingIntoADateTimeOfHttpHeaders -> + writable { + rust(".into_iter().map(#T::from).collect()", PythonServerRuntimeType.dateTime(runtimeConfig).toSymbol()) + } + else -> emptySection } - else -> emptySection - } } /** @@ -87,60 +95,73 @@ class PythonServerAfterDeserializedMemberHttpBindingCustomization(private val ru * `aws_smithy_http_server_python::types::ByteStream` which already implements the `Stream` trait. */ class PythonServerStreamPayloadSerializerCustomization() : ServerHttpBoundProtocolCustomization() { - override fun section(section: ServerHttpBoundProtocolSection): Writable = when (section) { - is ServerHttpBoundProtocolSection.WrapStreamPayload -> writable { - section.params.payloadGenerator.generatePayload(this, section.params.shapeName, section.params.shape) - } + override fun section(section: ServerHttpBoundProtocolSection): Writable = + when (section) { + is ServerHttpBoundProtocolSection.WrapStreamPayload -> + writable { + section.params.payloadGenerator.generatePayload(this, section.params.shapeName, section.params.shape) + } - else -> emptySection - } + else -> emptySection + } } class PythonServerProtocolLoader( private val supportedProtocols: ProtocolMap, ) : ProtocolLoader(supportedProtocols) { - companion object { fun defaultProtocols(runtimeConfig: RuntimeConfig) = mapOf( - RestJson1Trait.ID to ServerRestJsonFactory( - additionalParserCustomizations = listOf( - PythonServerAfterDeserializedMemberJsonParserCustomization(runtimeConfig), - ), - additionalServerHttpBoundProtocolCustomizations = listOf( - PythonServerAfterDeserializedMemberServerHttpBoundCustomization(), - PythonServerStreamPayloadSerializerCustomization(), - ), - additionalHttpBindingCustomizations = listOf( - PythonServerAfterDeserializedMemberHttpBindingCustomization(runtimeConfig), - ), - ), - AwsJson1_0Trait.ID to ServerAwsJsonFactory( - AwsJsonVersion.Json10, - additionalParserCustomizations = listOf( - PythonServerAfterDeserializedMemberJsonParserCustomization(runtimeConfig), - ), - additionalServerHttpBoundProtocolCustomizations = listOf( - PythonServerAfterDeserializedMemberServerHttpBoundCustomization(), - PythonServerStreamPayloadSerializerCustomization(), - ), - additionalHttpBindingCustomizations = listOf( - PythonServerAfterDeserializedMemberHttpBindingCustomization(runtimeConfig), - ), - ), - AwsJson1_1Trait.ID to ServerAwsJsonFactory( - AwsJsonVersion.Json11, - additionalParserCustomizations = listOf( - PythonServerAfterDeserializedMemberJsonParserCustomization(runtimeConfig), + RestJson1Trait.ID to + ServerRestJsonFactory( + additionalParserCustomizations = + listOf( + PythonServerAfterDeserializedMemberJsonParserCustomization(runtimeConfig), + ), + additionalServerHttpBoundProtocolCustomizations = + listOf( + PythonServerAfterDeserializedMemberServerHttpBoundCustomization(), + PythonServerStreamPayloadSerializerCustomization(), + ), + additionalHttpBindingCustomizations = + listOf( + PythonServerAfterDeserializedMemberHttpBindingCustomization(runtimeConfig), + ), ), - additionalServerHttpBoundProtocolCustomizations = listOf( - PythonServerAfterDeserializedMemberServerHttpBoundCustomization(), - PythonServerStreamPayloadSerializerCustomization(), + AwsJson1_0Trait.ID to + ServerAwsJsonFactory( + AwsJsonVersion.Json10, + additionalParserCustomizations = + listOf( + PythonServerAfterDeserializedMemberJsonParserCustomization(runtimeConfig), + ), + additionalServerHttpBoundProtocolCustomizations = + listOf( + PythonServerAfterDeserializedMemberServerHttpBoundCustomization(), + PythonServerStreamPayloadSerializerCustomization(), + ), + additionalHttpBindingCustomizations = + listOf( + PythonServerAfterDeserializedMemberHttpBindingCustomization(runtimeConfig), + ), ), - additionalHttpBindingCustomizations = listOf( - PythonServerAfterDeserializedMemberHttpBindingCustomization(runtimeConfig), + AwsJson1_1Trait.ID to + ServerAwsJsonFactory( + AwsJsonVersion.Json11, + additionalParserCustomizations = + listOf( + PythonServerAfterDeserializedMemberJsonParserCustomization(runtimeConfig), + ), + additionalServerHttpBoundProtocolCustomizations = + listOf( + PythonServerAfterDeserializedMemberServerHttpBoundCustomization(), + PythonServerStreamPayloadSerializerCustomization(), + ), + additionalHttpBindingCustomizations = + listOf( + PythonServerAfterDeserializedMemberHttpBindingCustomization(runtimeConfig), + ), ), - ), ) } } diff --git a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/testutil/PythonServerTestHelpers.kt b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/testutil/PythonServerTestHelpers.kt index c7e6023f3cc..3f4199c4fa4 100644 --- a/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/testutil/PythonServerTestHelpers.kt +++ b/codegen-server/python/src/main/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/testutil/PythonServerTestHelpers.kt @@ -21,10 +21,9 @@ import java.io.File import java.nio.file.Path val TestRuntimeConfig = - RuntimeConfig(runtimeCrateLocation = RuntimeCrateLocation.Path(File("../../rust-runtime").absolutePath)) + RuntimeConfig(runtimeCrateLocation = RuntimeCrateLocation.path(File("../../rust-runtime").absolutePath)) -fun generatePythonServerPluginContext(model: Model) = - generatePluginContext(model, runtimeConfig = TestRuntimeConfig) +fun generatePythonServerPluginContext(model: Model) = generatePluginContext(model, runtimeConfig = TestRuntimeConfig) fun executePythonServerCodegenVisitor(pluginCtx: PluginContext) { val codegenDecorator = diff --git a/codegen-server/python/src/test/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerSymbolProviderTest.kt b/codegen-server/python/src/test/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerSymbolProviderTest.kt index e3ab955a9f1..3f0922f49e4 100644 --- a/codegen-server/python/src/test/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerSymbolProviderTest.kt +++ b/codegen-server/python/src/test/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerSymbolProviderTest.kt @@ -21,7 +21,8 @@ internal class PythonServerSymbolProviderTest { @Test fun `python symbol provider rewrites timestamp shape symbol`() { - val model = """ + val model = + """ namespace test structure TimestampStruct { @@ -45,7 +46,7 @@ internal class PythonServerSymbolProviderTest { key: String, value: Timestamp } - """.asSmithyModel() + """.asSmithyModel() val provider = PythonServerSymbolVisitor(serverTestRustSettings(), model, null, ServerTestRustSymbolProviderConfig) @@ -72,7 +73,8 @@ internal class PythonServerSymbolProviderTest { @Test fun `python symbol provider rewrites blob shape symbol`() { - val model = """ + val model = + """ namespace test structure BlobStruct { @@ -96,7 +98,7 @@ internal class PythonServerSymbolProviderTest { key: String, value: Blob } - """.asSmithyModel() + """.asSmithyModel() val provider = PythonServerSymbolVisitor(serverTestRustSettings(), model, null, ServerTestRustSymbolProviderConfig) diff --git a/codegen-server/python/src/test/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerTypesTest.kt b/codegen-server/python/src/test/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerTypesTest.kt index 9c38d343958..44b83c31326 100644 --- a/codegen-server/python/src/test/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerTypesTest.kt +++ b/codegen-server/python/src/test/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonServerTypesTest.kt @@ -19,7 +19,8 @@ import kotlin.io.path.appendText internal class PythonServerTypesTest { @Test fun `document type`() { - val model = """ + val model = + """ namespace test use aws.protocols#restJson1 @@ -44,50 +45,51 @@ internal class PythonServerTypesTest { structure EchoOutput { value: Document, } - """.asSmithyModel() + """.asSmithyModel() val (pluginCtx, testDir) = generatePythonServerPluginContext(model) executePythonServerCodegenVisitor(pluginCtx) - val testCases = listOf( - Pair( - """ { "value": 42 } """, - """ - assert input.value == 42 - output = EchoOutput(value=input.value) - """, - ), - Pair( - """ { "value": "foobar" } """, - """ - assert input.value == "foobar" - output = EchoOutput(value=input.value) - """, - ), - Pair( - """ - { - "value": [ - true, - false, - 42, - 42.0, - -42, - { - "nested": "value" - }, - { - "nested": [1, 2, 3] - } - ] - } - """, - """ - assert input.value == [True, False, 42, 42.0, -42, {"nested": "value"}, {"nested": [1, 2, 3]}] - output = EchoOutput(value=input.value) - """, - ), - ) + val testCases = + listOf( + Pair( + """ { "value": 42 } """, + """ + assert input.value == 42 + output = EchoOutput(value=input.value) + """, + ), + Pair( + """ { "value": "foobar" } """, + """ + assert input.value == "foobar" + output = EchoOutput(value=input.value) + """, + ), + Pair( + """ + { + "value": [ + true, + false, + 42, + 42.0, + -42, + { + "nested": "value" + }, + { + "nested": [1, 2, 3] + } + ] + } + """, + """ + assert input.value == [True, False, 42, 42.0, -42, {"nested": "value"}, {"nested": [1, 2, 3]}] + output = EchoOutput(value=input.value) + """, + ), + ) val writer = RustWriter.forModule("service") writer.tokioTest("document_type") { @@ -147,7 +149,8 @@ internal class PythonServerTypesTest { @Test fun `timestamp type`() { - val model = """ + val model = + """ namespace test use aws.protocols#restJson1 @@ -178,7 +181,7 @@ internal class PythonServerTypesTest { value: Timestamp, opt_value: Timestamp, } - """.asSmithyModel() + """.asSmithyModel() val (pluginCtx, testDir) = generatePythonServerPluginContext(model) executePythonServerCodegenVisitor(pluginCtx) diff --git a/codegen-server/python/src/test/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonTypeInformationGenerationTest.kt b/codegen-server/python/src/test/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonTypeInformationGenerationTest.kt index c552d32eddb..9a7bbc1ed79 100644 --- a/codegen-server/python/src/test/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonTypeInformationGenerationTest.kt +++ b/codegen-server/python/src/test/kotlin/software/amazon/smithy/rust/codegen/server/python/smithy/generators/PythonTypeInformationGenerationTest.kt @@ -16,7 +16,8 @@ import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestCode internal class PythonTypeInformationGenerationTest { @Test fun `generates python type information`() { - val model = """ + val model = + """ namespace test structure Foo { @@ -24,7 +25,7 @@ internal class PythonTypeInformationGenerationTest { bar: String, baz: Integer } - """.asSmithyModel() + """.asSmithyModel() val foo = model.lookup("test#Foo") val codegenContext = serverTestCodegenContext(model) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstrainedShapeSymbolMetadataProvider.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstrainedShapeSymbolMetadataProvider.kt index df933eb657d..f100fb55704 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstrainedShapeSymbolMetadataProvider.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstrainedShapeSymbolMetadataProvider.kt @@ -31,10 +31,12 @@ class ConstrainedShapeSymbolMetadataProvider( private val base: RustSymbolProvider, private val constrainedTypes: Boolean, ) : SymbolMetadataProvider(base) { - override fun memberMeta(memberShape: MemberShape) = base.toSymbol(memberShape).expectRustMetadata() + override fun structureMeta(structureShape: StructureShape) = base.toSymbol(structureShape).expectRustMetadata() + override fun unionMeta(unionShape: UnionShape) = base.toSymbol(unionShape).expectRustMetadata() + override fun enumMeta(stringShape: StringShape) = base.toSymbol(stringShape).expectRustMetadata() private fun addDerivesAndAdjustVisibilityIfConstrained(shape: Shape): RustMetadata { @@ -58,8 +60,14 @@ class ConstrainedShapeSymbolMetadataProvider( } override fun listMeta(listShape: ListShape): RustMetadata = addDerivesAndAdjustVisibilityIfConstrained(listShape) + override fun mapMeta(mapShape: MapShape): RustMetadata = addDerivesAndAdjustVisibilityIfConstrained(mapShape) - override fun stringMeta(stringShape: StringShape): RustMetadata = addDerivesAndAdjustVisibilityIfConstrained(stringShape) - override fun numberMeta(numberShape: NumberShape): RustMetadata = addDerivesAndAdjustVisibilityIfConstrained(numberShape) + + override fun stringMeta(stringShape: StringShape): RustMetadata = + addDerivesAndAdjustVisibilityIfConstrained(stringShape) + + override fun numberMeta(numberShape: NumberShape): RustMetadata = + addDerivesAndAdjustVisibilityIfConstrained(numberShape) + override fun blobMeta(blobShape: BlobShape) = addDerivesAndAdjustVisibilityIfConstrained(blobShape) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstrainedShapeSymbolProvider.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstrainedShapeSymbolProvider.kt index 0dfda68d1eb..4d4d9db21a5 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstrainedShapeSymbolProvider.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstrainedShapeSymbolProvider.kt @@ -144,8 +144,9 @@ open class ConstrainedShapeSymbolProvider( supportedCollectionConstraintTraits.mapNotNull { shape.getTrait(it).orNull() }.toSet() val allConstraintTraits = allConstraintTraits.mapNotNull { shape.getTrait(it).orNull() }.toSet() - return supportedConstraintTraits.isNotEmpty() && allConstraintTraits.subtract(supportedConstraintTraits) - .isEmpty() + return supportedConstraintTraits.isNotEmpty() && + allConstraintTraits.subtract(supportedConstraintTraits) + .isEmpty() } /** @@ -160,8 +161,9 @@ open class ConstrainedShapeSymbolProvider( defaultModule: RustModule.LeafModule, pubCrateServerBuilder: Boolean, ): Pair { - val syntheticMemberTrait = shape.getTrait() - ?: return Pair(shape.contextName(serviceShape), defaultModule) + val syntheticMemberTrait = + shape.getTrait() + ?: return Pair(shape.contextName(serviceShape), defaultModule) return if (syntheticMemberTrait.container is StructureShape) { val builderModule = syntheticMemberTrait.container.serverBuilderModule(base, pubCrateServerBuilder) @@ -171,19 +173,22 @@ open class ConstrainedShapeSymbolProvider( // For non-structure shapes, the new shape defined for a constrained member shape // needs to be placed in an inline module named `pub {container_name_in_snake_case}`. val moduleName = RustReservedWords.escapeIfNeeded(syntheticMemberTrait.container.id.name.toSnakeCase()) - val innerModuleName = moduleName + if (pubCrateServerBuilder) { - "_internal" - } else { - "" - } + val innerModuleName = + moduleName + + if (pubCrateServerBuilder) { + "_internal" + } else { + "" + } - val innerModule = RustModule.new( - innerModuleName, - visibility = Visibility.publicIf(!pubCrateServerBuilder, Visibility.PUBCRATE), - parent = defaultModule, - inline = true, - documentationOverride = "", - ) + val innerModule = + RustModule.new( + innerModuleName, + visibility = Visibility.publicIf(!pubCrateServerBuilder, Visibility.PUBCRATE), + parent = defaultModule, + inline = true, + documentationOverride = "", + ) val renameTo = syntheticMemberTrait.member.memberName ?: syntheticMemberTrait.member.id.name Pair(renameTo.toPascalCase(), innerModule) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintViolationSymbolProvider.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintViolationSymbolProvider.kt index c42ed10198f..ca8ae559f80 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintViolationSymbolProvider.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintViolationSymbolProvider.kt @@ -72,31 +72,34 @@ class ConstraintViolationSymbolProvider( private val serviceShape: ServiceShape, ) : WrappingSymbolProvider(base) { private val constraintViolationName = "ConstraintViolation" - private val visibility = when (publicConstrainedTypes) { - true -> Visibility.PUBLIC - false -> Visibility.PUBCRATE - } + private val visibility = + when (publicConstrainedTypes) { + true -> Visibility.PUBLIC + false -> Visibility.PUBCRATE + } private fun Shape.shapeModule(): RustModule.LeafModule { - val documentation = if (publicConstrainedTypes && this.isDirectlyConstrained(base)) { - val symbol = base.toSymbol(this) - "See [`${this.contextName(serviceShape)}`]($symbol)." - } else { - "" - } + val documentation = + if (publicConstrainedTypes && this.isDirectlyConstrained(base)) { + val symbol = base.toSymbol(this) + "See [`${this.contextName(serviceShape)}`]($symbol)." + } else { + "" + } val syntheticTrait = getTrait() - val (module, name) = if (syntheticTrait != null) { - // For constrained member shapes, the ConstraintViolation code needs to go in an inline rust module - // that is a descendant of the module that contains the extracted shape itself. - val overriddenMemberModule = this.getParentAndInlineModuleForConstrainedMember(base, publicConstrainedTypes)!! - val name = syntheticTrait.member.memberName - Pair(overriddenMemberModule.second, RustReservedWords.escapeIfNeeded(name).toSnakeCase()) - } else { - // Need to use the context name so we get the correct name for maps. - Pair(ServerRustModule.Model, RustReservedWords.escapeIfNeeded(this.contextName(serviceShape)).toSnakeCase()) - } + val (module, name) = + if (syntheticTrait != null) { + // For constrained member shapes, the ConstraintViolation code needs to go in an inline rust module + // that is a descendant of the module that contains the extracted shape itself. + val overriddenMemberModule = this.getParentAndInlineModuleForConstrainedMember(base, publicConstrainedTypes)!! + val name = syntheticTrait.member.memberName + Pair(overriddenMemberModule.second, RustReservedWords.escapeIfNeeded(name).toSnakeCase()) + } else { + // Need to use the context name so we get the correct name for maps. + Pair(ServerRustModule.Model, RustReservedWords.escapeIfNeeded(this.contextName(serviceShape)).toSnakeCase()) + } return RustModule.new( name = name, diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt index 5d0313e132c..f6dc9eac664 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/Constraints.kt @@ -41,7 +41,7 @@ import software.amazon.smithy.rust.codegen.core.util.toSnakeCase import software.amazon.smithy.rust.codegen.server.smithy.generators.serverBuilderModule import software.amazon.smithy.rust.codegen.server.smithy.traits.SyntheticStructureFromConstrainedMemberTrait -/** +/* * This file contains utilities to work with constrained shapes. */ @@ -49,27 +49,28 @@ import software.amazon.smithy.rust.codegen.server.smithy.traits.SyntheticStructu * Whether the shape has any trait that could cause a request to be rejected with a constraint violation, _whether * we support it or not_. */ -fun Shape.hasConstraintTrait() = - allConstraintTraits.any(this::hasTrait) - -val allConstraintTraits = setOf( - LengthTrait::class.java, - PatternTrait::class.java, - RangeTrait::class.java, - UniqueItemsTrait::class.java, - EnumTrait::class.java, - RequiredTrait::class.java, -) +fun Shape.hasConstraintTrait() = allConstraintTraits.any(this::hasTrait) + +val allConstraintTraits = + setOf( + LengthTrait::class.java, + PatternTrait::class.java, + RangeTrait::class.java, + UniqueItemsTrait::class.java, + EnumTrait::class.java, + RequiredTrait::class.java, + ) val supportedStringConstraintTraits = setOf(LengthTrait::class.java, PatternTrait::class.java) /** * Supported constraint traits for the `list` and `set` shapes. */ -val supportedCollectionConstraintTraits = setOf( - LengthTrait::class.java, - UniqueItemsTrait::class.java, -) +val supportedCollectionConstraintTraits = + setOf( + LengthTrait::class.java, + UniqueItemsTrait::class.java, + ) /** * We say a shape is _directly_ constrained if: @@ -86,30 +87,39 @@ val supportedCollectionConstraintTraits = setOf( * * [the spec]: https://awslabs.github.io/smithy/2.0/spec/constraint-traits.html */ -fun Shape.isDirectlyConstrained(symbolProvider: SymbolProvider): Boolean = when (this) { - is StructureShape -> { - // TODO(https://github.com/smithy-lang/smithy-rs/issues/1302, https://github.com/awslabs/smithy/issues/1179): - // The only reason why the functions in this file have - // to take in a `SymbolProvider` is because non-`required` blob streaming members are interpreted as - // `required`, so we can't use `member.isOptional` here. - this.members().any { !symbolProvider.toSymbol(it).isOptional() && !it.hasNonNullDefault() } - } +fun Shape.isDirectlyConstrained(symbolProvider: SymbolProvider): Boolean = + when (this) { + is StructureShape -> { + // TODO(https://github.com/smithy-lang/smithy-rs/issues/1302, https://github.com/awslabs/smithy/issues/1179): + // The only reason why the functions in this file have + // to take in a `SymbolProvider` is because non-`required` blob streaming members are interpreted as + // `required`, so we can't use `member.isOptional` here. + this.members().any { !symbolProvider.toSymbol(it).isOptional() && !it.hasNonNullDefault() } + } - is MapShape -> this.hasTrait() - is StringShape -> this.hasTrait() || supportedStringConstraintTraits.any { this.hasTrait(it) } - is CollectionShape -> supportedCollectionConstraintTraits.any { this.hasTrait(it) } - is IntegerShape, is ShortShape, is LongShape, is ByteShape -> this.hasTrait() - is BlobShape -> this.hasTrait() - else -> false -} + is MapShape -> this.hasTrait() + is StringShape -> this.hasTrait() || supportedStringConstraintTraits.any { this.hasTrait(it) } + is CollectionShape -> supportedCollectionConstraintTraits.any { this.hasTrait(it) } + is IntegerShape, is ShortShape, is LongShape, is ByteShape -> this.hasTrait() + is BlobShape -> this.hasTrait() + else -> false + } -fun MemberShape.hasConstraintTraitOrTargetHasConstraintTrait(model: Model, symbolProvider: SymbolProvider): Boolean = +fun MemberShape.hasConstraintTraitOrTargetHasConstraintTrait( + model: Model, + symbolProvider: SymbolProvider, +): Boolean = this.isDirectlyConstrained(symbolProvider) || model.expectShape(this.target).isDirectlyConstrained(symbolProvider) -fun Shape.isTransitivelyButNotDirectlyConstrained(model: Model, symbolProvider: SymbolProvider): Boolean = - !this.isDirectlyConstrained(symbolProvider) && this.canReachConstrainedShape(model, symbolProvider) +fun Shape.isTransitivelyButNotDirectlyConstrained( + model: Model, + symbolProvider: SymbolProvider, +): Boolean = !this.isDirectlyConstrained(symbolProvider) && this.canReachConstrainedShape(model, symbolProvider) -fun Shape.canReachConstrainedShape(model: Model, symbolProvider: SymbolProvider): Boolean = +fun Shape.canReachConstrainedShape( + model: Model, + symbolProvider: SymbolProvider, +): Boolean = if (this is MemberShape) { // TODO(https://github.com/smithy-lang/smithy-rs/issues/1401) Constraint traits on member shapes are not implemented // yet. Also, note that a walker over a member shape can, perhaps counterintuitively, reach the _containing_ shape, @@ -119,18 +129,24 @@ fun Shape.canReachConstrainedShape(model: Model, symbolProvider: SymbolProvider) DirectedWalker(model).walkShapes(this).toSet().any { it.isDirectlyConstrained(symbolProvider) } } -fun MemberShape.targetCanReachConstrainedShape(model: Model, symbolProvider: SymbolProvider): Boolean = - model.expectShape(this.target).canReachConstrainedShape(model, symbolProvider) - -fun Shape.hasPublicConstrainedWrapperTupleType(model: Model, publicConstrainedTypes: Boolean): Boolean = when (this) { - is CollectionShape -> publicConstrainedTypes && supportedCollectionConstraintTraits.any(this::hasTrait) - is MapShape -> publicConstrainedTypes && this.hasTrait() - is StringShape -> !this.hasTrait() && (publicConstrainedTypes && supportedStringConstraintTraits.any(this::hasTrait)) - is IntegerShape, is ShortShape, is LongShape, is ByteShape -> publicConstrainedTypes && this.hasTrait() - is MemberShape -> model.expectShape(this.target).hasPublicConstrainedWrapperTupleType(model, publicConstrainedTypes) - is BlobShape -> publicConstrainedTypes && this.hasTrait() - else -> false -} +fun MemberShape.targetCanReachConstrainedShape( + model: Model, + symbolProvider: SymbolProvider, +): Boolean = model.expectShape(this.target).canReachConstrainedShape(model, symbolProvider) + +fun Shape.hasPublicConstrainedWrapperTupleType( + model: Model, + publicConstrainedTypes: Boolean, +): Boolean = + when (this) { + is CollectionShape -> publicConstrainedTypes && supportedCollectionConstraintTraits.any(this::hasTrait) + is MapShape -> publicConstrainedTypes && this.hasTrait() + is StringShape -> !this.hasTrait() && (publicConstrainedTypes && supportedStringConstraintTraits.any(this::hasTrait)) + is IntegerShape, is ShortShape, is LongShape, is ByteShape -> publicConstrainedTypes && this.hasTrait() + is MemberShape -> model.expectShape(this.target).hasPublicConstrainedWrapperTupleType(model, publicConstrainedTypes) + is BlobShape -> publicConstrainedTypes && this.hasTrait() + else -> false + } fun Shape.wouldHaveConstrainedWrapperTupleTypeWerePublicConstrainedTypesEnabled(model: Model): Boolean = hasPublicConstrainedWrapperTupleType(model, true) @@ -141,8 +157,11 @@ fun Shape.wouldHaveConstrainedWrapperTupleTypeWerePublicConstrainedTypesEnabled( * This function is used in core code generators, so it takes in a [CodegenContext] that is downcast * to [ServerCodegenContext] when generating servers. */ -fun workingWithPublicConstrainedWrapperTupleType(shape: Shape, model: Model, publicConstrainedTypes: Boolean): Boolean = - shape.hasPublicConstrainedWrapperTupleType(model, publicConstrainedTypes) +fun workingWithPublicConstrainedWrapperTupleType( + shape: Shape, + model: Model, + publicConstrainedTypes: Boolean, +): Boolean = shape.hasPublicConstrainedWrapperTupleType(model, publicConstrainedTypes) /** * Returns whether a shape's type _name_ contains a non-public type when `publicConstrainedTypes` is `false`. @@ -159,16 +178,19 @@ fun Shape.typeNameContainsNonPublicType( model: Model, symbolProvider: SymbolProvider, publicConstrainedTypes: Boolean, -): Boolean = !publicConstrainedTypes && when (this) { - is SimpleShape -> wouldHaveConstrainedWrapperTupleTypeWerePublicConstrainedTypesEnabled(model) - is MemberShape -> model.expectShape(this.target) - .typeNameContainsNonPublicType(model, symbolProvider, publicConstrainedTypes) - - is CollectionShape -> this.canReachConstrainedShape(model, symbolProvider) - is MapShape -> this.canReachConstrainedShape(model, symbolProvider) - is StructureShape, is UnionShape -> false - else -> UNREACHABLE("the above arms should be exhaustive, but we received shape: $this") -} +): Boolean = + !publicConstrainedTypes && + when (this) { + is SimpleShape -> wouldHaveConstrainedWrapperTupleTypeWerePublicConstrainedTypesEnabled(model) + is MemberShape -> + model.expectShape(this.target) + .typeNameContainsNonPublicType(model, symbolProvider, publicConstrainedTypes) + + is CollectionShape -> this.canReachConstrainedShape(model, symbolProvider) + is MapShape -> this.canReachConstrainedShape(model, symbolProvider) + is StructureShape, is UnionShape -> false + else -> UNREACHABLE("the above arms should be exhaustive, but we received shape: $this") + } /** * For synthetic shapes that are added to the model because of member constrained shapes, it returns @@ -183,7 +205,10 @@ fun Shape.overriddenConstrainedMemberInfo(): Pair? { /** * Returns the parent and the inline module that this particular shape should go in. */ -fun Shape.getParentAndInlineModuleForConstrainedMember(symbolProvider: RustSymbolProvider, publicConstrainedTypes: Boolean): Pair? { +fun Shape.getParentAndInlineModuleForConstrainedMember( + symbolProvider: RustSymbolProvider, + publicConstrainedTypes: Boolean, +): Pair? { val overriddenTrait = getTrait() ?: return null return if (overriddenTrait.container is StructureShape) { val structureModule = symbolProvider.toSymbol(overriddenTrait.container).module() @@ -202,12 +227,13 @@ fun Shape.getParentAndInlineModuleForConstrainedMember(symbolProvider: RustSymbo Pair(shapeModule.parent as RustModule.LeafModule, shapeModule) } else { val name = RustReservedWords.escapeIfNeeded(overriddenTrait.container.id.name).toSnakeCase() + "_internal" - val innerModule = RustModule.new( - name = name, - visibility = Visibility.PUBCRATE, - parent = ServerRustModule.Model, - inline = true, - ) + val innerModule = + RustModule.new( + name = name, + visibility = Visibility.PUBCRATE, + parent = ServerRustModule.Model, + inline = true, + ) Pair(ServerRustModule.Model, innerModule) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/DeriveEqAndHashSymbolMetadataProvider.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/DeriveEqAndHashSymbolMetadataProvider.kt index d3f70592714..d2ff87195dc 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/DeriveEqAndHashSymbolMetadataProvider.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/DeriveEqAndHashSymbolMetadataProvider.kt @@ -83,12 +83,18 @@ class DeriveEqAndHashSymbolMetadataProvider( override fun memberMeta(memberShape: MemberShape) = base.toSymbol(memberShape).expectRustMetadata() override fun structureMeta(structureShape: StructureShape) = addDeriveEqAndHashIfPossible(structureShape) + override fun unionMeta(unionShape: UnionShape) = addDeriveEqAndHashIfPossible(unionShape) + override fun enumMeta(stringShape: StringShape) = addDeriveEqAndHashIfPossible(stringShape) override fun listMeta(listShape: ListShape): RustMetadata = addDeriveEqAndHashIfPossible(listShape) + override fun mapMeta(mapShape: MapShape): RustMetadata = addDeriveEqAndHashIfPossible(mapShape) + override fun stringMeta(stringShape: StringShape): RustMetadata = addDeriveEqAndHashIfPossible(stringShape) + override fun numberMeta(numberShape: NumberShape): RustMetadata = addDeriveEqAndHashIfPossible(numberShape) + override fun blobMeta(blobShape: BlobShape): RustMetadata = addDeriveEqAndHashIfPossible(blobShape) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/LengthTraitValidationErrorMessage.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/LengthTraitValidationErrorMessage.kt index cb08de3c734..f31feae6ad3 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/LengthTraitValidationErrorMessage.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/LengthTraitValidationErrorMessage.kt @@ -9,15 +9,16 @@ import software.amazon.smithy.model.traits.LengthTrait fun LengthTrait.validationErrorMessage(): String { val beginning = "Value with length {} at '{}' failed to satisfy constraint: Member must have length " - val ending = if (this.min.isPresent && this.max.isPresent) { - "between ${this.min.get()} and ${this.max.get()}, inclusive" - } else if (this.min.isPresent) { - ( - "greater than or equal to ${this.min.get()}" + val ending = + if (this.min.isPresent && this.max.isPresent) { + "between ${this.min.get()} and ${this.max.get()}, inclusive" + } else if (this.min.isPresent) { + ( + "greater than or equal to ${this.min.get()}" ) - } else { - check(this.max.isPresent) - "less than or equal to ${this.max.get()}" - } + } else { + check(this.max.isPresent) + "less than or equal to ${this.max.get()}" + } return "$beginning$ending" } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PatternTraitEscapedSpecialCharsValidator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PatternTraitEscapedSpecialCharsValidator.kt index a26dff9e36c..4a51a2040a2 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PatternTraitEscapedSpecialCharsValidator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PatternTraitEscapedSpecialCharsValidator.kt @@ -14,18 +14,20 @@ import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.expectTrait class PatternTraitEscapedSpecialCharsValidator : AbstractValidator() { - private val specialCharsWithEscapes = mapOf( - '\b' to "\\b", - '\u000C' to "\\f", - '\n' to "\\n", - '\r' to "\\r", - '\t' to "\\t", - ) + private val specialCharsWithEscapes = + mapOf( + '\b' to "\\b", + '\u000C' to "\\f", + '\n' to "\\n", + '\r' to "\\r", + '\t' to "\\t", + ) private val specialChars = specialCharsWithEscapes.keys override fun validate(model: Model): List { - val shapes = model.getStringShapesWithTrait(PatternTrait::class.java) + - model.getMemberShapesWithTrait(PatternTrait::class.java) + val shapes = + model.getStringShapesWithTrait(PatternTrait::class.java) + + model.getMemberShapesWithTrait(PatternTrait::class.java) return shapes .filter { shape -> checkMisuse(shape) } .map { shape -> makeError(shape) } @@ -34,10 +36,11 @@ class PatternTraitEscapedSpecialCharsValidator : AbstractValidator() { private fun makeError(shape: Shape): ValidationEvent { val pattern = shape.expectTrait() - val replacement = pattern.pattern.toString() - .map { specialCharsWithEscapes.getOrElse(it) { it.toString() } } - .joinToString("") - .dq() + val replacement = + pattern.pattern.toString() + .map { specialCharsWithEscapes.getOrElse(it) { it.toString() } } + .joinToString("") + .dq() val message = """ Non-escaped special characters used inside `@pattern`. diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PubCrateConstrainedShapeSymbolProvider.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PubCrateConstrainedShapeSymbolProvider.kt index c64182f152d..24c32c66c20 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PubCrateConstrainedShapeSymbolProvider.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PubCrateConstrainedShapeSymbolProvider.kt @@ -68,12 +68,13 @@ class PubCrateConstrainedShapeSymbolProvider( check(shape is CollectionShape || shape is MapShape) val name = constrainedTypeNameForCollectionOrMapShape(shape, serviceShape) - val module = RustModule.new( - RustReservedWords.escapeIfNeeded(name.toSnakeCase()), - visibility = Visibility.PUBCRATE, - parent = ServerRustModule.ConstrainedModule, - inline = true, - ) + val module = + RustModule.new( + RustReservedWords.escapeIfNeeded(name.toSnakeCase()), + visibility = Visibility.PUBCRATE, + parent = ServerRustModule.ConstrainedModule, + inline = true, + ) val rustType = RustType.Opaque(name, module.fullyQualifiedPath()) return Symbol.builder() .rustType(rustType) @@ -127,7 +128,10 @@ class PubCrateConstrainedShapeSymbolProvider( } } -fun constrainedTypeNameForCollectionOrMapShape(shape: Shape, serviceShape: ServiceShape): String { +fun constrainedTypeNameForCollectionOrMapShape( + shape: Shape, + serviceShape: ServiceShape, +): String { check(shape is CollectionShape || shape is MapShape) return "${shape.id.getName(serviceShape).toPascalCase()}Constrained" } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RangeTraitValidationErrorMessage.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RangeTraitValidationErrorMessage.kt index 9cde66e6e04..560777debbc 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RangeTraitValidationErrorMessage.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RangeTraitValidationErrorMessage.kt @@ -9,15 +9,16 @@ import software.amazon.smithy.model.traits.RangeTrait fun RangeTrait.validationErrorMessage(): String { val beginning = "Value at '{}' failed to satisfy constraint: Member must be " - val ending = if (this.min.isPresent && this.max.isPresent) { - "between ${this.min.get()} and ${this.max.get()}, inclusive" - } else if (this.min.isPresent) { - ( - "greater than or equal to ${this.min.get()}" + val ending = + if (this.min.isPresent && this.max.isPresent) { + "between ${this.min.get()} and ${this.max.get()}, inclusive" + } else if (this.min.isPresent) { + ( + "greater than or equal to ${this.min.get()}" ) - } else { - check(this.max.isPresent) - "less than or equal to ${this.max.get()}" - } + } else { + check(this.max.isPresent) + "less than or equal to ${this.max.get()}" + } return "$beginning$ending" } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriter.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriter.kt index 96b3b5739c3..2a6867c6f6a 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriter.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriter.kt @@ -147,7 +147,8 @@ private val crateToInlineModule: ConcurrentHashMap = class InnerModule(private val moduleDocProvider: ModuleDocProvider, debugMode: Boolean) { // Holds the root modules to start rendering the descendents from. private val topLevelModuleWriters: ConcurrentHashMap = ConcurrentHashMap() - private val inlineModuleWriters: ConcurrentHashMap> = ConcurrentHashMap() + private val inlineModuleWriters: ConcurrentHashMap> = + ConcurrentHashMap() private val docWriters: ConcurrentHashMap> = ConcurrentHashMap() private val writerCreator = RustWriter.factory(debugMode) @@ -155,13 +156,19 @@ class InnerModule(private val moduleDocProvider: ModuleDocProvider, debugMode: B // indicating that it contains generated code and should not be manually edited. This comment // appears on each descendent inline module. To remove those comments, each time an inline // module is rendered, first `emptyLineCount` characters are removed from it. - private val emptyLineCount: Int = writerCreator - .apply("lines-it-always-writes.rs", "crate") - .toString() - .split("\n")[0] - .length - - fun withInlineModule(outerWriter: RustWriter, innerModule: RustModule.LeafModule, docWriter: DocWriter? = null, writable: Writable) { + private val emptyLineCount: Int = + writerCreator + .apply("lines-it-always-writes.rs", "crate") + .toString() + .split("\n")[0] + .length + + fun withInlineModule( + outerWriter: RustWriter, + innerModule: RustModule.LeafModule, + docWriter: DocWriter? = null, + writable: Writable, + ) { if (docWriter != null) { val moduleDocWriterList = docWriters.getOrPut(innerModule) { mutableListOf() } moduleDocWriterList.add(docWriter) @@ -172,7 +179,12 @@ class InnerModule(private val moduleDocProvider: ModuleDocProvider, debugMode: B /** * Given a `RustCrate` and a `RustModule.LeafModule()`, it creates a writer to that module and calls the writable. */ - fun withInlineModuleHierarchyUsingCrate(rustCrate: RustCrate, inlineModule: RustModule.LeafModule, docWriter: DocWriter? = null, writable: Writable) { + fun withInlineModuleHierarchyUsingCrate( + rustCrate: RustCrate, + inlineModule: RustModule.LeafModule, + docWriter: DocWriter? = null, + writable: Writable, + ) { val hierarchy = getHierarchy(inlineModule).toMutableList() check(!hierarchy.first().isInline()) { "When adding a `RustModule.LeafModule` to the crate, the topmost module in the hierarchy cannot be an inline module." @@ -211,7 +223,12 @@ class InnerModule(private val moduleDocProvider: ModuleDocProvider, debugMode: B * Given a `Writer` to a module and an inline `RustModule.LeafModule()`, it creates a writer to that module and calls the writable. * It registers the complete hierarchy including the `outerWriter` if that is not already registrered. */ - fun withInlineModuleHierarchy(outerWriter: RustWriter, inlineModule: RustModule.LeafModule, docWriter: DocWriter? = null, writable: Writable) { + fun withInlineModuleHierarchy( + outerWriter: RustWriter, + inlineModule: RustModule.LeafModule, + docWriter: DocWriter? = null, + writable: Writable, + ) { val hierarchy = getHierarchy(inlineModule).toMutableList() if (!hierarchy.first().isInline()) { hierarchy.removeFirst() @@ -263,12 +280,18 @@ class InnerModule(private val moduleDocProvider: ModuleDocProvider, debugMode: B fun render() { var writerToAddDependencies: RustWriter? = null - fun writeInlineCode(rustWriter: RustWriter, code: String) { + fun writeInlineCode( + rustWriter: RustWriter, + code: String, + ) { val inlineCode = code.drop(emptyLineCount) rustWriter.writeWithNoFormatting(inlineCode) } - fun renderDescendents(topLevelWriter: RustWriter, inMemoryWriter: RustWriter) { + fun renderDescendents( + topLevelWriter: RustWriter, + inMemoryWriter: RustWriter, + ) { // Traverse all descendent inline modules and render them. inlineModuleWriters[inMemoryWriter]!!.forEach { writeDocs(it.inlineModule) @@ -300,7 +323,10 @@ class InnerModule(private val moduleDocProvider: ModuleDocProvider, debugMode: B * Given the inline-module returns an existing `RustWriter`, or if that inline module * has never been registered before then a new `RustWriter` is created and returned. */ - private fun getWriter(outerWriter: RustWriter, inlineModule: RustModule.LeafModule): RustWriter { + private fun getWriter( + outerWriter: RustWriter, + inlineModule: RustModule.LeafModule, + ): RustWriter { val nestedModuleWriter = inlineModuleWriters[outerWriter] if (nestedModuleWriter != null) { return findOrAddToList(nestedModuleWriter, inlineModule) @@ -326,9 +352,10 @@ class InnerModule(private val moduleDocProvider: ModuleDocProvider, debugMode: B inlineModuleList: MutableList, lookForModule: RustModule.LeafModule, ): RustWriter { - val inlineModuleAndWriter = inlineModuleList.firstOrNull() { - it.inlineModule.name == lookForModule.name - } + val inlineModuleAndWriter = + inlineModuleList.firstOrNull { + it.inlineModule.name == lookForModule.name + } return if (inlineModuleAndWriter == null) { val inlineWriter = createNewInlineModule() inlineModuleList.add(InlineModuleWithWriter(lookForModule, inlineWriter)) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustServerCodegenPlugin.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustServerCodegenPlugin.kt index 2672bbe9f3d..e68fa26a33c 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustServerCodegenPlugin.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustServerCodegenPlugin.kt @@ -70,30 +70,29 @@ class RustServerCodegenPlugin : ServerDecoratableBuildPlugin() { constrainedTypes: Boolean = true, includeConstrainedShapeProvider: Boolean = true, codegenDecorator: ServerCodegenDecorator, - ) = - SymbolVisitor(settings, model, serviceShape = serviceShape, config = rustSymbolProviderConfig) - // Generate public constrained types for directly constrained shapes. - .let { - if (includeConstrainedShapeProvider) ConstrainedShapeSymbolProvider(it, serviceShape, constrainedTypes) else it - } - // Generate different types for EventStream shapes (e.g. transcribe streaming) - .let { EventStreamSymbolProvider(rustSymbolProviderConfig.runtimeConfig, it, CodegenTarget.SERVER) } - // Generate [ByteStream] instead of `Blob` for streaming binary shapes (e.g. S3 GetObject) - .let { StreamingShapeSymbolProvider(it) } - // Add Rust attributes (like `#[derive(PartialEq)]`) to generated shapes - .let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf()) } - // Constrained shapes generate newtypes that need the same derives we place on types generated from aggregate shapes. - .let { ConstrainedShapeSymbolMetadataProvider(it, constrainedTypes) } - // Streaming shapes need different derives (e.g. they cannot derive `PartialEq`) - .let { StreamingShapeMetadataProvider(it) } - // Derive `Eq` and `Hash` if possible. - .let { DeriveEqAndHashSymbolMetadataProvider(it) } - // Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot - // be the name of an operation input - .let { RustReservedWordSymbolProvider(it, ServerReservedWords) } - // Allows decorators to inject a custom symbol provider - .let { codegenDecorator.symbolProvider(it) } - // Inject custom symbols. - .let { CustomShapeSymbolProvider(it) } + ) = SymbolVisitor(settings, model, serviceShape = serviceShape, config = rustSymbolProviderConfig) + // Generate public constrained types for directly constrained shapes. + .let { + if (includeConstrainedShapeProvider) ConstrainedShapeSymbolProvider(it, serviceShape, constrainedTypes) else it + } + // Generate different types for EventStream shapes (e.g. transcribe streaming) + .let { EventStreamSymbolProvider(rustSymbolProviderConfig.runtimeConfig, it, CodegenTarget.SERVER) } + // Generate [ByteStream] instead of `Blob` for streaming binary shapes (e.g. S3 GetObject) + .let { StreamingShapeSymbolProvider(it) } + // Add Rust attributes (like `#[derive(PartialEq)]`) to generated shapes + .let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf()) } + // Constrained shapes generate newtypes that need the same derives we place on types generated from aggregate shapes. + .let { ConstrainedShapeSymbolMetadataProvider(it, constrainedTypes) } + // Streaming shapes need different derives (e.g. they cannot derive `PartialEq`) + .let { StreamingShapeMetadataProvider(it) } + // Derive `Eq` and `Hash` if possible. + .let { DeriveEqAndHashSymbolMetadataProvider(it) } + // Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot + // be the name of an operation input + .let { RustReservedWordSymbolProvider(it, ServerReservedWords) } + // Allows decorators to inject a custom symbol provider + .let { codegenDecorator.symbolProvider(it) } + // Inject custom symbols. + .let { CustomShapeSymbolProvider(it) } } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCargoDependency.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCargoDependency.kt index 779fcb16863..01df0c0a937 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCargoDependency.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCargoDependency.kt @@ -15,7 +15,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig * For a dependency that is used in the client, or in both the client and the server, use [CargoDependency] directly. */ object ServerCargoDependency { - val AsyncTrait: CargoDependency = CargoDependency("async-trait", CratesIo("0.1")) + val AsyncTrait: CargoDependency = CargoDependency("async-trait", CratesIo("0.1.74")) val FormUrlEncoded: CargoDependency = CargoDependency("form_urlencoded", CratesIo("1")) val FuturesUtil: CargoDependency = CargoDependency("futures-util", CratesIo("0.3")) val Mime: CargoDependency = CargoDependency("mime", CratesIo("0.3")) @@ -29,5 +29,6 @@ object ServerCargoDependency { val HyperDev: CargoDependency = CargoDependency("hyper", CratesIo("0.14.12"), DependencyScope.Dev) fun smithyHttpServer(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-http-server") + fun smithyTypes(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-types") } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenContext.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenContext.kt index d952a7771b0..41c3c94708e 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenContext.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenContext.kt @@ -37,8 +37,8 @@ data class ServerCodegenContext( val constraintViolationSymbolProvider: ConstraintViolationSymbolProvider, val pubCrateConstrainedShapeSymbolProvider: PubCrateConstrainedShapeSymbolProvider, ) : CodegenContext( - model, symbolProvider, moduleDocProvider, serviceShape, protocol, settings, CodegenTarget.SERVER, -) { + model, symbolProvider, moduleDocProvider, serviceShape, protocol, settings, CodegenTarget.SERVER, + ) { override fun builderInstantiator(): BuilderInstantiator { return ServerBuilderInstantiator(symbolProvider, returnSymbolToParseFn(this)) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt index 9e9ce5c598d..87b55066165 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt @@ -101,7 +101,6 @@ open class ServerCodegenVisitor( context: PluginContext, private val codegenDecorator: ServerCodegenDecorator, ) : ShapeVisitor.Default() { - protected val logger = Logger.getLogger(javaClass.name) protected var settings = ServerRustSettings.from(context.model, context.settings) @@ -114,12 +113,13 @@ open class ServerCodegenVisitor( protected var validationExceptionConversionGenerator: ValidationExceptionConversionGenerator init { - val rustSymbolProviderConfig = RustSymbolProviderConfig( - runtimeConfig = settings.runtimeConfig, - renameExceptions = false, - nullabilityCheckMode = NullableIndex.CheckMode.SERVER, - moduleProvider = ServerModuleProvider, - ) + val rustSymbolProviderConfig = + RustSymbolProviderConfig( + runtimeConfig = settings.runtimeConfig, + renameExceptions = false, + nullabilityCheckMode = NullableIndex.CheckMode.SERVER, + moduleProvider = ServerModuleProvider, + ) val baseModel = baselineTransform(context.model) val service = settings.getService(baseModel) @@ -135,45 +135,50 @@ open class ServerCodegenVisitor( model = codegenDecorator.transformModel(service, baseModel, settings) - val serverSymbolProviders = ServerSymbolProviders.from( - settings, - model, - service, - rustSymbolProviderConfig, - settings.codegenConfig.publicConstrainedTypes, - codegenDecorator, - RustServerCodegenPlugin::baseSymbolProvider, - ) + val serverSymbolProviders = + ServerSymbolProviders.from( + settings, + model, + service, + rustSymbolProviderConfig, + settings.codegenConfig.publicConstrainedTypes, + codegenDecorator, + RustServerCodegenPlugin::baseSymbolProvider, + ) - codegenContext = ServerCodegenContext( - model, - serverSymbolProviders.symbolProvider, - null, - service, - protocolShape, - settings, - serverSymbolProviders.unconstrainedShapeSymbolProvider, - serverSymbolProviders.constrainedShapeSymbolProvider, - serverSymbolProviders.constraintViolationSymbolProvider, - serverSymbolProviders.pubCrateConstrainedShapeSymbolProvider, - ) + codegenContext = + ServerCodegenContext( + model, + serverSymbolProviders.symbolProvider, + null, + service, + protocolShape, + settings, + serverSymbolProviders.unconstrainedShapeSymbolProvider, + serverSymbolProviders.constrainedShapeSymbolProvider, + serverSymbolProviders.constraintViolationSymbolProvider, + serverSymbolProviders.pubCrateConstrainedShapeSymbolProvider, + ) // We can use a not-null assertion because [CombinedServerCodegenDecorator] returns a not null value. validationExceptionConversionGenerator = codegenDecorator.validationExceptionConversion(codegenContext)!! - codegenContext = codegenContext.copy( - moduleDocProvider = codegenDecorator.moduleDocumentationCustomization( - codegenContext, - ServerModuleDocProvider(codegenContext), - ), - ) + codegenContext = + codegenContext.copy( + moduleDocProvider = + codegenDecorator.moduleDocumentationCustomization( + codegenContext, + ServerModuleDocProvider(codegenContext), + ), + ) - rustCrate = RustCrate( - context.fileManifest, - codegenContext.symbolProvider, - settings.codegenConfig, - codegenContext.expectModuleDocProvider(), - ) + rustCrate = + RustCrate( + context.fileManifest, + codegenContext.symbolProvider, + settings.codegenConfig, + codegenContext.expectModuleDocProvider(), + ) protocolGenerator = this.protocolGeneratorFactory.buildProtocolGenerator(codegenContext) } @@ -209,8 +214,7 @@ open class ServerCodegenVisitor( /** * Exposure purely for unit test purposes. */ - internal fun baselineTransformInternalTest(model: Model) = - baselineTransform(model) + internal fun baselineTransformInternalTest(model: Model) = baselineTransform(model) /** * Execute code generation @@ -324,12 +328,13 @@ open class ServerCodegenVisitor( writer: RustWriter, ) { if (codegenContext.settings.codegenConfig.publicConstrainedTypes || shape.isReachableFromOperationInput()) { - val serverBuilderGenerator = ServerBuilderGenerator( - codegenContext, - shape, - validationExceptionConversionGenerator, - protocolGenerator.protocol, - ) + val serverBuilderGenerator = + ServerBuilderGenerator( + codegenContext, + shape, + validationExceptionConversionGenerator, + protocolGenerator.protocol, + ) serverBuilderGenerator.render(rustCrate, writer) if (codegenContext.settings.codegenConfig.publicConstrainedTypes) { @@ -366,14 +371,16 @@ open class ServerCodegenVisitor( } override fun listShape(shape: ListShape) = collectionShape(shape) + override fun setShape(shape: SetShape) = collectionShape(shape) private fun collectionShape(shape: CollectionShape) { val renderUnconstrainedList = - shape.isReachableFromOperationInput() && shape.canReachConstrainedShape( - model, - codegenContext.symbolProvider, - ) + shape.isReachableFromOperationInput() && + shape.canReachConstrainedShape( + model, + codegenContext.symbolProvider, + ) val isDirectlyConstrained = shape.isDirectlyConstrained(codegenContext.symbolProvider) if (renderUnconstrainedList) { @@ -433,10 +440,11 @@ open class ServerCodegenVisitor( override fun mapShape(shape: MapShape) { val renderUnconstrainedMap = - shape.isReachableFromOperationInput() && shape.canReachConstrainedShape( - model, - codegenContext.symbolProvider, - ) + shape.isReachableFromOperationInput() && + shape.canReachConstrainedShape( + model, + codegenContext.symbolProvider, + ) val isDirectlyConstrained = shape.isDirectlyConstrained(codegenContext.symbolProvider) if (renderUnconstrainedMap) { @@ -498,15 +506,21 @@ open class ServerCodegenVisitor( * Although raw strings require no code generation, enums are actually [EnumTrait] applied to string shapes. */ override fun stringShape(shape: StringShape) { - fun serverEnumGeneratorFactory(codegenContext: ServerCodegenContext, shape: StringShape) = - ServerEnumGenerator(codegenContext, shape, validationExceptionConversionGenerator) + fun serverEnumGeneratorFactory( + codegenContext: ServerCodegenContext, + shape: StringShape, + ) = ServerEnumGenerator(codegenContext, shape, validationExceptionConversionGenerator) stringShape(shape, ::serverEnumGeneratorFactory) } override fun integerShape(shape: IntegerShape) = integralShape(shape) + override fun shortShape(shape: ShortShape) = integralShape(shape) + override fun longShape(shape: LongShape) = integralShape(shape) + override fun byteShape(shape: ByteShape) = integralShape(shape) + private fun integralShape(shape: NumberShape) { if (shape.isDirectlyConstrained(codegenContext.symbolProvider)) { logger.info("[rust-server-codegen] Generating a constrained integral $shape") @@ -569,7 +583,8 @@ open class ServerCodegenVisitor( UnionGenerator(model, codegenContext.symbolProvider, this, shape, renderUnknownVariant = false).render() } - if (shape.isReachableFromOperationInput() && shape.canReachConstrainedShape( + if (shape.isReachableFromOperationInput() && + shape.canReachConstrainedShape( model, codegenContext.symbolProvider, ) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerReservedWords.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerReservedWords.kt index 64d9ea04f41..23c2e5c1684 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerReservedWords.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerReservedWords.kt @@ -8,8 +8,9 @@ package software.amazon.smithy.rust.codegen.server.smithy import software.amazon.smithy.rust.codegen.core.rustlang.RustReservedWordConfig import software.amazon.smithy.rust.codegen.core.smithy.generators.StructureGenerator -val ServerReservedWords = RustReservedWordConfig( - structureMemberMap = StructureGenerator.structureMemberNameMap, - unionMemberMap = emptyMap(), - enumMemberMap = emptyMap(), -) +val ServerReservedWords = + RustReservedWordConfig( + structureMemberMap = StructureGenerator.structureMemberNameMap, + unionMemberMap = emptyMap(), + enumMemberMap = emptyMap(), + ) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRuntimeType.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRuntimeType.kt index 46b18face58..7e539915281 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRuntimeType.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRuntimeType.kt @@ -17,8 +17,11 @@ object ServerRuntimeType { fun router(runtimeConfig: RuntimeConfig) = ServerCargoDependency.smithyHttpServer(runtimeConfig).toType().resolve("routing::Router") - fun protocol(name: String, path: String, runtimeConfig: RuntimeConfig) = - ServerCargoDependency.smithyHttpServer(runtimeConfig).toType().resolve("protocol::$path::$name") + fun protocol( + name: String, + path: String, + runtimeConfig: RuntimeConfig, + ) = ServerCargoDependency.smithyHttpServer(runtimeConfig).toType().resolve("protocol::$path::$name") fun protocol(runtimeConfig: RuntimeConfig) = protocol("Protocol", "", runtimeConfig) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRustModule.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRustModule.kt index 2c2ef75f744..b7e349ddc02 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRustModule.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRustModule.kt @@ -30,6 +30,7 @@ import software.amazon.smithy.rust.codegen.core.util.hasTrait import software.amazon.smithy.rust.codegen.core.util.toSnakeCase import software.amazon.smithy.rust.codegen.server.smithy.generators.DocHandlerGenerator import software.amazon.smithy.rust.codegen.server.smithy.generators.handlerImports + object ServerRustModule { val root = RustModule.LibRs @@ -67,43 +68,49 @@ class ServerModuleDocProvider(private val codegenContext: ServerCodegenContext) } } - private fun operationShapeModuleDoc(): Writable = writable { - val index = TopDownIndex.of(codegenContext.model) - val operations = index.getContainedOperations(codegenContext.serviceShape).toSortedSet(compareBy { it.id }) + private fun operationShapeModuleDoc(): Writable = + writable { + val index = TopDownIndex.of(codegenContext.model) + val operations = index.getContainedOperations(codegenContext.serviceShape).toSortedSet(compareBy { it.id }) - val firstOperation = operations.first() ?: return@writable - val crateName = codegenContext.settings.moduleName.toSnakeCase() + val firstOperation = operations.first() ?: return@writable + val crateName = codegenContext.settings.moduleName.toSnakeCase() - rustTemplate( - """ - /// A collection of types representing each operation defined in the service closure. - /// - /// The [plugin system](#{SmithyHttpServer}::plugin) makes use of these - /// [zero-sized types](https://doc.rust-lang.org/nomicon/exotic-sizes.html##zero-sized-types-zsts) (ZSTs) to - /// parameterize [`Plugin`](#{SmithyHttpServer}::plugin::Plugin) implementations. Their traits, such as - /// [`OperationShape`](#{SmithyHttpServer}::operation::OperationShape), can be used to provide - /// operation specific information to the [`Layer`](#{Tower}::Layer) being applied. - """.trimIndent(), - "SmithyHttpServer" to - ServerCargoDependency.smithyHttpServer(codegenContext.runtimeConfig).toType(), - "Tower" to ServerCargoDependency.Tower.toType(), - "Handler" to DocHandlerGenerator(codegenContext, firstOperation, "handler", commentToken = "///").docSignature(), - "HandlerImports" to handlerImports(crateName, operations, commentToken = "///"), - ) - } + rustTemplate( + """ + /// A collection of types representing each operation defined in the service closure. + /// + /// The [plugin system](#{SmithyHttpServer}::plugin) makes use of these + /// [zero-sized types](https://doc.rust-lang.org/nomicon/exotic-sizes.html##zero-sized-types-zsts) (ZSTs) to + /// parameterize [`Plugin`](#{SmithyHttpServer}::plugin::Plugin) implementations. Their traits, such as + /// [`OperationShape`](#{SmithyHttpServer}::operation::OperationShape), can be used to provide + /// operation specific information to the [`Layer`](#{Tower}::Layer) being applied. + """.trimIndent(), + "SmithyHttpServer" to + ServerCargoDependency.smithyHttpServer(codegenContext.runtimeConfig).toType(), + "Tower" to ServerCargoDependency.Tower.toType(), + "Handler" to DocHandlerGenerator(codegenContext, firstOperation, "handler", commentToken = "///").docSignature(), + "HandlerImports" to handlerImports(crateName, operations, commentToken = "///"), + ) + } } object ServerModuleProvider : ModuleProvider { - override fun moduleForShape(context: ModuleProviderContext, shape: Shape): RustModule.LeafModule = when (shape) { - is OperationShape -> ServerRustModule.Operation - is StructureShape -> when { - shape.hasTrait() -> ServerRustModule.Error - shape.hasTrait() -> ServerRustModule.Input - shape.hasTrait() -> ServerRustModule.Output + override fun moduleForShape( + context: ModuleProviderContext, + shape: Shape, + ): RustModule.LeafModule = + when (shape) { + is OperationShape -> ServerRustModule.Operation + is StructureShape -> + when { + shape.hasTrait() -> ServerRustModule.Error + shape.hasTrait() -> ServerRustModule.Input + shape.hasTrait() -> ServerRustModule.Output + else -> ServerRustModule.Model + } else -> ServerRustModule.Model } - else -> ServerRustModule.Model - } override fun moduleForOperationError( context: ModuleProviderContext, @@ -115,18 +122,24 @@ object ServerModuleProvider : ModuleProvider { eventStream: UnionShape, ): RustModule.LeafModule = ServerRustModule.Error - override fun moduleForBuilder(context: ModuleProviderContext, shape: Shape, symbol: Symbol): RustModule.LeafModule { + override fun moduleForBuilder( + context: ModuleProviderContext, + shape: Shape, + symbol: Symbol, + ): RustModule.LeafModule { val pubCrate = !(context.settings as ServerRustSettings).codegenConfig.publicConstrainedTypes - val builderNamespace = RustReservedWords.escapeIfNeeded(symbol.name.toSnakeCase()) + - if (pubCrate) { - "_internal" - } else { - "" + val builderNamespace = + RustReservedWords.escapeIfNeeded(symbol.name.toSnakeCase()) + + if (pubCrate) { + "_internal" + } else { + "" + } + val visibility = + when (pubCrate) { + true -> Visibility.PUBCRATE + false -> Visibility.PUBLIC } - val visibility = when (pubCrate) { - true -> Visibility.PUBCRATE - false -> Visibility.PUBLIC - } return RustModule.new( builderNamespace, visibility, diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRustSettings.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRustSettings.kt index 7b0ba87e611..6f6c25a450a 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRustSettings.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerRustSettings.kt @@ -14,7 +14,7 @@ import software.amazon.smithy.rust.codegen.core.smithy.CoreRustSettings import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig import java.util.Optional -/** +/* * [ServerRustSettings] and [ServerCodegenConfig] classes. * * These classes are entirely analogous to [ClientRustSettings] and [ClientCodegenConfig]. Refer to the documentation @@ -40,20 +40,23 @@ data class ServerRustSettings( override val examplesUri: String?, override val customizationConfig: ObjectNode?, ) : CoreRustSettings( - service, - moduleName, - moduleVersion, - moduleAuthors, - moduleDescription, - moduleRepository, - runtimeConfig, - codegenConfig, - license, - examplesUri, - customizationConfig, -) { + service, + moduleName, + moduleVersion, + moduleAuthors, + moduleDescription, + moduleRepository, + runtimeConfig, + codegenConfig, + license, + examplesUri, + customizationConfig, + ) { companion object { - fun from(model: Model, config: ObjectNode): ServerRustSettings { + fun from( + model: Model, + config: ObjectNode, + ): ServerRustSettings { val coreRustSettings = CoreRustSettings.from(model, config) val codegenSettingsNode = config.getObjectMember(CODEGEN_SETTINGS) val coreCodegenConfig = CoreCodegenConfig.fromNode(codegenSettingsNode) @@ -91,27 +94,29 @@ data class ServerCodegenConfig( */ val experimentalCustomValidationExceptionWithReasonPleaseDoNotUse: String? = defaultExperimentalCustomValidationExceptionWithReasonPleaseDoNotUse, ) : CoreCodegenConfig( - formatTimeoutSeconds, debugMode, -) { + formatTimeoutSeconds, debugMode, + ) { companion object { private const val defaultPublicConstrainedTypes = true private const val defaultIgnoreUnsupportedConstraints = false private val defaultExperimentalCustomValidationExceptionWithReasonPleaseDoNotUse = null - fun fromCodegenConfigAndNode(coreCodegenConfig: CoreCodegenConfig, node: Optional) = - if (node.isPresent) { - ServerCodegenConfig( - formatTimeoutSeconds = coreCodegenConfig.formatTimeoutSeconds, - debugMode = coreCodegenConfig.debugMode, - publicConstrainedTypes = node.get().getBooleanMemberOrDefault("publicConstrainedTypes", defaultPublicConstrainedTypes), - ignoreUnsupportedConstraints = node.get().getBooleanMemberOrDefault("ignoreUnsupportedConstraints", defaultIgnoreUnsupportedConstraints), - experimentalCustomValidationExceptionWithReasonPleaseDoNotUse = node.get().getStringMemberOrDefault("experimentalCustomValidationExceptionWithReasonPleaseDoNotUse", defaultExperimentalCustomValidationExceptionWithReasonPleaseDoNotUse), - ) - } else { - ServerCodegenConfig( - formatTimeoutSeconds = coreCodegenConfig.formatTimeoutSeconds, - debugMode = coreCodegenConfig.debugMode, - ) - } + fun fromCodegenConfigAndNode( + coreCodegenConfig: CoreCodegenConfig, + node: Optional, + ) = if (node.isPresent) { + ServerCodegenConfig( + formatTimeoutSeconds = coreCodegenConfig.formatTimeoutSeconds, + debugMode = coreCodegenConfig.debugMode, + publicConstrainedTypes = node.get().getBooleanMemberOrDefault("publicConstrainedTypes", defaultPublicConstrainedTypes), + ignoreUnsupportedConstraints = node.get().getBooleanMemberOrDefault("ignoreUnsupportedConstraints", defaultIgnoreUnsupportedConstraints), + experimentalCustomValidationExceptionWithReasonPleaseDoNotUse = node.get().getStringMemberOrDefault("experimentalCustomValidationExceptionWithReasonPleaseDoNotUse", defaultExperimentalCustomValidationExceptionWithReasonPleaseDoNotUse), + ) + } else { + ServerCodegenConfig( + formatTimeoutSeconds = coreCodegenConfig.formatTimeoutSeconds, + debugMode = coreCodegenConfig.debugMode, + ) + } } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerSymbolProviders.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerSymbolProviders.kt index a2693050a3c..c8035121d65 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerSymbolProviders.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerSymbolProviders.kt @@ -11,6 +11,9 @@ import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProviderConfig import software.amazon.smithy.rust.codegen.server.smithy.customize.ServerCodegenDecorator +typealias BaseSymbolProviderFactory = + (settings: ServerRustSettings, model: Model, service: ServiceShape, rustSymbolProviderConfig: RustSymbolProviderConfig, publicConstrainedTypes: Boolean, includeConstraintShapeProvider: Boolean, codegenDecorator: ServerCodegenDecorator) -> RustSymbolProvider + /** * Just a handy class to centralize initialization all the symbol providers required by the server code generators, to * make the init blocks of the codegen visitors ([ServerCodegenVisitor] and [PythonServerCodegenVisitor]), and the @@ -31,41 +34,46 @@ class ServerSymbolProviders private constructor( rustSymbolProviderConfig: RustSymbolProviderConfig, publicConstrainedTypes: Boolean, codegenDecorator: ServerCodegenDecorator, - baseSymbolProviderFactory: (settings: ServerRustSettings, model: Model, service: ServiceShape, rustSymbolProviderConfig: RustSymbolProviderConfig, publicConstrainedTypes: Boolean, includeConstraintShapeProvider: Boolean, codegenDecorator: ServerCodegenDecorator) -> RustSymbolProvider, + baseSymbolProviderFactory: BaseSymbolProviderFactory, ): ServerSymbolProviders { - val baseSymbolProvider = baseSymbolProviderFactory(settings, model, service, rustSymbolProviderConfig, publicConstrainedTypes, publicConstrainedTypes, codegenDecorator) + val baseSymbolProvider = + baseSymbolProviderFactory(settings, model, service, rustSymbolProviderConfig, publicConstrainedTypes, publicConstrainedTypes, codegenDecorator) return ServerSymbolProviders( symbolProvider = baseSymbolProvider, - constrainedShapeSymbolProvider = baseSymbolProviderFactory( - settings, - model, - service, - rustSymbolProviderConfig, - publicConstrainedTypes, - true, - codegenDecorator, - ), - unconstrainedShapeSymbolProvider = UnconstrainedShapeSymbolProvider( + constrainedShapeSymbolProvider = baseSymbolProviderFactory( settings, model, service, rustSymbolProviderConfig, - false, - false, + publicConstrainedTypes, + true, codegenDecorator, ), - publicConstrainedTypes, service, - ), - pubCrateConstrainedShapeSymbolProvider = PubCrateConstrainedShapeSymbolProvider( - baseSymbolProvider, - service, - ), - constraintViolationSymbolProvider = ConstraintViolationSymbolProvider( - baseSymbolProvider, - publicConstrainedTypes, - service, - ), + unconstrainedShapeSymbolProvider = + UnconstrainedShapeSymbolProvider( + baseSymbolProviderFactory( + settings, + model, + service, + rustSymbolProviderConfig, + false, + false, + codegenDecorator, + ), + publicConstrainedTypes, service, + ), + pubCrateConstrainedShapeSymbolProvider = + PubCrateConstrainedShapeSymbolProvider( + baseSymbolProvider, + service, + ), + constraintViolationSymbolProvider = + ConstraintViolationSymbolProvider( + baseSymbolProvider, + publicConstrainedTypes, + service, + ), ) } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/UnconstrainedShapeSymbolProvider.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/UnconstrainedShapeSymbolProvider.kt index 488c9347a20..a615d403665 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/UnconstrainedShapeSymbolProvider.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/UnconstrainedShapeSymbolProvider.kt @@ -100,12 +100,13 @@ class UnconstrainedShapeSymbolProvider( val name = unconstrainedTypeNameForCollectionOrMapOrUnionShape(shape) val parent = shape.getParentAndInlineModuleForConstrainedMember(this, publicConstrainedTypes)?.second ?: ServerRustModule.UnconstrainedModule - val module = RustModule.new( - RustReservedWords.escapeIfNeeded(name.toSnakeCase()), - visibility = Visibility.PUBCRATE, - parent = parent, - inline = true, - ) + val module = + RustModule.new( + RustReservedWords.escapeIfNeeded(name.toSnakeCase()), + visibility = Visibility.PUBCRATE, + parent = parent, + inline = true, + ) val rustType = RustType.Opaque(name, module.fullyQualifiedPath()) return Symbol.builder() .rustType(rustType) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraints.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraints.kt index abee410b5b0..0d3f50ddca1 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraints.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraints.kt @@ -37,7 +37,12 @@ private sealed class UnsupportedConstraintMessageKind { private val constraintTraitsUberIssue = "https://github.com/smithy-lang/smithy-rs/issues/1401" fun intoLogMessage(ignoreUnsupportedConstraints: Boolean): LogMessage { - fun buildMessage(intro: String, willSupport: Boolean, trackingIssue: String? = null, canBeIgnored: Boolean = true): String { + fun buildMessage( + intro: String, + willSupport: Boolean, + trackingIssue: String? = null, + canBeIgnored: Boolean = true, + ): String { var msg = """ $intro This is not supported in the smithy-rs server SDK.""" @@ -62,79 +67,85 @@ private sealed class UnsupportedConstraintMessageKind { constraintTrait: Trait, trackingIssue: String, willSupport: Boolean = true, - ) = - buildMessage( - "The ${shape.type} shape `${shape.id}` has the constraint trait `${constraintTrait.toShapeId()}` attached.", - willSupport, - trackingIssue, - ) + ) = buildMessage( + "The ${shape.type} shape `${shape.id}` has the constraint trait `${constraintTrait.toShapeId()}` attached.", + willSupport, + trackingIssue, + ) val level = if (ignoreUnsupportedConstraints) Level.WARNING else Level.SEVERE return when (this) { - is UnsupportedConstraintOnMemberShape -> LogMessage( - level, - buildMessageShapeHasUnsupportedConstraintTrait(shape, constraintTrait, constraintTraitsUberIssue), - ) + is UnsupportedConstraintOnMemberShape -> + LogMessage( + level, + buildMessageShapeHasUnsupportedConstraintTrait(shape, constraintTrait, constraintTraitsUberIssue), + ) - is UnsupportedConstraintOnShapeReachableViaAnEventStream -> LogMessage( - Level.SEVERE, - buildMessage( - """ - The ${shape.type} shape `${shape.id}` has the constraint trait `${constraintTrait.toShapeId()}` attached. - This shape is also part of an event stream; it is unclear what the semantics for constrained shapes in event streams are. - Please remove the trait from the shape to synthesize your model. - """.trimIndent().replace("\n", " "), - willSupport = false, - "https://github.com/awslabs/smithy/issues/1388", - canBeIgnored = false, - ), - ) + is UnsupportedConstraintOnShapeReachableViaAnEventStream -> + LogMessage( + Level.SEVERE, + buildMessage( + """ + The ${shape.type} shape `${shape.id}` has the constraint trait `${constraintTrait.toShapeId()}` attached. + This shape is also part of an event stream; it is unclear what the semantics for constrained shapes in event streams are. + Please remove the trait from the shape to synthesize your model. + """.trimIndent().replace("\n", " "), + willSupport = false, + "https://github.com/awslabs/smithy/issues/1388", + canBeIgnored = false, + ), + ) - is UnsupportedLengthTraitOnStreamingBlobShape -> LogMessage( - level, - buildMessage( - """ - The ${shape.type} shape `${shape.id}` has both the `${lengthTrait.toShapeId()}` and `${streamingTrait.toShapeId()}` constraint traits attached. - It is unclear what the semantics for streaming blob shapes are. - """.trimIndent().replace("\n", " "), - willSupport = false, - "https://github.com/awslabs/smithy/issues/1389", - ), - ) + is UnsupportedLengthTraitOnStreamingBlobShape -> + LogMessage( + level, + buildMessage( + """ + The ${shape.type} shape `${shape.id}` has both the `${lengthTrait.toShapeId()}` and `${streamingTrait.toShapeId()}` constraint traits attached. + It is unclear what the semantics for streaming blob shapes are. + """.trimIndent().replace("\n", " "), + willSupport = false, + "https://github.com/awslabs/smithy/issues/1389", + ), + ) - is UnsupportedRangeTraitOnShape -> LogMessage( - level, - buildMessageShapeHasUnsupportedConstraintTrait( - shape, - rangeTrait, - willSupport = false, - trackingIssue = "https://github.com/smithy-lang/smithy-rs/issues/2007", - ), - ) + is UnsupportedRangeTraitOnShape -> + LogMessage( + level, + buildMessageShapeHasUnsupportedConstraintTrait( + shape, + rangeTrait, + willSupport = false, + trackingIssue = "https://github.com/smithy-lang/smithy-rs/issues/2007", + ), + ) - is UnsupportedUniqueItemsTraitOnShape -> LogMessage( - level, - buildMessageShapeHasUnsupportedConstraintTrait(shape, uniqueItemsTrait, constraintTraitsUberIssue), - ) + is UnsupportedUniqueItemsTraitOnShape -> + LogMessage( + level, + buildMessageShapeHasUnsupportedConstraintTrait(shape, uniqueItemsTrait, constraintTraitsUberIssue), + ) - is UnsupportedMapShapeReachableFromUniqueItemsList -> LogMessage( - Level.SEVERE, - buildMessage( - """ - The map shape `${mapShape.id}` is reachable from the list shape `${listShape.id}`, which has the - `@uniqueItems` trait attached. - """.trimIndent().replace("\n", " "), - willSupport = false, - trackingIssue = "https://github.com/awslabs/smithy/issues/1567", - canBeIgnored = false, - ), - ) + is UnsupportedMapShapeReachableFromUniqueItemsList -> + LogMessage( + Level.SEVERE, + buildMessage( + """ + The map shape `${mapShape.id}` is reachable from the list shape `${listShape.id}`, which has the + `@uniqueItems` trait attached. + """.trimIndent().replace("\n", " "), + willSupport = false, + trackingIssue = "https://github.com/awslabs/smithy/issues/1567", + canBeIgnored = false, + ), + ) } } } private data class OperationWithConstrainedInputWithoutValidationException(val shape: OperationShape) + private data class UnsupportedConstraintOnMemberShape(val shape: MemberShape, val constraintTrait: Trait) : UnsupportedConstraintMessageKind() @@ -160,6 +171,7 @@ private data class UnsupportedMapShapeReachableFromUniqueItemsList( ) : UnsupportedConstraintMessageKind() data class LogMessage(val level: Level, val message: String) + data class ValidationResult(val shouldAbort: Boolean, val messages: List) : Throwable(message = messages.joinToString("\n") { it.message }) @@ -176,17 +188,18 @@ fun validateOperationsWithConstrainedInputHaveValidationExceptionAttached( // TODO(https://github.com/smithy-lang/smithy-rs/issues/1401): This check will go away once we add support for // `disableDefaultValidation` set to `true`, allowing service owners to map from constraint violations to operation errors. val walker = DirectedWalker(model) - val operationsWithConstrainedInputWithoutValidationExceptionSet = walker.walkShapes(service) - .filterIsInstance() - .asSequence() - .filter { operationShape -> - // Walk the shapes reachable via this operation input. - walker.walkShapes(operationShape.inputShape(model)) - .any { it is SetShape || it is EnumShape || it.hasConstraintTrait() } - } - .filter { !it.errors.contains(validationExceptionShapeId) } - .map { OperationWithConstrainedInputWithoutValidationException(it) } - .toSet() + val operationsWithConstrainedInputWithoutValidationExceptionSet = + walker.walkShapes(service) + .filterIsInstance() + .asSequence() + .filter { operationShape -> + // Walk the shapes reachable via this operation input. + walker.walkShapes(operationShape.inputShape(model)) + .any { it is SetShape || it is EnumShape || it.hasConstraintTrait() } + } + .filter { !it.errors.contains(validationExceptionShapeId) } + .map { OperationWithConstrainedInputWithoutValidationException(it) } + .toSet() val messages = operationsWithConstrainedInputWithoutValidationExceptionSet.map { @@ -224,63 +237,70 @@ fun validateUnsupportedConstraints( // 1. Constraint traits on streaming blob shapes are used. Their semantics are unclear. // TODO(https://github.com/awslabs/smithy/issues/1389) - val unsupportedLengthTraitOnStreamingBlobShapeSet = walker - .walkShapes(service) - .asSequence() - .filterIsInstance() - .filter { it.hasTrait() && it.hasTrait() } - .map { UnsupportedLengthTraitOnStreamingBlobShape(it, it.expectTrait(), it.expectTrait()) } - .toSet() + val unsupportedLengthTraitOnStreamingBlobShapeSet = + walker + .walkShapes(service) + .asSequence() + .filterIsInstance() + .filter { it.hasTrait() && it.hasTrait() } + .map { UnsupportedLengthTraitOnStreamingBlobShape(it, it.expectTrait(), it.expectTrait()) } + .toSet() // 2. Constraint traits in event streams are used. Their semantics are unclear. // TODO(https://github.com/awslabs/smithy/issues/1388) - val eventStreamShapes = walker - .walkShapes(service) - .asSequence() - .filter { it.hasTrait() } - val unsupportedConstraintOnNonErrorShapeReachableViaAnEventStreamSet = eventStreamShapes - .flatMap { walker.walkShapes(it) } - .filterMapShapesToTraits(allConstraintTraits) - .map { (shape, trait) -> UnsupportedConstraintOnShapeReachableViaAnEventStream(shape, trait) } - .toSet() - val eventStreamErrors = eventStreamShapes.map { - it.expectTrait() - }.map { it.errorMembers } - val unsupportedConstraintErrorShapeReachableViaAnEventStreamSet = eventStreamErrors - .flatMap { it } - .flatMap { walker.walkShapes(it) } - .filterMapShapesToTraits(allConstraintTraits) - .map { (shape, trait) -> UnsupportedConstraintOnShapeReachableViaAnEventStream(shape, trait) } - .toSet() + val eventStreamShapes = + walker + .walkShapes(service) + .asSequence() + .filter { it.hasTrait() } + val unsupportedConstraintOnNonErrorShapeReachableViaAnEventStreamSet = + eventStreamShapes + .flatMap { walker.walkShapes(it) } + .filterMapShapesToTraits(allConstraintTraits) + .map { (shape, trait) -> UnsupportedConstraintOnShapeReachableViaAnEventStream(shape, trait) } + .toSet() + val eventStreamErrors = + eventStreamShapes.map { + it.expectTrait() + }.map { it.errorMembers } + val unsupportedConstraintErrorShapeReachableViaAnEventStreamSet = + eventStreamErrors + .flatMap { it } + .flatMap { walker.walkShapes(it) } + .filterMapShapesToTraits(allConstraintTraits) + .map { (shape, trait) -> UnsupportedConstraintOnShapeReachableViaAnEventStream(shape, trait) } + .toSet() val unsupportedConstraintShapeReachableViaAnEventStreamSet = unsupportedConstraintOnNonErrorShapeReachableViaAnEventStreamSet + unsupportedConstraintErrorShapeReachableViaAnEventStreamSet // 3. Range trait used on unsupported shapes. // TODO(https://github.com/smithy-lang/smithy-rs/issues/2007) - val unsupportedRangeTraitOnShapeSet = walker - .walkShapes(service) - .asSequence() - .filterNot { it is IntegerShape || it is ShortShape || it is LongShape || it is ByteShape } - .filterMapShapesToTraits(setOf(RangeTrait::class.java)) - .map { (shape, rangeTrait) -> UnsupportedRangeTraitOnShape(shape, rangeTrait as RangeTrait) } - .toSet() + val unsupportedRangeTraitOnShapeSet = + walker + .walkShapes(service) + .asSequence() + .filterNot { it is IntegerShape || it is ShortShape || it is LongShape || it is ByteShape } + .filterMapShapesToTraits(setOf(RangeTrait::class.java)) + .map { (shape, rangeTrait) -> UnsupportedRangeTraitOnShape(shape, rangeTrait as RangeTrait) } + .toSet() // 4. `@uniqueItems` cannot reach a map shape. // See https://github.com/awslabs/smithy/issues/1567. - val mapShapeReachableFromUniqueItemsListShapeSet = walker - .walkShapes(service) - .asSequence() - .filterMapShapesToTraits(setOf(UniqueItemsTrait::class.java)) - .flatMap { (listShape, uniqueItemsTrait) -> - walker.walkShapes(listShape).filterIsInstance().map { mapShape -> - UnsupportedMapShapeReachableFromUniqueItemsList( - listShape as ListShape, - uniqueItemsTrait as UniqueItemsTrait, - mapShape, - ) + val mapShapeReachableFromUniqueItemsListShapeSet = + walker + .walkShapes(service) + .asSequence() + .filterMapShapesToTraits(setOf(UniqueItemsTrait::class.java)) + .flatMap { (listShape, uniqueItemsTrait) -> + walker.walkShapes(listShape).filterIsInstance().map { mapShape -> + UnsupportedMapShapeReachableFromUniqueItemsList( + listShape as ListShape, + uniqueItemsTrait as UniqueItemsTrait, + mapShape, + ) + } } - } - .toSet() + .toSet() val messages = ( @@ -294,16 +314,17 @@ fun validateUnsupportedConstraints( mapShapeReachableFromUniqueItemsListShapeSet.map { it.intoLogMessage(codegenConfig.ignoreUnsupportedConstraints) } - ).toMutableList() + ).toMutableList() if (messages.isEmpty() && codegenConfig.ignoreUnsupportedConstraints) { - messages += LogMessage( - Level.SEVERE, - """ - The `ignoreUnsupportedConstraints` flag in the `codegen` configuration is set to `true`, but it has no - effect. All the constraint traits used in the model are well-supported, please remove this flag. - """.trimIndent().replace("\n", " "), - ) + messages += + LogMessage( + Level.SEVERE, + """ + The `ignoreUnsupportedConstraints` flag in the `codegen` configuration is set to `true`, but it has no + effect. All the constraint traits used in the model are well-supported, please remove this flag. + """.trimIndent().replace("\n", " "), + ) } return ValidationResult(shouldAbort = messages.any { it.level == Level.SEVERE }, messages) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/AdditionalErrorsDecorator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/AdditionalErrorsDecorator.kt index 8842686d116..3dbf7c9804d 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/AdditionalErrorsDecorator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/AdditionalErrorsDecorator.kt @@ -35,8 +35,11 @@ class AddInternalServerErrorToInfallibleOperationsDecorator : ServerCodegenDecor override val name: String = "AddInternalServerErrorToInfallibleOperations" override val order: Byte = 0 - override fun transformModel(service: ServiceShape, model: Model, settings: ServerRustSettings): Model = - addErrorShapeToModelOperations(service, model) { shape -> shape.allErrors(model).isEmpty() } + override fun transformModel( + service: ServiceShape, + model: Model, + settings: ServerRustSettings, + ): Model = addErrorShapeToModelOperations(service, model) { shape -> shape.allErrors(model).isEmpty() } } /** @@ -61,11 +64,18 @@ class AddInternalServerErrorToAllOperationsDecorator : ServerCodegenDecorator { override val name: String = "AddInternalServerErrorToAllOperations" override val order: Byte = 0 - override fun transformModel(service: ServiceShape, model: Model, settings: ServerRustSettings): Model = - addErrorShapeToModelOperations(service, model) { true } + override fun transformModel( + service: ServiceShape, + model: Model, + settings: ServerRustSettings, + ): Model = addErrorShapeToModelOperations(service, model) { true } } -fun addErrorShapeToModelOperations(service: ServiceShape, model: Model, opSelector: (OperationShape) -> Boolean): Model { +fun addErrorShapeToModelOperations( + service: ServiceShape, + model: Model, + opSelector: (OperationShape) -> Boolean, +): Model { val errorShape = internalServerError(service.id.namespace) val modelShapes = model.toBuilder().addShapes(listOf(errorShape)).build() return ModelTransformer.create().mapShapes(modelShapes) { shape -> diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/BeforeIteratingOverMapOrCollectionJsonCustomization.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/BeforeIteratingOverMapOrCollectionJsonCustomization.kt index 8dabd4ac02a..b891de94856 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/BeforeIteratingOverMapOrCollectionJsonCustomization.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/BeforeIteratingOverMapOrCollectionJsonCustomization.kt @@ -21,19 +21,21 @@ import software.amazon.smithy.rust.codegen.server.smithy.workingWithPublicConstr * That value will be a `std::collections::HashMap` for map shapes, and a `std::vec::Vec` for collection shapes. */ class BeforeIteratingOverMapOrCollectionJsonCustomization(private val codegenContext: ServerCodegenContext) : JsonSerializerCustomization() { - override fun section(section: JsonSerializerSection): Writable = when (section) { - is JsonSerializerSection.BeforeIteratingOverMapOrCollection -> writable { - check(section.shape is CollectionShape || section.shape is MapShape) - if (workingWithPublicConstrainedWrapperTupleType( - section.shape, - codegenContext.model, - codegenContext.settings.codegenConfig.publicConstrainedTypes, - ) - ) { - section.context.valueExpression = - ValueExpression.Reference("&${section.context.valueExpression.name}.0") - } + override fun section(section: JsonSerializerSection): Writable = + when (section) { + is JsonSerializerSection.BeforeIteratingOverMapOrCollection -> + writable { + check(section.shape is CollectionShape || section.shape is MapShape) + if (workingWithPublicConstrainedWrapperTupleType( + section.shape, + codegenContext.model, + codegenContext.settings.codegenConfig.publicConstrainedTypes, + ) + ) { + section.context.valueExpression = + ValueExpression.Reference("&${section.context.valueExpression.name}.0") + } + } + else -> emptySection } - else -> emptySection - } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/BeforeSerializingMemberJsonCustomization.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/BeforeSerializingMemberJsonCustomization.kt index 71122511ad8..bd548cb743b 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/BeforeSerializingMemberJsonCustomization.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/BeforeSerializingMemberJsonCustomization.kt @@ -24,21 +24,23 @@ import software.amazon.smithy.rust.codegen.server.smithy.workingWithPublicConstr */ class BeforeSerializingMemberJsonCustomization(private val codegenContext: ServerCodegenContext) : JsonSerializerCustomization() { - override fun section(section: JsonSerializerSection): Writable = when (section) { - is JsonSerializerSection.BeforeSerializingNonNullMember -> writable { - if (workingWithPublicConstrainedWrapperTupleType( - section.shape, - codegenContext.model, - codegenContext.settings.codegenConfig.publicConstrainedTypes, - ) - ) { - if (section.shape is IntegerShape || section.shape is ShortShape || section.shape is LongShape || section.shape is ByteShape || section.shape is BlobShape) { - section.context.valueExpression = - ValueExpression.Reference("&${section.context.valueExpression.name}.0") + override fun section(section: JsonSerializerSection): Writable = + when (section) { + is JsonSerializerSection.BeforeSerializingNonNullMember -> + writable { + if (workingWithPublicConstrainedWrapperTupleType( + section.shape, + codegenContext.model, + codegenContext.settings.codegenConfig.publicConstrainedTypes, + ) + ) { + if (section.shape is IntegerShape || section.shape is ShortShape || section.shape is LongShape || section.shape is ByteShape || section.shape is BlobShape) { + section.context.valueExpression = + ValueExpression.Reference("&${section.context.valueExpression.name}.0") + } + } } - } - } - else -> emptySection - } + else -> emptySection + } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/CustomValidationExceptionWithReasonDecorator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/CustomValidationExceptionWithReasonDecorator.kt index b2b2aa0b992..ad080febbba 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/CustomValidationExceptionWithReasonDecorator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/CustomValidationExceptionWithReasonDecorator.kt @@ -53,8 +53,9 @@ class CustomValidationExceptionWithReasonDecorator : ServerCodegenDecorator { override val order: Byte get() = -69 - override fun validationExceptionConversion(codegenContext: ServerCodegenContext): - ValidationExceptionConversionGenerator? = + override fun validationExceptionConversion( + codegenContext: ServerCodegenContext, + ): ValidationExceptionConversionGenerator? = if (codegenContext.settings.codegenConfig.experimentalCustomValidationExceptionWithReasonPleaseDoNotUse != null) { ValidationExceptionWithReasonConversionGenerator(codegenContext) } else { @@ -67,136 +68,141 @@ class ValidationExceptionWithReasonConversionGenerator(private val codegenContex override val shapeId: ShapeId = ShapeId.from(codegenContext.settings.codegenConfig.experimentalCustomValidationExceptionWithReasonPleaseDoNotUse) - override fun renderImplFromConstraintViolationForRequestRejection(protocol: ServerProtocol): Writable = writable { - rustTemplate( - """ - impl #{From} for #{RequestRejection} { - fn from(constraint_violation: ConstraintViolation) -> Self { - let first_validation_exception_field = constraint_violation.as_validation_exception_field("".to_owned()); - let validation_exception = crate::error::ValidationException { - message: format!("1 validation error detected. {}", &first_validation_exception_field.message), - reason: crate::model::ValidationExceptionReason::FieldValidationFailed, - fields: Some(vec![first_validation_exception_field]), - }; - Self::ConstraintViolation( - crate::protocol_serde::shape_validation_exception::ser_validation_exception_error(&validation_exception) - .expect("validation exceptions should never fail to serialize; please file a bug report under https://github.com/smithy-lang/smithy-rs/issues") - ) + override fun renderImplFromConstraintViolationForRequestRejection(protocol: ServerProtocol): Writable = + writable { + rustTemplate( + """ + impl #{From} for #{RequestRejection} { + fn from(constraint_violation: ConstraintViolation) -> Self { + let first_validation_exception_field = constraint_violation.as_validation_exception_field("".to_owned()); + let validation_exception = crate::error::ValidationException { + message: format!("1 validation error detected. {}", &first_validation_exception_field.message), + reason: crate::model::ValidationExceptionReason::FieldValidationFailed, + fields: Some(vec![first_validation_exception_field]), + }; + Self::ConstraintViolation( + crate::protocol_serde::shape_validation_exception::ser_validation_exception_error(&validation_exception) + .expect("validation exceptions should never fail to serialize; please file a bug report under https://github.com/smithy-lang/smithy-rs/issues") + ) + } } - } - """, - "RequestRejection" to protocol.requestRejection(codegenContext.runtimeConfig), - "From" to RuntimeType.From, - ) - } + """, + "RequestRejection" to protocol.requestRejection(codegenContext.runtimeConfig), + "From" to RuntimeType.From, + ) + } - override fun stringShapeConstraintViolationImplBlock(stringConstraintsInfo: Collection): Writable = writable { - val validationExceptionFields = - stringConstraintsInfo.map { - writable { - when (it) { - is Pattern -> { - rustTemplate( - """ - Self::Pattern(_) => crate::model::ValidationExceptionField { - message: #{MessageWritable:W}, - name: path, - reason: crate::model::ValidationExceptionFieldReason::PatternNotValid, - }, - """, - "MessageWritable" to it.errorMessage(), - ) - } - is Length -> { - rust( - """ - Self::Length(length) => crate::model::ValidationExceptionField { - message: format!("${it.lengthTrait.validationErrorMessage()}", length, &path), - name: path, - reason: crate::model::ValidationExceptionFieldReason::LengthNotValid, - }, - """, - ) + override fun stringShapeConstraintViolationImplBlock(stringConstraintsInfo: Collection): Writable = + writable { + val validationExceptionFields = + stringConstraintsInfo.map { + writable { + when (it) { + is Pattern -> { + rustTemplate( + """ + Self::Pattern(_) => crate::model::ValidationExceptionField { + message: #{MessageWritable:W}, + name: path, + reason: crate::model::ValidationExceptionFieldReason::PatternNotValid, + }, + """, + "MessageWritable" to it.errorMessage(), + ) + } + is Length -> { + rust( + """ + Self::Length(length) => crate::model::ValidationExceptionField { + message: format!("${it.lengthTrait.validationErrorMessage()}", length, &path), + name: path, + reason: crate::model::ValidationExceptionFieldReason::LengthNotValid, + }, + """, + ) + } } } - } - }.join("\n") + }.join("\n") - rustTemplate( - """ - pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { - match self { - #{ValidationExceptionFields:W} - } - } - """, - "String" to RuntimeType.String, - "ValidationExceptionFields" to validationExceptionFields, - ) - } - - override fun enumShapeConstraintViolationImplBlock(enumTrait: EnumTrait) = writable { - val enumValueSet = enumTrait.enumDefinitionValues.joinToString(", ") - val message = "Value at '{}' failed to satisfy constraint: Member must satisfy enum value set: [$enumValueSet]" - rustTemplate( - """ - pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { - crate::model::ValidationExceptionField { - message: format!(r##"$message"##, &path), - name: path, - reason: crate::model::ValidationExceptionFieldReason::ValueNotValid, + rustTemplate( + """ + pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { + match self { + #{ValidationExceptionFields:W} + } } - } - """, - "String" to RuntimeType.String, - ) - } + """, + "String" to RuntimeType.String, + "ValidationExceptionFields" to validationExceptionFields, + ) + } - override fun numberShapeConstraintViolationImplBlock(rangeInfo: Range) = writable { - rustTemplate( - """ - pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { - match self { - Self::Range(_) => crate::model::ValidationExceptionField { - message: format!("${rangeInfo.rangeTrait.validationErrorMessage()}", &path), + override fun enumShapeConstraintViolationImplBlock(enumTrait: EnumTrait) = + writable { + val enumValueSet = enumTrait.enumDefinitionValues.joinToString(", ") + val message = "Value at '{}' failed to satisfy constraint: Member must satisfy enum value set: [$enumValueSet]" + rustTemplate( + """ + pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { + crate::model::ValidationExceptionField { + message: format!(r##"$message"##, &path), name: path, reason: crate::model::ValidationExceptionFieldReason::ValueNotValid, } } - } - """, - "String" to RuntimeType.String, - ) - } + """, + "String" to RuntimeType.String, + ) + } - override fun blobShapeConstraintViolationImplBlock(blobConstraintsInfo: Collection) = writable { - val validationExceptionFields = - blobConstraintsInfo.map { - writable { - rust( - """ - Self::Length(length) => crate::model::ValidationExceptionField { - message: format!("${it.lengthTrait.validationErrorMessage()}", length, &path), + override fun numberShapeConstraintViolationImplBlock(rangeInfo: Range) = + writable { + rustTemplate( + """ + pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { + match self { + Self::Range(_) => crate::model::ValidationExceptionField { + message: format!("${rangeInfo.rangeTrait.validationErrorMessage()}", &path), name: path, - reason: crate::model::ValidationExceptionFieldReason::LengthNotValid, - }, - """, - ) + reason: crate::model::ValidationExceptionFieldReason::ValueNotValid, + } + } } - }.join("\n") + """, + "String" to RuntimeType.String, + ) + } - rustTemplate( - """ - pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { - match self { - #{ValidationExceptionFields:W} + override fun blobShapeConstraintViolationImplBlock(blobConstraintsInfo: Collection) = + writable { + val validationExceptionFields = + blobConstraintsInfo.map { + writable { + rust( + """ + Self::Length(length) => crate::model::ValidationExceptionField { + message: format!("${it.lengthTrait.validationErrorMessage()}", length, &path), + name: path, + reason: crate::model::ValidationExceptionFieldReason::LengthNotValid, + }, + """, + ) + } + }.join("\n") + + rustTemplate( + """ + pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { + match self { + #{ValidationExceptionFields:W} + } } - } - """, - "String" to RuntimeType.String, - "ValidationExceptionFields" to validationExceptionFields, - ) - } + """, + "String" to RuntimeType.String, + "ValidationExceptionFields" to validationExceptionFields, + ) + } override fun mapShapeConstraintViolationImplBlock( shape: MapShape, @@ -231,60 +237,61 @@ class ValidationExceptionWithReasonConversionGenerator(private val codegenContex } } - override fun builderConstraintViolationImplBlock(constraintViolations: Collection) = writable { - rustBlock("match self") { - constraintViolations.forEach { - if (it.hasInner()) { - rust("""ConstraintViolation::${it.name()}(inner) => inner.as_validation_exception_field(path + "/${it.forMember.memberName}"),""") - } else { - rust( - """ - ConstraintViolation::${it.name()} => crate::model::ValidationExceptionField { - message: format!("Value at '{}/${it.forMember.memberName}' failed to satisfy constraint: Member must not be null", path), - name: path + "/${it.forMember.memberName}", - reason: crate::model::ValidationExceptionFieldReason::Other, - }, - """, - ) + override fun builderConstraintViolationImplBlock(constraintViolations: Collection) = + writable { + rustBlock("match self") { + constraintViolations.forEach { + if (it.hasInner()) { + rust("""ConstraintViolation::${it.name()}(inner) => inner.as_validation_exception_field(path + "/${it.forMember.memberName}"),""") + } else { + rust( + """ + ConstraintViolation::${it.name()} => crate::model::ValidationExceptionField { + message: format!("Value at '{}/${it.forMember.memberName}' failed to satisfy constraint: Member must not be null", path), + name: path + "/${it.forMember.memberName}", + reason: crate::model::ValidationExceptionFieldReason::Other, + }, + """, + ) + } } } } - } override fun collectionShapeConstraintViolationImplBlock( - collectionConstraintsInfo: - Collection, + collectionConstraintsInfo: Collection, isMemberConstrained: Boolean, ) = writable { - val validationExceptionFields = collectionConstraintsInfo.map { - writable { - when (it) { - is CollectionTraitInfo.Length -> { - rust( - """ - Self::Length(length) => crate::model::ValidationExceptionField { - message: format!("${it.lengthTrait.validationErrorMessage()}", length, &path), - name: path, - reason: crate::model::ValidationExceptionFieldReason::LengthNotValid, - }, - """, - ) - } - is CollectionTraitInfo.UniqueItems -> { - rust( - """ - Self::UniqueItems { duplicate_indices, .. } => - crate::model::ValidationExceptionField { - message: format!("${it.uniqueItemsTrait.validationErrorMessage()}", &duplicate_indices, &path), + val validationExceptionFields = + collectionConstraintsInfo.map { + writable { + when (it) { + is CollectionTraitInfo.Length -> { + rust( + """ + Self::Length(length) => crate::model::ValidationExceptionField { + message: format!("${it.lengthTrait.validationErrorMessage()}", length, &path), name: path, - reason: crate::model::ValidationExceptionFieldReason::ValueNotValid, + reason: crate::model::ValidationExceptionFieldReason::LengthNotValid, }, - """, - ) + """, + ) + } + is CollectionTraitInfo.UniqueItems -> { + rust( + """ + Self::UniqueItems { duplicate_indices, .. } => + crate::model::ValidationExceptionField { + message: format!("${it.uniqueItemsTrait.validationErrorMessage()}", &duplicate_indices, &path), + name: path, + reason: crate::model::ValidationExceptionFieldReason::ValueNotValid, + }, + """, + ) + } } } - } - }.toMutableList() + }.toMutableList() if (isMemberConstrained) { validationExceptionFields += { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt index 7823c53326d..f4205e794d3 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/ServerRequiredCustomizations.kt @@ -31,10 +31,12 @@ class ServerRequiredCustomizations : ServerCodegenDecorator { override fun libRsCustomizations( codegenContext: ServerCodegenContext, baseCustomizations: List, - ): List = - baseCustomizations + AllowLintsCustomization() + ): List = baseCustomizations + AllowLintsCustomization() - override fun extras(codegenContext: ServerCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ServerCodegenContext, + rustCrate: RustCrate, + ) { val rc = codegenContext.runtimeConfig // Add rt-tokio feature for `ByteStream::from_path` diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/SmithyValidationExceptionDecorator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/SmithyValidationExceptionDecorator.kt index f9124f7f778..9e9438b6416 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/SmithyValidationExceptionDecorator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/SmithyValidationExceptionDecorator.kt @@ -53,72 +53,76 @@ class SmithyValidationExceptionDecorator : ServerCodegenDecorator { override val order: Byte get() = 69 - override fun validationExceptionConversion(codegenContext: ServerCodegenContext): ValidationExceptionConversionGenerator = - SmithyValidationExceptionConversionGenerator(codegenContext) + override fun validationExceptionConversion( + codegenContext: ServerCodegenContext, + ): ValidationExceptionConversionGenerator = SmithyValidationExceptionConversionGenerator(codegenContext) } class SmithyValidationExceptionConversionGenerator(private val codegenContext: ServerCodegenContext) : ValidationExceptionConversionGenerator { - // Define a companion object so that we can refer to this shape id globally. companion object { val SHAPE_ID: ShapeId = ShapeId.from("smithy.framework#ValidationException") } + override val shapeId: ShapeId = SHAPE_ID - override fun renderImplFromConstraintViolationForRequestRejection(protocol: ServerProtocol): Writable = writable { - rustTemplate( - """ - impl #{From} for #{RequestRejection} { - fn from(constraint_violation: ConstraintViolation) -> Self { - let first_validation_exception_field = constraint_violation.as_validation_exception_field("".to_owned()); - let validation_exception = crate::error::ValidationException { - message: format!("1 validation error detected. {}", &first_validation_exception_field.message), - field_list: Some(vec![first_validation_exception_field]), - }; - Self::ConstraintViolation( - crate::protocol_serde::shape_validation_exception::ser_validation_exception_error(&validation_exception) - .expect("validation exceptions should never fail to serialize; please file a bug report under https://github.com/smithy-lang/smithy-rs/issues") - ) + override fun renderImplFromConstraintViolationForRequestRejection(protocol: ServerProtocol): Writable = + writable { + rustTemplate( + """ + impl #{From} for #{RequestRejection} { + fn from(constraint_violation: ConstraintViolation) -> Self { + let first_validation_exception_field = constraint_violation.as_validation_exception_field("".to_owned()); + let validation_exception = crate::error::ValidationException { + message: format!("1 validation error detected. {}", &first_validation_exception_field.message), + field_list: Some(vec![first_validation_exception_field]), + }; + Self::ConstraintViolation( + crate::protocol_serde::shape_validation_exception::ser_validation_exception_error(&validation_exception) + .expect("validation exceptions should never fail to serialize; please file a bug report under https://github.com/smithy-lang/smithy-rs/issues") + ) + } } - } - """, - "RequestRejection" to protocol.requestRejection(codegenContext.runtimeConfig), - "From" to RuntimeType.From, - ) - } + """, + "RequestRejection" to protocol.requestRejection(codegenContext.runtimeConfig), + "From" to RuntimeType.From, + ) + } - override fun stringShapeConstraintViolationImplBlock(stringConstraintsInfo: Collection): Writable = writable { - val constraintsInfo: List = stringConstraintsInfo.map(StringTraitInfo::toTraitInfo) + override fun stringShapeConstraintViolationImplBlock(stringConstraintsInfo: Collection): Writable = + writable { + val constraintsInfo: List = stringConstraintsInfo.map(StringTraitInfo::toTraitInfo) - rustTemplate( - """ - pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { - match self { - #{ValidationExceptionFields:W} + rustTemplate( + """ + pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { + match self { + #{ValidationExceptionFields:W} + } } - } - """, - "String" to RuntimeType.String, - "ValidationExceptionFields" to constraintsInfo.map { it.asValidationExceptionField }.join("\n"), - ) - } + """, + "String" to RuntimeType.String, + "ValidationExceptionFields" to constraintsInfo.map { it.asValidationExceptionField }.join("\n"), + ) + } - override fun blobShapeConstraintViolationImplBlock(blobConstraintsInfo: Collection): Writable = writable { - val constraintsInfo: List = blobConstraintsInfo.map(BlobLength::toTraitInfo) + override fun blobShapeConstraintViolationImplBlock(blobConstraintsInfo: Collection): Writable = + writable { + val constraintsInfo: List = blobConstraintsInfo.map(BlobLength::toTraitInfo) - rustTemplate( - """ - pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { - match self { - #{ValidationExceptionFields:W} + rustTemplate( + """ + pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { + match self { + #{ValidationExceptionFields:W} + } } - } - """, - "String" to RuntimeType.String, - "ValidationExceptionFields" to constraintsInfo.map { it.asValidationExceptionField }.join("\n"), - ) - } + """, + "String" to RuntimeType.String, + "ValidationExceptionFields" to constraintsInfo.map { it.asValidationExceptionField }.join("\n"), + ) + } override fun mapShapeConstraintViolationImplBlock( shape: MapShape, @@ -155,63 +159,66 @@ class SmithyValidationExceptionConversionGenerator(private val codegenContext: S } } - override fun enumShapeConstraintViolationImplBlock(enumTrait: EnumTrait) = writable { - val enumValueSet = enumTrait.enumDefinitionValues.joinToString(", ") - val message = "Value at '{}' failed to satisfy constraint: Member must satisfy enum value set: [$enumValueSet]" - rustTemplate( - """ - pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { - crate::model::ValidationExceptionField { - message: format!(r##"$message"##, &path), - path, + override fun enumShapeConstraintViolationImplBlock(enumTrait: EnumTrait) = + writable { + val enumValueSet = enumTrait.enumDefinitionValues.joinToString(", ") + val message = "Value at '{}' failed to satisfy constraint: Member must satisfy enum value set: [$enumValueSet]" + rustTemplate( + """ + pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { + crate::model::ValidationExceptionField { + message: format!(r##"$message"##, &path), + path, + } } - } - """, - "String" to RuntimeType.String, - ) - } + """, + "String" to RuntimeType.String, + ) + } - override fun numberShapeConstraintViolationImplBlock(rangeInfo: Range) = writable { - rustTemplate( - """ - pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { - match self { - #{ValidationExceptionFields:W} + override fun numberShapeConstraintViolationImplBlock(rangeInfo: Range) = + writable { + rustTemplate( + """ + pub(crate) fn as_validation_exception_field(self, path: #{String}) -> crate::model::ValidationExceptionField { + match self { + #{ValidationExceptionFields:W} + } } - } - """, - "String" to RuntimeType.String, - "ValidationExceptionFields" to rangeInfo.toTraitInfo().asValidationExceptionField, - ) - } + """, + "String" to RuntimeType.String, + "ValidationExceptionFields" to rangeInfo.toTraitInfo().asValidationExceptionField, + ) + } - override fun builderConstraintViolationImplBlock(constraintViolations: Collection) = writable { - rustBlock("match self") { - constraintViolations.forEach { - if (it.hasInner()) { - rust("""ConstraintViolation::${it.name()}(inner) => inner.as_validation_exception_field(path + "/${it.forMember.memberName}"),""") - } else { - rust( - """ - ConstraintViolation::${it.name()} => crate::model::ValidationExceptionField { - message: format!("Value at '{}/${it.forMember.memberName}' failed to satisfy constraint: Member must not be null", path), - path: path + "/${it.forMember.memberName}", - }, - """, - ) + override fun builderConstraintViolationImplBlock(constraintViolations: Collection) = + writable { + rustBlock("match self") { + constraintViolations.forEach { + if (it.hasInner()) { + rust("""ConstraintViolation::${it.name()}(inner) => inner.as_validation_exception_field(path + "/${it.forMember.memberName}"),""") + } else { + rust( + """ + ConstraintViolation::${it.name()} => crate::model::ValidationExceptionField { + message: format!("Value at '{}/${it.forMember.memberName}' failed to satisfy constraint: Member must not be null", path), + path: path + "/${it.forMember.memberName}", + }, + """, + ) + } } } } - } override fun collectionShapeConstraintViolationImplBlock( - collectionConstraintsInfo: - Collection, + collectionConstraintsInfo: Collection, isMemberConstrained: Boolean, ) = writable { - val validationExceptionFields = collectionConstraintsInfo.map { - it.toTraitInfo().asValidationExceptionField - }.toMutableList() + val validationExceptionFields = + collectionConstraintsInfo.map { + it.toTraitInfo().asValidationExceptionField + }.toMutableList() if (isMemberConstrained) { validationExceptionFields += { rust( diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customize/ServerCodegenDecorator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customize/ServerCodegenDecorator.kt index 22df729e5ae..5bd79ed7a06 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customize/ServerCodegenDecorator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customize/ServerCodegenDecorator.kt @@ -27,8 +27,13 @@ typealias ServerProtocolMap = ProtocolMap { - fun protocols(serviceId: ShapeId, currentProtocols: ServerProtocolMap): ServerProtocolMap = currentProtocols - fun validationExceptionConversion(codegenContext: ServerCodegenContext): ValidationExceptionConversionGenerator? = null + fun protocols( + serviceId: ShapeId, + currentProtocols: ServerProtocolMap, + ): ServerProtocolMap = currentProtocols + + fun validationExceptionConversion(codegenContext: ServerCodegenContext): ValidationExceptionConversionGenerator? = + null /** * Injection point to allow a decorator to postprocess the error message that arises when an operation is @@ -42,7 +47,8 @@ interface ServerCodegenDecorator : CoreCodegenDecorator = emptyList() + fun postprocessOperationGenerateAdditionalStructures(operationShape: OperationShape): List = + emptyList() /** * For each service, this hook allows decorators to return a collection of structure shapes that will additionally be generated. @@ -67,7 +73,6 @@ interface ServerCodegenDecorator : CoreCodegenDecorator) : CombinedCoreCodegenDecorator(decorators), ServerCodegenDecorator { - private val orderedDecorators = decorators.sortedBy { it.order } override val name: String @@ -75,22 +80,31 @@ class CombinedServerCodegenDecorator(decorators: List) : override val order: Byte get() = 0 - override fun protocols(serviceId: ShapeId, currentProtocols: ServerProtocolMap): ServerProtocolMap = + override fun protocols( + serviceId: ShapeId, + currentProtocols: ServerProtocolMap, + ): ServerProtocolMap = combineCustomizations(currentProtocols) { decorator, protocolMap -> decorator.protocols(serviceId, protocolMap) } - override fun validationExceptionConversion(codegenContext: ServerCodegenContext): ValidationExceptionConversionGenerator = + override fun validationExceptionConversion( + codegenContext: ServerCodegenContext, + ): ValidationExceptionConversionGenerator = // We use `firstNotNullOf` instead of `firstNotNullOfOrNull` because the [SmithyValidationExceptionDecorator] // is registered. orderedDecorators.firstNotNullOf { it.validationExceptionConversion(codegenContext) } - override fun postprocessValidationExceptionNotAttachedErrorMessage(validationResult: ValidationResult): ValidationResult = + override fun postprocessValidationExceptionNotAttachedErrorMessage( + validationResult: ValidationResult, + ): ValidationResult = orderedDecorators.foldRight(validationResult) { decorator, accumulated -> decorator.postprocessValidationExceptionNotAttachedErrorMessage(accumulated) } - override fun postprocessOperationGenerateAdditionalStructures(operationShape: OperationShape): List = + override fun postprocessOperationGenerateAdditionalStructures( + operationShape: OperationShape, + ): List = orderedDecorators.flatMap { it.postprocessOperationGenerateAdditionalStructures(operationShape) } override fun postprocessServiceGenerateAdditionalStructures(serviceShape: ServiceShape): List = diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedBlobGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedBlobGenerator.kt index 5a1c3bc4e18..9d90562908a 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedBlobGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedBlobGenerator.kt @@ -47,9 +47,10 @@ class ConstrainedBlobGenerator( PubCrateConstraintViolationSymbolProvider(this) } } - private val blobConstraintsInfo: List = listOf(LengthTrait::class.java) - .mapNotNull { shape.getTrait(it).orNull() } - .map { BlobLength(it) } + private val blobConstraintsInfo: List = + listOf(LengthTrait::class.java) + .mapNotNull { shape.getTrait(it).orNull() } + .map { BlobLength(it) } private val constraintsInfo: List = blobConstraintsInfo.map { it.toTraitInfo() } fun render() { @@ -116,7 +117,11 @@ class ConstrainedBlobGenerator( } } - private fun renderConstraintViolationEnum(writer: RustWriter, shape: BlobShape, constraintViolation: Symbol) { + private fun renderConstraintViolationEnum( + writer: RustWriter, + shape: BlobShape, + constraintViolation: Symbol, + ) { writer.rustTemplate( """ ##[derive(Debug, PartialEq)] @@ -141,41 +146,46 @@ class ConstrainedBlobGenerator( } data class BlobLength(val lengthTrait: LengthTrait) { - fun toTraitInfo(): TraitInfo = TraitInfo( - { rust("Self::check_length(&value)?;") }, - { - docs("Error when a blob doesn't satisfy its `@length` requirements.") - rust("Length(usize)") - }, - { - rust( - """ - Self::Length(length) => crate::model::ValidationExceptionField { - message: format!("${lengthTrait.validationErrorMessage()}", length, &path), - path, + fun toTraitInfo(): TraitInfo = + TraitInfo( + { rust("Self::check_length(&value)?;") }, + { + docs("Error when a blob doesn't satisfy its `@length` requirements.") + rust("Length(usize)") + }, + { + rust( + """ + Self::Length(length) => crate::model::ValidationExceptionField { + message: format!("${lengthTrait.validationErrorMessage()}", length, &path), + path, },""", - ) - }, - this::renderValidationFunction, - ) + ) + }, + this::renderValidationFunction, + ) /** * Renders a `check_length` function to validate the blob matches the * required length indicated by the `@length` trait. */ - private fun renderValidationFunction(constraintViolation: Symbol, unconstrainedTypeName: String): Writable = { - rust( - """ - fn check_length(blob: &$unconstrainedTypeName) -> Result<(), $constraintViolation> { - let length = blob.as_ref().len(); + private fun renderValidationFunction( + constraintViolation: Symbol, + unconstrainedTypeName: String, + ): Writable = + { + rust( + """ + fn check_length(blob: &$unconstrainedTypeName) -> Result<(), $constraintViolation> { + let length = blob.as_ref().len(); - if ${lengthTrait.rustCondition("length")} { - Ok(()) - } else { - Err($constraintViolation::Length(length)) + if ${lengthTrait.rustCondition("length")} { + Ok(()) + } else { + Err($constraintViolation::Length(length)) + } } - } - """, - ) - } + """, + ) + } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedCollectionGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedCollectionGenerator.kt index f705e4af3a0..d2029bfd2e5 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedCollectionGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedCollectionGenerator.kt @@ -76,12 +76,13 @@ class ConstrainedCollectionGenerator( val constraintViolation = constraintViolationSymbolProvider.toSymbol(shape) val constrainedSymbol = symbolProvider.toSymbol(shape) - val codegenScope = arrayOf( - "ValueMemberSymbol" to constrainedShapeSymbolProvider.toSymbol(shape.member), - "From" to RuntimeType.From, - "TryFrom" to RuntimeType.TryFrom, - "ConstraintViolation" to constraintViolation, - ) + val codegenScope = + arrayOf( + "ValueMemberSymbol" to constrainedShapeSymbolProvider.toSymbol(shape.member), + "From" to RuntimeType.From, + "TryFrom" to RuntimeType.TryFrom, + "ConstraintViolation" to constraintViolation, + ) writer.documentShape(shape, model) writer.docs(rustDocsConstrainedTypeEpilogue(name)) @@ -116,9 +117,10 @@ class ConstrainedCollectionGenerator( #{ValidationFunctions:W} """, *codegenScope, - "ValidationFunctions" to constraintsInfo.map { - it.validationFunctionDefinition(constraintViolation, inner) - }.join("\n"), + "ValidationFunctions" to + constraintsInfo.map { + it.validationFunctionDefinition(constraintViolation, inner) + }.join("\n"), ) } @@ -355,7 +357,11 @@ sealed class CollectionTraitInfo { } companion object { - private fun fromTrait(trait: Trait, shape: CollectionShape, symbolProvider: SymbolProvider): CollectionTraitInfo { + private fun fromTrait( + trait: Trait, + shape: CollectionShape, + symbolProvider: SymbolProvider, + ): CollectionTraitInfo { check(shape.hasTrait(trait.toShapeId())) return when (trait) { is LengthTrait -> { @@ -370,7 +376,10 @@ sealed class CollectionTraitInfo { } } - fun fromShape(shape: CollectionShape, symbolProvider: SymbolProvider): List = + fun fromShape( + shape: CollectionShape, + symbolProvider: SymbolProvider, + ): List = supportedCollectionConstraintTraits .mapNotNull { shape.getTrait(it).orNull() } .map { trait -> fromTrait(trait, shape, symbolProvider) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGenerator.kt index 28b0d9f8d75..2128cdaec84 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGenerator.kt @@ -64,14 +64,15 @@ class ConstrainedMapGenerator( val constraintViolation = constraintViolationSymbolProvider.toSymbol(shape) val constrainedSymbol = symbolProvider.toSymbol(shape) - val codegenScope = arrayOf( - "HashMap" to RuntimeType.HashMap, - "KeySymbol" to constrainedShapeSymbolProvider.toSymbol(model.expectShape(shape.key.target)), - "ValueMemberSymbol" to constrainedShapeSymbolProvider.toSymbol(shape.value), - "From" to RuntimeType.From, - "TryFrom" to RuntimeType.TryFrom, - "ConstraintViolation" to constraintViolation, - ) + val codegenScope = + arrayOf( + "HashMap" to RuntimeType.HashMap, + "KeySymbol" to constrainedShapeSymbolProvider.toSymbol(model.expectShape(shape.key.target)), + "ValueMemberSymbol" to constrainedShapeSymbolProvider.toSymbol(shape.value), + "From" to RuntimeType.From, + "TryFrom" to RuntimeType.TryFrom, + "ConstraintViolation" to constraintViolation, + ) writer.documentShape(shape, model) writer.docs(rustDocsConstrainedTypeEpilogue(name)) @@ -134,11 +135,12 @@ class ConstrainedMapGenerator( ) { val keyShape = model.expectShape(shape.key.target, StringShape::class.java) val keyNeedsConversion = keyShape.typeNameContainsNonPublicType(model, symbolProvider, publicConstrainedTypes) - val key = if (keyNeedsConversion) { - "k.into()" - } else { - "k" - } + val key = + if (keyNeedsConversion) { + "k.into()" + } else { + "k" + } writer.rustTemplate( """ diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGeneratorCommon.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGeneratorCommon.kt index fb5ce1daee0..0c88a447c47 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGeneratorCommon.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGeneratorCommon.kt @@ -16,7 +16,13 @@ import software.amazon.smithy.rust.codegen.server.smithy.isDirectlyConstrained * Common helper functions used in [UnconstrainedMapGenerator] and [MapConstraintViolationGenerator]. */ -fun isKeyConstrained(shape: StringShape, symbolProvider: SymbolProvider) = shape.isDirectlyConstrained(symbolProvider) +fun isKeyConstrained( + shape: StringShape, + symbolProvider: SymbolProvider, +) = shape.isDirectlyConstrained(symbolProvider) -fun isValueConstrained(shape: Shape, model: Model, symbolProvider: SymbolProvider): Boolean = - shape.canReachConstrainedShape(model, symbolProvider) +fun isValueConstrained( + shape: Shape, + model: Model, + symbolProvider: SymbolProvider, +): Boolean = shape.canReachConstrainedShape(model, symbolProvider) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedNumberGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedNumberGenerator.kt index 9680865a915..248f9a57747 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedNumberGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedNumberGenerator.kt @@ -50,13 +50,14 @@ class ConstrainedNumberGenerator( val constrainedShapeSymbolProvider = codegenContext.constrainedShapeSymbolProvider val publicConstrainedTypes = codegenContext.settings.codegenConfig.publicConstrainedTypes - private val unconstrainedType = when (shape) { - is ByteShape -> RustType.Integer(8) - is ShortShape -> RustType.Integer(16) - is IntegerShape -> RustType.Integer(32) - is LongShape -> RustType.Integer(64) - else -> UNREACHABLE("Trying to generate a constrained number for an unsupported Smithy number shape") - } + private val unconstrainedType = + when (shape) { + is ByteShape -> RustType.Integer(8) + is ShortShape -> RustType.Integer(16) + is IntegerShape -> RustType.Integer(32) + is LongShape -> RustType.Integer(64) + else -> UNREACHABLE("Trying to generate a constrained number for an unsupported Smithy number shape") + } private val constraintViolationSymbolProvider = with(codegenContext.constraintViolationSymbolProvider) { @@ -158,46 +159,52 @@ class ConstrainedNumberGenerator( } data class Range(val rangeTrait: RangeTrait) { - fun toTraitInfo(): TraitInfo = TraitInfo( - { rust("Self::check_range(value)?;") }, - { docs("Error when a number doesn't satisfy its `@range` requirements.") }, - { - rust( - """ - Self::Range(_) => crate::model::ValidationExceptionField { - message: format!("${rangeTrait.validationErrorMessage()}", &path), - path, - }, - """, - ) - }, - this::renderValidationFunction, - ) + fun toTraitInfo(): TraitInfo = + TraitInfo( + { rust("Self::check_range(value)?;") }, + { docs("Error when a number doesn't satisfy its `@range` requirements.") }, + { + rust( + """ + Self::Range(_) => crate::model::ValidationExceptionField { + message: format!("${rangeTrait.validationErrorMessage()}", &path), + path, + }, + """, + ) + }, + this::renderValidationFunction, + ) /** * Renders a `check_range` function to validate that the value matches the * required range indicated by the `@range` trait. */ - private fun renderValidationFunction(constraintViolation: Symbol, unconstrainedTypeName: String): Writable = { - val valueVariableName = "value" - val condition = if (rangeTrait.min.isPresent && rangeTrait.max.isPresent) { - "(${rangeTrait.min.get()}..=${rangeTrait.max.get()}).contains(&$valueVariableName)" - } else if (rangeTrait.min.isPresent) { - "${rangeTrait.min.get()} <= $valueVariableName" - } else { - "$valueVariableName <= ${rangeTrait.max.get()}" - } - - rust( - """ - fn check_range($valueVariableName: $unconstrainedTypeName) -> Result<(), $constraintViolation> { - if $condition { - Ok(()) + private fun renderValidationFunction( + constraintViolation: Symbol, + unconstrainedTypeName: String, + ): Writable = + { + val valueVariableName = "value" + val condition = + if (rangeTrait.min.isPresent && rangeTrait.max.isPresent) { + "(${rangeTrait.min.get()}..=${rangeTrait.max.get()}).contains(&$valueVariableName)" + } else if (rangeTrait.min.isPresent) { + "${rangeTrait.min.get()} <= $valueVariableName" } else { - Err($constraintViolation::Range($valueVariableName)) + "$valueVariableName <= ${rangeTrait.max.get()}" } - } - """, - ) - } + + rust( + """ + fn check_range($valueVariableName: $unconstrainedTypeName) -> Result<(), $constraintViolation> { + if $condition { + Ok(()) + } else { + Err($constraintViolation::Range($valueVariableName)) + } + } + """, + ) + } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedShapeGeneratorCommon.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedShapeGeneratorCommon.kt index 1e63fda7125..e001eda9818 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedShapeGeneratorCommon.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedShapeGeneratorCommon.kt @@ -9,18 +9,20 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators * Functions shared amongst the constrained shape generators, to keep them DRY and consistent. */ -fun rustDocsConstrainedTypeEpilogue(typeName: String) = """ +fun rustDocsConstrainedTypeEpilogue(typeName: String) = + """ This is a constrained type because its corresponding modeled Smithy shape has one or more [constraint traits]. Use [`$typeName::try_from`] to construct values of this type. [constraint traits]: https://awslabs.github.io/smithy/1.0/spec/core/constraint-traits.html -""" + """ -fun rustDocsTryFromMethod(typeName: String, inner: String) = +fun rustDocsTryFromMethod( + typeName: String, + inner: String, +) = "Constructs a `$typeName` from an [`$inner`], failing when the provided value does not satisfy the modeled constraints." -fun rustDocsInnerMethod(inner: String) = - "Returns an immutable reference to the underlying [`$inner`]." +fun rustDocsInnerMethod(inner: String) = "Returns an immutable reference to the underlying [`$inner`]." -fun rustDocsIntoInnerMethod(inner: String) = - "Consumes the value, returning the underlying [`$inner`]." +fun rustDocsIntoInnerMethod(inner: String) = "Consumes the value, returning the underlying [`$inner`]." diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGenerator.kt index 7ab164b39bf..994dff469fe 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGenerator.kt @@ -147,7 +147,11 @@ class ConstrainedStringGenerator( renderTests(shape) } - private fun renderConstraintViolationEnum(writer: RustWriter, shape: StringShape, constraintViolation: Symbol) { + private fun renderConstraintViolationEnum( + writer: RustWriter, + shape: StringShape, + constraintViolation: Symbol, + ) { writer.rustTemplate( """ ##[derive(Debug, PartialEq)] @@ -186,49 +190,55 @@ class ConstrainedStringGenerator( } } } + data class Length(val lengthTrait: LengthTrait) : StringTraitInfo() { - override fun toTraitInfo(): TraitInfo = TraitInfo( - tryFromCheck = { rust("Self::check_length(&value)?;") }, - constraintViolationVariant = { - docs("Error when a string doesn't satisfy its `@length` requirements.") - rust("Length(usize)") - }, - asValidationExceptionField = { - rust( - """ - Self::Length(length) => crate::model::ValidationExceptionField { - message: format!("${lengthTrait.validationErrorMessage()}", length, &path), - path, - }, - """, - ) - }, - validationFunctionDefinition = this::renderValidationFunction, - ) + override fun toTraitInfo(): TraitInfo = + TraitInfo( + tryFromCheck = { rust("Self::check_length(&value)?;") }, + constraintViolationVariant = { + docs("Error when a string doesn't satisfy its `@length` requirements.") + rust("Length(usize)") + }, + asValidationExceptionField = { + rust( + """ + Self::Length(length) => crate::model::ValidationExceptionField { + message: format!("${lengthTrait.validationErrorMessage()}", length, &path), + path, + }, + """, + ) + }, + validationFunctionDefinition = this::renderValidationFunction, + ) /** * Renders a `check_length` function to validate the string matches the * required length indicated by the `@length` trait. */ @Suppress("UNUSED_PARAMETER") - private fun renderValidationFunction(constraintViolation: Symbol, unconstrainedTypeName: String): Writable = { - // Note that we're using the linear time check `chars().count()` instead of `len()` on the input value, since the - // Smithy specification says the `length` trait counts the number of Unicode code points when applied to string shapes. - // https://awslabs.github.io/smithy/1.0/spec/core/constraint-traits.html#length-trait - rust( - """ - fn check_length(string: &str) -> Result<(), $constraintViolation> { - let length = string.chars().count(); + private fun renderValidationFunction( + constraintViolation: Symbol, + unconstrainedTypeName: String, + ): Writable = + { + // Note that we're using the linear time check `chars().count()` instead of `len()` on the input value, since the + // Smithy specification says the `length` trait counts the number of Unicode code points when applied to string shapes. + // https://awslabs.github.io/smithy/1.0/spec/core/constraint-traits.html#length-trait + rust( + """ + fn check_length(string: &str) -> Result<(), $constraintViolation> { + let length = string.chars().count(); - if ${lengthTrait.rustCondition("length")} { - Ok(()) - } else { - Err($constraintViolation::Length(length)) + if ${lengthTrait.rustCondition("length")} { + Ok(()) + } else { + Err($constraintViolation::Length(length)) + } } - } - """, - ) - } + """, + ) + } } data class Pattern(val symbol: Symbol, val patternTrait: PatternTrait, val isSensitive: Boolean) : StringTraitInfo() { @@ -253,16 +263,17 @@ data class Pattern(val symbol: Symbol, val patternTrait: PatternTrait, val isSen ) }, this::renderValidationFunction, - testCases = listOf { - unitTest("regex_compiles") { - rustTemplate( - """ - #{T}::compile_regex(); - """, - "T" to symbol, - ) - } - }, + testCases = + listOf { + unitTest("regex_compiles") { + rustTemplate( + """ + #{T}::compile_regex(); + """, + "T" to symbol, + ) + } + }, ) } @@ -282,7 +293,10 @@ data class Pattern(val symbol: Symbol, val patternTrait: PatternTrait, val isSen * Renders a `check_pattern` function to validate the string matches the * supplied regex in the `@pattern` trait. */ - private fun renderValidationFunction(constraintViolation: Symbol, unconstrainedTypeName: String): Writable { + private fun renderValidationFunction( + constraintViolation: Symbol, + unconstrainedTypeName: String, + ): Writable { val pattern = patternTrait.pattern val errorMessageForUnsupportedRegex = """The regular expression $pattern is not supported by the `regex` crate; feel free to file an issue under https://github.com/smithy-lang/smithy-rs/issues for support""" @@ -317,18 +331,21 @@ data class Pattern(val symbol: Symbol, val patternTrait: PatternTrait, val isSen sealed class StringTraitInfo { companion object { - fun fromTrait(symbol: Symbol, trait: Trait, isSensitive: Boolean) = - when (trait) { - is PatternTrait -> { - Pattern(symbol, trait, isSensitive) - } - - is LengthTrait -> { - Length(trait) - } + fun fromTrait( + symbol: Symbol, + trait: Trait, + isSensitive: Boolean, + ) = when (trait) { + is PatternTrait -> { + Pattern(symbol, trait, isSensitive) + } - else -> PANIC("StringTraitInfo.fromTrait called with unsupported trait $trait") + is LengthTrait -> { + Length(trait) } + + else -> PANIC("StringTraitInfo.fromTrait called with unsupported trait $trait") + } } abstract fun toTraitInfo(): TraitInfo diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/DocHandlerGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/DocHandlerGenerator.kt index d67b79b4553..1872bc29ae5 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/DocHandlerGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/DocHandlerGenerator.kt @@ -36,11 +36,12 @@ class DocHandlerGenerator( * Returns the function signature for an operation handler implementation. Used in the documentation. */ fun docSignature(): Writable { - val outputT = if (operation.errors.isEmpty()) { - "${OutputModule.name}::${outputSymbol.name}" - } else { - "Result<${OutputModule.name}::${outputSymbol.name}, ${ErrorModule.name}::${errorSymbol.name}>" - } + val outputT = + if (operation.errors.isEmpty()) { + "${OutputModule.name}::${outputSymbol.name}" + } else { + "Result<${OutputModule.name}::${outputSymbol.name}, ${ErrorModule.name}::${errorSymbol.name}>" + } return writable { rust( @@ -58,11 +59,12 @@ class DocHandlerGenerator( * difference that we don't ellide the error for use in `tower::service_fn`. */ fun docFixedSignature(): Writable { - val errorT = if (operation.errors.isEmpty()) { - "std::convert::Infallible" - } else { - "${ErrorModule.name}::${errorSymbol.name}" - } + val errorT = + if (operation.errors.isEmpty()) { + "std::convert::Infallible" + } else { + "${ErrorModule.name}::${errorSymbol.name}" + } return writable { rust( diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/LenghTraitCommon.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/LenghTraitCommon.kt index bc074126ee1..ab8691b0cd2 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/LenghTraitCommon.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/LenghTraitCommon.kt @@ -8,13 +8,14 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators import software.amazon.smithy.model.traits.LengthTrait fun LengthTrait.rustCondition(lengthVariable: String): String { - val condition = if (min.isPresent && max.isPresent) { - "(${min.get()}..=${max.get()}).contains(&$lengthVariable)" - } else if (min.isPresent) { - "${min.get()} <= $lengthVariable" - } else { - "$lengthVariable <= ${max.get()}" - } + val condition = + if (min.isPresent && max.isPresent) { + "(${min.get()}..=${max.get()}).contains(&$lengthVariable)" + } else if (min.isPresent) { + "${min.get()} <= $lengthVariable" + } else { + "$lengthVariable <= ${max.get()}" + } return condition } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/MapConstraintViolationGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/MapConstraintViolationGenerator.kt index 38917b14776..eb4fcc66879 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/MapConstraintViolationGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/MapConstraintViolationGenerator.kt @@ -63,11 +63,12 @@ class MapConstraintViolationGenerator( } val constraintViolationCodegenScope = constraintViolationCodegenScopeMutableList.toTypedArray() - val constraintViolationVisibility = if (publicConstrainedTypes) { - Visibility.PUBLIC - } else { - Visibility.PUBCRATE - } + val constraintViolationVisibility = + if (publicConstrainedTypes) { + Visibility.PUBLIC + } else { + Visibility.PUBCRATE + } inlineModuleCreator(constraintViolationSymbol) { // TODO(https://github.com/smithy-lang/smithy-rs/issues/1401) We should really have two `ConstraintViolation` @@ -94,13 +95,14 @@ class MapConstraintViolationGenerator( #{MapShapeConstraintViolationImplBlock} } """, - "MapShapeConstraintViolationImplBlock" to validationExceptionConversionGenerator.mapShapeConstraintViolationImplBlock( - shape, - keyShape, - valueShape, - symbolProvider, - model, - ), + "MapShapeConstraintViolationImplBlock" to + validationExceptionConversionGenerator.mapShapeConstraintViolationImplBlock( + shape, + keyShape, + valueShape, + symbolProvider, + model, + ), ) } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/PubCrateConstrainedCollectionGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/PubCrateConstrainedCollectionGenerator.kt index 016da351773..294719fd7d3 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/PubCrateConstrainedCollectionGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/PubCrateConstrainedCollectionGenerator.kt @@ -59,19 +59,21 @@ class PubCrateConstrainedCollectionGenerator( val unconstrainedSymbol = unconstrainedShapeSymbolProvider.toSymbol(shape) val name = constrainedSymbol.name val innerShape = model.expectShape(shape.member.target) - val innerMemberSymbol = if (innerShape.isTransitivelyButNotDirectlyConstrained(model, symbolProvider)) { - pubCrateConstrainedShapeSymbolProvider.toSymbol(shape.member) - } else { - constrainedShapeSymbolProvider.toSymbol(shape.member) - } + val innerMemberSymbol = + if (innerShape.isTransitivelyButNotDirectlyConstrained(model, symbolProvider)) { + pubCrateConstrainedShapeSymbolProvider.toSymbol(shape.member) + } else { + constrainedShapeSymbolProvider.toSymbol(shape.member) + } - val codegenScope = arrayOf( - "InnerMemberSymbol" to innerMemberSymbol, - "ConstrainedTrait" to RuntimeType.ConstrainedTrait, - "UnconstrainedSymbol" to unconstrainedSymbol, - "Symbol" to symbol, - "From" to RuntimeType.From, - ) + val codegenScope = + arrayOf( + "InnerMemberSymbol" to innerMemberSymbol, + "ConstrainedTrait" to RuntimeType.ConstrainedTrait, + "UnconstrainedSymbol" to unconstrainedSymbol, + "Symbol" to symbol, + "From" to RuntimeType.From, + ) inlineModuleCreator(constrainedSymbol) { rustTemplate( diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/PubCrateConstrainedMapGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/PubCrateConstrainedMapGenerator.kt index 838d4da0856..7a62171fc66 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/PubCrateConstrainedMapGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/PubCrateConstrainedMapGenerator.kt @@ -59,20 +59,22 @@ class PubCrateConstrainedMapGenerator( val keyShape = model.expectShape(shape.key.target, StringShape::class.java) val valueShape = model.expectShape(shape.value.target) val keySymbol = constrainedShapeSymbolProvider.toSymbol(keyShape) - val valueMemberSymbol = if (valueShape.isTransitivelyButNotDirectlyConstrained(model, symbolProvider)) { - pubCrateConstrainedShapeSymbolProvider.toSymbol(shape.value) - } else { - constrainedShapeSymbolProvider.toSymbol(shape.value) - } + val valueMemberSymbol = + if (valueShape.isTransitivelyButNotDirectlyConstrained(model, symbolProvider)) { + pubCrateConstrainedShapeSymbolProvider.toSymbol(shape.value) + } else { + constrainedShapeSymbolProvider.toSymbol(shape.value) + } - val codegenScope = arrayOf( - "KeySymbol" to keySymbol, - "ValueMemberSymbol" to valueMemberSymbol, - "ConstrainedTrait" to RuntimeType.ConstrainedTrait, - "UnconstrainedSymbol" to unconstrainedSymbol, - "Symbol" to symbol, - "From" to RuntimeType.From, - ) + val codegenScope = + arrayOf( + "KeySymbol" to keySymbol, + "ValueMemberSymbol" to valueMemberSymbol, + "ConstrainedTrait" to RuntimeType.ConstrainedTrait, + "UnconstrainedSymbol" to unconstrainedSymbol, + "Symbol" to symbol, + "From" to RuntimeType.From, + ) inlineModuleCreator(constrainedSymbol) { rustTemplate( diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ScopeMacroGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ScopeMacroGenerator.kt index 7c3acff6ab2..1329c2b7cdb 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ScopeMacroGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ScopeMacroGenerator.kt @@ -27,153 +27,158 @@ class ScopeMacroGenerator( private val index = TopDownIndex.of(codegenContext.model) private val operations = index.getContainedOperations(codegenContext.serviceShape).toSortedSet(compareBy { it.id }) - private fun macro(): Writable = writable { - val firstOperationName = codegenContext.symbolProvider.toSymbol(operations.first()).name.toPascalCase() - val operationNames = operations.joinToString(" ") { - codegenContext.symbolProvider.toSymbol(it).name.toPascalCase() - } + private fun macro(): Writable = + writable { + val firstOperationName = codegenContext.symbolProvider.toSymbol(operations.first()).name.toPascalCase() + val operationNames = + operations.joinToString(" ") { + codegenContext.symbolProvider.toSymbol(it).name.toPascalCase() + } - // When writing `macro_rules!` we add whitespace between `$` and the arguments to avoid Kotlin templating. + // When writing `macro_rules!` we add whitespace between `$` and the arguments to avoid Kotlin templating. - // To acheive the desired API we need to calculate the set theoretic complement `B \ A`. - // The macro below, for rules prefixed with `@`, encodes a state machine which performs this. - // The initial state is `(A) () (B)`, where `A` and `B` are lists of elements of `A` and `B`. - // The rules, in order: - // - Terminate on pattern `() (t0, t1, ...) (b0, b1, ...)`, the complement has been calculated as - // `{ t0, t1, ..., b0, b1, ...}`. - // - Send pattern `(x, a0, a1, ...) (t0, t1, ...) (x, b0, b1, ...)` to - // `(a0, a1, ...) (t0, t1, ...) (b0, b1, ...)`, eliminating a matching `x` from `A` and `B`. - // - Send pattern `(a0, a1, ...) (t0, t1, ...) ()` to `(a0, a1, ...) () (t0, t1, ...)`, restarting the search. - // - Send pattern `(a0, a1, ...) (t0, t1, ...) (b0, b1, ...)` to `(a0, a1, ...) (b0, t0, t1, ...) (b1, ...)`, - // iterating through the `B`. - val operationBranches = operations - .map { codegenContext.symbolProvider.toSymbol(it).name.toPascalCase() }.joinToString("") { - """ - // $it match found, pop from both `member` and `not_member` - (@ $ name: ident, $ contains: ident ($it $($ member: ident)*) ($($ temp: ident)*) ($it $($ not_member: ident)*)) => { - scope! { @ $ name, $ contains ($($ member)*) ($($ temp)*) ($($ not_member)*) } - }; - // $it match not found, pop from `not_member` into `temp` stack - (@ $ name: ident, $ contains: ident ($it $($ member: ident)*) ($($ temp: ident)*) ($ other: ident $($ not_member: ident)*)) => { - scope! { @ $ name, $ contains ($it $($ member)*) ($ other $($ temp)*) ($($ not_member)*) } - }; - """ - } - val crateName = codegenContext.moduleUseName() + // To acheive the desired API we need to calculate the set theoretic complement `B \ A`. + // The macro below, for rules prefixed with `@`, encodes a state machine which performs this. + // The initial state is `(A) () (B)`, where `A` and `B` are lists of elements of `A` and `B`. + // The rules, in order: + // - Terminate on pattern `() (t0, t1, ...) (b0, b1, ...)`, the complement has been calculated as + // `{ t0, t1, ..., b0, b1, ...}`. + // - Send pattern `(x, a0, a1, ...) (t0, t1, ...) (x, b0, b1, ...)` to + // `(a0, a1, ...) (t0, t1, ...) (b0, b1, ...)`, eliminating a matching `x` from `A` and `B`. + // - Send pattern `(a0, a1, ...) (t0, t1, ...) ()` to `(a0, a1, ...) () (t0, t1, ...)`, restarting the search. + // - Send pattern `(a0, a1, ...) (t0, t1, ...) (b0, b1, ...)` to `(a0, a1, ...) (b0, t0, t1, ...) (b1, ...)`, + // iterating through the `B`. + val operationBranches = + operations + .map { codegenContext.symbolProvider.toSymbol(it).name.toPascalCase() }.joinToString("") { + """ + // $it match found, pop from both `member` and `not_member` + (@ $ name: ident, $ contains: ident ($it $($ member: ident)*) ($($ temp: ident)*) ($it $($ not_member: ident)*)) => { + scope! { @ $ name, $ contains ($($ member)*) ($($ temp)*) ($($ not_member)*) } + }; + // $it match not found, pop from `not_member` into `temp` stack + (@ $ name: ident, $ contains: ident ($it $($ member: ident)*) ($($ temp: ident)*) ($ other: ident $($ not_member: ident)*)) => { + scope! { @ $ name, $ contains ($it $($ member)*) ($ other $($ temp)*) ($($ not_member)*) } + }; + """ + } + val crateName = codegenContext.moduleUseName() - // If we have a second operation we can perform further checks - val otherOperationName: String? = operations.toList().getOrNull(1)?.let { - codegenContext.symbolProvider.toSymbol(it).name - } - val furtherTests = if (otherOperationName != null) { - writable { - rustTemplate( - """ - /// ## let a = Plugin::<(), $otherOperationName, u64>::apply(&scoped_a, 6); - /// ## let b = Plugin::<(), $otherOperationName, u64>::apply(&scoped_b, 6); - /// ## assert_eq!(a, 6_u64); - /// ## assert_eq!(b, 3_u32); - """, - ) - } - } else { - writable {} - } + // If we have a second operation we can perform further checks + val otherOperationName: String? = + operations.toList().getOrNull(1)?.let { + codegenContext.symbolProvider.toSymbol(it).name + } + val furtherTests = + if (otherOperationName != null) { + writable { + rustTemplate( + """ + /// ## let a = Plugin::<(), $otherOperationName, u64>::apply(&scoped_a, 6); + /// ## let b = Plugin::<(), $otherOperationName, u64>::apply(&scoped_b, 6); + /// ## assert_eq!(a, 6_u64); + /// ## assert_eq!(b, 3_u32); + """, + ) + } + } else { + writable {} + } - rustTemplate( - """ - /// A macro to help with scoping [plugins](#{SmithyHttpServer}::plugin) to a subset of all operations. - /// - /// In contrast to [`aws_smithy_http_server::scope`](#{SmithyHttpServer}::scope), this macro has knowledge - /// of the service and any operations _not_ specified will be placed in the opposing group. - /// - /// ## Example - /// - /// ```rust - /// scope! { - /// /// Includes [`$firstOperationName`], excluding all other operations. - /// struct ScopeA { - /// includes: [$firstOperationName] - /// } - /// } - /// - /// scope! { - /// /// Excludes [`$firstOperationName`], excluding all other operations. - /// struct ScopeB { - /// excludes: [$firstOperationName] - /// } - /// } - /// - /// ## use #{SmithyHttpServer}::plugin::{Plugin, Scoped}; - /// ## use $crateName::scope; - /// ## struct MockPlugin; - /// ## impl Plugin for MockPlugin { type Output = u32; fn apply(&self, input: T) -> u32 { 3 } } - /// ## let scoped_a = Scoped::new::(MockPlugin); - /// ## let scoped_b = Scoped::new::(MockPlugin); - /// ## let a = Plugin::<(), $crateName::operation_shape::$firstOperationName, u64>::apply(&scoped_a, 6); - /// ## let b = Plugin::<(), $crateName::operation_shape::$firstOperationName, u64>::apply(&scoped_b, 6); - /// ## assert_eq!(a, 3_u32); - /// ## assert_eq!(b, 6_u64); - /// ``` - ##[macro_export] - macro_rules! scope { - // Completed, render impls - (@ $ name: ident, $ contains: ident () ($($ temp: ident)*) ($($ not_member: ident)*)) => { - $( - impl #{SmithyHttpServer}::plugin::scoped::Membership<$ temp> for $ name { - type Contains = #{SmithyHttpServer}::plugin::scoped::$ contains; + rustTemplate( + """ + /// A macro to help with scoping [plugins](#{SmithyHttpServer}::plugin) to a subset of all operations. + /// + /// In contrast to [`aws_smithy_http_server::scope`](#{SmithyHttpServer}::scope), this macro has knowledge + /// of the service and any operations _not_ specified will be placed in the opposing group. + /// + /// ## Example + /// + /// ```rust + /// scope! { + /// /// Includes [`$firstOperationName`], excluding all other operations. + /// struct ScopeA { + /// includes: [$firstOperationName] + /// } + /// } + /// + /// scope! { + /// /// Excludes [`$firstOperationName`], excluding all other operations. + /// struct ScopeB { + /// excludes: [$firstOperationName] + /// } + /// } + /// + /// ## use #{SmithyHttpServer}::plugin::{Plugin, Scoped}; + /// ## use $crateName::scope; + /// ## struct MockPlugin; + /// ## impl Plugin for MockPlugin { type Output = u32; fn apply(&self, input: T) -> u32 { 3 } } + /// ## let scoped_a = Scoped::new::(MockPlugin); + /// ## let scoped_b = Scoped::new::(MockPlugin); + /// ## let a = Plugin::<(), $crateName::operation_shape::$firstOperationName, u64>::apply(&scoped_a, 6); + /// ## let b = Plugin::<(), $crateName::operation_shape::$firstOperationName, u64>::apply(&scoped_b, 6); + /// ## assert_eq!(a, 3_u32); + /// ## assert_eq!(b, 6_u64); + /// ``` + ##[macro_export] + macro_rules! scope { + // Completed, render impls + (@ $ name: ident, $ contains: ident () ($($ temp: ident)*) ($($ not_member: ident)*)) => { + $( + impl #{SmithyHttpServer}::plugin::scoped::Membership<$ temp> for $ name { + type Contains = #{SmithyHttpServer}::plugin::scoped::$ contains; + } + )* + $( + impl #{SmithyHttpServer}::plugin::scoped::Membership<$ not_member> for $ name { + type Contains = #{SmithyHttpServer}::plugin::scoped::$ contains; + } + )* + }; + // All `not_member`s exhausted, move `temp` into `not_member` + (@ $ name: ident, $ contains: ident ($($ member: ident)*) ($($ temp: ident)*) ()) => { + scope! { @ $ name, $ contains ($($ member)*) () ($($ temp)*) } + }; + $operationBranches + ( + $(##[$ attrs:meta])* + $ vis:vis struct $ name:ident { + includes: [$($ include:ident),*] } - )* - $( - impl #{SmithyHttpServer}::plugin::scoped::Membership<$ not_member> for $ name { - type Contains = #{SmithyHttpServer}::plugin::scoped::$ contains; + ) => { + use $ crate::operation_shape::*; + #{SmithyHttpServer}::scope! { + $(##[$ attrs])* + $ vis struct $ name { + includes: [$($ include),*], + excludes: [] + } } - )* - }; - // All `not_member`s exhausted, move `temp` into `not_member` - (@ $ name: ident, $ contains: ident ($($ member: ident)*) ($($ temp: ident)*) ()) => { - scope! { @ $ name, $ contains ($($ member)*) () ($($ temp)*) } - }; - $operationBranches - ( - $(##[$ attrs:meta])* - $ vis:vis struct $ name:ident { - includes: [$($ include:ident),*] - } - ) => { - use $ crate::operation_shape::*; - #{SmithyHttpServer}::scope! { - $(##[$ attrs])* - $ vis struct $ name { - includes: [$($ include),*], - excludes: [] + scope! { @ $ name, False ($($ include)*) () ($operationNames) } + }; + ( + $(##[$ attrs:meta])* + $ vis:vis struct $ name:ident { + excludes: [$($ exclude:ident),*] } - } - scope! { @ $ name, False ($($ include)*) () ($operationNames) } - }; - ( - $(##[$ attrs:meta])* - $ vis:vis struct $ name:ident { - excludes: [$($ exclude:ident),*] - } - ) => { - use $ crate::operation_shape::*; + ) => { + use $ crate::operation_shape::*; - #{SmithyHttpServer}::scope! { - $(##[$ attrs])* - $ vis struct $ name { - includes: [], - excludes: [$($ exclude),*] + #{SmithyHttpServer}::scope! { + $(##[$ attrs])* + $ vis struct $ name { + includes: [], + excludes: [$($ exclude),*] + } } - } - scope! { @ $ name, True ($($ exclude)*) () ($operationNames) } - }; - } - """, - *codegenScope, - "FurtherTests" to furtherTests, - ) - } + scope! { @ $ name, True ($($ exclude)*) () ($operationNames) } + }; + } + """, + *codegenScope, + "FurtherTests" to furtherTests, + ) + } fun render(writer: RustWriter) { macro()(writer) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderConstraintViolations.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderConstraintViolations.kt index d91176c0f8f..3e9595ca638 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderConstraintViolations.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderConstraintViolations.kt @@ -50,12 +50,13 @@ class ServerBuilderConstraintViolations( } } private val members: List = shape.allMembers.values.toList() - val all = members.flatMap { member -> - listOfNotNull( - forMember(member), - builderConstraintViolationForMember(member), - ) - } + val all = + members.flatMap { member -> + listOfNotNull( + forMember(member), + builderConstraintViolationForMember(member), + ) + } fun render( writer: RustWriter, @@ -117,11 +118,12 @@ class ServerBuilderConstraintViolations( rustBlock("fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result") { rustBlock("match self") { all.forEach { - val arm = if (it.hasInner()) { - "ConstraintViolation::${it.name()}(_)" - } else { - "ConstraintViolation::${it.name()}" - } + val arm = + if (it.hasInner()) { + "ConstraintViolation::${it.name()}(_)" + } else { + "ConstraintViolation::${it.name()}" + } rust("""$arm => write!(f, "${it.message(symbolProvider, model)}"),""") } } @@ -192,10 +194,11 @@ enum class ConstraintViolationKind { } data class ConstraintViolation(val forMember: MemberShape, val kind: ConstraintViolationKind) { - fun name() = when (kind) { - ConstraintViolationKind.MISSING_MEMBER -> "Missing${forMember.memberName.toPascalCase()}" - ConstraintViolationKind.CONSTRAINED_SHAPE_FAILURE -> forMember.memberName.toPascalCase() - } + fun name() = + when (kind) { + ConstraintViolationKind.MISSING_MEMBER -> "Missing${forMember.memberName.toPascalCase()}" + ConstraintViolationKind.CONSTRAINED_SHAPE_FAILURE -> forMember.memberName.toPascalCase() + } /** * Whether the constraint violation is a Rust tuple struct with one element. @@ -205,7 +208,10 @@ data class ConstraintViolation(val forMember: MemberShape, val kind: ConstraintV /** * A message for a `ConstraintViolation` variant. This is used in both Rust documentation and the `Display` trait implementation. */ - fun message(symbolProvider: SymbolProvider, model: Model): String { + fun message( + symbolProvider: SymbolProvider, + model: Model, + ): String { val memberName = symbolProvider.toMemberName(forMember) val structureSymbol = symbolProvider.toSymbol(model.expectShape(forMember.container)) return when (kind) { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGenerator.kt index b8c74b9c5c1..b44e7f04b4a 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGenerator.kt @@ -107,24 +107,28 @@ class ServerBuilderGenerator( takeInUnconstrainedTypes: Boolean, ): Boolean { val members = structureShape.members() + fun isOptional(member: MemberShape) = symbolProvider.toSymbol(member).isOptional() + fun hasDefault(member: MemberShape) = member.hasNonNullDefault() + fun isNotConstrained(member: MemberShape) = !member.canReachConstrainedShape(model, symbolProvider) - val notFallible = members.all { - if (structureShape.isReachableFromOperationInput()) { - // When deserializing an input structure, constraints might not be satisfied by the data in the - // incoming request. - // For this builder not to be fallible, no members must be constrained (constraints in input must - // always be checked) and all members must _either_ be optional (no need to set it; not required) - // or have a default value. - isNotConstrained(it) && (isOptional(it) || hasDefault(it)) - } else { - // This structure will be constructed manually by the user. - // Constraints will have to be dealt with before members are set in the builder. - isOptional(it) || hasDefault(it) + val notFallible = + members.all { + if (structureShape.isReachableFromOperationInput()) { + // When deserializing an input structure, constraints might not be satisfied by the data in the + // incoming request. + // For this builder not to be fallible, no members must be constrained (constraints in input must + // always be checked) and all members must _either_ be optional (no need to set it; not required) + // or have a default value. + isNotConstrained(it) && (isOptional(it) || hasDefault(it)) + } else { + // This structure will be constructed manually by the user. + // Constraints will have to be dealt with before members are set in the builder. + isOptional(it) || hasDefault(it) + } } - } return if (takeInUnconstrainedTypes) { !notFallible && structureShape.canReachConstrainedShape(model, symbolProvider) @@ -150,15 +154,19 @@ class ServerBuilderGenerator( ServerBuilderConstraintViolations(codegenContext, shape, takeInUnconstrainedTypes, customValidationExceptionWithReasonConversionGenerator) private val lifetime = shape.lifetimeDeclaration(symbolProvider) - private val codegenScope = arrayOf( - "RequestRejection" to protocol.requestRejection(codegenContext.runtimeConfig), - "Structure" to structureSymbol, - "From" to RuntimeType.From, - "TryFrom" to RuntimeType.TryFrom, - "MaybeConstrained" to RuntimeType.MaybeConstrained, - ) + private val codegenScope = + arrayOf( + "RequestRejection" to protocol.requestRejection(codegenContext.runtimeConfig), + "Structure" to structureSymbol, + "From" to RuntimeType.From, + "TryFrom" to RuntimeType.TryFrom, + "MaybeConstrained" to RuntimeType.MaybeConstrained, + ) - fun render(rustCrate: RustCrate, writer: RustWriter) { + fun render( + rustCrate: RustCrate, + writer: RustWriter, + ) { val docWriter: () -> Unit = { writer.docs("See #D.", structureSymbol) } rustCrate.withInMemoryInlineModule(writer, builderSymbol.module(), docWriter) { renderBuilder(this) @@ -194,9 +202,10 @@ class ServerBuilderGenerator( // since we are a builder and everything is optional. val baseDerives = structureSymbol.expectRustMetadata().derives // Filter out any derive that isn't Debug or Clone. Then add a Default derive - val builderDerives = baseDerives.filter { - it == RuntimeType.Debug || it == RuntimeType.Clone - } + RuntimeType.Default + val builderDerives = + baseDerives.filter { + it == RuntimeType.Debug || it == RuntimeType.Clone + } + RuntimeType.Default Attribute(derive(builderDerives)).render(writer) writer.rustBlock("${visibility.toRustQualifier()} struct Builder$lifetime") { members.forEach { renderBuilderMember(this, it) } @@ -287,7 +296,10 @@ class ServerBuilderGenerator( } } - private fun renderBuilderMember(writer: RustWriter, member: MemberShape) { + private fun renderBuilderMember( + writer: RustWriter, + member: MemberShape, + ) { val memberSymbol = builderMemberSymbol(member) val memberName = constrainedShapeSymbolProvider.toMemberName(member) // Builder members are crate-public to enable using them directly in serializers/deserializers. @@ -383,14 +395,15 @@ class ServerBuilderGenerator( member: MemberShape, ) { val builderMemberSymbol = builderMemberSymbol(member) - val inputType = builderMemberSymbol.rustType().stripOuter().implInto() - .letIf( - // TODO(https://github.com/smithy-lang/smithy-rs/issues/1302, https://github.com/awslabs/smithy/issues/1179): - // The only reason why this condition can't simply be `member.isOptional` - // is because non-`required` blob streaming members are interpreted as - // `required`, so we can't use `member.isOptional` here. - symbolProvider.toSymbol(member).isOptional(), - ) { "Option<$it>" } + val inputType = + builderMemberSymbol.rustType().stripOuter().implInto() + .letIf( + // TODO(https://github.com/smithy-lang/smithy-rs/issues/1302, https://github.com/awslabs/smithy/issues/1179): + // The only reason why this condition can't simply be `member.isOptional` + // is because non-`required` blob streaming members are interpreted as + // `required`, so we can't use `member.isOptional` here. + symbolProvider.toSymbol(member).isOptional(), + ) { "Option<$it>" } val memberName = symbolProvider.toMemberName(member) writer.documentShape(member, model) @@ -415,7 +428,7 @@ class ServerBuilderGenerator( private fun renderTryFromBuilderImpl(writer: RustWriter) { writer.rustTemplate( """ - impl #{TryFrom} for #{Structure}$lifetime { + impl $lifetime #{TryFrom} for #{Structure}$lifetime { type Error = ConstraintViolation; fn try_from(builder: Builder $lifetime) -> Result { @@ -430,8 +443,8 @@ class ServerBuilderGenerator( private fun renderFromBuilderImpl(writer: RustWriter) { writer.rustTemplate( """ - impl #{From} for #{Structure} $lifetime { - fn from(builder: Builder) -> Self { + impl$lifetime #{From} for #{Structure} $lifetime { + fn from(builder: Builder$lifetime) -> Self { builder.build() } } @@ -463,13 +476,14 @@ class ServerBuilderGenerator( */ private fun builderMemberSymbol(member: MemberShape): Symbol = if (takeInUnconstrainedTypes && member.targetCanReachConstrainedShape(model, symbolProvider)) { - val strippedOption = if (member.hasConstraintTraitOrTargetHasConstraintTrait(model, symbolProvider)) { - constrainedShapeSymbolProvider.toSymbol(member) - } else { - pubCrateConstrainedShapeSymbolProvider.toSymbol(member) - } - // Strip the `Option` in case the member is not `required`. - .mapRustType { it.stripOuter() } + val strippedOption = + if (member.hasConstraintTraitOrTargetHasConstraintTrait(model, symbolProvider)) { + constrainedShapeSymbolProvider.toSymbol(member) + } else { + pubCrateConstrainedShapeSymbolProvider.toSymbol(member) + } + // Strip the `Option` in case the member is not `required`. + .mapRustType { it.stripOuter() } val hadBox = strippedOption.isRustBoxed() strippedOption @@ -543,13 +557,18 @@ class ServerBuilderGenerator( } } - private fun enforceConstraints(writer: RustWriter, member: MemberShape, constraintViolation: ConstraintViolation) { + private fun enforceConstraints( + writer: RustWriter, + member: MemberShape, + constraintViolation: ConstraintViolation, + ) { // This member is constrained. Enforce the constraint traits on the value set in the builder. // The code is slightly different in case the member is recursive, since it will be wrapped in // `std::boxed::Box`. - val hasBox = builderMemberSymbol(member) - .mapRustType { it.stripOuter() } - .isRustBoxed() + val hasBox = + builderMemberSymbol(member) + .mapRustType { it.stripOuter() } + .isRustBoxed() val errHasBox = member.hasTrait() if (hasBox) { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorCommon.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorCommon.kt index 4912d9eb314..9c80cd12581 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorCommon.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorCommon.kt @@ -21,7 +21,6 @@ import software.amazon.smithy.model.shapes.DocumentShape import software.amazon.smithy.model.shapes.DoubleShape import software.amazon.smithy.model.shapes.EnumShape import software.amazon.smithy.model.shapes.FloatShape -import software.amazon.smithy.model.shapes.IntEnumShape import software.amazon.smithy.model.shapes.IntegerShape import software.amazon.smithy.model.shapes.ListShape import software.amazon.smithy.model.shapes.LongShape @@ -32,22 +31,23 @@ import software.amazon.smithy.model.shapes.ShortShape import software.amazon.smithy.model.shapes.StringShape import software.amazon.smithy.model.shapes.TimestampShape import software.amazon.smithy.model.traits.DefaultTrait -import software.amazon.smithy.model.traits.EnumDefinition import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.core.rustlang.map +import software.amazon.smithy.rust.codegen.core.rustlang.qualifiedName import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.core.smithy.RustSymbolProvider -import software.amazon.smithy.rust.codegen.core.smithy.generators.EnumMemberModel -import software.amazon.smithy.rust.codegen.core.util.UNREACHABLE +import software.amazon.smithy.rust.codegen.core.smithy.generators.PrimitiveInstantiator +import software.amazon.smithy.rust.codegen.core.smithy.rustType import software.amazon.smithy.rust.codegen.core.util.dq import software.amazon.smithy.rust.codegen.core.util.expectTrait import software.amazon.smithy.rust.codegen.core.util.isStreaming import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.server.smithy.hasPublicConstrainedWrapperTupleType -/** +/* * Some common freestanding functions shared across: * - [ServerBuilderGenerator]; and * - [ServerBuilderGeneratorWithoutPublicConstrainedTypes], @@ -57,7 +57,11 @@ import software.amazon.smithy.rust.codegen.server.smithy.hasPublicConstrainedWra /** * Returns a writable to render the return type of the server builders' `build()` method. */ -fun buildFnReturnType(isBuilderFallible: Boolean, structureSymbol: Symbol, lifetime: String) = writable { +fun buildFnReturnType( + isBuilderFallible: Boolean, + structureSymbol: Symbol, + lifetime: String, +) = writable { if (isBuilderFallible) { rust("Result<#T $lifetime, ConstraintViolation>", structureSymbol) } else { @@ -78,8 +82,14 @@ fun generateFallbackCodeToDefaultValue( symbolProvider: RustSymbolProvider, publicConstrainedTypes: Boolean, ) { - val defaultValue = defaultValue(model, runtimeConfig, symbolProvider, member) + var defaultValue = defaultValue(model, runtimeConfig, symbolProvider, member) val targetShape = model.expectShape(member.target) + val targetSymbol = symbolProvider.toSymbol(targetShape) + // We need an .into() conversion to create defaults for the server types. A larger scale refactoring could store this information in the + // symbol, however, retrieving it in this manner works for the moment. + if (targetSymbol.rustType().qualifiedName().startsWith("::aws_smithy_http_server_python")) { + defaultValue = defaultValue.map { rust("#T.into()", it) } + } if (member.isStreaming(model)) { writer.rust(".unwrap_or_default()") @@ -127,32 +137,7 @@ fun defaultValue( val unsupportedDefaultValueException = CodegenException("Default value $node for member shape ${member.id} is unsupported or cannot exist; please file a bug report under https://github.com/smithy-lang/smithy-rs/issues") when (val target = model.expectShape(member.target)) { - is EnumShape, is IntEnumShape -> { - val value = when (target) { - is IntEnumShape -> node.expectNumberNode().value - is EnumShape -> node.expectStringNode().value - else -> throw CodegenException("Default value for shape ${target.id} must be of EnumShape or IntEnumShape") - } - val enumValues = when (target) { - is IntEnumShape -> target.enumValues - is EnumShape -> target.enumValues - else -> UNREACHABLE( - "Target shape ${target.id} must be an `EnumShape` or an `IntEnumShape` at this point, otherwise it would have failed above", - ) - } - val variant = enumValues - .entries - .filter { entry -> entry.value == value } - .map { entry -> - EnumMemberModel.toEnumVariantName( - symbolProvider, - target, - EnumDefinition.builder().name(entry.key).value(entry.value.toString()).build(), - )!! - } - .first() - rust("#T::${variant.name}", symbolProvider.toSymbol(target)) - } + is EnumShape -> PrimitiveInstantiator(runtimeConfig, symbolProvider).instantiate(target, node)(this) is ByteShape -> rust(node.expectNumberNode().value.toString() + "i8") is ShortShape -> rust(node.expectNumberNode().value.toString() + "i16") @@ -162,43 +147,58 @@ fun defaultValue( is DoubleShape -> rust(node.expectNumberNode().value.toDouble().toString() + "f64") is BooleanShape -> rust(node.expectBooleanNode().value.toString()) is StringShape -> rust("String::from(${node.expectStringNode().value.dq()})") - is TimestampShape -> when (node) { - is NumberNode -> rust(node.expectNumberNode().value.toString()) - is StringNode -> { - val value = node.expectStringNode().value - rustTemplate( - """ - #{SmithyTypes}::DateTime::from_str("$value", #{SmithyTypes}::date_time::Format::DateTime) - .expect("default value `$value` cannot be parsed into a valid date time; please file a bug report under https://github.com/smithy-lang/smithy-rs/issues") - """, - "SmithyTypes" to types, - ) + is TimestampShape -> + when (node) { + is NumberNode -> PrimitiveInstantiator(runtimeConfig, symbolProvider).instantiate(target, node)(this) + is StringNode -> { + val value = node.expectStringNode().value + rustTemplate( + """ + #{SmithyTypes}::DateTime::from_str("$value", #{SmithyTypes}::date_time::Format::DateTime) + .expect("default value `$value` cannot be parsed into a valid date time; please file a bug report under https://github.com/smithy-lang/smithy-rs/issues") + """, + "SmithyTypes" to types, + ) + } + else -> throw unsupportedDefaultValueException } - else -> throw unsupportedDefaultValueException - } is ListShape -> { check(node is ArrayNode && node.isEmpty) rust("Vec::new()") } + is MapShape -> { check(node is ObjectNode && node.isEmpty) rust("std::collections::HashMap::new()") } + is DocumentShape -> { when (node) { - is NullNode -> rustTemplate( - "#{SmithyTypes}::Document::Null", - "SmithyTypes" to types, - ) + is NullNode -> + rustTemplate( + "#{SmithyTypes}::Document::Null", + "SmithyTypes" to types, + ) + + is BooleanNode -> + rustTemplate( + """#{SmithyTypes}::Document::Bool(${node.value})""", + "SmithyTypes" to types, + ) + + is StringNode -> + rustTemplate( + "#{SmithyTypes}::Document::String(String::from(${node.value.dq()}))", + "SmithyTypes" to types, + ) - is BooleanNode -> rustTemplate("""#{SmithyTypes}::Document::Bool(${node.value})""", "SmithyTypes" to types) - is StringNode -> rustTemplate("#{SmithyTypes}::Document::String(String::from(${node.value.dq()}))", "SmithyTypes" to types) is NumberNode -> { val value = node.value.toString() - val variant = when (node.value) { - is Float, is Double -> "Float" - else -> if (node.value.toLong() >= 0) "PosInt" else "NegInt" - } + val variant = + when (node.value) { + is Float, is Double -> "Float" + else -> if (node.value.toLong() >= 0) "PosInt" else "NegInt" + } rustTemplate( "#{SmithyTypes}::Document::Number(#{SmithyTypes}::Number::$variant($value))", "SmithyTypes" to types, @@ -212,14 +212,17 @@ fun defaultValue( is ObjectNode -> { check(node.isEmpty) - rustTemplate("#{SmithyTypes}::Document::Object(std::collections::HashMap::new())", "SmithyTypes" to types) + rustTemplate( + "#{SmithyTypes}::Document::Object(std::collections::HashMap::new())", + "SmithyTypes" to types, + ) } else -> throw unsupportedDefaultValueException } } - is BlobShape -> rust("Default::default()") + is BlobShape -> PrimitiveInstantiator(runtimeConfig, symbolProvider).instantiate(target, node)(this) else -> throw unsupportedDefaultValueException } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorWithoutPublicConstrainedTypes.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorWithoutPublicConstrainedTypes.kt index 7589a761c08..4583d9be455 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorWithoutPublicConstrainedTypes.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorWithoutPublicConstrainedTypes.kt @@ -64,12 +64,15 @@ class ServerBuilderGeneratorWithoutPublicConstrainedTypes( symbolProvider: SymbolProvider, ): Boolean { val members = structureShape.members() + fun isOptional(member: MemberShape) = symbolProvider.toSymbol(member).isOptional() + fun hasDefault(member: MemberShape) = member.hasNonNullDefault() - val notFallible = members.all { - isOptional(it) || hasDefault(it) - } + val notFallible = + members.all { + isOptional(it) || hasDefault(it) + } return !notFallible } @@ -87,15 +90,19 @@ class ServerBuilderGeneratorWithoutPublicConstrainedTypes( ServerBuilderConstraintViolations(codegenContext, shape, builderTakesInUnconstrainedTypes = false, validationExceptionConversionGenerator) private val lifetime = shape.lifetimeDeclaration(symbolProvider) - private val codegenScope = arrayOf( - "RequestRejection" to protocol.requestRejection(codegenContext.runtimeConfig), - "Structure" to structureSymbol, - "From" to RuntimeType.From, - "TryFrom" to RuntimeType.TryFrom, - "MaybeConstrained" to RuntimeType.MaybeConstrained, - ) + private val codegenScope = + arrayOf( + "RequestRejection" to protocol.requestRejection(codegenContext.runtimeConfig), + "Structure" to structureSymbol, + "From" to RuntimeType.From, + "TryFrom" to RuntimeType.TryFrom, + "MaybeConstrained" to RuntimeType.MaybeConstrained, + ) - fun render(rustCrate: RustCrate, writer: RustWriter) { + fun render( + rustCrate: RustCrate, + writer: RustWriter, + ) { check(!codegenContext.settings.codegenConfig.publicConstrainedTypes) { "ServerBuilderGeneratorWithoutPublicConstrainedTypes should only be used when `publicConstrainedTypes` is false" } @@ -206,7 +213,10 @@ class ServerBuilderGeneratorWithoutPublicConstrainedTypes( } } - private fun renderBuilderMember(writer: RustWriter, member: MemberShape) { + private fun renderBuilderMember( + writer: RustWriter, + member: MemberShape, + ) { val memberSymbol = builderMemberSymbol(member) val memberName = symbolProvider.toMemberName(member) // Builder members are crate-public to enable using them directly in serializers/deserializers. @@ -220,7 +230,10 @@ class ServerBuilderGeneratorWithoutPublicConstrainedTypes( * * This method is meant for use by the user; it is not used by the generated crate's (de)serializers. */ - private fun renderBuilderMemberFn(writer: RustWriter, member: MemberShape) { + private fun renderBuilderMemberFn( + writer: RustWriter, + member: MemberShape, + ) { val memberSymbol = symbolProvider.toSymbol(member) val memberName = symbolProvider.toMemberName(member) @@ -239,7 +252,7 @@ class ServerBuilderGeneratorWithoutPublicConstrainedTypes( private fun renderTryFromBuilderImpl(writer: RustWriter) { writer.rustTemplate( """ - impl #{TryFrom} for #{Structure}$lifetime { + impl $lifetime #{TryFrom} for #{Structure}$lifetime { type Error = ConstraintViolation; fn try_from(builder: Builder $lifetime) -> Result { @@ -254,7 +267,7 @@ class ServerBuilderGeneratorWithoutPublicConstrainedTypes( private fun renderFromBuilderImpl(writer: RustWriter) { writer.rustTemplate( """ - impl #{From} for #{Structure}$lifetime { + impl$lifetime #{From} for #{Structure}$lifetime { fn from(builder: Builder $lifetime) -> Self { builder.build() } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderSymbol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderSymbol.kt index f0ca507db16..9e79f918c64 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderSymbol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderSymbol.kt @@ -24,18 +24,23 @@ fun StructureShape.serverBuilderSymbol(codegenContext: ServerCodegenContext): Sy ) // TODO(https://github.com/smithy-lang/smithy-rs/issues/2396): Replace this with `RustSymbolProvider.moduleForBuilder` -fun StructureShape.serverBuilderModule(symbolProvider: SymbolProvider, pubCrate: Boolean): RustModule.LeafModule { +fun StructureShape.serverBuilderModule( + symbolProvider: SymbolProvider, + pubCrate: Boolean, +): RustModule.LeafModule { val structureSymbol = symbolProvider.toSymbol(this) - val builderNamespace = RustReservedWords.escapeIfNeeded(structureSymbol.name.toSnakeCase()) + - if (pubCrate) { - "_internal" - } else { - "" + val builderNamespace = + RustReservedWords.escapeIfNeeded(structureSymbol.name.toSnakeCase()) + + if (pubCrate) { + "_internal" + } else { + "" + } + val visibility = + when (pubCrate) { + true -> Visibility.PUBCRATE + false -> Visibility.PUBLIC } - val visibility = when (pubCrate) { - true -> Visibility.PUBCRATE - false -> Visibility.PUBLIC - } return RustModule.new( builderNamespace, visibility, @@ -46,7 +51,10 @@ fun StructureShape.serverBuilderModule(symbolProvider: SymbolProvider, pubCrate: } // TODO(https://github.com/smithy-lang/smithy-rs/issues/2396): Replace this with `RustSymbolProvider.symbolForBuilder` -fun StructureShape.serverBuilderSymbol(symbolProvider: SymbolProvider, pubCrate: Boolean): Symbol { +fun StructureShape.serverBuilderSymbol( + symbolProvider: SymbolProvider, + pubCrate: Boolean, +): Symbol { val builderModule = serverBuilderModule(symbolProvider, pubCrate) val rustType = RustType.Opaque("Builder", builderModule.fullyQualifiedPath()) return Symbol.builder() diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt index 09a0d2d5cd7..354cbc0f662 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGenerator.kt @@ -38,71 +38,75 @@ open class ConstrainedEnum( } private val constraintViolationSymbol = constraintViolationSymbolProvider.toSymbol(shape) private val constraintViolationName = constraintViolationSymbol.name - private val codegenScope = arrayOf( - "String" to RuntimeType.String, - ) - - override fun implFromForStr(context: EnumGeneratorContext): Writable = writable { - withInlineModule(constraintViolationSymbol.module(), codegenContext.moduleDocProvider) { - rustTemplate( - """ - ##[derive(Debug, PartialEq)] - pub struct $constraintViolationName(pub(crate) #{String}); - """, - *codegenScope, - ) + private val codegenScope = + arrayOf( + "String" to RuntimeType.String, + ) - if (shape.isReachableFromOperationInput()) { + override fun implFromForStr(context: EnumGeneratorContext): Writable = + writable { + withInlineModule(constraintViolationSymbol.module(), codegenContext.moduleDocProvider) { rustTemplate( """ - impl $constraintViolationName { - #{EnumShapeConstraintViolationImplBlock:W} - } + ##[derive(Debug, PartialEq)] + pub struct $constraintViolationName(pub(crate) #{String}); """, - "EnumShapeConstraintViolationImplBlock" to validationExceptionConversionGenerator.enumShapeConstraintViolationImplBlock( - context.enumTrait, - ), + *codegenScope, ) + + if (shape.isReachableFromOperationInput()) { + rustTemplate( + """ + impl $constraintViolationName { + #{EnumShapeConstraintViolationImplBlock:W} + } + """, + "EnumShapeConstraintViolationImplBlock" to + validationExceptionConversionGenerator.enumShapeConstraintViolationImplBlock( + context.enumTrait, + ), + ) + } } - } - rustBlock("impl #T<&str> for ${context.enumName}", RuntimeType.TryFrom) { - rust("type Error = #T;", constraintViolationSymbol) - rustBlockTemplate("fn try_from(s: &str) -> #{Result}>::Error>", *preludeScope) { - rustBlock("match s") { - context.sortedMembers.forEach { member -> - rust("${member.value.dq()} => Ok(${context.enumName}::${member.derivedName()}),") + rustBlock("impl #T<&str> for ${context.enumName}", RuntimeType.TryFrom) { + rust("type Error = #T;", constraintViolationSymbol) + rustBlockTemplate("fn try_from(s: &str) -> #{Result}>::Error>", *preludeScope) { + rustBlock("match s") { + context.sortedMembers.forEach { member -> + rust("${member.value.dq()} => Ok(${context.enumName}::${member.derivedName()}),") + } + rust("_ => Err(#T(s.to_owned()))", constraintViolationSymbol) } - rust("_ => Err(#T(s.to_owned()))", constraintViolationSymbol) } } - } - rustTemplate( - """ - impl #{TryFrom}<#{String}> for ${context.enumName} { - type Error = #{ConstraintViolation}; - fn try_from(s: #{String}) -> #{Result}>::Error> { - s.as_str().try_into() + rustTemplate( + """ + impl #{TryFrom}<#{String}> for ${context.enumName} { + type Error = #{ConstraintViolation}; + fn try_from(s: #{String}) -> #{Result}>::Error> { + s.as_str().try_into() + } } - } - """, - *preludeScope, - "ConstraintViolation" to constraintViolationSymbol, - ) - } + """, + *preludeScope, + "ConstraintViolation" to constraintViolationSymbol, + ) + } - override fun implFromStr(context: EnumGeneratorContext): Writable = writable { - rustTemplate( - """ - impl std::str::FromStr for ${context.enumName} { - type Err = #{ConstraintViolation}; - fn from_str(s: &str) -> std::result::Result::Err> { - Self::try_from(s) + override fun implFromStr(context: EnumGeneratorContext): Writable = + writable { + rustTemplate( + """ + impl std::str::FromStr for ${context.enumName} { + type Err = #{ConstraintViolation}; + fn from_str(s: &str) -> std::result::Result::Err> { + Self::try_from(s) + } } - } - """, - "ConstraintViolation" to constraintViolationSymbol, - ) - } + """, + "ConstraintViolation" to constraintViolationSymbol, + ) + } } class ServerEnumGenerator( @@ -110,8 +114,8 @@ class ServerEnumGenerator( shape: StringShape, validationExceptionConversionGenerator: ValidationExceptionConversionGenerator, ) : EnumGenerator( - codegenContext.model, - codegenContext.symbolProvider, - shape, - enumType = ConstrainedEnum(codegenContext, shape, validationExceptionConversionGenerator), -) + codegenContext.model, + codegenContext.symbolProvider, + shape, + enumType = ConstrainedEnum(codegenContext, shape, validationExceptionConversionGenerator), + ) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerHttpSensitivityGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerHttpSensitivityGenerator.kt index 0347013de5c..468c59547b0 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerHttpSensitivityGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerHttpSensitivityGenerator.kt @@ -33,25 +33,28 @@ import java.util.Optional /** Models the ways status codes can be bound and sensitive. */ class StatusCodeSensitivity(private val sensitive: Boolean, runtimeConfig: RuntimeConfig) { - private val codegenScope = arrayOf( - "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(runtimeConfig).toType(), - ) + private val codegenScope = + arrayOf( + "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(runtimeConfig).toType(), + ) /** Returns the type of the `MakeFmt`. */ - fun type(): Writable = writable { - if (sensitive) { - rustTemplate("#{SmithyHttpServer}::instrumentation::MakeSensitive", *codegenScope) - } else { - rustTemplate("#{SmithyHttpServer}::instrumentation::MakeIdentity", *codegenScope) + fun type(): Writable = + writable { + if (sensitive) { + rustTemplate("#{SmithyHttpServer}::instrumentation::MakeSensitive", *codegenScope) + } else { + rustTemplate("#{SmithyHttpServer}::instrumentation::MakeIdentity", *codegenScope) + } } - } /** Returns the setter. */ - fun setter(): Writable = writable { - if (sensitive) { - rust(".status_code()") + fun setter(): Writable = + writable { + if (sensitive) { + rust(".status_code()") + } } - } } /** Represents the information needed to specify the position of a greedy label. */ @@ -68,54 +71,59 @@ class LabelSensitivity(internal val labelIndexes: List, internal val greedy arrayOf("SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(runtimeConfig).toType()) /** Returns the closure used during construction. */ - fun closure(): Writable = writable { - if (labelIndexes.isNotEmpty()) { - rustTemplate( - """ - { - |index: usize| matches!(index, ${labelIndexes.joinToString("|")}) - } as fn(usize) -> bool - """, - *codegenScope, - ) - } else { - rust("{ |_index: usize| false } as fn(usize) -> bool") + fun closure(): Writable = + writable { + if (labelIndexes.isNotEmpty()) { + rustTemplate( + """ + { + |index: usize| matches!(index, ${labelIndexes.joinToString("|")}) + } as fn(usize) -> bool + """, + *codegenScope, + ) + } else { + rust("{ |_index: usize| false } as fn(usize) -> bool") + } } - } + private fun hasRedactions(): Boolean = labelIndexes.isNotEmpty() || greedyLabel != null /** Returns the type of the `MakeFmt`. */ - fun type(): Writable = if (hasRedactions()) { - writable { - rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::uri::MakeLabel bool>", *codegenScope) - } - } else { - writable { - rustTemplate("#{SmithyHttpServer}::instrumentation::MakeIdentity", *codegenScope) + fun type(): Writable = + if (hasRedactions()) { + writable { + rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::uri::MakeLabel bool>", *codegenScope) + } + } else { + writable { + rustTemplate("#{SmithyHttpServer}::instrumentation::MakeIdentity", *codegenScope) + } } - } /** Returns the value of the `GreedyLabel`. */ - private fun greedyLabelStruct(): Writable = writable { - if (greedyLabel != null) { - rustTemplate( - """ + private fun greedyLabelStruct(): Writable = + writable { + if (greedyLabel != null) { + rustTemplate( + """ Some(#{SmithyHttpServer}::instrumentation::sensitivity::uri::GreedyLabel::new(${greedyLabel.segmentIndex}, ${greedyLabel.endOffset}))""", - *codegenScope, - ) - } else { - rust("None") + *codegenScope, + ) + } else { + rust("None") + } } - } /** Returns the setter enclosing the closure or suffix position. */ - fun setter(): Writable = if (hasRedactions()) { - writable { - rustTemplate(".label(#{Closure:W}, #{GreedyLabel:W})", "Closure" to closure(), "GreedyLabel" to greedyLabelStruct()) + fun setter(): Writable = + if (hasRedactions()) { + writable { + rustTemplate(".label(#{Closure:W}, #{GreedyLabel:W})", "Closure" to closure(), "GreedyLabel" to greedyLabelStruct()) + } + } else { + writable { } } - } else { - writable { } - } } /** Models the ways headers can be bound and sensitive */ @@ -124,10 +132,11 @@ sealed class HeaderSensitivity( val headerKeys: List, runtimeConfig: RuntimeConfig, ) { - private val codegenScope = arrayOf( - "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(runtimeConfig).toType(), - "Http" to CargoDependency.Http.toType(), - ) + private val codegenScope = + arrayOf( + "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(runtimeConfig).toType(), + "Http" to CargoDependency.Http.toType(), + ) /** The case where `prefixHeaders` value is not sensitive. */ class NotSensitiveMapValue( @@ -148,55 +157,62 @@ sealed class HeaderSensitivity( ) : HeaderSensitivity(headerKeys, runtimeConfig) /** Is there anything to redact? */ - internal fun hasRedactions(): Boolean = headerKeys.isNotEmpty() || when (this) { - is NotSensitiveMapValue -> prefixHeader != null - is SensitiveMapValue -> true - } + internal fun hasRedactions(): Boolean = + headerKeys.isNotEmpty() || + when (this) { + is NotSensitiveMapValue -> prefixHeader != null + is SensitiveMapValue -> true + } /** Returns the type of the `MakeDebug`. */ - fun type(): Writable = writable { - if (hasRedactions()) { - rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::headers::MakeHeaders #{SmithyHttpServer}::instrumentation::sensitivity::headers::HeaderMarker>", *codegenScope) - } else { - rustTemplate("#{SmithyHttpServer}::instrumentation::MakeIdentity", *codegenScope) + fun type(): Writable = + writable { + if (hasRedactions()) { + rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::headers::MakeHeaders #{SmithyHttpServer}::instrumentation::sensitivity::headers::HeaderMarker>", *codegenScope) + } else { + rustTemplate("#{SmithyHttpServer}::instrumentation::MakeIdentity", *codegenScope) + } } - } /** Returns the closure used during construction. */ internal fun closure(): Writable { - val nameMatch = if (headerKeys.isEmpty()) { - writable { - rust("false") - } - } else { - writable { - val matches = headerKeys.joinToString("|") { it.dq() } - rust("matches!(name.as_str(), $matches)") + val nameMatch = + if (headerKeys.isEmpty()) { + writable { + rust("false") + } + } else { + writable { + val matches = headerKeys.joinToString("|") { it.dq() } + rust("matches!(name.as_str(), $matches)") + } } - } - val suffixAndValue = when (this) { - is NotSensitiveMapValue -> writable { - prefixHeader?.let { - rust( - """ - let starts_with = name.as_str().starts_with("$it"); - let key_suffix = if starts_with { Some(${it.length}) } else { None }; - """, - ) - } ?: rust("let key_suffix = None;") - rust("let value = name_match;") - } - is SensitiveMapValue -> writable { - rust("let starts_with = name.as_str().starts_with(${prefixHeader.dq()});") - if (keySensitive) { - rust("let key_suffix = if starts_with { Some(${prefixHeader.length}) } else { None };") - } else { - rust("let key_suffix = None;") - } - rust("let value = name_match || starts_with;") + val suffixAndValue = + when (this) { + is NotSensitiveMapValue -> + writable { + prefixHeader?.let { + rust( + """ + let starts_with = name.as_str().starts_with("$it"); + let key_suffix = if starts_with { Some(${it.length}) } else { None }; + """, + ) + } ?: rust("let key_suffix = None;") + rust("let value = name_match;") + } + is SensitiveMapValue -> + writable { + rust("let starts_with = name.as_str().starts_with(${prefixHeader.dq()});") + if (keySensitive) { + rust("let key_suffix = if starts_with { Some(${prefixHeader.length}) } else { None };") + } else { + rust("let key_suffix = None;") + } + rust("let value = name_match || starts_with;") + } } - } return writable { rustTemplate( @@ -217,11 +233,12 @@ sealed class HeaderSensitivity( } /** Returns the setter enclosing the closure. */ - fun setter(): Writable = writable { - if (hasRedactions()) { - rustTemplate(".header(#{Closure:W})", "Closure" to closure()) + fun setter(): Writable = + writable { + if (hasRedactions()) { + rustTemplate(".header(#{Closure:W})", "Closure" to closure()) + } } - } } /** Models the ways query strings can be bound and sensitive. */ @@ -244,37 +261,42 @@ sealed class QuerySensitivity( class SensitiveMapValue(allKeysSensitive: Boolean, runtimeConfig: RuntimeConfig) : QuerySensitivity(allKeysSensitive, runtimeConfig) /** Is there anything to redact? */ - internal fun hasRedactions(): Boolean = when (this) { - is NotSensitiveMapValue -> allKeysSensitive || queryKeys.isNotEmpty() - is SensitiveMapValue -> true - } + internal fun hasRedactions(): Boolean = + when (this) { + is NotSensitiveMapValue -> allKeysSensitive || queryKeys.isNotEmpty() + is SensitiveMapValue -> true + } /** Returns the type of the `MakeFmt`. */ - fun type(): Writable = writable { - if (hasRedactions()) { - rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::uri::MakeQuery #{SmithyHttpServer}::instrumentation::sensitivity::uri::QueryMarker>", *codegenScope) - } else { - rustTemplate("#{SmithyHttpServer}::instrumentation::MakeIdentity", *codegenScope) + fun type(): Writable = + writable { + if (hasRedactions()) { + rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::uri::MakeQuery #{SmithyHttpServer}::instrumentation::sensitivity::uri::QueryMarker>", *codegenScope) + } else { + rustTemplate("#{SmithyHttpServer}::instrumentation::MakeIdentity", *codegenScope) + } } - } /** Returns the closure used during construction. */ internal fun closure(): Writable { - val value = when (this) { - is SensitiveMapValue -> writable { - rust("true") - } - is NotSensitiveMapValue -> if (queryKeys.isEmpty()) { - writable { - rust("false;") - } - } else { - writable { - val matches = queryKeys.joinToString("|") { it.dq() } - rust("matches!(name, $matches);") - } + val value = + when (this) { + is SensitiveMapValue -> + writable { + rust("true") + } + is NotSensitiveMapValue -> + if (queryKeys.isEmpty()) { + writable { + rust("false;") + } + } else { + writable { + val matches = queryKeys.joinToString("|") { it.dq() } + rust("matches!(name, $matches);") + } + } } - } return writable { rustTemplate( @@ -294,11 +316,12 @@ sealed class QuerySensitivity( } /** Returns the setter enclosing the closure. */ - fun setters(): Writable = writable { - if (hasRedactions()) { - rustTemplate(".query(#{Closure:W})", "Closure" to closure()) + fun setters(): Writable = + writable { + if (hasRedactions()) { + rustTemplate(".query(#{Closure:W})", "Closure" to closure()) + } } - } } /** Represents a `RequestFmt` or `ResponseFmt` type and value. */ @@ -322,10 +345,11 @@ class ServerHttpSensitivityGenerator( private val operation: OperationShape, private val runtimeConfig: RuntimeConfig, ) { - private val codegenScope = arrayOf( - "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(runtimeConfig).toType(), - "Http" to CargoDependency.Http.toType(), - ) + private val codegenScope = + arrayOf( + "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(runtimeConfig).toType(), + "Http" to CargoDependency.Http.toType(), + ) /** Constructs `StatusCodeSensitivity` of a `Shape` */ private fun findStatusCodeSensitivity(rootShape: Shape): StatusCodeSensitivity { @@ -333,10 +357,11 @@ class ServerHttpSensitivityGenerator( val rootSensitive = rootShape.hasTrait() // Find all sensitive `httpResponseCode` bindings in the `rootShape`. - val isSensitive = rootShape - .members() - .filter { it.hasTrait() } - .any { rootSensitive || it.getMemberTrait(model, SensitiveTrait::class.java).isPresent } + val isSensitive = + rootShape + .members() + .filter { it.hasTrait() } + .any { rootSensitive || it.getMemberTrait(model, SensitiveTrait::class.java).isPresent } return StatusCodeSensitivity(isSensitive, runtimeConfig) } @@ -351,17 +376,20 @@ class ServerHttpSensitivityGenerator( // Is `rootShape` sensitive and does `httpPrefixHeaders` exist? val rootSensitive = rootShape.hasTrait() - if (rootSensitive) if (prefixHeader != null) { - return HeaderSensitivity.SensitiveMapValue( - headerKeys.map { it.second }, true, - prefixHeader.second, runtimeConfig, - ) + if (rootSensitive) { + if (prefixHeader != null) { + return HeaderSensitivity.SensitiveMapValue( + headerKeys.map { it.second }, true, + prefixHeader.second, runtimeConfig, + ) + } } // Which headers are sensitive? - val sensitiveHeaders = headerKeys - .filter { (member, _) -> rootSensitive || member.getMemberTrait(model, SensitiveTrait::class.java).orNull() != null } - .map { (_, name) -> name } + val sensitiveHeaders = + headerKeys + .filter { (member, _) -> rootSensitive || member.getMemberTrait(model, SensitiveTrait::class.java).orNull() != null } + .map { (_, name) -> name } return if (prefixHeader != null) { // Get the `httpPrefixHeader` map. @@ -390,17 +418,20 @@ class ServerHttpSensitivityGenerator( // Is `rootShape` sensitive and does `httpQueryParams` exist? val rootSensitive = rootShape.hasTrait() - if (rootSensitive) if (queryParams != null) { - return QuerySensitivity.SensitiveMapValue(true, runtimeConfig) + if (rootSensitive) { + if (queryParams != null) { + return QuerySensitivity.SensitiveMapValue(true, runtimeConfig) + } } // Find all `httpQuery` bindings in the `rootShape`. val queryKeys = rootShape.members().mapNotNull { member -> member.getTrait()?.let { trait -> Pair(member, trait.value) } }.distinct() // Which queries are sensitive? - val sensitiveQueries = queryKeys - .filter { (member, _) -> rootSensitive || member.getMemberTrait(model, SensitiveTrait::class.java).orNull() != null } - .map { (_, name) -> name } + val sensitiveQueries = + queryKeys + .filter { (member, _) -> rootSensitive || member.getMemberTrait(model, SensitiveTrait::class.java).orNull() != null } + .map { (_, name) -> name } return if (queryParams != null) { // Get the `httpQueryParams` map. @@ -421,41 +452,48 @@ class ServerHttpSensitivityGenerator( } /** Constructs `LabelSensitivity` of a `Shape` */ - internal fun findLabelSensitivity(uriPattern: UriPattern, rootShape: Shape): LabelSensitivity { + internal fun findLabelSensitivity( + uriPattern: UriPattern, + rootShape: Shape, + ): LabelSensitivity { // Is root shape sensitive? val rootSensitive = rootShape.hasTrait() // Find `httpLabel` trait which are also sensitive. - val httpLabels = rootShape - .members() - .filter { it.hasTrait() } - .filter { rootSensitive || it.getMemberTrait(model, SensitiveTrait::class.java).orNull() != null } + val httpLabels = + rootShape + .members() + .filter { it.hasTrait() } + .filter { rootSensitive || it.getMemberTrait(model, SensitiveTrait::class.java).orNull() != null } + + val labelIndexes = + httpLabels + .mapNotNull { member -> + uriPattern + .segments + .withIndex() + .find { (_, segment) -> + segment.isLabel && !segment.isGreedyLabel && segment.content == member.memberName + } + } + .map { (index, _) -> index } - val labelIndexes = httpLabels - .mapNotNull { member -> + val greedyLabel = + httpLabels.mapNotNull { member -> uriPattern .segments .withIndex() - .find { (_, segment) -> - segment.isLabel && !segment.isGreedyLabel && segment.content == member.memberName - } - } - .map { (index, _) -> index } - - val greedyLabel = httpLabels.mapNotNull { member -> - uriPattern - .segments - .withIndex() - .find { (_, segment) -> segment.isGreedyLabel && segment.content == member.memberName } - } - .singleOrNull() - ?.let { (index, _) -> - val remainder = uriPattern - .segments - .drop(index + 1) - .sumOf { it.content.length + 1 } - GreedyLabel(index, remainder) + .find { (_, segment) -> segment.isGreedyLabel && segment.content == member.memberName } } + .singleOrNull() + ?.let { (index, _) -> + val remainder = + uriPattern + .segments + .drop(index + 1) + .sumOf { it.content.length + 1 } + GreedyLabel(index, remainder) + } return LabelSensitivity(labelIndexes, greedyLabel, runtimeConfig) } @@ -473,12 +511,14 @@ class ServerHttpSensitivityGenerator( } private fun defaultRequestFmt(): MakeFmt { - val type = writable { - rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::DefaultRequestFmt", *codegenScope) - } - val value = writable { - rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::RequestFmt::new()", *codegenScope) - } + val type = + writable { + rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::DefaultRequestFmt", *codegenScope) + } + val value = + writable { + rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::RequestFmt::new()", *codegenScope) + } return MakeFmt(type, value) } @@ -496,39 +536,43 @@ class ServerHttpSensitivityGenerator( // httpQuery/httpQueryParams bindings val querySensitivity = findQuerySensitivity(inputShape) - val type = writable { - rustTemplate( - """ - #{SmithyHttpServer}::instrumentation::sensitivity::RequestFmt< - #{HeaderType:W}, - #{SmithyHttpServer}::instrumentation::sensitivity::uri::MakeUri< - #{LabelType:W}, - #{QueryType:W} + val type = + writable { + rustTemplate( + """ + #{SmithyHttpServer}::instrumentation::sensitivity::RequestFmt< + #{HeaderType:W}, + #{SmithyHttpServer}::instrumentation::sensitivity::uri::MakeUri< + #{LabelType:W}, + #{QueryType:W} + > > - > - """, - "HeaderType" to headerSensitivity.type(), - "LabelType" to labelSensitivity.type(), - "QueryType" to querySensitivity.type(), - *codegenScope, - ) - } + """, + "HeaderType" to headerSensitivity.type(), + "LabelType" to labelSensitivity.type(), + "QueryType" to querySensitivity.type(), + *codegenScope, + ) + } - val value = writable { - rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::RequestFmt::new()", *codegenScope) - } + headerSensitivity.setter() + labelSensitivity.setter() + querySensitivity.setters() + val value = + writable { + rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::RequestFmt::new()", *codegenScope) + } + headerSensitivity.setter() + labelSensitivity.setter() + querySensitivity.setters() return MakeFmt(type, value) } private fun defaultResponseFmt(): MakeFmt { - val type = writable { - rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::DefaultResponseFmt", *codegenScope) - } + val type = + writable { + rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::DefaultResponseFmt", *codegenScope) + } - val value = writable { - rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::ResponseFmt::new()", *codegenScope) - } + val value = + writable { + rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::ResponseFmt::new()", *codegenScope) + } return MakeFmt(type, value) } @@ -543,18 +587,20 @@ class ServerHttpSensitivityGenerator( // Status code bindings val statusCodeSensitivity = findStatusCodeSensitivity(outputShape) - val type = writable { - rustTemplate( - "#{SmithyHttpServer}::instrumentation::sensitivity::ResponseFmt<#{HeaderType:W}, #{StatusType:W}>", - "HeaderType" to headerSensitivity.type(), - "StatusType" to statusCodeSensitivity.type(), - *codegenScope, - ) - } + val type = + writable { + rustTemplate( + "#{SmithyHttpServer}::instrumentation::sensitivity::ResponseFmt<#{HeaderType:W}, #{StatusType:W}>", + "HeaderType" to headerSensitivity.type(), + "StatusType" to statusCodeSensitivity.type(), + *codegenScope, + ) + } - val value = writable { - rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::ResponseFmt::new()", *codegenScope) - } + headerSensitivity.setter() + statusCodeSensitivity.setter() + val value = + writable { + rustTemplate("#{SmithyHttpServer}::instrumentation::sensitivity::ResponseFmt::new()", *codegenScope) + } + headerSensitivity.setter() + statusCodeSensitivity.setter() return MakeFmt(type, value) } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiator.kt index fade448863b..d06c21ff70c 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiator.kt @@ -26,14 +26,15 @@ import software.amazon.smithy.rust.codegen.server.smithy.traits.isReachableFromO class ServerAfterInstantiatingValueConstrainItIfNecessary(val codegenContext: CodegenContext) : InstantiatorCustomization() { - - override fun section(section: InstantiatorSection): Writable = when (section) { - is InstantiatorSection.AfterInstantiatingValue -> writable { - if (section.shape.isDirectlyConstrained(codegenContext.symbolProvider)) { - rust(""".try_into().expect("this is only used in tests")""") - } + override fun section(section: InstantiatorSection): Writable = + when (section) { + is InstantiatorSection.AfterInstantiatingValue -> + writable { + if (section.shape.isDirectlyConstrained(codegenContext.symbolProvider)) { + rust(""".try_into().expect("this is only used in tests")""") + } + } } - } } class ServerBuilderKindBehavior(val codegenContext: CodegenContext) : Instantiator.BuilderKindBehavior { @@ -41,11 +42,12 @@ class ServerBuilderKindBehavior(val codegenContext: CodegenContext) : Instantiat // Only operation input builders take in unconstrained types. val takesInUnconstrainedTypes = shape.isReachableFromOperationInput() - val publicConstrainedTypes = if (codegenContext is ServerCodegenContext) { - codegenContext.settings.codegenConfig.publicConstrainedTypes - } else { - true - } + val publicConstrainedTypes = + if (codegenContext is ServerCodegenContext) { + codegenContext.settings.codegenConfig.publicConstrainedTypes + } else { + true + } return if (publicConstrainedTypes) { ServerBuilderGenerator.hasFallibleBuilder( @@ -76,6 +78,7 @@ class ServerInstantiator(codegenContext: CodegenContext, customWritable: CustomW ServerBuilderKindBehavior(codegenContext), defaultsForRequiredFields = true, customizations = listOf(ServerAfterInstantiatingValueConstrainItIfNecessary(codegenContext)), + // Construct with direct pattern to more closely replicate actual server customer usage constructPattern = InstantiatorConstructPattern.DIRECT, customWritable = customWritable, ) @@ -84,7 +87,11 @@ class ServerBuilderInstantiator( private val symbolProvider: RustSymbolProvider, private val symbolParseFn: (Shape) -> ReturnSymbolToParse, ) : BuilderInstantiator { - override fun setField(builder: String, value: Writable, field: MemberShape): Writable { + override fun setField( + builder: String, + value: Writable, + field: MemberShape, + ): Writable { // Server builders have the ability to have non-optional fields. When one of these fields is used, // we need to use `if let(...)` to only set the field when it is present. return if (!symbolProvider.toSymbol(field).isOptional()) { @@ -104,12 +111,17 @@ class ServerBuilderInstantiator( } } - override fun finalizeBuilder(builder: String, shape: StructureShape, mapErr: Writable?): Writable = writable { - val returnSymbolToParse = symbolParseFn(shape) - if (returnSymbolToParse.isUnconstrained) { - rust(builder) - } else { - rust("$builder.build()") + override fun finalizeBuilder( + builder: String, + shape: StructureShape, + mapErr: Writable?, + ): Writable = + writable { + val returnSymbolToParse = symbolParseFn(shape) + if (returnSymbolToParse.isUnconstrained) { + rust(builder) + } else { + rust("$builder.build()") + } } - } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationErrorGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationErrorGenerator.kt index 0330b05905a..62ac9c38b73 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationErrorGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationErrorGenerator.kt @@ -39,23 +39,26 @@ open class ServerOperationErrorGenerator( private fun operationErrors(): List = (operationOrEventStream as OperationShape).operationErrors(model).map { it.asStructureShape().get() } + private fun eventStreamErrors(): List = (operationOrEventStream as UnionShape).eventStreamErrors() .map { model.expectShape(it.asMemberShape().get().target, StructureShape::class.java) } open fun render(writer: RustWriter) { - val (errorSymbol, errors) = when (operationOrEventStream) { - is OperationShape -> symbolProvider.symbolForOperationError(operationOrEventStream) to operationErrors() - is UnionShape -> symbolProvider.symbolForEventStreamError(operationOrEventStream) to eventStreamErrors() - else -> UNREACHABLE("OperationErrorGenerator only supports operation or event stream shapes") - } + val (errorSymbol, errors) = + when (operationOrEventStream) { + is OperationShape -> symbolProvider.symbolForOperationError(operationOrEventStream) to operationErrors() + is UnionShape -> symbolProvider.symbolForEventStreamError(operationOrEventStream) to eventStreamErrors() + else -> UNREACHABLE("OperationErrorGenerator only supports operation or event stream shapes") + } if (errors.isEmpty()) { return } - val meta = RustMetadata( - derives = setOf(RuntimeType.Debug), - visibility = Visibility.PUBLIC, - ) + val meta = + RustMetadata( + derives = setOf(RuntimeType.Debug), + visibility = Visibility.PUBLIC, + ) writer.rust("/// Error type for the `${symbol.name}` operation.") writer.rust("/// Each variant represents an error that can occur for the `${symbol.name}` operation.") diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt index 3a5af6cb509..f7fe272f699 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationGenerator.kt @@ -34,14 +34,15 @@ class ServerOperationGenerator( private val operationId = operation.id /** Returns `std::convert::Infallible` if the model provides no errors. */ - private fun operationError(): Writable = writable { - if (operation.errors.isEmpty()) { - rust("std::convert::Infallible") - } else { - // Name comes from [ServerOperationErrorGenerator]. - rust("crate::error::${symbolProvider.toSymbol(operation).name}Error") + private fun operationError(): Writable = + writable { + if (operation.errors.isEmpty()) { + rust("std::convert::Infallible") + } else { + // Name comes from [ServerOperationErrorGenerator]. + rust("crate::error::${symbolProvider.toSymbol(operation).name}Error") + } } - } fun render(writer: RustWriter) { writer.documentShape(operation, model) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerRootGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerRootGenerator.kt index 63f55954da2..177c6fa8455 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerRootGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerRootGenerator.kt @@ -34,11 +34,12 @@ open class ServerRootGenerator( private val isConfigBuilderFallible: Boolean, ) { private val index = TopDownIndex.of(codegenContext.model) - private val operations = index.getContainedOperations(codegenContext.serviceShape).toSortedSet( - compareBy { - it.id - }, - ).toList() + private val operations = + index.getContainedOperations(codegenContext.serviceShape).toSortedSet( + compareBy { + it.id + }, + ).toList() private val serviceName = codegenContext.serviceShape.id.name.toPascalCase() fun documentation(writer: RustWriter) { @@ -52,11 +53,12 @@ open class ServerRootGenerator( val crateName = codegenContext.moduleUseName() val builderName = "${serviceName}Builder" val hasErrors = operations.any { it.errors.isNotEmpty() } - val handlers: Writable = operations - .map { operation -> - DocHandlerGenerator(codegenContext, operation, builderFieldNames[operation]!!, "//!").docSignature() - } - .join("//!\n") + val handlers: Writable = + operations + .map { operation -> + DocHandlerGenerator(codegenContext, operation, builderFieldNames[operation]!!, "//!").docSignature() + } + .join("//!\n") val unwrapConfigBuilder = if (isConfigBuilderFallible) ".expect(\"config failed to build\")" else "" @@ -246,11 +248,12 @@ open class ServerRootGenerator( documentation(rustWriter) // Only export config builder error if fallible. - val configErrorReExport = if (isConfigBuilderFallible) { - "${serviceName}ConfigError," - } else { - "" - } + val configErrorReExport = + if (isConfigBuilderFallible) { + "${serviceName}ConfigError," + } else { + "" + } rustWriter.rust( """ pub use crate::service::{ diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerRuntimeTypesReExportsGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerRuntimeTypesReExportsGenerator.kt index a6f62246d87..e432d7e8468 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerRuntimeTypesReExportsGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerRuntimeTypesReExportsGenerator.kt @@ -14,9 +14,10 @@ class ServerRuntimeTypesReExportsGenerator( codegenContext: CodegenContext, ) { private val runtimeConfig = codegenContext.runtimeConfig - private val codegenScope = arrayOf( - "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(runtimeConfig).toType(), - ) + private val codegenScope = + arrayOf( + "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(runtimeConfig).toType(), + ) fun render(writer: RustWriter) { writer.rustTemplate( diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt index 8eaec006a71..1898c6c3db0 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerServiceGenerator.kt @@ -80,269 +80,276 @@ class ServerServiceGenerator( private val requestSpecMap: Map> = operations.associateWith { operationShape -> val operationName = symbolProvider.toSymbol(operationShape).name - val spec = protocol.serverRouterRequestSpec( - operationShape, - operationName, - serviceName, - smithyHttpServer.resolve("routing::request_spec"), - ) + val spec = + protocol.serverRouterRequestSpec( + operationShape, + operationName, + serviceName, + smithyHttpServer.resolve("routing::request_spec"), + ) val functionName = RustReservedWords.escapeIfNeeded(operationName.toSnakeCase()) - val functionBody = writable { + val functionBody = + writable { + rustTemplate( + """ + fn $functionName() -> #{SpecType} { + #{Spec:W} + } + """, + "Spec" to spec, + "SpecType" to protocol.serverRouterRequestSpecType(smithyHttpServer.resolve("routing::request_spec")), + ) + } + Pair(functionName, functionBody) + } + + /** A `Writable` block containing all the `Handler` and `Operation` setters for the builder. */ + private fun builderSetters(): Writable = + writable { + for ((operationShape, structName) in operationStructNames) { + val fieldName = builderFieldNames[operationShape] + val docHandler = DocHandlerGenerator(codegenContext, operationShape, "handler", "///") + val handler = docHandler.docSignature() + val handlerFixed = docHandler.docFixedSignature() + val unwrapConfigBuilder = + if (isConfigBuilderFallible) { + ".expect(\"config failed to build\")" + } else { + "" + } rustTemplate( """ - fn $functionName() -> #{SpecType} { - #{Spec:W} + /// Sets the [`$structName`](crate::operation_shape::$structName) operation. + /// + /// This should be an async function satisfying the [`Handler`](#{SmithyHttpServer}::operation::Handler) trait. + /// See the [operation module documentation](#{SmithyHttpServer}::operation) for more information. + /// + /// ## Example + /// + /// ```no_run + /// use $crateName::{$serviceName, ${serviceName}Config}; + /// + #{HandlerImports:W} + /// + #{Handler:W} + /// + /// let config = ${serviceName}Config::builder().build()$unwrapConfigBuilder; + /// let app = $serviceName::builder(config) + /// .$fieldName(handler) + /// /* Set other handlers */ + /// .build() + /// .unwrap(); + /// ## let app: $serviceName<#{SmithyHttpServer}::routing::RoutingService<#{Router}<#{SmithyHttpServer}::routing::Route>, #{Protocol}>> = app; + /// ``` + /// + pub fn $fieldName(self, handler: HandlerType) -> Self + where + HandlerType: #{SmithyHttpServer}::operation::Handler, + + ModelPl: #{SmithyHttpServer}::plugin::Plugin< + $serviceName, + crate::operation_shape::$structName, + #{SmithyHttpServer}::operation::IntoService + >, + #{SmithyHttpServer}::operation::UpgradePlugin::: #{SmithyHttpServer}::plugin::Plugin< + $serviceName, + crate::operation_shape::$structName, + ModelPl::Output + >, + HttpPl: #{SmithyHttpServer}::plugin::Plugin< + $serviceName, + crate::operation_shape::$structName, + < + #{SmithyHttpServer}::operation::UpgradePlugin:: + as #{SmithyHttpServer}::plugin::Plugin< + $serviceName, + crate::operation_shape::$structName, + ModelPl::Output + > + >::Output + >, + + HttpPl::Output: #{Tower}::Service<#{Http}::Request, Response = #{Http}::Response<#{SmithyHttpServer}::body::BoxBody>, Error = ::std::convert::Infallible> + Clone + Send + 'static, + >>::Future: Send + 'static, + + { + use #{SmithyHttpServer}::operation::OperationShapeExt; + use #{SmithyHttpServer}::plugin::Plugin; + let svc = crate::operation_shape::$structName::from_handler(handler); + let svc = self.model_plugin.apply(svc); + let svc = #{SmithyHttpServer}::operation::UpgradePlugin::::new().apply(svc); + let svc = self.http_plugin.apply(svc); + self.${fieldName}_custom(svc) + } + + /// Sets the [`$structName`](crate::operation_shape::$structName) operation. + /// + /// This should be an async function satisfying the [`Handler`](#{SmithyHttpServer}::operation::Handler) trait. + /// See the [operation module documentation](#{SmithyHttpServer}::operation) for more information. + /// + /// ## Example + /// + /// ```no_run + /// use $crateName::{$serviceName, ${serviceName}Config}; + /// + #{HandlerImports:W} + /// + #{HandlerFixed:W} + /// + /// let config = ${serviceName}Config::builder().build()$unwrapConfigBuilder; + /// let svc = #{Tower}::util::service_fn(handler); + /// let app = $serviceName::builder(config) + /// .${fieldName}_service(svc) + /// /* Set other handlers */ + /// .build() + /// .unwrap(); + /// ## let app: $serviceName<#{SmithyHttpServer}::routing::RoutingService<#{Router}<#{SmithyHttpServer}::routing::Route>, #{Protocol}>> = app; + /// ``` + /// + pub fn ${fieldName}_service(self, service: S) -> Self + where + S: #{SmithyHttpServer}::operation::OperationService, + + ModelPl: #{SmithyHttpServer}::plugin::Plugin< + $serviceName, + crate::operation_shape::$structName, + #{SmithyHttpServer}::operation::Normalize + >, + #{SmithyHttpServer}::operation::UpgradePlugin::: #{SmithyHttpServer}::plugin::Plugin< + $serviceName, + crate::operation_shape::$structName, + ModelPl::Output + >, + HttpPl: #{SmithyHttpServer}::plugin::Plugin< + $serviceName, + crate::operation_shape::$structName, + < + #{SmithyHttpServer}::operation::UpgradePlugin:: + as #{SmithyHttpServer}::plugin::Plugin< + $serviceName, + crate::operation_shape::$structName, + ModelPl::Output + > + >::Output + >, + + HttpPl::Output: #{Tower}::Service<#{Http}::Request, Response = #{Http}::Response<#{SmithyHttpServer}::body::BoxBody>, Error = ::std::convert::Infallible> + Clone + Send + 'static, + >>::Future: Send + 'static, + + { + use #{SmithyHttpServer}::operation::OperationShapeExt; + use #{SmithyHttpServer}::plugin::Plugin; + let svc = crate::operation_shape::$structName::from_service(service); + let svc = self.model_plugin.apply(svc); + let svc = #{SmithyHttpServer}::operation::UpgradePlugin::::new().apply(svc); + let svc = self.http_plugin.apply(svc); + self.${fieldName}_custom(svc) + } + + /// Sets the [`$structName`](crate::operation_shape::$structName) to a custom [`Service`](tower::Service). + /// not constrained by the Smithy contract. + fn ${fieldName}_custom(mut self, svc: S) -> Self + where + S: #{Tower}::Service<#{Http}::Request, Response = #{Http}::Response<#{SmithyHttpServer}::body::BoxBody>, Error = ::std::convert::Infallible> + Clone + Send + 'static, + S::Future: Send + 'static, + { + self.$fieldName = Some(#{SmithyHttpServer}::routing::Route::new(svc)); + self } """, - "Spec" to spec, - "SpecType" to protocol.serverRouterRequestSpecType(smithyHttpServer.resolve("routing::request_spec")), + "Router" to protocol.routerType(), + "Protocol" to protocol.markerStruct(), + "Handler" to handler, + "HandlerFixed" to handlerFixed, + "HandlerImports" to handlerImports(crateName, operations), + *codegenScope, ) - } - Pair(functionName, functionBody) - } - /** A `Writable` block containing all the `Handler` and `Operation` setters for the builder. */ - private fun builderSetters(): Writable = writable { - for ((operationShape, structName) in operationStructNames) { - val fieldName = builderFieldNames[operationShape] - val docHandler = DocHandlerGenerator(codegenContext, operationShape, "handler", "///") - val handler = docHandler.docSignature() - val handlerFixed = docHandler.docFixedSignature() - val unwrapConfigBuilder = if (isConfigBuilderFallible) { - ".expect(\"config failed to build\")" - } else { - "" + // Adds newline between setters. + rust("") } - rustTemplate( - """ - /// Sets the [`$structName`](crate::operation_shape::$structName) operation. - /// - /// This should be an async function satisfying the [`Handler`](#{SmithyHttpServer}::operation::Handler) trait. - /// See the [operation module documentation](#{SmithyHttpServer}::operation) for more information. - /// - /// ## Example - /// - /// ```no_run - /// use $crateName::{$serviceName, ${serviceName}Config}; - /// - #{HandlerImports:W} - /// - #{Handler:W} - /// - /// let config = ${serviceName}Config::builder().build()$unwrapConfigBuilder; - /// let app = $serviceName::builder(config) - /// .$fieldName(handler) - /// /* Set other handlers */ - /// .build() - /// .unwrap(); - /// ## let app: $serviceName<#{SmithyHttpServer}::routing::RoutingService<#{Router}<#{SmithyHttpServer}::routing::Route>, #{Protocol}>> = app; - /// ``` - /// - pub fn $fieldName(self, handler: HandlerType) -> Self - where - HandlerType: #{SmithyHttpServer}::operation::Handler, - - ModelPl: #{SmithyHttpServer}::plugin::Plugin< - $serviceName, - crate::operation_shape::$structName, - #{SmithyHttpServer}::operation::IntoService - >, - #{SmithyHttpServer}::operation::UpgradePlugin::: #{SmithyHttpServer}::plugin::Plugin< - $serviceName, - crate::operation_shape::$structName, - ModelPl::Output - >, - HttpPl: #{SmithyHttpServer}::plugin::Plugin< - $serviceName, - crate::operation_shape::$structName, - < - #{SmithyHttpServer}::operation::UpgradePlugin:: - as #{SmithyHttpServer}::plugin::Plugin< - $serviceName, - crate::operation_shape::$structName, - ModelPl::Output - > - >::Output - >, + } - HttpPl::Output: #{Tower}::Service<#{Http}::Request, Response = #{Http}::Response<#{SmithyHttpServer}::body::BoxBody>, Error = ::std::convert::Infallible> + Clone + Send + 'static, - >>::Future: Send + 'static, + private fun buildMethod(): Writable = + writable { + val missingOperationsVariableName = "missing_operation_names" + val expectMessageVariableName = "unexpected_error_msg" - { - use #{SmithyHttpServer}::operation::OperationShapeExt; - use #{SmithyHttpServer}::plugin::Plugin; - let svc = crate::operation_shape::$structName::from_handler(handler); - let svc = self.model_plugin.apply(svc); - let svc = #{SmithyHttpServer}::operation::UpgradePlugin::::new().apply(svc); - let svc = self.http_plugin.apply(svc); - self.${fieldName}_custom(svc) + val nullabilityChecks = + writable { + for (operationShape in operations) { + val fieldName = builderFieldNames[operationShape]!! + val operationZstTypeName = operationStructNames[operationShape]!! + rust( + """ + if self.$fieldName.is_none() { + $missingOperationsVariableName.insert(crate::operation_shape::$operationZstTypeName::ID, ".$fieldName()"); + } + """, + ) + } + } + val routesArrayElements = + writable { + for (operationShape in operations) { + val fieldName = builderFieldNames[operationShape]!! + val (specBuilderFunctionName, _) = requestSpecMap.getValue(operationShape) + rust( + """ + ($requestSpecsModuleName::$specBuilderFunctionName(), self.$fieldName.expect($expectMessageVariableName)), + """, + ) + } } - /// Sets the [`$structName`](crate::operation_shape::$structName) operation. - /// - /// This should be an async function satisfying the [`Handler`](#{SmithyHttpServer}::operation::Handler) trait. - /// See the [operation module documentation](#{SmithyHttpServer}::operation) for more information. - /// - /// ## Example - /// - /// ```no_run - /// use $crateName::{$serviceName, ${serviceName}Config}; - /// - #{HandlerImports:W} - /// - #{HandlerFixed:W} + rustTemplate( + """ + /// Constructs a [`$serviceName`] from the arguments provided to the builder. /// - /// let config = ${serviceName}Config::builder().build()$unwrapConfigBuilder; - /// let svc = #{Tower}::util::service_fn(handler); - /// let app = $serviceName::builder(config) - /// .${fieldName}_service(svc) - /// /* Set other handlers */ - /// .build() - /// .unwrap(); - /// ## let app: $serviceName<#{SmithyHttpServer}::routing::RoutingService<#{Router}<#{SmithyHttpServer}::routing::Route>, #{Protocol}>> = app; - /// ``` + /// Forgetting to register a handler for one or more operations will result in an error. /// - pub fn ${fieldName}_service(self, service: S) -> Self - where - S: #{SmithyHttpServer}::operation::OperationService, - - ModelPl: #{SmithyHttpServer}::plugin::Plugin< - $serviceName, - crate::operation_shape::$structName, - #{SmithyHttpServer}::operation::Normalize - >, - #{SmithyHttpServer}::operation::UpgradePlugin::: #{SmithyHttpServer}::plugin::Plugin< - $serviceName, - crate::operation_shape::$structName, - ModelPl::Output - >, - HttpPl: #{SmithyHttpServer}::plugin::Plugin< - $serviceName, - crate::operation_shape::$structName, - < - #{SmithyHttpServer}::operation::UpgradePlugin:: - as #{SmithyHttpServer}::plugin::Plugin< - $serviceName, - crate::operation_shape::$structName, - ModelPl::Output - > - >::Output + /// Check out [`$builderName::build_unchecked`] if you'd prefer the service to return status code 500 when an + /// unspecified route is requested. + pub fn build(self) -> Result< + $serviceName< + #{SmithyHttpServer}::routing::RoutingService< + #{Router}, + #{Protocol}, + >, >, - - HttpPl::Output: #{Tower}::Service<#{Http}::Request, Response = #{Http}::Response<#{SmithyHttpServer}::body::BoxBody>, Error = ::std::convert::Infallible> + Clone + Send + 'static, - >>::Future: Send + 'static, - - { - use #{SmithyHttpServer}::operation::OperationShapeExt; - use #{SmithyHttpServer}::plugin::Plugin; - let svc = crate::operation_shape::$structName::from_service(service); - let svc = self.model_plugin.apply(svc); - let svc = #{SmithyHttpServer}::operation::UpgradePlugin::::new().apply(svc); - let svc = self.http_plugin.apply(svc); - self.${fieldName}_custom(svc) - } - - /// Sets the [`$structName`](crate::operation_shape::$structName) to a custom [`Service`](tower::Service). - /// not constrained by the Smithy contract. - fn ${fieldName}_custom(mut self, svc: S) -> Self + MissingOperationsError, + > where - S: #{Tower}::Service<#{Http}::Request, Response = #{Http}::Response<#{SmithyHttpServer}::body::BoxBody>, Error = ::std::convert::Infallible> + Clone + Send + 'static, - S::Future: Send + 'static, + L: #{Tower}::Layer<#{SmithyHttpServer}::routing::Route>, { - self.$fieldName = Some(#{SmithyHttpServer}::routing::Route::new(svc)); - self + let router = { + use #{SmithyHttpServer}::operation::OperationShape; + let mut $missingOperationsVariableName = std::collections::HashMap::new(); + #{NullabilityChecks:W} + if !$missingOperationsVariableName.is_empty() { + return Err(MissingOperationsError { + operation_names2setter_methods: $missingOperationsVariableName, + }); + } + let $expectMessageVariableName = "this should never panic since we are supposed to check beforehand that a handler has been registered for this operation; please file a bug report under https://github.com/smithy-lang/smithy-rs/issues"; + + #{PatternInitializations:W} + + #{Router}::from_iter([#{RoutesArrayElements:W}]) + }; + let svc = #{SmithyHttpServer}::routing::RoutingService::new(router); + let svc = svc.map(|s| s.layer(self.layer)); + Ok($serviceName { svc }) } """, - "Router" to protocol.routerType(), - "Protocol" to protocol.markerStruct(), - "Handler" to handler, - "HandlerFixed" to handlerFixed, - "HandlerImports" to handlerImports(crateName, operations), *codegenScope, + "Protocol" to protocol.markerStruct(), + "Router" to protocol.routerType(), + "NullabilityChecks" to nullabilityChecks, + "RoutesArrayElements" to routesArrayElements, + "PatternInitializations" to patternInitializations(), ) - - // Adds newline between setters. - rust("") - } - } - - private fun buildMethod(): Writable = writable { - val missingOperationsVariableName = "missing_operation_names" - val expectMessageVariableName = "unexpected_error_msg" - - val nullabilityChecks = writable { - for (operationShape in operations) { - val fieldName = builderFieldNames[operationShape]!! - val operationZstTypeName = operationStructNames[operationShape]!! - rust( - """ - if self.$fieldName.is_none() { - $missingOperationsVariableName.insert(crate::operation_shape::$operationZstTypeName::ID, ".$fieldName()"); - } - """, - ) - } } - val routesArrayElements = writable { - for (operationShape in operations) { - val fieldName = builderFieldNames[operationShape]!! - val (specBuilderFunctionName, _) = requestSpecMap.getValue(operationShape) - rust( - """ - ($requestSpecsModuleName::$specBuilderFunctionName(), self.$fieldName.expect($expectMessageVariableName)), - """, - ) - } - } - - rustTemplate( - """ - /// Constructs a [`$serviceName`] from the arguments provided to the builder. - /// - /// Forgetting to register a handler for one or more operations will result in an error. - /// - /// Check out [`$builderName::build_unchecked`] if you'd prefer the service to return status code 500 when an - /// unspecified route is requested. - pub fn build(self) -> Result< - $serviceName< - #{SmithyHttpServer}::routing::RoutingService< - #{Router}, - #{Protocol}, - >, - >, - MissingOperationsError, - > - where - L: #{Tower}::Layer<#{SmithyHttpServer}::routing::Route>, - { - let router = { - use #{SmithyHttpServer}::operation::OperationShape; - let mut $missingOperationsVariableName = std::collections::HashMap::new(); - #{NullabilityChecks:W} - if !$missingOperationsVariableName.is_empty() { - return Err(MissingOperationsError { - operation_names2setter_methods: $missingOperationsVariableName, - }); - } - let $expectMessageVariableName = "this should never panic since we are supposed to check beforehand that a handler has been registered for this operation; please file a bug report under https://github.com/smithy-lang/smithy-rs/issues"; - - #{PatternInitializations:W} - - #{Router}::from_iter([#{RoutesArrayElements:W}]) - }; - let svc = #{SmithyHttpServer}::routing::RoutingService::new(router); - let svc = svc.map(|s| s.layer(self.layer)); - Ok($serviceName { svc }) - } - """, - *codegenScope, - "Protocol" to protocol.markerStruct(), - "Router" to protocol.routerType(), - "NullabilityChecks" to nullabilityChecks, - "RoutesArrayElements" to routesArrayElements, - "PatternInitializations" to patternInitializations(), - ) - } /** * Renders `PatternString::compile_regex()` function calls for every @@ -350,14 +357,15 @@ class ServerServiceGenerator( */ @Suppress("DEPRECATION") private fun patternInitializations(): Writable { - val patterns = Walker(model).walkShapes(service) - .filter { shape -> shape is StringShape && shape.hasTrait() && !shape.hasTrait() } - .map { shape -> codegenContext.constrainedShapeSymbolProvider.toSymbol(shape) } - .map { symbol -> - writable { - rustTemplate("#{Type}::compile_regex();", "Type" to symbol) + val patterns = + Walker(model).walkShapes(service) + .filter { shape -> shape is StringShape && shape.hasTrait() && !shape.hasTrait() } + .map { shape -> codegenContext.constrainedShapeSymbolProvider.toSymbol(shape) } + .map { symbol -> + writable { + rustTemplate("#{Type}::compile_regex();", "Type" to symbol) + } } - } patterns.letIf(patterns.isNotEmpty()) { val docs = listOf(writable { rust("// Eagerly initialize regexes for `@pattern` strings.") }) @@ -368,406 +376,417 @@ class ServerServiceGenerator( return patterns.join("") } - private fun buildUncheckedMethod(): Writable = writable { - val pairs = writable { - for (operationShape in operations) { - val fieldName = builderFieldNames[operationShape]!! - val (specBuilderFunctionName, _) = requestSpecMap.getValue(operationShape) - rustTemplate( - """ - ( - $requestSpecsModuleName::$specBuilderFunctionName(), - self.$fieldName.unwrap_or_else(|| { - let svc = #{SmithyHttpServer}::operation::MissingFailure::<#{Protocol}>::default(); - #{SmithyHttpServer}::routing::Route::new(svc) - }) - ), - """, - "SmithyHttpServer" to smithyHttpServer, - "Protocol" to protocol.markerStruct(), - ) - } + private fun buildUncheckedMethod(): Writable = + writable { + val pairs = + writable { + for (operationShape in operations) { + val fieldName = builderFieldNames[operationShape]!! + val (specBuilderFunctionName, _) = requestSpecMap.getValue(operationShape) + rustTemplate( + """ + ( + $requestSpecsModuleName::$specBuilderFunctionName(), + self.$fieldName.unwrap_or_else(|| { + let svc = #{SmithyHttpServer}::operation::MissingFailure::<#{Protocol}>::default(); + #{SmithyHttpServer}::routing::Route::new(svc) + }) + ), + """, + "SmithyHttpServer" to smithyHttpServer, + "Protocol" to protocol.markerStruct(), + ) + } + } + rustTemplate( + """ + /// Constructs a [`$serviceName`] from the arguments provided to the builder. + /// Operations without a handler default to returning 500 Internal Server Error to the caller. + /// + /// Check out [`$builderName::build`] if you'd prefer the builder to fail if one or more operations do + /// not have a registered handler. + pub fn build_unchecked(self) -> $serviceName + where + Body: Send + 'static, + L: #{Tower}::Layer< + #{SmithyHttpServer}::routing::RoutingService<#{Router}<#{SmithyHttpServer}::routing::Route>, #{Protocol}> + > + { + let router = #{Router}::from_iter([#{Pairs:W}]); + let svc = self + .layer + .layer(#{SmithyHttpServer}::routing::RoutingService::new(router)); + $serviceName { svc } + } + """, + *codegenScope, + "Protocol" to protocol.markerStruct(), + "Router" to protocol.routerType(), + "Pairs" to pairs, + ) } - rustTemplate( - """ - /// Constructs a [`$serviceName`] from the arguments provided to the builder. - /// Operations without a handler default to returning 500 Internal Server Error to the caller. - /// - /// Check out [`$builderName::build`] if you'd prefer the builder to fail if one or more operations do - /// not have a registered handler. - pub fn build_unchecked(self) -> $serviceName - where - Body: Send + 'static, - L: #{Tower}::Layer< - #{SmithyHttpServer}::routing::RoutingService<#{Router}<#{SmithyHttpServer}::routing::Route>, #{Protocol}> - > - { - let router = #{Router}::from_iter([#{Pairs:W}]); - let svc = self - .layer - .layer(#{SmithyHttpServer}::routing::RoutingService::new(router)); - $serviceName { svc } - } - """, - *codegenScope, - "Protocol" to protocol.markerStruct(), - "Router" to protocol.routerType(), - "Pairs" to pairs, - ) - } /** Returns a `Writable` containing the builder struct definition and its implementations. */ - private fun builder(): Writable = writable { - val builderGenerics = listOf("Body", "L", "HttpPl", "ModelPl").joinToString(", ") - rustTemplate( - """ - /// The service builder for [`$serviceName`]. - /// - /// Constructed via [`$serviceName::builder`]. - pub struct $builderName<$builderGenerics> { - ${builderFields.joinToString(", ")}, - layer: L, - http_plugin: HttpPl, - model_plugin: ModelPl - } - - impl<$builderGenerics> $builderName<$builderGenerics> { - #{Setters:W} - } + private fun builder(): Writable = + writable { + val builderGenerics = listOf("Body", "L", "HttpPl", "ModelPl").joinToString(", ") + rustTemplate( + """ + /// The service builder for [`$serviceName`]. + /// + /// Constructed via [`$serviceName::builder`]. + pub struct $builderName<$builderGenerics> { + ${builderFields.joinToString(", ")}, + layer: L, + http_plugin: HttpPl, + model_plugin: ModelPl + } - impl<$builderGenerics> $builderName<$builderGenerics> { - #{BuildMethod:W} + impl<$builderGenerics> $builderName<$builderGenerics> { + #{Setters:W} + } - #{BuildUncheckedMethod:W} - } - """, - "Setters" to builderSetters(), - "BuildMethod" to buildMethod(), - "BuildUncheckedMethod" to buildUncheckedMethod(), - *codegenScope, - ) - } + impl<$builderGenerics> $builderName<$builderGenerics> { + #{BuildMethod:W} - private fun requestSpecsModule(): Writable = writable { - val functions = writable { - for ((_, function) in requestSpecMap.values) { - rustTemplate( - """ - pub(super) #{Function:W} - """, - "Function" to function, - ) - } + #{BuildUncheckedMethod:W} + } + """, + "Setters" to builderSetters(), + "BuildMethod" to buildMethod(), + "BuildUncheckedMethod" to buildUncheckedMethod(), + *codegenScope, + ) } - rustTemplate( - """ - mod $requestSpecsModuleName { - #{SpecFunctions:W} - } - """, - "SpecFunctions" to functions, - ) - } - /** Returns a `Writable` comma delimited sequence of `builder_field: None`. */ - private fun notSetFields(): Writable = builderFieldNames.values.map { + private fun requestSpecsModule(): Writable = writable { + val functions = + writable { + for ((_, function) in requestSpecMap.values) { + rustTemplate( + """ + pub(super) #{Function:W} + """, + "Function" to function, + ) + } + } rustTemplate( - "$it: None", - *codegenScope, + """ + mod $requestSpecsModuleName { + #{SpecFunctions:W} + } + """, + "SpecFunctions" to functions, ) } - }.join(", ") + + /** Returns a `Writable` comma delimited sequence of `builder_field: None`. */ + private fun notSetFields(): Writable = + builderFieldNames.values.map { + writable { + rustTemplate( + "$it: None", + *codegenScope, + ) + } + }.join(", ") /** Returns a `Writable` containing the service struct definition and its implementations. */ - private fun serviceStruct(): Writable = writable { - documentShape(service, model) + private fun serviceStruct(): Writable = + writable { + documentShape(service, model) - rustTemplate( - """ - /// - /// See the [root](crate) documentation for more information. - ##[derive(Clone)] - pub struct $serviceName< - S = #{SmithyHttpServer}::routing::RoutingService< - #{Router}< - #{SmithyHttpServer}::routing::Route< - #{SmithyHttpServer}::body::BoxBody + rustTemplate( + """ + /// + /// See the [root](crate) documentation for more information. + ##[derive(Clone)] + pub struct $serviceName< + S = #{SmithyHttpServer}::routing::RoutingService< + #{Router}< + #{SmithyHttpServer}::routing::Route< + #{SmithyHttpServer}::body::BoxBody + >, >, - >, - #{Protocol}, - > - > { - // This is the router wrapped by layers. - svc: S, - } + #{Protocol}, + > + > { + // This is the router wrapped by layers. + svc: S, + } - impl $serviceName<()> { - /// Constructs a builder for [`$serviceName`]. - /// You must specify a configuration object holding any plugins and layers that should be applied - /// to the operations in this service. - pub fn builder< - Body, - L, - HttpPl: #{SmithyHttpServer}::plugin::HttpMarker, - ModelPl: #{SmithyHttpServer}::plugin::ModelMarker, - >( - config: ${serviceName}Config, - ) -> $builderName { - $builderName { - #{NotSetFields1:W}, - layer: config.layers, - http_plugin: config.http_plugins, - model_plugin: config.model_plugins, + impl $serviceName<()> { + /// Constructs a builder for [`$serviceName`]. + /// You must specify a configuration object holding any plugins and layers that should be applied + /// to the operations in this service. + pub fn builder< + Body, + L, + HttpPl: #{SmithyHttpServer}::plugin::HttpMarker, + ModelPl: #{SmithyHttpServer}::plugin::ModelMarker, + >( + config: ${serviceName}Config, + ) -> $builderName { + $builderName { + #{NotSetFields1:W}, + layer: config.layers, + http_plugin: config.http_plugins, + model_plugin: config.model_plugins, + } } - } - /// Constructs a builder for [`$serviceName`]. - /// You must specify what plugins should be applied to the operations in this service. - /// - /// Use [`$serviceName::builder_without_plugins`] if you don't need to apply plugins. - /// - /// Check out [`HttpPlugins`](#{SmithyHttpServer}::plugin::HttpPlugins) and - /// [`ModelPlugins`](#{SmithyHttpServer}::plugin::ModelPlugins) if you need to apply - /// multiple plugins. - ##[deprecated( - since = "0.57.0", - note = "please use the `builder` constructor and register plugins on the `${serviceName}Config` object instead; see https://github.com/smithy-lang/smithy-rs/discussions/3096" - )] - pub fn builder_with_plugins< - Body, - HttpPl: #{SmithyHttpServer}::plugin::HttpMarker, - ModelPl: #{SmithyHttpServer}::plugin::ModelMarker - >( - http_plugin: HttpPl, - model_plugin: ModelPl - ) -> $builderName { - $builderName { - #{NotSetFields2:W}, - layer: #{Tower}::layer::util::Identity::new(), - http_plugin, - model_plugin + /// Constructs a builder for [`$serviceName`]. + /// You must specify what plugins should be applied to the operations in this service. + /// + /// Use [`$serviceName::builder_without_plugins`] if you don't need to apply plugins. + /// + /// Check out [`HttpPlugins`](#{SmithyHttpServer}::plugin::HttpPlugins) and + /// [`ModelPlugins`](#{SmithyHttpServer}::plugin::ModelPlugins) if you need to apply + /// multiple plugins. + ##[deprecated( + since = "0.57.0", + note = "please use the `builder` constructor and register plugins on the `${serviceName}Config` object instead; see https://github.com/smithy-lang/smithy-rs/discussions/3096" + )] + pub fn builder_with_plugins< + Body, + HttpPl: #{SmithyHttpServer}::plugin::HttpMarker, + ModelPl: #{SmithyHttpServer}::plugin::ModelMarker + >( + http_plugin: HttpPl, + model_plugin: ModelPl + ) -> $builderName { + $builderName { + #{NotSetFields2:W}, + layer: #{Tower}::layer::util::Identity::new(), + http_plugin, + model_plugin + } } - } - /// Constructs a builder for [`$serviceName`]. - /// - /// Use [`$serviceName::builder_with_plugins`] if you need to specify plugins. - ##[deprecated( - since = "0.57.0", - note = "please use the `builder` constructor instead; see https://github.com/smithy-lang/smithy-rs/discussions/3096" - )] - pub fn builder_without_plugins() -> $builderName< - Body, - #{Tower}::layer::util::Identity, - #{SmithyHttpServer}::plugin::IdentityPlugin, - #{SmithyHttpServer}::plugin::IdentityPlugin - > { - Self::builder_with_plugins(#{SmithyHttpServer}::plugin::IdentityPlugin, #{SmithyHttpServer}::plugin::IdentityPlugin) + /// Constructs a builder for [`$serviceName`]. + /// + /// Use [`$serviceName::builder_with_plugins`] if you need to specify plugins. + ##[deprecated( + since = "0.57.0", + note = "please use the `builder` constructor instead; see https://github.com/smithy-lang/smithy-rs/discussions/3096" + )] + pub fn builder_without_plugins() -> $builderName< + Body, + #{Tower}::layer::util::Identity, + #{SmithyHttpServer}::plugin::IdentityPlugin, + #{SmithyHttpServer}::plugin::IdentityPlugin + > { + Self::builder_with_plugins(#{SmithyHttpServer}::plugin::IdentityPlugin, #{SmithyHttpServer}::plugin::IdentityPlugin) + } } - } - impl $serviceName { - /// Converts [`$serviceName`] into a [`MakeService`](tower::make::MakeService). - pub fn into_make_service(self) -> #{SmithyHttpServer}::routing::IntoMakeService { - #{SmithyHttpServer}::routing::IntoMakeService::new(self) - } + impl $serviceName { + /// Converts [`$serviceName`] into a [`MakeService`](tower::make::MakeService). + pub fn into_make_service(self) -> #{SmithyHttpServer}::routing::IntoMakeService { + #{SmithyHttpServer}::routing::IntoMakeService::new(self) + } - /// Converts [`$serviceName`] into a [`MakeService`](tower::make::MakeService) with [`ConnectInfo`](#{SmithyHttpServer}::request::connect_info::ConnectInfo). - pub fn into_make_service_with_connect_info(self) -> #{SmithyHttpServer}::routing::IntoMakeServiceWithConnectInfo { - #{SmithyHttpServer}::routing::IntoMakeServiceWithConnectInfo::new(self) + /// Converts [`$serviceName`] into a [`MakeService`](tower::make::MakeService) with [`ConnectInfo`](#{SmithyHttpServer}::request::connect_info::ConnectInfo). + pub fn into_make_service_with_connect_info(self) -> #{SmithyHttpServer}::routing::IntoMakeServiceWithConnectInfo { + #{SmithyHttpServer}::routing::IntoMakeServiceWithConnectInfo::new(self) + } } - } - impl - $serviceName< - #{SmithyHttpServer}::routing::RoutingService< - #{Router}, - #{Protocol}, - >, - > - { - /// Applies a [`Layer`](#{Tower}::Layer) uniformly to all routes. - ##[deprecated( - since = "0.57.0", - note = "please add layers to the `${serviceName}Config` object instead; see https://github.com/smithy-lang/smithy-rs/discussions/3096" - )] - pub fn layer( - self, - layer: &L, - ) -> $serviceName< - #{SmithyHttpServer}::routing::RoutingService< - #{Router}, - #{Protocol}, - >, - > - where - L: #{Tower}::Layer, + impl + $serviceName< + #{SmithyHttpServer}::routing::RoutingService< + #{Router}, + #{Protocol}, + >, + > { - $serviceName { - svc: self.svc.map(|s| s.layer(layer)), + /// Applies a [`Layer`](#{Tower}::Layer) uniformly to all routes. + ##[deprecated( + since = "0.57.0", + note = "please add layers to the `${serviceName}Config` object instead; see https://github.com/smithy-lang/smithy-rs/discussions/3096" + )] + pub fn layer( + self, + layer: &L, + ) -> $serviceName< + #{SmithyHttpServer}::routing::RoutingService< + #{Router}, + #{Protocol}, + >, + > + where + L: #{Tower}::Layer, + { + $serviceName { + svc: self.svc.map(|s| s.layer(layer)), + } } - } - /// Applies [`Route::new`](#{SmithyHttpServer}::routing::Route::new) to all routes. - /// - /// This has the effect of erasing all types accumulated via layers. - pub fn boxed( - self, - ) -> $serviceName< - #{SmithyHttpServer}::routing::RoutingService< - #{Router}< - #{SmithyHttpServer}::routing::Route, + /// Applies [`Route::new`](#{SmithyHttpServer}::routing::Route::new) to all routes. + /// + /// This has the effect of erasing all types accumulated via layers. + pub fn boxed( + self, + ) -> $serviceName< + #{SmithyHttpServer}::routing::RoutingService< + #{Router}< + #{SmithyHttpServer}::routing::Route, + >, + #{Protocol}, >, - #{Protocol}, - >, - > + > + where + S: #{Tower}::Service< + #{Http}::Request, + Response = #{Http}::Response<#{SmithyHttpServer}::body::BoxBody>, + Error = std::convert::Infallible, + >, + S: Clone + Send + 'static, + S::Future: Send + 'static, + { + self.layer(&::tower::layer::layer_fn( + #{SmithyHttpServer}::routing::Route::new, + )) + } + } + + impl #{Tower}::Service for $serviceName where - S: #{Tower}::Service< - #{Http}::Request, - Response = #{Http}::Response<#{SmithyHttpServer}::body::BoxBody>, - Error = std::convert::Infallible, - >, - S: Clone + Send + 'static, - S::Future: Send + 'static, + S: #{Tower}::Service, { - self.layer(&::tower::layer::layer_fn( - #{SmithyHttpServer}::routing::Route::new, - )) - } - } + type Response = S::Response; + type Error = S::Error; + type Future = S::Future; - impl #{Tower}::Service for $serviceName - where - S: #{Tower}::Service, - { - type Response = S::Response; - type Error = S::Error; - type Future = S::Future; + fn poll_ready(&mut self, cx: &mut std::task::Context) -> std::task::Poll> { + self.svc.poll_ready(cx) + } - fn poll_ready(&mut self, cx: &mut std::task::Context) -> std::task::Poll> { - self.svc.poll_ready(cx) + fn call(&mut self, request: R) -> Self::Future { + self.svc.call(request) + } } + """, + "NotSetFields1" to notSetFields(), + "NotSetFields2" to notSetFields(), + "Router" to protocol.routerType(), + "Protocol" to protocol.markerStruct(), + *codegenScope, + ) + } - fn call(&mut self, request: R) -> Self::Future { - self.svc.call(request) + private fun missingOperationsError(): Writable = + writable { + rustTemplate( + """ + /// The error encountered when calling the [`$builderName::build`] method if one or more operation handlers are not + /// specified. + ##[derive(Debug)] + pub struct MissingOperationsError { + operation_names2setter_methods: std::collections::HashMap<#{SmithyHttpServer}::shape_id::ShapeId, &'static str>, } - } - """, - "NotSetFields1" to notSetFields(), - "NotSetFields2" to notSetFields(), - "Router" to protocol.routerType(), - "Protocol" to protocol.markerStruct(), - *codegenScope, - ) - } - private fun missingOperationsError(): Writable = writable { - rustTemplate( - """ - /// The error encountered when calling the [`$builderName::build`] method if one or more operation handlers are not - /// specified. - ##[derive(Debug)] - pub struct MissingOperationsError { - operation_names2setter_methods: std::collections::HashMap<#{SmithyHttpServer}::shape_id::ShapeId, &'static str>, - } - - impl std::fmt::Display for MissingOperationsError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "You must specify a handler for all operations attached to `$serviceName`.\n\ - We are missing handlers for the following operations:\n", - )?; - for operation_name in self.operation_names2setter_methods.keys() { - writeln!(f, "- {}", operation_name.absolute())?; + impl std::fmt::Display for MissingOperationsError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "You must specify a handler for all operations attached to `$serviceName`.\n\ + We are missing handlers for the following operations:\n", + )?; + for operation_name in self.operation_names2setter_methods.keys() { + writeln!(f, "- {}", operation_name.absolute())?; + } + + writeln!(f, "\nUse the dedicated methods on `$builderName` to register the missing handlers:")?; + for setter_name in self.operation_names2setter_methods.values() { + writeln!(f, "- {}", setter_name)?; + } + Ok(()) } - - writeln!(f, "\nUse the dedicated methods on `$builderName` to register the missing handlers:")?; - for setter_name in self.operation_names2setter_methods.values() { - writeln!(f, "- {}", setter_name)?; - } - Ok(()) } - } - - impl std::error::Error for MissingOperationsError {} - """, - *codegenScope, - ) - } - - private fun serviceShapeImpl(): Writable = writable { - val namespace = serviceId.namespace - val name = serviceId.name - val absolute = serviceId.toString().replace("#", "##") - val version = codegenContext.serviceShape.version?.let { "Some(\"$it\")" } ?: "None" - rustTemplate( - """ - impl #{SmithyHttpServer}::service::ServiceShape for $serviceName { - const ID: #{SmithyHttpServer}::shape_id::ShapeId = #{SmithyHttpServer}::shape_id::ShapeId::new("$absolute", "$namespace", "$name"); - const VERSION: Option<&'static str> = $version; + impl std::error::Error for MissingOperationsError {} + """, + *codegenScope, + ) + } - type Protocol = #{Protocol}; + private fun serviceShapeImpl(): Writable = + writable { + val namespace = serviceId.namespace + val name = serviceId.name + val absolute = serviceId.toString().replace("#", "##") + val version = codegenContext.serviceShape.version?.let { "Some(\"$it\")" } ?: "None" + rustTemplate( + """ + impl #{SmithyHttpServer}::service::ServiceShape for $serviceName { + const ID: #{SmithyHttpServer}::shape_id::ShapeId = #{SmithyHttpServer}::shape_id::ShapeId::new("$absolute", "$namespace", "$name"); - type Operations = Operation; - } - """, - "Protocol" to protocol.markerStruct(), - *codegenScope, - ) - } + const VERSION: Option<&'static str> = $version; - private fun operationEnum(): Writable = writable { - val operations = operationStructNames.values.joinToString(",") - val matchArms: Writable = operationStructNames.map { - (shape, name) -> - writable { - val absolute = shape.id.toString().replace("#", "##") - rustTemplate( - """ - Operation::$name => #{SmithyHttpServer}::shape_id::ShapeId::new("$absolute", "${shape.id.namespace}", "${shape.id.name}") - """, - *codegenScope, - ) - } - }.join(",") - rustTemplate( - """ - /// An enumeration of all [operations](https://smithy.io/2.0/spec/service-types.html##operation) in $serviceName. - ##[derive(Debug, PartialEq, Eq, Clone, Copy)] - pub enum Operation { - $operations - } + type Protocol = #{Protocol}; - impl Operation { - /// Returns the [operations](https://smithy.io/2.0/spec/service-types.html##operation) [`ShapeId`](#{SmithyHttpServer}::shape_id::ShapeId). - pub fn shape_id(&self) -> #{SmithyHttpServer}::shape_id::ShapeId { - match self { - #{Arms} - } + type Operations = Operation; } - } - """, - *codegenScope, - "Arms" to matchArms, - ) + """, + "Protocol" to protocol.markerStruct(), + *codegenScope, + ) + } - for ((_, value) in operationStructNames) { + private fun operationEnum(): Writable = + writable { + val operations = operationStructNames.values.joinToString(",") + val matchArms: Writable = + operationStructNames.map { + (shape, name) -> + writable { + val absolute = shape.id.toString().replace("#", "##") + rustTemplate( + """ + Operation::$name => #{SmithyHttpServer}::shape_id::ShapeId::new("$absolute", "${shape.id.namespace}", "${shape.id.name}") + """, + *codegenScope, + ) + } + }.join(",") rustTemplate( """ - impl #{SmithyHttpServer}::service::ContainsOperation - for $serviceName - { - const VALUE: Operation = Operation::$value; + /// An enumeration of all [operations](https://smithy.io/2.0/spec/service-types.html##operation) in $serviceName. + ##[derive(Debug, PartialEq, Eq, Clone, Copy)] + pub enum Operation { + $operations + } + + impl Operation { + /// Returns the [operations](https://smithy.io/2.0/spec/service-types.html##operation) [`ShapeId`](#{SmithyHttpServer}::shape_id::ShapeId). + pub fn shape_id(&self) -> #{SmithyHttpServer}::shape_id::ShapeId { + match self { + #{Arms} + } + } } """, *codegenScope, + "Arms" to matchArms, ) + + for ((_, value) in operationStructNames) { + rustTemplate( + """ + impl #{SmithyHttpServer}::service::ContainsOperation + for $serviceName + { + const VALUE: Operation = Operation::$value; + } + """, + *codegenScope, + ) + } } - } fun render(writer: RustWriter) { writer.rustTemplate( @@ -802,7 +821,11 @@ class ServerServiceGenerator( * use my_service::{input, output, error}; * ``` */ -fun handlerImports(crateName: String, operations: Collection, commentToken: String = "///") = writable { +fun handlerImports( + crateName: String, + operations: Collection, + commentToken: String = "///", +) = writable { val hasErrors = operations.any { it.errors.isNotEmpty() } val errorImport = if (hasErrors) ", ${ErrorModule.name}" else "" if (operations.isNotEmpty()) { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServiceConfigGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServiceConfigGenerator.kt index 525487968fa..81bcbaaf437 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServiceConfigGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServiceConfigGenerator.kt @@ -5,6 +5,7 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators +import software.amazon.smithy.codegen.core.CodegenException import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Writable import software.amazon.smithy.rust.codegen.core.rustlang.conditionalBlock @@ -13,6 +14,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.join import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustBlockTemplate import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate +import software.amazon.smithy.rust.codegen.core.rustlang.rustTypeParameters import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope @@ -33,7 +35,7 @@ data class ConfigMethod( val docs: String, /** The parameters of the method. **/ val params: List, - /** In case the method is fallible, the error type it returns. **/ + /** In case the method is fallible, the concrete error type it returns. **/ val errorType: RuntimeType?, /** The code block inside the method. **/ val initializer: Initializer, @@ -104,15 +106,45 @@ data class Initializer( * } * * has two variable bindings. The `bar` name is bound to a `String` variable and the `baz` name is bound to a - * `u64` variable. + * `u64` variable. Both are bindings that use concrete types. Types can also be generic: + * + * ```rust + * fn foo(bar: T) { } * ``` */ -data class Binding( - /** The name of the variable. */ - val name: String, - /** The type of the variable. */ - val ty: RuntimeType, -) +sealed class Binding { + data class Generic( + /** The name of the variable. The name of the type parameter will be the PascalCased variable name. */ + val name: String, + /** The type of the variable. */ + val ty: RuntimeType, + /** + * The generic type parameters contained in `ty`. For example, if `ty` renders to `Vec` with `T` being a + * generic type parameter, then `genericTys` should be a singleton set containing `"T"`. + * You can't use `L`, `H`, or `M` as the names to refer to any generic types. + * */ + val genericTys: Set, + ) : Binding() + + data class Concrete( + /** The name of the variable. */ + val name: String, + /** The type of the variable. */ + val ty: RuntimeType, + ) : Binding() + + fun name() = + when (this) { + is Concrete -> this.name + is Generic -> this.name + } + + fun ty() = + when (this) { + is Concrete -> this.ty + is Generic -> this.ty + } +} class ServiceConfigGenerator( codegenContext: ServerCodegenContext, @@ -120,26 +152,28 @@ class ServiceConfigGenerator( ) { private val crateName = codegenContext.moduleUseName() private val smithyHttpServer = ServerCargoDependency.smithyHttpServer(codegenContext.runtimeConfig).toType() - private val codegenScope = arrayOf( - *preludeScope, - "Debug" to RuntimeType.Debug, - "SmithyHttpServer" to smithyHttpServer, - "PluginStack" to smithyHttpServer.resolve("plugin::PluginStack"), - "ModelMarker" to smithyHttpServer.resolve("plugin::ModelMarker"), - "HttpMarker" to smithyHttpServer.resolve("plugin::HttpMarker"), - "Tower" to RuntimeType.Tower, - "Stack" to RuntimeType.Tower.resolve("layer::util::Stack"), - ) + private val codegenScope = + arrayOf( + *preludeScope, + "Debug" to RuntimeType.Debug, + "SmithyHttpServer" to smithyHttpServer, + "PluginStack" to smithyHttpServer.resolve("plugin::PluginStack"), + "ModelMarker" to smithyHttpServer.resolve("plugin::ModelMarker"), + "HttpMarker" to smithyHttpServer.resolve("plugin::HttpMarker"), + "Tower" to RuntimeType.Tower, + "Stack" to RuntimeType.Tower.resolve("layer::util::Stack"), + ) private val serviceName = codegenContext.serviceShape.id.name.toPascalCase() fun render(writer: RustWriter) { - val unwrapConfigBuilder = if (isBuilderFallible) { - """ - /// .expect("config failed to build"); - """ - } else { - ";" - } + val unwrapConfigBuilder = + if (isBuilderFallible) { + """ + /// .expect("config failed to build"); + """ + } else { + ";" + } writer.rustTemplate( """ @@ -197,12 +231,12 @@ class ServiceConfigGenerator( pub(crate) model_plugins: M, #{BuilderRequiredMethodFlagDefinitions:W} } - + #{BuilderRequiredMethodError:W} impl ${serviceName}ConfigBuilder { #{InjectedMethods:W} - + /// Add a [`#{Tower}::Layer`] to the service. pub fn layer(self, layer: NewLayer) -> ${serviceName}ConfigBuilder<#{Stack}, H, M> { ${serviceName}ConfigBuilder { @@ -246,7 +280,7 @@ class ServiceConfigGenerator( #{BuilderRequiredMethodFlagsMove3:W} } } - + #{BuilderBuildMethod:W} } """, @@ -264,182 +298,211 @@ class ServiceConfigGenerator( private val isBuilderFallible = configMethods.isBuilderFallible() - private fun builderBuildRequiredMethodChecks() = configMethods.filter { it.isRequired }.map { - writable { - rustTemplate( - """ - if !self.${it.requiredBuilderFlagName()} { - return #{Err}(${serviceName}ConfigError::${it.requiredErrorVariant()}); - } - """, - *codegenScope, - ) - } - }.join("\n") + private fun builderBuildRequiredMethodChecks() = + configMethods.filter { it.isRequired }.map { + writable { + rustTemplate( + """ + if !self.${it.requiredBuilderFlagName()} { + return #{Err}(${serviceName}ConfigError::${it.requiredErrorVariant()}); + } + """, + *codegenScope, + ) + } + }.join("\n") - private fun builderRequiredMethodFlagsDefinitions() = configMethods.filter { it.isRequired }.map { - writable { rust("pub(crate) ${it.requiredBuilderFlagName()}: bool,") } - }.join("\n") + private fun builderRequiredMethodFlagsDefinitions() = + configMethods.filter { it.isRequired }.map { + writable { rust("pub(crate) ${it.requiredBuilderFlagName()}: bool,") } + }.join("\n") - private fun builderRequiredMethodFlagsInit() = configMethods.filter { it.isRequired }.map { - writable { rust("${it.requiredBuilderFlagName()}: false,") } - }.join("\n") + private fun builderRequiredMethodFlagsInit() = + configMethods.filter { it.isRequired }.map { + writable { rust("${it.requiredBuilderFlagName()}: false,") } + }.join("\n") - private fun builderRequiredMethodFlagsMove() = configMethods.filter { it.isRequired }.map { - writable { rust("${it.requiredBuilderFlagName()}: self.${it.requiredBuilderFlagName()},") } - }.join("\n") + private fun builderRequiredMethodFlagsMove() = + configMethods.filter { it.isRequired }.map { + writable { rust("${it.requiredBuilderFlagName()}: self.${it.requiredBuilderFlagName()},") } + }.join("\n") - private fun builderRequiredMethodError() = writable { - if (isBuilderFallible) { - val variants = configMethods.filter { it.isRequired }.map { - writable { - rust( - """ - ##[error("service is not fully configured; invoke `${it.name}` on the config builder")] - ${it.requiredErrorVariant()}, + private fun builderRequiredMethodError() = + writable { + if (isBuilderFallible) { + val variants = + configMethods.filter { it.isRequired }.map { + writable { + rust( + """ + ##[error("service is not fully configured; invoke `${it.name}` on the config builder")] + ${it.requiredErrorVariant()}, + """, + ) + } + } + rustTemplate( + """ + ##[derive(Debug, #{ThisError}::Error)] + pub enum ${serviceName}ConfigError { + #{Variants:W} + } """, - ) - } + "ThisError" to ServerCargoDependency.ThisError.toType(), + "Variants" to variants.join("\n"), + ) } - rustTemplate( - """ - ##[derive(Debug, #{ThisError}::Error)] - pub enum ${serviceName}ConfigError { - #{Variants:W} - } - """, - "ThisError" to ServerCargoDependency.ThisError.toType(), - "Variants" to variants.join("\n"), - ) } - } - private fun injectedMethods() = configMethods.map { - writable { - val paramBindings = it.params.map { binding -> - writable { rustTemplate("${binding.name}: #{BindingTy},", "BindingTy" to binding.ty) } - }.join("\n") - - // This produces a nested type like: "S>", where - // - "S" denotes a "stack type" with two generic type parameters: the first is the "inner" part of the stack - // and the second is the "outer" part of the stack. The outer part gets executed first. For an example, - // see `aws_smithy_http_server::plugin::PluginStack`. - // - "A", "B" are the types of the "things" that are added. - // - "T" is the generic type variable name used in the enclosing impl block. - fun List.stackReturnType(genericTypeVarName: String, stackType: RuntimeType): Writable = - this.fold(writable { rust(genericTypeVarName) }) { acc, next -> + private fun injectedMethods() = + configMethods.map { + writable { + val paramBindings = + it.params.map { binding -> + writable { rustTemplate("${binding.name()}: #{BindingTy},", "BindingTy" to binding.ty()) } + }.join("\n") + val genericBindings = it.params.filterIsInstance() + val lhmBindings = + genericBindings.filter { + it.genericTys.contains("L") || it.genericTys.contains("H") || it.genericTys.contains("M") + } + if (lhmBindings.isNotEmpty()) { + throw CodegenException( + "Injected config method `${it.name}` has generic bindings that use `L`, `H`, or `M` to refer to the generic types. This is not allowed. Invalid generic bindings: $lhmBindings", + ) + } + val paramBindingsGenericTys = genericBindings.flatMap { it.genericTys }.toSet() + val paramBindingsGenericsWritable = rustTypeParameters(*paramBindingsGenericTys.toTypedArray()) + + // This produces a nested type like: "S>", where + // - "S" denotes a "stack type" with two generic type parameters: the first is the "inner" part of the stack + // and the second is the "outer" part of the stack. The outer part gets executed first. For an example, + // see `aws_smithy_http_server::plugin::PluginStack`. + // - "A", "B" are the types of the "things" that are added. + // - "T" is the generic type variable name used in the enclosing impl block. + fun List.stackReturnType( + genericTypeVarName: String, + stackType: RuntimeType, + ): Writable = + this.fold(writable { rust(genericTypeVarName) }) { acc, next -> + writable { + rustTemplate( + "#{StackType}<#{Ty}, #{Acc:W}>", + "StackType" to stackType, + "Ty" to next.ty(), + "Acc" to acc, + ) + } + } + + val layersReturnTy = + it.initializer.layerBindings.stackReturnType("L", RuntimeType.Tower.resolve("layer::util::Stack")) + val httpPluginsReturnTy = + it.initializer.httpPluginBindings.stackReturnType("H", smithyHttpServer.resolve("plugin::PluginStack")) + val modelPluginsReturnTy = + it.initializer.modelPluginBindings.stackReturnType("M", smithyHttpServer.resolve("plugin::PluginStack")) + + val configBuilderReturnTy = writable { rustTemplate( - "#{StackType}<#{Ty}, #{Acc:W}>", - "StackType" to stackType, - "Ty" to next.ty, - "Acc" to acc, + """ + ${serviceName}ConfigBuilder< + #{LayersReturnTy:W}, + #{HttpPluginsReturnTy:W}, + #{ModelPluginsReturnTy:W}, + > + """, + "LayersReturnTy" to layersReturnTy, + "HttpPluginsReturnTy" to httpPluginsReturnTy, + "ModelPluginsReturnTy" to modelPluginsReturnTy, ) } - } - val layersReturnTy = - it.initializer.layerBindings.stackReturnType("L", RuntimeType.Tower.resolve("layer::util::Stack")) - val httpPluginsReturnTy = - it.initializer.httpPluginBindings.stackReturnType("H", smithyHttpServer.resolve("plugin::PluginStack")) - val modelPluginsReturnTy = - it.initializer.modelPluginBindings.stackReturnType("M", smithyHttpServer.resolve("plugin::PluginStack")) + val returnTy = + if (it.errorType != null) { + writable { + rustTemplate( + "#{Result}<#{T:W}, #{E}>", + "T" to configBuilderReturnTy, + "E" to it.errorType, + *codegenScope, + ) + } + } else { + configBuilderReturnTy + } - val configBuilderReturnTy = writable { - rustTemplate( + docs(it.docs) + rustBlockTemplate( """ - ${serviceName}ConfigBuilder< - #{LayersReturnTy:W}, - #{HttpPluginsReturnTy:W}, - #{ModelPluginsReturnTy:W}, - > + pub fn ${it.name}#{ParamBindingsGenericsWritable}( + ##[allow(unused_mut)] + mut self, + #{ParamBindings:W} + ) -> #{ReturnTy:W} """, - "LayersReturnTy" to layersReturnTy, - "HttpPluginsReturnTy" to httpPluginsReturnTy, - "ModelPluginsReturnTy" to modelPluginsReturnTy, - ) - } + "ReturnTy" to returnTy, + "ParamBindings" to paramBindings, + "ParamBindingsGenericsWritable" to paramBindingsGenericsWritable, + ) { + rustTemplate("#{InitializerCode:W}", "InitializerCode" to it.initializer.code) + + check(it.initializer.layerBindings.size + it.initializer.httpPluginBindings.size + it.initializer.modelPluginBindings.size > 0) { + "This method's initializer does not register any layers, HTTP plugins, or model plugins. It must register at least something!" + } - val returnTy = if (it.errorType != null) { - writable { - rustTemplate( - "#{Result}<#{T:W}, #{E}>", - "T" to configBuilderReturnTy, - "E" to it.errorType, - *codegenScope, - ) + if (it.isRequired) { + rust("self.${it.requiredBuilderFlagName()} = true;") + } + conditionalBlock("Ok(", ")", conditional = it.errorType != null) { + val registrations = + ( + it.initializer.layerBindings.map { ".layer(${it.name()})" } + + it.initializer.httpPluginBindings.map { ".http_plugin(${it.name()})" } + + it.initializer.modelPluginBindings.map { ".model_plugin(${it.name()})" } + ).joinToString("") + rust("self$registrations") + } } + } + }.join("\n\n") + + private fun builderBuildReturnType() = + writable { + val t = "super::${serviceName}Config" + + if (isBuilderFallible) { + rustTemplate("#{Result}<$t, ${serviceName}ConfigError>", *codegenScope) } else { - configBuilderReturnTy + rust(t) } + } - docs(it.docs) + private fun builderBuildMethod() = + writable { rustBlockTemplate( """ - pub fn ${it.name}( - ##[allow(unused_mut)] - mut self, - #{ParamBindings:W} - ) -> #{ReturnTy:W} + /// Build the configuration. + pub fn build(self) -> #{BuilderBuildReturnTy:W} """, - "ReturnTy" to returnTy, - "ParamBindings" to paramBindings, + "BuilderBuildReturnTy" to builderBuildReturnType(), ) { - rustTemplate("#{InitializerCode:W}", "InitializerCode" to it.initializer.code) - - check(it.initializer.layerBindings.size + it.initializer.httpPluginBindings.size + it.initializer.modelPluginBindings.size > 0) { - "This method's initializer does not register any layers, HTTP plugins, or model plugins. It must register at least something!" - } + rustTemplate( + "#{BuilderBuildRequiredMethodChecks:W}", + "BuilderBuildRequiredMethodChecks" to builderBuildRequiredMethodChecks(), + ) - if (it.isRequired) { - rust("self.${it.requiredBuilderFlagName()} = true;") - } - conditionalBlock("Ok(", ")", conditional = it.errorType != null) { - val registrations = ( - it.initializer.layerBindings.map { ".layer(${it.name})" } + - it.initializer.httpPluginBindings.map { ".http_plugin(${it.name})" } + - it.initializer.modelPluginBindings.map { ".model_plugin(${it.name})" } - ).joinToString("") - rust("self$registrations") + conditionalBlock("Ok(", ")", isBuilderFallible) { + rust( + """ + super::${serviceName}Config { + layers: self.layers, + http_plugins: self.http_plugins, + model_plugins: self.model_plugins, + } + """, + ) } } } - }.join("\n\n") - - private fun builderBuildReturnType() = writable { - val t = "super::${serviceName}Config" - - if (isBuilderFallible) { - rustTemplate("#{Result}<$t, ${serviceName}ConfigError>", *codegenScope) - } else { - rust(t) - } - } - - private fun builderBuildMethod() = writable { - rustBlockTemplate( - """ - /// Build the configuration. - pub fn build(self) -> #{BuilderBuildReturnTy:W} - """, - "BuilderBuildReturnTy" to builderBuildReturnType(), - ) { - rustTemplate( - "#{BuilderBuildRequiredMethodChecks:W}", - "BuilderBuildRequiredMethodChecks" to builderBuildRequiredMethodChecks(), - ) - - conditionalBlock("Ok(", ")", isBuilderFallible) { - rust( - """ - super::${serviceName}Config { - layers: self.layers, - http_plugins: self.http_plugins, - model_plugins: self.model_plugins, - } - """, - ) - } - } - } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/TraitInfo.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/TraitInfo.kt index 2179130dff2..611c8400e8f 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/TraitInfo.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/TraitInfo.kt @@ -44,13 +44,14 @@ fun RustWriter.renderTryFrom( #{ValidationFunctions:W} } """, - "ValidationFunctions" to constraintsInfo.map { - it.validationFunctionDefinition( - constraintViolationError, - unconstrainedTypeName, - ) - } - .join("\n"), + "ValidationFunctions" to + constraintsInfo.map { + it.validationFunctionDefinition( + constraintViolationError, + unconstrainedTypeName, + ) + } + .join("\n"), ) this.rustTemplate( diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedCollectionGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedCollectionGenerator.kt index 6916617b6ff..041b5a13811 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedCollectionGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedCollectionGenerator.kt @@ -60,11 +60,12 @@ class UnconstrainedCollectionGenerator( } private val constraintViolationSymbol = constraintViolationSymbolProvider.toSymbol(shape) private val constrainedShapeSymbolProvider = codegenContext.constrainedShapeSymbolProvider - private val constrainedSymbol = if (shape.isDirectlyConstrained(symbolProvider)) { - constrainedShapeSymbolProvider.toSymbol(shape) - } else { - pubCrateConstrainedShapeSymbolProvider.toSymbol(shape) - } + private val constrainedSymbol = + if (shape.isDirectlyConstrained(symbolProvider)) { + constrainedShapeSymbolProvider.toSymbol(shape) + } else { + pubCrateConstrainedShapeSymbolProvider.toSymbol(shape) + } private val innerShape = model.expectShape(shape.member.target) fun render() { @@ -103,22 +104,25 @@ class UnconstrainedCollectionGenerator( !innerShape.isDirectlyConstrained(symbolProvider) && innerShape !is StructureShape && innerShape !is UnionShape - val constrainedMemberSymbol = if (resolvesToNonPublicConstrainedValueType) { - pubCrateConstrainedShapeSymbolProvider.toSymbol(shape.member) - } else { - constrainedShapeSymbolProvider.toSymbol(shape.member) - } + val constrainedMemberSymbol = + if (resolvesToNonPublicConstrainedValueType) { + pubCrateConstrainedShapeSymbolProvider.toSymbol(shape.member) + } else { + constrainedShapeSymbolProvider.toSymbol(shape.member) + } val innerConstraintViolationSymbol = constraintViolationSymbolProvider.toSymbol(innerShape) - val boxErr = if (shape.member.hasTrait()) { - ".map_err(|(idx, inner_violation)| (idx, Box::new(inner_violation)))" - } else { - "" - } - val constrainValueWritable = writable { - conditionalBlock("inner.map(|inner| ", ").transpose()", constrainedMemberSymbol.isOptional()) { - rust("inner.try_into().map_err(|inner_violation| (idx, inner_violation))") + val boxErr = + if (shape.member.hasTrait()) { + ".map_err(|(idx, inner_violation)| (idx, Box::new(inner_violation)))" + } else { + "" + } + val constrainValueWritable = + writable { + conditionalBlock("inner.map(|inner| ", ").transpose()", constrainedMemberSymbol.isOptional()) { + rust("inner.try_into().map_err(|inner_violation| (idx, inner_violation))") + } } - } rustTemplate( """ diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedMapGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedMapGenerator.kt index 0862a26987c..c0114c8a8d0 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedMapGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedMapGenerator.kt @@ -60,11 +60,12 @@ class UnconstrainedMapGenerator( } private val constraintViolationSymbol = constraintViolationSymbolProvider.toSymbol(shape) private val constrainedShapeSymbolProvider = codegenContext.constrainedShapeSymbolProvider - private val constrainedSymbol = if (shape.isDirectlyConstrained(symbolProvider)) { - constrainedShapeSymbolProvider.toSymbol(shape) - } else { - pubCrateConstrainedShapeSymbolProvider.toSymbol(shape) - } + private val constrainedSymbol = + if (shape.isDirectlyConstrained(symbolProvider)) { + constrainedShapeSymbolProvider.toSymbol(shape) + } else { + pubCrateConstrainedShapeSymbolProvider.toSymbol(shape) + } private val keyShape = model.expectShape(shape.key.target, StringShape::class.java) private val valueShape = model.expectShape(shape.value.target) @@ -107,74 +108,80 @@ class UnconstrainedMapGenerator( !valueShape.isDirectlyConstrained(symbolProvider) && valueShape !is StructureShape && valueShape !is UnionShape - val constrainedMemberValueSymbol = if (resolvesToNonPublicConstrainedValueType) { - pubCrateConstrainedShapeSymbolProvider.toSymbol(shape.value) - } else { - constrainedShapeSymbolProvider.toSymbol(shape.value) - } - val constrainedValueSymbol = if (resolvesToNonPublicConstrainedValueType) { - pubCrateConstrainedShapeSymbolProvider.toSymbol(valueShape) - } else { - constrainedShapeSymbolProvider.toSymbol(valueShape) - } + val constrainedMemberValueSymbol = + if (resolvesToNonPublicConstrainedValueType) { + pubCrateConstrainedShapeSymbolProvider.toSymbol(shape.value) + } else { + constrainedShapeSymbolProvider.toSymbol(shape.value) + } + val constrainedValueSymbol = + if (resolvesToNonPublicConstrainedValueType) { + pubCrateConstrainedShapeSymbolProvider.toSymbol(valueShape) + } else { + constrainedShapeSymbolProvider.toSymbol(valueShape) + } val constrainedKeySymbol = constrainedShapeSymbolProvider.toSymbol(keyShape) val epilogueWritable = writable { rust("Ok((k, v))") } - val constrainKeyWritable = writable { - rustTemplate( - "let k: #{ConstrainedKeySymbol} = k.try_into().map_err(Self::Error::Key)?;", - "ConstrainedKeySymbol" to constrainedKeySymbol, - ) - } - val constrainValueWritable = writable { - val boxErr = if (shape.value.hasTrait()) { - ".map_err(Box::new)" - } else { - "" + val constrainKeyWritable = + writable { + rustTemplate( + "let k: #{ConstrainedKeySymbol} = k.try_into().map_err(Self::Error::Key)?;", + "ConstrainedKeySymbol" to constrainedKeySymbol, + ) } - if (constrainedMemberValueSymbol.isOptional()) { - // The map is `@sparse`. - rustBlock("match v") { - rust("None => Ok((k, None)),") - withBlock("Some(v) =>", ",") { - // DRYing this up with the else branch below would make this less understandable. - rustTemplate( - """ - match #{ConstrainedValueSymbol}::try_from(v)$boxErr { - Ok(v) => Ok((k, Some(v))), - Err(inner_constraint_violation) => Err(Self::Error::Value(k, inner_constraint_violation)), - } - """, - "ConstrainedValueSymbol" to constrainedValueSymbol, - ) + val constrainValueWritable = + writable { + val boxErr = + if (shape.value.hasTrait()) { + ".map_err(Box::new)" + } else { + "" } - } - } else { - rustTemplate( - """ - match #{ConstrainedValueSymbol}::try_from(v)$boxErr { - Ok(v) => #{Epilogue:W}, - Err(inner_constraint_violation) => Err(Self::Error::Value(k, inner_constraint_violation)), + if (constrainedMemberValueSymbol.isOptional()) { + // The map is `@sparse`. + rustBlock("match v") { + rust("None => Ok((k, None)),") + withBlock("Some(v) =>", ",") { + // DRYing this up with the else branch below would make this less understandable. + rustTemplate( + """ + match #{ConstrainedValueSymbol}::try_from(v)$boxErr { + Ok(v) => Ok((k, Some(v))), + Err(inner_constraint_violation) => Err(Self::Error::Value(k, inner_constraint_violation)), + } + """, + "ConstrainedValueSymbol" to constrainedValueSymbol, + ) + } } - """, - "ConstrainedValueSymbol" to constrainedValueSymbol, - "Epilogue" to epilogueWritable, - ) + } else { + rustTemplate( + """ + match #{ConstrainedValueSymbol}::try_from(v)$boxErr { + Ok(v) => #{Epilogue:W}, + Err(inner_constraint_violation) => Err(Self::Error::Value(k, inner_constraint_violation)), + } + """, + "ConstrainedValueSymbol" to constrainedValueSymbol, + "Epilogue" to epilogueWritable, + ) + } } - } - val constrainKVWritable = if ( - isKeyConstrained(keyShape, symbolProvider) && - isValueConstrained(valueShape, model, symbolProvider) - ) { - listOf(constrainKeyWritable, constrainValueWritable).join("\n") - } else if (isKeyConstrained(keyShape, symbolProvider)) { - listOf(constrainKeyWritable, epilogueWritable).join("\n") - } else if (isValueConstrained(valueShape, model, symbolProvider)) { - constrainValueWritable - } else { - epilogueWritable - } + val constrainKVWritable = + if ( + isKeyConstrained(keyShape, symbolProvider) && + isValueConstrained(valueShape, model, symbolProvider) + ) { + listOf(constrainKeyWritable, constrainValueWritable).join("\n") + } else if (isKeyConstrained(keyShape, symbolProvider)) { + listOf(constrainKeyWritable, epilogueWritable).join("\n") + } else if (isValueConstrained(valueShape, model, symbolProvider)) { + constrainValueWritable + } else { + epilogueWritable + } rustTemplate( """ diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedUnionGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedUnionGenerator.kt index d4f6cd48605..b4a0976e6be 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedUnionGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/UnconstrainedUnionGenerator.kt @@ -128,11 +128,12 @@ class UnconstrainedUnionGenerator( "UnconstrainedSymbol" to symbol, ) - val constraintViolationVisibility = if (publicConstrainedTypes) { - Visibility.PUBLIC - } else { - Visibility.PUBCRATE - } + val constraintViolationVisibility = + if (publicConstrainedTypes) { + Visibility.PUBLIC + } else { + Visibility.PUBCRATE + } inlineModuleCreator( constraintViolationSymbol, @@ -172,7 +173,10 @@ class UnconstrainedUnionGenerator( .filter { it.targetCanReachConstrainedShape(model, symbolProvider) } .map { ConstraintViolation(it) } - private fun renderConstraintViolation(writer: RustWriter, constraintViolation: ConstraintViolation) { + private fun renderConstraintViolation( + writer: RustWriter, + constraintViolation: ConstraintViolation, + ) { val targetShape = model.expectShape(constraintViolation.forMember.target) val constraintViolationSymbol = @@ -188,68 +192,71 @@ class UnconstrainedUnionGenerator( ) } - private fun generateTryFromUnconstrainedUnionImpl() = writable { - withBlock("Ok(", ")") { - withBlock("match value {", "}") { - sortedMembers.forEach { member -> - val memberName = unconstrainedShapeSymbolProvider.toMemberName(member) - withBlockTemplate( - "#{UnconstrainedUnion}::$memberName(unconstrained) => Self::$memberName(", - "),", - "UnconstrainedUnion" to symbol, - ) { - if (!member.canReachConstrainedShape(model, symbolProvider)) { - rust("unconstrained") - } else { - val targetShape = model.expectShape(member.target) - val resolveToNonPublicConstrainedType = - targetShape !is StructureShape && targetShape !is UnionShape && !targetShape.hasTrait() && - (!publicConstrainedTypes || !targetShape.isDirectlyConstrained(symbolProvider)) - - val (unconstrainedVar, boxIt) = if (member.hasTrait()) { - "(*unconstrained)" to ".map(Box::new)" + private fun generateTryFromUnconstrainedUnionImpl() = + writable { + withBlock("Ok(", ")") { + withBlock("match value {", "}") { + sortedMembers.forEach { member -> + val memberName = unconstrainedShapeSymbolProvider.toMemberName(member) + withBlockTemplate( + "#{UnconstrainedUnion}::$memberName(unconstrained) => Self::$memberName(", + "),", + "UnconstrainedUnion" to symbol, + ) { + if (!member.canReachConstrainedShape(model, symbolProvider)) { + rust("unconstrained") } else { - "unconstrained" to "" - } - val boxErr = if (member.hasTrait()) { - ".map_err(Box::new)" - } else { - "" - } + val targetShape = model.expectShape(member.target) + val resolveToNonPublicConstrainedType = + targetShape !is StructureShape && targetShape !is UnionShape && !targetShape.hasTrait() && + (!publicConstrainedTypes || !targetShape.isDirectlyConstrained(symbolProvider)) - if (resolveToNonPublicConstrainedType) { - val constrainedSymbol = - if (!publicConstrainedTypes && targetShape.isDirectlyConstrained(symbolProvider)) { - codegenContext.constrainedShapeSymbolProvider.toSymbol(targetShape) + val (unconstrainedVar, boxIt) = + if (member.hasTrait()) { + "(*unconstrained)" to ".map(Box::new)" } else { - pubCrateConstrainedShapeSymbolProvider.toSymbol(targetShape) + "unconstrained" to "" } - rustTemplate( - """ - { - let constrained: #{ConstrainedSymbol} = $unconstrainedVar - .try_into()$boxIt$boxErr - .map_err(Self::Error::${ConstraintViolation(member).name()})?; - constrained.into() + val boxErr = + if (member.hasTrait()) { + ".map_err(Box::new)" + } else { + "" } - """, - "ConstrainedSymbol" to constrainedSymbol, - ) - } else { - rust( - """ - $unconstrainedVar - .try_into() - $boxIt - $boxErr - .map_err(Self::Error::${ConstraintViolation(member).name()})? - """, - ) + + if (resolveToNonPublicConstrainedType) { + val constrainedSymbol = + if (!publicConstrainedTypes && targetShape.isDirectlyConstrained(symbolProvider)) { + codegenContext.constrainedShapeSymbolProvider.toSymbol(targetShape) + } else { + pubCrateConstrainedShapeSymbolProvider.toSymbol(targetShape) + } + rustTemplate( + """ + { + let constrained: #{ConstrainedSymbol} = $unconstrainedVar + .try_into()$boxIt$boxErr + .map_err(Self::Error::${ConstraintViolation(member).name()})?; + constrained.into() + } + """, + "ConstrainedSymbol" to constrainedSymbol, + ) + } else { + rust( + """ + $unconstrainedVar + .try_into() + $boxIt + $boxErr + .map_err(Self::Error::${ConstraintViolation(member).name()})? + """, + ) + } } } } } } } - } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ValidationExceptionConversionGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ValidationExceptionConversionGenerator.kt index 3434afb0b12..b43af2a1fde 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ValidationExceptionConversionGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ValidationExceptionConversionGenerator.kt @@ -31,8 +31,11 @@ interface ValidationExceptionConversionGenerator { // Simple shapes. fun stringShapeConstraintViolationImplBlock(stringConstraintsInfo: Collection): Writable + fun enumShapeConstraintViolationImplBlock(enumTrait: EnumTrait): Writable + fun numberShapeConstraintViolationImplBlock(rangeInfo: Range): Writable + fun blobShapeConstraintViolationImplBlock(blobConstraintsInfo: Collection): Writable // Aggregate shapes. @@ -43,7 +46,9 @@ interface ValidationExceptionConversionGenerator { symbolProvider: RustSymbolProvider, model: Model, ): Writable + fun builderConstraintViolationImplBlock(constraintViolations: Collection): Writable + fun collectionShapeConstraintViolationImplBlock( collectionConstraintsInfo: Collection, isMemberConstrained: Boolean, diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/RestRequestSpecGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/RestRequestSpecGenerator.kt index b43eb582e60..a02a0634a23 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/RestRequestSpecGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/RestRequestSpecGenerator.kt @@ -36,34 +36,38 @@ class RestRequestSpecGenerator( }.toTypedArray() // TODO(https://github.com/smithy-lang/smithy-rs/issues/950): Support the `endpoint` trait. - val pathSegmentsVec = writable { - withBlock("vec![", "]") { - for (segment in httpTrait.uri.segments) { - val variant = when { - segment.isGreedyLabel -> "Greedy" - segment.isLabel -> "Label" - else -> """Literal(String::from("${segment.content}"))""" + val pathSegmentsVec = + writable { + withBlock("vec![", "]") { + for (segment in httpTrait.uri.segments) { + val variant = + when { + segment.isGreedyLabel -> "Greedy" + segment.isLabel -> "Label" + else -> """Literal(String::from("${segment.content}"))""" + } + rustTemplate( + "#{PathSegment}::$variant,", + *extraCodegenScope, + ) } - rustTemplate( - "#{PathSegment}::$variant,", - *extraCodegenScope, - ) } } - } - val querySegmentsVec = writable { - withBlock("vec![", "]") { - for (queryLiteral in httpTrait.uri.queryLiterals) { - val variant = if (queryLiteral.value == "") { - """Key(String::from("${queryLiteral.key}"))""" - } else { - """KeyValue(String::from("${queryLiteral.key}"), String::from("${queryLiteral.value}"))""" + val querySegmentsVec = + writable { + withBlock("vec![", "]") { + for (queryLiteral in httpTrait.uri.queryLiterals) { + val variant = + if (queryLiteral.value == "") { + """Key(String::from("${queryLiteral.key}"))""" + } else { + """KeyValue(String::from("${queryLiteral.key}"), String::from("${queryLiteral.value}"))""" + } + rustTemplate("#{QuerySegment}::$variant,", *extraCodegenScope) } - rustTemplate("#{QuerySegment}::$variant,", *extraCodegenScope) } } - } return writable { rustTemplate( diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/ServerRequestBindingGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/ServerRequestBindingGenerator.kt index e1e6c747f76..ce02e2c99bf 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/ServerRequestBindingGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/ServerRequestBindingGenerator.kt @@ -50,16 +50,16 @@ class ServerRequestBindingGenerator( binding: HttpBindingDescriptor, errorSymbol: Symbol, structuredHandler: RustWriter.(String) -> Unit, - ): RuntimeType = httpBindingGenerator.generateDeserializePayloadFn( - binding, - errorSymbol, - structuredHandler, - HttpMessageType.REQUEST, - ) + ): RuntimeType = + httpBindingGenerator.generateDeserializePayloadFn( + binding, + errorSymbol, + structuredHandler, + HttpMessageType.REQUEST, + ) - fun generateDeserializePrefixHeadersFn( - binding: HttpBindingDescriptor, - ): RuntimeType = httpBindingGenerator.generateDeserializePrefixHeaderFn(binding) + fun generateDeserializePrefixHeadersFn(binding: HttpBindingDescriptor): RuntimeType = + httpBindingGenerator.generateDeserializePrefixHeaderFn(binding) } /** @@ -68,20 +68,22 @@ class ServerRequestBindingGenerator( */ class ServerRequestAfterDeserializingIntoAHashMapOfHttpPrefixHeadersWrapInUnconstrainedMapHttpBindingCustomization(val codegenContext: ServerCodegenContext) : HttpBindingCustomization() { - override fun section(section: HttpBindingSection): Writable = when (section) { - is HttpBindingSection.BeforeRenderingHeaderValue, - is HttpBindingSection.BeforeIteratingOverMapShapeBoundWithHttpPrefixHeaders, - -> emptySection - is HttpBindingSection.AfterDeserializingIntoAHashMapOfHttpPrefixHeaders -> writable { - if (section.memberShape.targetCanReachConstrainedShape(codegenContext.model, codegenContext.unconstrainedShapeSymbolProvider)) { - rust( - "let out = out.map(#T);", - codegenContext.unconstrainedShapeSymbolProvider.toSymbol(section.memberShape).mapRustType { - it.stripOuter() - }, - ) - } + override fun section(section: HttpBindingSection): Writable = + when (section) { + is HttpBindingSection.BeforeRenderingHeaderValue, + is HttpBindingSection.BeforeIteratingOverMapShapeBoundWithHttpPrefixHeaders, + -> emptySection + is HttpBindingSection.AfterDeserializingIntoAHashMapOfHttpPrefixHeaders -> + writable { + if (section.memberShape.targetCanReachConstrainedShape(codegenContext.model, codegenContext.unconstrainedShapeSymbolProvider)) { + rust( + "let out = out.map(#T);", + codegenContext.unconstrainedShapeSymbolProvider.toSymbol(section.memberShape).mapRustType { + it.stripOuter() + }, + ) + } + } + else -> emptySection } - else -> emptySection - } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/ServerResponseBindingGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/ServerResponseBindingGenerator.kt index 01448d27a47..960cbd735d7 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/ServerResponseBindingGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/http/ServerResponseBindingGenerator.kt @@ -57,23 +57,25 @@ class ServerResponseBindingGenerator( */ class ServerResponseBeforeIteratingOverMapBoundWithHttpPrefixHeadersUnwrapConstrainedMapHttpBindingCustomization(val codegenContext: ServerCodegenContext) : HttpBindingCustomization() { - override fun section(section: HttpBindingSection): Writable = when (section) { - is HttpBindingSection.BeforeIteratingOverMapShapeBoundWithHttpPrefixHeaders -> writable { - if (workingWithPublicConstrainedWrapperTupleType( - section.shape, - codegenContext.model, - codegenContext.settings.codegenConfig.publicConstrainedTypes, - ) - ) { - rust("let ${section.variableName} = &${section.variableName}.0;") - } - } + override fun section(section: HttpBindingSection): Writable = + when (section) { + is HttpBindingSection.BeforeIteratingOverMapShapeBoundWithHttpPrefixHeaders -> + writable { + if (workingWithPublicConstrainedWrapperTupleType( + section.shape, + codegenContext.model, + codegenContext.settings.codegenConfig.publicConstrainedTypes, + ) + ) { + rust("let ${section.variableName} = &${section.variableName}.0;") + } + } - is HttpBindingSection.BeforeRenderingHeaderValue, - is HttpBindingSection.AfterDeserializingIntoAHashMapOfHttpPrefixHeaders, - is HttpBindingSection.AfterDeserializingIntoADateTimeOfHttpHeaders, - -> emptySection - } + is HttpBindingSection.BeforeRenderingHeaderValue, + is HttpBindingSection.AfterDeserializingIntoAHashMapOfHttpPrefixHeaders, + is HttpBindingSection.AfterDeserializingIntoADateTimeOfHttpHeaders, + -> emptySection + } } /** @@ -82,26 +84,29 @@ class ServerResponseBeforeIteratingOverMapBoundWithHttpPrefixHeadersUnwrapConstr */ class ServerResponseBeforeRenderingHeadersHttpBindingCustomization(val codegenContext: ServerCodegenContext) : HttpBindingCustomization() { - override fun section(section: HttpBindingSection): Writable = when (section) { - is HttpBindingSection.BeforeRenderingHeaderValue -> writable { - val isIntegral = section.context.shape is ByteShape || section.context.shape is ShortShape || section.context.shape is IntegerShape || section.context.shape is LongShape - val isCollection = section.context.shape is CollectionShape + override fun section(section: HttpBindingSection): Writable = + when (section) { + is HttpBindingSection.BeforeRenderingHeaderValue -> + writable { + val isIntegral = section.context.shape is ByteShape || section.context.shape is ShortShape || section.context.shape is IntegerShape || section.context.shape is LongShape + val isCollection = section.context.shape is CollectionShape - val workingWithPublicWrapper = workingWithPublicConstrainedWrapperTupleType( - section.context.shape, - codegenContext.model, - codegenContext.settings.codegenConfig.publicConstrainedTypes, - ) + val workingWithPublicWrapper = + workingWithPublicConstrainedWrapperTupleType( + section.context.shape, + codegenContext.model, + codegenContext.settings.codegenConfig.publicConstrainedTypes, + ) - if (workingWithPublicWrapper && (isIntegral || isCollection)) { - section.context.valueExpression = - ValueExpression.Reference("&${section.context.valueExpression.name.removePrefix("&")}.0") - } - } + if (workingWithPublicWrapper && (isIntegral || isCollection)) { + section.context.valueExpression = + ValueExpression.Reference("&${section.context.valueExpression.name.removePrefix("&")}.0") + } + } - is HttpBindingSection.BeforeIteratingOverMapShapeBoundWithHttpPrefixHeaders, - is HttpBindingSection.AfterDeserializingIntoAHashMapOfHttpPrefixHeaders, - is HttpBindingSection.AfterDeserializingIntoADateTimeOfHttpHeaders, - -> emptySection - } + is HttpBindingSection.BeforeIteratingOverMapShapeBoundWithHttpPrefixHeaders, + is HttpBindingSection.AfterDeserializingIntoAHashMapOfHttpPrefixHeaders, + is HttpBindingSection.AfterDeserializingIntoADateTimeOfHttpHeaders, + -> emptySection + } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt index f86c547da19..2fb76bf879b 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocol.kt @@ -126,10 +126,11 @@ class ServerAwsJsonProtocol( private val runtimeConfig = codegenContext.runtimeConfig override val protocolModulePath: String - get() = when (version) { - is AwsJsonVersion.Json10 -> "aws_json_10" - is AwsJsonVersion.Json11 -> "aws_json_11" - } + get() = + when (version) { + is AwsJsonVersion.Json10 -> "aws_json_10" + is AwsJsonVersion.Json11 -> "aws_json_11" + } override fun structuredDataParser(): StructuredDataParserGenerator = jsonParserGenerator( @@ -149,8 +150,9 @@ class ServerAwsJsonProtocol( } } - override fun routerType() = ServerCargoDependency.smithyHttpServer(runtimeConfig).toType() - .resolve("protocol::aws_json::router::AwsJsonRouter") + override fun routerType() = + ServerCargoDependency.smithyHttpServer(runtimeConfig).toType() + .resolve("protocol::aws_json::router::AwsJsonRouter") /** * Returns the operation name as required by the awsJson1.x protocols. @@ -164,14 +166,13 @@ class ServerAwsJsonProtocol( rust("""String::from("$serviceName.$operationName")""") } - override fun serverRouterRequestSpecType( - requestSpecModule: RuntimeType, - ): RuntimeType = RuntimeType.String + override fun serverRouterRequestSpecType(requestSpecModule: RuntimeType): RuntimeType = RuntimeType.String - override fun serverRouterRuntimeConstructor() = when (version) { - AwsJsonVersion.Json10 -> "new_aws_json_10_router" - AwsJsonVersion.Json11 -> "new_aws_json_11_router" - } + override fun serverRouterRuntimeConstructor() = + when (version) { + AwsJsonVersion.Json10 -> "new_aws_json_10_router" + AwsJsonVersion.Json11 -> "new_aws_json_11_router" + } override fun requestRejection(runtimeConfig: RuntimeConfig): RuntimeType = ServerCargoDependency.smithyHttpServer(runtimeConfig) @@ -259,17 +260,19 @@ class ServerRestXmlProtocol( */ class ServerRequestBeforeBoxingDeserializedMemberConvertToMaybeConstrainedJsonParserCustomization(val codegenContext: ServerCodegenContext) : JsonParserCustomization() { - override fun section(section: JsonParserSection): Writable = when (section) { - is JsonParserSection.BeforeBoxingDeserializedMember -> writable { - // We're only interested in _structure_ member shapes that can reach constrained shapes. - if ( - codegenContext.model.expectShape(section.shape.container) is StructureShape && - section.shape.targetCanReachConstrainedShape(codegenContext.model, codegenContext.symbolProvider) - ) { - rust(".map(|x| x.into())") - } + override fun section(section: JsonParserSection): Writable = + when (section) { + is JsonParserSection.BeforeBoxingDeserializedMember -> + writable { + // We're only interested in _structure_ member shapes that can reach constrained shapes. + if ( + codegenContext.model.expectShape(section.shape.container) is StructureShape && + section.shape.targetCanReachConstrainedShape(codegenContext.model, codegenContext.symbolProvider) + ) { + rust(".map(|x| x.into())") + } + } + + else -> emptySection } - - else -> emptySection - } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt index 968f87ea3a0..b9cb2f533e0 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt @@ -76,37 +76,40 @@ class ServerProtocolTestGenerator( private val operations = TopDownIndex.of(codegenContext.model).getContainedOperations(codegenContext.serviceShape).sortedBy { it.id } - private val operationInputOutputTypes = operations.associateWith { - val inputSymbol = symbolProvider.toSymbol(it.inputShape(model)) - val outputSymbol = symbolProvider.toSymbol(it.outputShape(model)) - val operationSymbol = symbolProvider.toSymbol(it) - - val inputT = inputSymbol.fullName - val t = outputSymbol.fullName - val outputT = if (it.errors.isEmpty()) { - t - } else { - val errorType = RuntimeType("crate::error::${operationSymbol.name}Error") - val e = errorType.fullyQualifiedName() - "Result<$t, $e>" - } + private val operationInputOutputTypes = + operations.associateWith { + val inputSymbol = symbolProvider.toSymbol(it.inputShape(model)) + val outputSymbol = symbolProvider.toSymbol(it.outputShape(model)) + val operationSymbol = symbolProvider.toSymbol(it) + + val inputT = inputSymbol.fullName + val t = outputSymbol.fullName + val outputT = + if (it.errors.isEmpty()) { + t + } else { + val errorType = RuntimeType("crate::error::${operationSymbol.name}Error") + val e = errorType.fullyQualifiedName() + "Result<$t, $e>" + } - inputT to outputT - } + inputT to outputT + } private val instantiator = ServerInstantiator(codegenContext) - private val codegenScope = arrayOf( - "Bytes" to RuntimeType.Bytes, - "SmithyHttp" to RuntimeType.smithyHttp(codegenContext.runtimeConfig), - "Http" to RuntimeType.Http, - "Hyper" to RuntimeType.Hyper, - "Tokio" to ServerCargoDependency.TokioDev.toType(), - "Tower" to RuntimeType.Tower, - "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(codegenContext.runtimeConfig).toType(), - "AssertEq" to RuntimeType.PrettyAssertions.resolve("assert_eq!"), - "Router" to ServerRuntimeType.router(codegenContext.runtimeConfig), - ) + private val codegenScope = + arrayOf( + "Bytes" to RuntimeType.Bytes, + "SmithyHttp" to RuntimeType.smithyHttp(codegenContext.runtimeConfig), + "Http" to RuntimeType.Http, + "Hyper" to RuntimeType.Hyper, + "Tokio" to ServerCargoDependency.TokioDev.toType(), + "Tower" to RuntimeType.Tower, + "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(codegenContext.runtimeConfig).toType(), + "AssertEq" to RuntimeType.PrettyAssertions.resolve("assert_eq!"), + "Router" to ServerRuntimeType.router(codegenContext.runtimeConfig), + ) sealed class TestCase { abstract val id: String @@ -142,67 +145,84 @@ class ServerProtocolTestGenerator( } } - private fun renderOperationTestCases(operationShape: OperationShape, writer: RustWriter) { + private fun renderOperationTestCases( + operationShape: OperationShape, + writer: RustWriter, + ) { val outputShape = operationShape.outputShape(codegenContext.model) val operationSymbol = symbolProvider.toSymbol(operationShape) - val requestTests = operationShape.getTrait() - ?.getTestCasesFor(AppliesTo.SERVER).orEmpty().map { TestCase.RequestTest(it, operationShape) } - val responseTests = operationShape.getTrait() - ?.getTestCasesFor(AppliesTo.SERVER).orEmpty().map { TestCase.ResponseTest(it, outputShape) } - val errorTests = operationIndex.getErrors(operationShape).flatMap { error -> - val testCases = error.getTrait() - ?.getTestCasesFor(AppliesTo.SERVER).orEmpty() - testCases.map { TestCase.ResponseTest(it, error) } - } - val malformedRequestTests = operationShape.getTrait() - ?.testCases.orEmpty().map { TestCase.MalformedRequestTest(it) } - val allTests: List = (requestTests + responseTests + errorTests + malformedRequestTests) - .filterMatching() - .fixBroken() + val requestTests = + operationShape.getTrait() + ?.getTestCasesFor(AppliesTo.SERVER).orEmpty().map { TestCase.RequestTest(it, operationShape) } + val responseTests = + operationShape.getTrait() + ?.getTestCasesFor(AppliesTo.SERVER).orEmpty().map { TestCase.ResponseTest(it, outputShape) } + val errorTests = + operationIndex.getErrors(operationShape).flatMap { error -> + val testCases = + error.getTrait() + ?.getTestCasesFor(AppliesTo.SERVER).orEmpty() + testCases.map { TestCase.ResponseTest(it, error) } + } + val malformedRequestTests = + operationShape.getTrait() + ?.testCases.orEmpty().map { TestCase.MalformedRequestTest(it) } + val allTests: List = + (requestTests + responseTests + errorTests + malformedRequestTests) + .filterMatching() + .fixBroken() if (allTests.isNotEmpty()) { val operationName = operationSymbol.name - val module = RustModule.LeafModule( - "server_${operationName.toSnakeCase()}_test", - RustMetadata( - additionalAttributes = listOf( - Attribute.CfgTest, - Attribute(allow("unreachable_code", "unused_variables")), + val module = + RustModule.LeafModule( + "server_${operationName.toSnakeCase()}_test", + RustMetadata( + additionalAttributes = + listOf( + Attribute.CfgTest, + Attribute(allow("unreachable_code", "unused_variables")), + ), + visibility = Visibility.PRIVATE, ), - visibility = Visibility.PRIVATE, - ), - inline = true, - ) + inline = true, + ) writer.withInlineModule(module, null) { renderAllTestCases(operationShape, allTests) } } } - private fun RustWriter.renderAllTestCases(operationShape: OperationShape, allTests: List) { + private fun RustWriter.renderAllTestCases( + operationShape: OperationShape, + allTests: List, + ) { allTests.forEach { val operationSymbol = symbolProvider.toSymbol(operationShape) renderTestCaseBlock(it, this) { when (it) { - is TestCase.RequestTest -> this.renderHttpRequestTestCase( - it.testCase, - operationShape, - operationSymbol, - ) - - is TestCase.ResponseTest -> this.renderHttpResponseTestCase( - it.testCase, - it.targetShape, - operationShape, - operationSymbol, - ) - - is TestCase.MalformedRequestTest -> this.renderHttpMalformedRequestTestCase( - it.testCase, - operationShape, - operationSymbol, - ) + is TestCase.RequestTest -> + this.renderHttpRequestTestCase( + it.testCase, + operationShape, + operationSymbol, + ) + + is TestCase.ResponseTest -> + this.renderHttpResponseTestCase( + it.testCase, + it.targetShape, + operationShape, + operationSymbol, + ) + + is TestCase.MalformedRequestTest -> + this.renderHttpMalformedRequestTestCase( + it.testCase, + operationShape, + operationSymbol, + ) } } } @@ -228,20 +248,21 @@ class ServerProtocolTestGenerator( // This function applies a "fix function" to each broken test before we synthesize it. // Broken tests are those whose definitions in the `awslabs/smithy` repository are wrong, usually because they have // not been written with a server-side perspective in mind. - private fun List.fixBroken(): List = this.map { - when (it) { - is TestCase.MalformedRequestTest -> { - val howToFixIt = BrokenMalformedRequestTests[Pair(codegenContext.serviceShape.id.toString(), it.id)] - if (howToFixIt == null) { - it - } else { - val fixed = howToFixIt(it.testCase) - TestCase.MalformedRequestTest(fixed) + private fun List.fixBroken(): List = + this.map { + when (it) { + is TestCase.MalformedRequestTest -> { + val howToFixIt = BrokenMalformedRequestTests[Pair(codegenContext.serviceShape.id.toString(), it.id)] + if (howToFixIt == null) { + it + } else { + val fixed = howToFixIt(it.testCase) + TestCase.MalformedRequestTest(fixed) + } } + else -> it } - else -> it } - } private fun renderTestCaseBlock( testCase: TestCase, @@ -261,11 +282,12 @@ class ServerProtocolTestGenerator( if (expectFail(testCase)) { testModuleWriter.writeWithNoFormatting("#[should_panic]") } - val fnNameSuffix = when (testCase.testType) { - is TestType.Response -> "_response" - is TestType.Request -> "_request" - is TestType.MalformedRequest -> "_malformed_request" - } + val fnNameSuffix = + when (testCase.testType) { + is TestType.Response -> "_response" + is TestType.Request -> "_request" + is TestType.MalformedRequest -> "_malformed_request" + } testModuleWriter.rustBlock("async fn ${testCase.id.toSnakeCase()}$fnNameSuffix()") { block(this) } @@ -305,9 +327,10 @@ class ServerProtocolTestGenerator( } } - private fun expectFail(testCase: TestCase): Boolean = ExpectFail.find { - it.id == testCase.id && it.testType == testCase.testType && it.service == codegenContext.serviceShape.id.toString() - } != null + private fun expectFail(testCase: TestCase): Boolean = + ExpectFail.find { + it.id == testCase.id && it.testType == testCase.testType && it.service == codegenContext.serviceShape.id.toString() + } != null /** * Renders an HTTP response test case. @@ -325,7 +348,7 @@ class ServerProtocolTestGenerator( if (!protocolSupport.responseSerialization || ( !protocolSupport.errorSerialization && shape.hasTrait() - ) + ) ) { rust("/* test case disabled for this protocol (not yet supported) */") return @@ -430,29 +453,31 @@ class ServerProtocolTestGenerator( } /** Returns the body of the request test. */ - private fun checkRequestHandler(operationShape: OperationShape, httpRequestTestCase: HttpRequestTestCase) = - writable { - val inputShape = operationShape.inputShape(codegenContext.model) - val outputShape = operationShape.outputShape(codegenContext.model) - - // Construct expected request. - withBlock("let expected = ", ";") { - instantiator.render(this, inputShape, httpRequestTestCase.params, httpRequestTestCase.headers) - } + private fun checkRequestHandler( + operationShape: OperationShape, + httpRequestTestCase: HttpRequestTestCase, + ) = writable { + val inputShape = operationShape.inputShape(codegenContext.model) + val outputShape = operationShape.outputShape(codegenContext.model) - checkRequestParams(inputShape, this) + // Construct expected request. + withBlock("let expected = ", ";") { + instantiator.render(this, inputShape, httpRequestTestCase.params, httpRequestTestCase.headers) + } - // Construct a dummy response. - withBlock("let response = ", ";") { - instantiator.render(this, outputShape, Node.objectNode()) - } + checkRequestParams(inputShape, this) - if (operationShape.errors.isEmpty()) { - rust("response") - } else { - rust("Ok(response)") - } + // Construct a dummy response. + withBlock("let response = ", ";") { + instantiator.render(this, outputShape, Node.objectNode()) + } + + if (operationShape.errors.isEmpty()) { + rust("response") + } else { + rust("Ok(response)") } + } /** Checks the request. */ private fun makeRequest( @@ -495,7 +520,10 @@ class ServerProtocolTestGenerator( ) } - private fun checkRequestParams(inputShape: StructureShape, rustWriter: RustWriter) { + private fun checkRequestParams( + inputShape: StructureShape, + rustWriter: RustWriter, + ) { if (inputShape.hasStreamingMember(model)) { // A streaming shape does not implement `PartialEq`, so we have to iterate over the input shape's members // and handle the equality assertion separately. @@ -521,10 +549,11 @@ class ServerProtocolTestGenerator( } } } else { - val hasFloatingPointMembers = inputShape.members().any { - val target = model.expectShape(it.target) - (target is DoubleShape) || (target is FloatShape) - } + val hasFloatingPointMembers = + inputShape.members().any { + val target = model.expectShape(it.target) + (target is DoubleShape) || (target is FloatShape) + } // TODO(https://github.com/smithy-lang/smithy-rs/issues/1147) Handle the case of nested floating point members. if (hasFloatingPointMembers) { @@ -560,7 +589,10 @@ class ServerProtocolTestGenerator( } } - private fun checkResponse(rustWriter: RustWriter, testCase: HttpResponseTestCase) { + private fun checkResponse( + rustWriter: RustWriter, + testCase: HttpResponseTestCase, + ) { checkStatusCode(rustWriter, testCase.code) checkHeaders(rustWriter, "http_response.headers()", testCase.headers) checkForbidHeaders(rustWriter, "http_response.headers()", testCase.forbidHeaders) @@ -578,7 +610,10 @@ class ServerProtocolTestGenerator( } } - private fun checkResponse(rustWriter: RustWriter, testCase: HttpMalformedResponseDefinition) { + private fun checkResponse( + rustWriter: RustWriter, + testCase: HttpMalformedResponseDefinition, + ) { checkStatusCode(rustWriter, testCase.code) checkHeaders(rustWriter, "http_response.headers()", testCase.headers) @@ -610,7 +645,11 @@ class ServerProtocolTestGenerator( } } - private fun checkBody(rustWriter: RustWriter, body: String, mediaType: String?) { + private fun checkBody( + rustWriter: RustWriter, + body: String, + mediaType: String?, + ) { rustWriter.rustTemplate( """ let body = #{Hyper}::body::to_bytes(http_response.into_body()).await.expect("unable to extract body to bytes"); @@ -638,7 +677,10 @@ class ServerProtocolTestGenerator( } } - private fun checkStatusCode(rustWriter: RustWriter, statusCode: Int) { + private fun checkStatusCode( + rustWriter: RustWriter, + statusCode: Int, + ) { rustWriter.rustTemplate( """ #{AssertEq}( @@ -650,7 +692,11 @@ class ServerProtocolTestGenerator( ) } - private fun checkRequiredHeaders(rustWriter: RustWriter, actualExpression: String, requireHeaders: List) { + private fun checkRequiredHeaders( + rustWriter: RustWriter, + actualExpression: String, + requireHeaders: List, + ) { basicCheck( requireHeaders, rustWriter, @@ -660,7 +706,11 @@ class ServerProtocolTestGenerator( ) } - private fun checkForbidHeaders(rustWriter: RustWriter, actualExpression: String, forbidHeaders: List) { + private fun checkForbidHeaders( + rustWriter: RustWriter, + actualExpression: String, + forbidHeaders: List, + ) { basicCheck( forbidHeaders, rustWriter, @@ -670,7 +720,11 @@ class ServerProtocolTestGenerator( ) } - private fun checkHeaders(rustWriter: RustWriter, actualExpression: String, headers: Map) { + private fun checkHeaders( + rustWriter: RustWriter, + actualExpression: String, + headers: Map, + ) { if (headers.isEmpty()) { return } @@ -715,13 +769,19 @@ class ServerProtocolTestGenerator( * wraps `inner` in a call to `aws_smithy_protocol_test::assert_ok`, a convenience wrapper * for pretty printing protocol test helper results */ - private fun assertOk(rustWriter: RustWriter, inner: Writable) { + private fun assertOk( + rustWriter: RustWriter, + inner: Writable, + ) { rustWriter.rust("#T(", RuntimeType.protocolTest(codegenContext.runtimeConfig, "assert_ok")) inner(rustWriter) rustWriter.write(");") } - private fun strSlice(writer: RustWriter, args: List) { + private fun strSlice( + writer: RustWriter, + args: List, + ) { writer.withBlock("&[", "]") { rust(args.joinToString(",") { it.dq() }) } @@ -730,7 +790,9 @@ class ServerProtocolTestGenerator( companion object { sealed class TestType { object Request : TestType() + object Response : TestType() + object MalformedRequest : TestType() } @@ -741,114 +803,114 @@ class ServerProtocolTestGenerator( // it makes sense to do the simplest thing for now. // The test will _fail_ if these pass, so we will discover & remove if we fix them by accident private const val AwsJson11 = "aws.protocoltests.json#JsonProtocol" + private const val AwsJson10 = "aws.protocoltests.json10#JsonRpc10" private const val RestJson = "aws.protocoltests.restjson#RestJson" private const val RestJsonValidation = "aws.protocoltests.restjson.validation#RestJsonValidation" - private val ExpectFail: Set = setOf( - // Endpoint trait is not implemented yet, see https://github.com/smithy-lang/smithy-rs/issues/950. - FailingTest(RestJson, "RestJsonEndpointTrait", TestType.Request), - FailingTest(RestJson, "RestJsonEndpointTraitWithHostLabel", TestType.Request), - - FailingTest(RestJson, "RestJsonOmitsEmptyListQueryValues", TestType.Request), - // Tests involving `@range` on floats. - // Pending resolution from the Smithy team, see https://github.com/smithy-lang/smithy-rs/issues/2007. - FailingTest(RestJsonValidation, "RestJsonMalformedRangeFloat_case0", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedRangeFloat_case1", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedRangeMaxFloat", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedRangeMinFloat", TestType.MalformedRequest), - - // Tests involving floating point shapes and the `@range` trait; see https://github.com/smithy-lang/smithy-rs/issues/2007 - FailingTest(RestJsonValidation, "RestJsonMalformedRangeFloatOverride_case0", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedRangeFloatOverride_case1", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedRangeMaxFloatOverride", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedRangeMinFloatOverride", TestType.MalformedRequest), - - // Some tests for the S3 service (restXml). - FailingTest("com.amazonaws.s3#AmazonS3", "GetBucketLocationUnwrappedOutput", TestType.Response), - FailingTest("com.amazonaws.s3#AmazonS3", "S3DefaultAddressing", TestType.Request), - FailingTest("com.amazonaws.s3#AmazonS3", "S3VirtualHostAddressing", TestType.Request), - FailingTest("com.amazonaws.s3#AmazonS3", "S3PathAddressing", TestType.Request), - FailingTest("com.amazonaws.s3#AmazonS3", "S3VirtualHostDualstackAddressing", TestType.Request), - FailingTest("com.amazonaws.s3#AmazonS3", "S3VirtualHostAccelerateAddressing", TestType.Request), - FailingTest("com.amazonaws.s3#AmazonS3", "S3VirtualHostDualstackAccelerateAddressing", TestType.Request), - FailingTest("com.amazonaws.s3#AmazonS3", "S3OperationAddressingPreferred", TestType.Request), - FailingTest("com.amazonaws.s3#AmazonS3", "S3OperationNoErrorWrappingResponse", TestType.Response), - - // AwsJson1.0 failing tests. - FailingTest("aws.protocoltests.json10#JsonRpc10", "AwsJson10EndpointTraitWithHostLabel", TestType.Request), - FailingTest("aws.protocoltests.json10#JsonRpc10", "AwsJson10EndpointTrait", TestType.Request), - - // AwsJson1.1 failing tests. - FailingTest(AwsJson11, "AwsJson11EndpointTraitWithHostLabel", TestType.Request), - FailingTest(AwsJson11, "AwsJson11EndpointTrait", TestType.Request), - FailingTest(AwsJson11, "parses_the_request_id_from_the_response", TestType.Response), - - // TODO(https://github.com/awslabs/smithy/issues/1683): This has been marked as failing until resolution of said issue - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsBlobList", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsBooleanList_case0", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsBooleanList_case1", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsStringList", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsByteList", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsShortList", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsIntegerList", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsLongList", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsTimestampList", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsDateTimeList", TestType.MalformedRequest), - FailingTest( - RestJsonValidation, - "RestJsonMalformedUniqueItemsHttpDateList_case0", - TestType.MalformedRequest, - ), - FailingTest( - RestJsonValidation, - "RestJsonMalformedUniqueItemsHttpDateList_case1", - TestType.MalformedRequest, - ), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsEnumList", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsIntEnumList", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsListList", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsStructureList", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsUnionList_case0", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsUnionList_case1", TestType.MalformedRequest), - - // TODO(https://github.com/smithy-lang/smithy-rs/issues/2472): We don't respect the `@internal` trait - FailingTest(RestJsonValidation, "RestJsonMalformedEnumList_case0", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedEnumList_case1", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedEnumMapKey_case0", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedEnumMapKey_case1", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedEnumMapValue_case0", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedEnumMapValue_case1", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedEnumString_case0", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedEnumString_case1", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedEnumUnion_case0", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedEnumUnion_case1", TestType.MalformedRequest), - - // TODO(https://github.com/awslabs/smithy/issues/1737): Specs on @internal, @tags, and enum values need to be clarified - FailingTest(RestJsonValidation, "RestJsonMalformedEnumTraitString_case0", TestType.MalformedRequest), - FailingTest(RestJsonValidation, "RestJsonMalformedEnumTraitString_case1", TestType.MalformedRequest), - ) + private val ExpectFail: Set = + setOf( + // Endpoint trait is not implemented yet, see https://github.com/smithy-lang/smithy-rs/issues/950. + FailingTest(RestJson, "RestJsonEndpointTrait", TestType.Request), + FailingTest(RestJson, "RestJsonEndpointTraitWithHostLabel", TestType.Request), + FailingTest(RestJson, "RestJsonOmitsEmptyListQueryValues", TestType.Request), + // Tests involving `@range` on floats. + // Pending resolution from the Smithy team, see https://github.com/smithy-lang/smithy-rs/issues/2007. + FailingTest(RestJsonValidation, "RestJsonMalformedRangeFloat_case0", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedRangeFloat_case1", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedRangeMaxFloat", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedRangeMinFloat", TestType.MalformedRequest), + // Tests involving floating point shapes and the `@range` trait; see https://github.com/smithy-lang/smithy-rs/issues/2007 + FailingTest(RestJsonValidation, "RestJsonMalformedRangeFloatOverride_case0", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedRangeFloatOverride_case1", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedRangeMaxFloatOverride", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedRangeMinFloatOverride", TestType.MalformedRequest), + // Some tests for the S3 service (restXml). + FailingTest("com.amazonaws.s3#AmazonS3", "GetBucketLocationUnwrappedOutput", TestType.Response), + FailingTest("com.amazonaws.s3#AmazonS3", "S3DefaultAddressing", TestType.Request), + FailingTest("com.amazonaws.s3#AmazonS3", "S3VirtualHostAddressing", TestType.Request), + FailingTest("com.amazonaws.s3#AmazonS3", "S3PathAddressing", TestType.Request), + FailingTest("com.amazonaws.s3#AmazonS3", "S3VirtualHostDualstackAddressing", TestType.Request), + FailingTest("com.amazonaws.s3#AmazonS3", "S3VirtualHostAccelerateAddressing", TestType.Request), + FailingTest("com.amazonaws.s3#AmazonS3", "S3VirtualHostDualstackAccelerateAddressing", TestType.Request), + FailingTest("com.amazonaws.s3#AmazonS3", "S3OperationAddressingPreferred", TestType.Request), + FailingTest("com.amazonaws.s3#AmazonS3", "S3OperationNoErrorWrappingResponse", TestType.Response), + // AwsJson1.0 failing tests. + FailingTest("aws.protocoltests.json10#JsonRpc10", "AwsJson10EndpointTraitWithHostLabel", TestType.Request), + FailingTest("aws.protocoltests.json10#JsonRpc10", "AwsJson10EndpointTrait", TestType.Request), + // AwsJson1.1 failing tests. + FailingTest(AwsJson11, "AwsJson11EndpointTraitWithHostLabel", TestType.Request), + FailingTest(AwsJson11, "AwsJson11EndpointTrait", TestType.Request), + FailingTest(AwsJson11, "parses_the_request_id_from_the_response", TestType.Response), + // TODO(https://github.com/awslabs/smithy/issues/1683): This has been marked as failing until resolution of said issue + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsBlobList", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsBooleanList_case0", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsBooleanList_case1", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsStringList", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsByteList", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsShortList", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsIntegerList", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsLongList", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsTimestampList", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsDateTimeList", TestType.MalformedRequest), + FailingTest( + RestJsonValidation, + "RestJsonMalformedUniqueItemsHttpDateList_case0", + TestType.MalformedRequest, + ), + FailingTest( + RestJsonValidation, + "RestJsonMalformedUniqueItemsHttpDateList_case1", + TestType.MalformedRequest, + ), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsEnumList", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsIntEnumList", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsListList", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsStructureList", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsUnionList_case0", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedUniqueItemsUnionList_case1", TestType.MalformedRequest), + // TODO(https://github.com/smithy-lang/smithy-rs/issues/2472): We don't respect the `@internal` trait + FailingTest(RestJsonValidation, "RestJsonMalformedEnumList_case0", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedEnumList_case1", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedEnumMapKey_case0", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedEnumMapKey_case1", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedEnumMapValue_case0", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedEnumMapValue_case1", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedEnumString_case0", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedEnumString_case1", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedEnumUnion_case0", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedEnumUnion_case1", TestType.MalformedRequest), + // TODO(https://github.com/awslabs/smithy/issues/1737): Specs on @internal, @tags, and enum values need to be clarified + FailingTest(RestJsonValidation, "RestJsonMalformedEnumTraitString_case0", TestType.MalformedRequest), + FailingTest(RestJsonValidation, "RestJsonMalformedEnumTraitString_case1", TestType.MalformedRequest), + // These tests are broken because they are missing a target header + FailingTest(AwsJson10, "AwsJson10ServerPopulatesNestedDefaultsWhenMissingInRequestBody", TestType.Request), + FailingTest(AwsJson10, "AwsJson10ServerPopulatesDefaultsWhenMissingInRequestBody", TestType.Request), + // Response defaults are not set when builders are not used https://github.com/smithy-lang/smithy-rs/issues/3339 + FailingTest(AwsJson10, "AwsJson10ServerPopulatesDefaultsInResponseWhenMissingInParams", TestType.Response), + FailingTest(AwsJson10, "AwsJson10ServerPopulatesNestedDefaultValuesWhenMissingInInResponseParams", TestType.Response), + ) private val RunOnly: Set? = null // These tests are not even attempted to be generated, either because they will not compile // or because they are flaky - private val DisableTests = setOf( - // TODO(https://github.com/smithy-lang/smithy-rs/issues/2891): Implement support for `@requestCompression` - "SDKAppendedGzipAfterProvidedEncoding_restJson1", - "SDKAppendedGzipAfterProvidedEncoding_restXml", - "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsJson1_0", - "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsJson1_1", - "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsQuery", - "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_ec2Query", - "SDKAppliedContentEncoding_awsJson1_0", - "SDKAppliedContentEncoding_awsJson1_1", - "SDKAppliedContentEncoding_awsQuery", - "SDKAppliedContentEncoding_ec2Query", - "SDKAppliedContentEncoding_restJson1", - "SDKAppliedContentEncoding_restXml", - - // RestXml S3 tests that fail to compile - "S3EscapeObjectKeyInUriLabel", - "S3EscapePathObjectKeyInUriLabel", - ) + private val DisableTests = + setOf( + // TODO(https://github.com/smithy-lang/smithy-rs/issues/2891): Implement support for `@requestCompression` + "SDKAppendedGzipAfterProvidedEncoding_restJson1", + "SDKAppendedGzipAfterProvidedEncoding_restXml", + "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsJson1_0", + "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsJson1_1", + "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_awsQuery", + "SDKAppendsGzipAndIgnoresHttpProvidedEncoding_ec2Query", + "SDKAppliedContentEncoding_awsJson1_0", + "SDKAppliedContentEncoding_awsJson1_1", + "SDKAppliedContentEncoding_awsQuery", + "SDKAppliedContentEncoding_ec2Query", + "SDKAppliedContentEncoding_restJson1", + "SDKAppliedContentEncoding_restXml", + // RestXml S3 tests that fail to compile + "S3EscapeObjectKeyInUriLabel", + "S3EscapePathObjectKeyInUriLabel", + ) private fun fixRestJsonAllQueryStringTypes( testCase: HttpRequestTestCase, @@ -905,20 +967,23 @@ class ServerProtocolTestGenerator( ).build() // TODO(https://github.com/awslabs/smithy/issues/1506) - private fun fixRestJsonMalformedPatternReDOSString(testCase: HttpMalformedRequestTestCase): HttpMalformedRequestTestCase { + private fun fixRestJsonMalformedPatternReDOSString( + testCase: HttpMalformedRequestTestCase, + ): HttpMalformedRequestTestCase { val brokenResponse = testCase.response val brokenBody = brokenResponse.body.get() - val fixedBody = HttpMalformedResponseBodyDefinition.builder() - .mediaType(brokenBody.mediaType) - .contents( - """ - { - "message" : "1 validation error detected. Value at '/evilString' failed to satisfy constraint: Member must satisfy regular expression pattern: ^([0-9]+)+${'$'}", - "fieldList" : [{"message": "Value at '/evilString' failed to satisfy constraint: Member must satisfy regular expression pattern: ^([0-9]+)+${'$'}", "path": "/evilString"}] - } - """.trimIndent(), - ) - .build() + val fixedBody = + HttpMalformedResponseBodyDefinition.builder() + .mediaType(brokenBody.mediaType) + .contents( + """ + { + "message" : "1 validation error detected. Value at '/evilString' failed to satisfy constraint: Member must satisfy regular expression pattern: ^([0-9]+)+${'$'}", + "fieldList" : [{"message": "Value at '/evilString' failed to satisfy constraint: Member must satisfy regular expression pattern: ^([0-9]+)+${'$'}", "path": "/evilString"}] + } + """.trimIndent(), + ) + .build() return testCase.toBuilder() .response(brokenResponse.toBuilder().body(fixedBody).build()) @@ -930,7 +995,8 @@ class ServerProtocolTestGenerator( // advantage that once our upstream PRs get merged and we upgrade to the next Smithy release, our build will // fail and we will take notice to remove the fixes from `rest-json-extras.smithy`. This is exactly what the // client does. - private val BrokenMalformedRequestTests: Map, KFunction1> = + private val BrokenMalformedRequestTests: + Map, KFunction1> = // TODO(https://github.com/awslabs/smithy/issues/1506) mapOf( Pair( diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerAwsJson.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerAwsJson.kt index 549ca88b1ee..f967e9450d3 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerAwsJson.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerAwsJson.kt @@ -51,12 +51,12 @@ class ServerAwsJsonFactory( override fun support(): ProtocolSupport { return ProtocolSupport( - /* Client support */ + // Client support requestSerialization = false, requestBodySerialization = false, responseDeserialization = false, errorDeserialization = false, - /* Server support */ + // Server support requestDeserialization = true, requestBodyDeserialization = true, responseSerialization = true, @@ -78,23 +78,26 @@ class ServerAwsJsonFactory( * > field named __type */ class ServerAwsJsonError(private val awsJsonVersion: AwsJsonVersion) : JsonSerializerCustomization() { - override fun section(section: JsonSerializerSection): Writable = when (section) { - is JsonSerializerSection.ServerError -> writable { - if (section.structureShape.hasTrait()) { - val typeId = when (awsJsonVersion) { - // AwsJson 1.0 wants the whole shape ID (namespace#Shape). - // https://awslabs.github.io/smithy/1.0/spec/aws/aws-json-1_0-protocol.html#operation-error-serialization - AwsJsonVersion.Json10 -> section.structureShape.id.toString() - // AwsJson 1.1 wants only the shape name (Shape). - // https://awslabs.github.io/smithy/1.0/spec/aws/aws-json-1_1-protocol.html#operation-error-serialization - AwsJsonVersion.Json11 -> section.structureShape.id.name.toString() + override fun section(section: JsonSerializerSection): Writable = + when (section) { + is JsonSerializerSection.ServerError -> + writable { + if (section.structureShape.hasTrait()) { + val typeId = + when (awsJsonVersion) { + // AwsJson 1.0 wants the whole shape ID (namespace#Shape). + // https://awslabs.github.io/smithy/1.0/spec/aws/aws-json-1_0-protocol.html#operation-error-serialization + AwsJsonVersion.Json10 -> section.structureShape.id.toString() + // AwsJson 1.1 wants only the shape name (Shape). + // https://awslabs.github.io/smithy/1.0/spec/aws/aws-json-1_1-protocol.html#operation-error-serialization + AwsJsonVersion.Json11 -> section.structureShape.id.name.toString() + } + rust("""${section.jsonObject}.key("__type").string("${escape(typeId)}");""") + } } - rust("""${section.jsonObject}.key("__type").string("${escape(typeId)}");""") - } - } - else -> emptySection - } + else -> emptySection + } } /** @@ -112,10 +115,11 @@ class ServerAwsJsonSerializerGenerator( codegenContext, httpBindingResolver, ::awsJsonFieldName, - customizations = listOf( - ServerAwsJsonError(awsJsonVersion), - BeforeIteratingOverMapOrCollectionJsonCustomization(codegenContext), - BeforeSerializingMemberJsonCustomization(codegenContext), - ), + customizations = + listOf( + ServerAwsJsonError(awsJsonVersion), + BeforeIteratingOverMapOrCollectionJsonCustomization(codegenContext), + BeforeSerializingMemberJsonCustomization(codegenContext), + ), ), ) : StructuredDataSerializerGenerator by jsonSerializerGenerator diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt index 49ddcb03349..071b1095047 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpBoundProtocolGenerator.kt @@ -122,9 +122,9 @@ class ServerHttpBoundProtocolGenerator( customizations: List = listOf(), additionalHttpBindingCustomizations: List = listOf(), ) : ServerProtocolGenerator( - protocol, - ServerHttpBoundProtocolTraitImplGenerator(codegenContext, protocol, customizations, additionalHttpBindingCustomizations), -) { + protocol, + ServerHttpBoundProtocolTraitImplGenerator(codegenContext, protocol, customizations, additionalHttpBindingCustomizations), + ) { // Define suffixes for operation input / output / error wrappers companion object { const val OPERATION_INPUT_WRAPPER_SUFFIX = "OperationInputWrapper" @@ -136,26 +136,26 @@ class ServerHttpBoundProtocolPayloadGenerator( codegenContext: CodegenContext, protocol: Protocol, ) : ProtocolPayloadGenerator by HttpBoundProtocolPayloadGenerator( - codegenContext, protocol, HttpMessageType.RESPONSE, - renderEventStreamBody = { writer, params -> - writer.rustTemplate( - """ - { - let error_marshaller = #{errorMarshallerConstructorFn}(); - let marshaller = #{marshallerConstructorFn}(); - let signer = #{NoOpSigner}{}; - let adapter: #{aws_smithy_http}::event_stream::MessageStreamAdapter<_, _> = - ${params.outerName}.${params.memberName}.into_body_stream(marshaller, error_marshaller, signer); - adapter - } - """, - "aws_smithy_http" to RuntimeType.smithyHttp(codegenContext.runtimeConfig), - "NoOpSigner" to RuntimeType.smithyEventStream(codegenContext.runtimeConfig).resolve("frame::NoOpSigner"), - "marshallerConstructorFn" to params.marshallerConstructorFn, - "errorMarshallerConstructorFn" to params.errorMarshallerConstructorFn, - ) - }, -) + codegenContext, protocol, HttpMessageType.RESPONSE, + renderEventStreamBody = { writer, params -> + writer.rustTemplate( + """ + { + let error_marshaller = #{errorMarshallerConstructorFn}(); + let marshaller = #{marshallerConstructorFn}(); + let signer = #{NoOpSigner}{}; + let adapter: #{aws_smithy_http}::event_stream::MessageStreamAdapter<_, _> = + ${params.outerName}.${params.memberName}.into_body_stream(marshaller, error_marshaller, signer); + adapter + } + """, + "aws_smithy_http" to RuntimeType.smithyHttp(codegenContext.runtimeConfig), + "NoOpSigner" to RuntimeType.smithyEventStream(codegenContext.runtimeConfig).resolve("frame::NoOpSigner"), + "marshallerConstructorFn" to params.marshallerConstructorFn, + "errorMarshallerConstructorFn" to params.errorMarshallerConstructorFn, + ) + }, + ) /* * Generate all operation input parsers and output serializers for streaming and @@ -175,32 +175,36 @@ class ServerHttpBoundProtocolTraitImplGenerator( private val httpBindingResolver = protocol.httpBindingResolver private val protocolFunctions = ProtocolFunctions(codegenContext) - private val codegenScope = arrayOf( - "AsyncTrait" to ServerCargoDependency.AsyncTrait.toType(), - "Cow" to RuntimeType.Cow, - "DateTime" to RuntimeType.dateTime(runtimeConfig), - "FormUrlEncoded" to ServerCargoDependency.FormUrlEncoded.toType(), - "FuturesUtil" to ServerCargoDependency.FuturesUtil.toType(), - "HttpBody" to RuntimeType.HttpBody, - "header_util" to RuntimeType.smithyHttp(runtimeConfig).resolve("header"), - "Hyper" to RuntimeType.Hyper, - "LazyStatic" to RuntimeType.LazyStatic, - "Mime" to ServerCargoDependency.Mime.toType(), - "Nom" to ServerCargoDependency.Nom.toType(), - "OnceCell" to RuntimeType.OnceCell, - "PercentEncoding" to RuntimeType.PercentEncoding, - "Regex" to RuntimeType.Regex, - "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(runtimeConfig).toType(), - "SmithyTypes" to RuntimeType.smithyTypes(runtimeConfig), - "RuntimeError" to protocol.runtimeError(runtimeConfig), - "RequestRejection" to protocol.requestRejection(runtimeConfig), - "ResponseRejection" to protocol.responseRejection(runtimeConfig), - "PinProjectLite" to ServerCargoDependency.PinProjectLite.toType(), - "http" to RuntimeType.Http, - "Tracing" to RuntimeType.Tracing, - ) + private val codegenScope = + arrayOf( + "AsyncTrait" to ServerCargoDependency.AsyncTrait.toType(), + "Cow" to RuntimeType.Cow, + "DateTime" to RuntimeType.dateTime(runtimeConfig), + "FormUrlEncoded" to ServerCargoDependency.FormUrlEncoded.toType(), + "FuturesUtil" to ServerCargoDependency.FuturesUtil.toType(), + "HttpBody" to RuntimeType.HttpBody, + "header_util" to RuntimeType.smithyHttp(runtimeConfig).resolve("header"), + "Hyper" to RuntimeType.Hyper, + "LazyStatic" to RuntimeType.LazyStatic, + "Mime" to ServerCargoDependency.Mime.toType(), + "Nom" to ServerCargoDependency.Nom.toType(), + "OnceCell" to RuntimeType.OnceCell, + "PercentEncoding" to RuntimeType.PercentEncoding, + "Regex" to RuntimeType.Regex, + "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(runtimeConfig).toType(), + "SmithyTypes" to RuntimeType.smithyTypes(runtimeConfig), + "RuntimeError" to protocol.runtimeError(runtimeConfig), + "RequestRejection" to protocol.requestRejection(runtimeConfig), + "ResponseRejection" to protocol.responseRejection(runtimeConfig), + "PinProjectLite" to ServerCargoDependency.PinProjectLite.toType(), + "http" to RuntimeType.Http, + "Tracing" to RuntimeType.Tracing, + ) - fun generateTraitImpls(operationWriter: RustWriter, operationShape: OperationShape) { + fun generateTraitImpls( + operationWriter: RustWriter, + operationShape: OperationShape, + ) { val inputSymbol = symbolProvider.toSymbol(operationShape.inputShape(model)) val outputSymbol = symbolProvider.toSymbol(operationShape.outputShape(model)) @@ -223,62 +227,66 @@ class ServerHttpBoundProtocolTraitImplGenerator( ) { val operationName = symbolProvider.toSymbol(operationShape).name val staticContentType = "CONTENT_TYPE_${operationName.uppercase()}" - val verifyAcceptHeader = writable { - httpBindingResolver.responseContentType(operationShape)?.also { contentType -> - rustTemplate( - """ - if !#{SmithyHttpServer}::protocol::accept_header_classifier(request.headers(), &$staticContentType) { - return Err(#{RequestRejection}::NotAcceptable); - } - """, - *codegenScope, - ) - } - } - val verifyAcceptHeaderStaticContentTypeInit = writable { - httpBindingResolver.responseContentType(operationShape)?.also { contentType -> - val init = when (contentType) { - "application/json" -> "const $staticContentType: #{Mime}::Mime = #{Mime}::APPLICATION_JSON;" - "application/octet-stream" -> "const $staticContentType: #{Mime}::Mime = #{Mime}::APPLICATION_OCTET_STREAM;" - "application/x-www-form-urlencoded" -> "const $staticContentType: #{Mime}::Mime = #{Mime}::APPLICATION_WWW_FORM_URLENCODED;" - else -> - """ - static $staticContentType: #{OnceCell}::sync::Lazy<#{Mime}::Mime> = #{OnceCell}::sync::Lazy::new(|| { - ${contentType.dq()}.parse::<#{Mime}::Mime>().expect("BUG: MIME parsing failed, content_type is not valid") - }); + val verifyAcceptHeader = + writable { + httpBindingResolver.responseContentType(operationShape)?.also { contentType -> + rustTemplate( """ + if !#{SmithyHttpServer}::protocol::accept_header_classifier(request.headers(), &$staticContentType) { + return Err(#{RequestRejection}::NotAcceptable); + } + """, + *codegenScope, + ) + } + } + val verifyAcceptHeaderStaticContentTypeInit = + writable { + httpBindingResolver.responseContentType(operationShape)?.also { contentType -> + val init = + when (contentType) { + "application/json" -> "const $staticContentType: #{Mime}::Mime = #{Mime}::APPLICATION_JSON;" + "application/octet-stream" -> "const $staticContentType: #{Mime}::Mime = #{Mime}::APPLICATION_OCTET_STREAM;" + "application/x-www-form-urlencoded" -> "const $staticContentType: #{Mime}::Mime = #{Mime}::APPLICATION_WWW_FORM_URLENCODED;" + else -> + """ + static $staticContentType: #{OnceCell}::sync::Lazy<#{Mime}::Mime> = #{OnceCell}::sync::Lazy::new(|| { + ${contentType.dq()}.parse::<#{Mime}::Mime>().expect("BUG: MIME parsing failed, content_type is not valid") + }); + """ + } + rustTemplate(init, *codegenScope) } - rustTemplate(init, *codegenScope) } - } // This checks for the expected `Content-Type` header if the `@httpPayload` trait is present, as dictated by // the core Smithy library, which _does not_ require deserializing the payload. // If no members have `@httpPayload`, the expected `Content-Type` header as dictated _by the protocol_ is // checked later on for non-streaming operations, in `serverRenderShapeParser`: that check _does_ require at // least buffering the entire payload, since the check must only be performed if the payload is empty. - val verifyRequestContentTypeHeader = writable { - operationShape - .inputShape(model) - .members() - .find { it.hasTrait() } - ?.let { payload -> - val target = model.expectShape(payload.target) - if (!target.isBlobShape || target.hasTrait()) { - // `null` is only returned by Smithy when there are no members, but we know there's at least - // the one with `@httpPayload`, so `!!` is safe here. - val expectedRequestContentType = httpBindingResolver.requestContentType(operationShape)!! - rustTemplate( - """ - #{SmithyHttpServer}::protocol::content_type_header_classifier_http( - request.headers(), - Some("$expectedRequestContentType"), - )?; - """, - *codegenScope, - ) + val verifyRequestContentTypeHeader = + writable { + operationShape + .inputShape(model) + .members() + .find { it.hasTrait() } + ?.let { payload -> + val target = model.expectShape(payload.target) + if (!target.isBlobShape || target.hasTrait()) { + // `null` is only returned by Smithy when there are no members, but we know there's at least + // the one with `@httpPayload`, so `!!` is safe here. + val expectedRequestContentType = httpBindingResolver.requestContentType(operationShape)!! + rustTemplate( + """ + #{SmithyHttpServer}::protocol::content_type_header_classifier_http( + request.headers(), + Some("$expectedRequestContentType"), + )?; + """, + *codegenScope, + ) + } } - } - } + } // Implement `from_request` trait for input types. val inputFuture = "${inputSymbol.name}Future" @@ -542,10 +550,11 @@ class ServerHttpBoundProtocolTraitImplGenerator( rustTemplate("let mut builder = #{http}::Response::builder();", *codegenScope) serverRenderResponseHeaders(operationShape) // Fallback to the default code of `@http`, which should be 200. - val httpTraitDefaultStatusCode = HttpTrait - .builder().method("GET").uri(UriPattern.parse("/")) /* Required to build */ - .build() - .code + val httpTraitDefaultStatusCode = + HttpTrait + .builder().method("GET").uri(UriPattern.parse("/")) // Required to build + .build() + .code check(httpTraitDefaultStatusCode == 200) val httpTraitStatusCode = operationShape.getTrait()?.code ?: httpTraitDefaultStatusCode bindings.find { it.location == HttpLocation.RESPONSE_CODE } @@ -605,7 +614,10 @@ class ServerHttpBoundProtocolTraitImplGenerator( * 2. The protocol-specific `Content-Type` header for the operation. * 3. Additional protocol-specific headers for errors, if [errorShape] is non-null. */ - private fun RustWriter.serverRenderResponseHeaders(operationShape: OperationShape, errorShape: StructureShape? = null) { + private fun RustWriter.serverRenderResponseHeaders( + operationShape: OperationShape, + errorShape: StructureShape? = null, + ) { val bindingGenerator = ServerResponseBindingGenerator(protocol, codegenContext, operationShape) val addHeadersFn = bindingGenerator.generateAddHeadersFn(errorShape ?: operationShape) if (addHeadersFn != null) { @@ -669,21 +681,22 @@ class ServerHttpBoundProtocolTraitImplGenerator( ) } - private fun serverRenderHttpResponseCode(defaultCode: Int) = writable { - check(defaultCode in 100..999) { - """ - Smithy library lied to us. According to https://smithy.io/2.0/spec/http-bindings.html#http-trait, - "The provided value SHOULD be between 100 and 599, and it MUST be between 100 and 999". - """.replace("\n", "").trimIndent() + private fun serverRenderHttpResponseCode(defaultCode: Int) = + writable { + check(defaultCode in 100..999) { + """ + Smithy library lied to us. According to https://smithy.io/2.0/spec/http-bindings.html#http-trait, + "The provided value SHOULD be between 100 and 599, and it MUST be between 100 and 999". + """.replace("\n", "").trimIndent() + } + rustTemplate( + """ + let http_status: u16 = $defaultCode; + builder = builder.status(http_status); + """, + *codegenScope, + ) } - rustTemplate( - """ - let http_status: u16 = $defaultCode; - builder = builder.status(http_status); - """, - *codegenScope, - ) - } private fun serverRenderResponseCodeBinding( binding: HttpBindingDescriptor, @@ -715,7 +728,8 @@ class ServerHttpBoundProtocolTraitImplGenerator( inputShape: StructureShape, bindings: List, ) { - val httpBindingGenerator = ServerRequestBindingGenerator(protocol, codegenContext, operationShape, additionalHttpBindingCustomizations) + val httpBindingGenerator = + ServerRequestBindingGenerator(protocol, codegenContext, operationShape, additionalHttpBindingCustomizations) val structuredDataParser = protocol.structuredDataParser() Attribute.AllowUnusedMut.render(this) rust( @@ -756,7 +770,8 @@ class ServerHttpBoundProtocolTraitImplGenerator( } for (binding in bindings) { val member = binding.member - val parsedValue = serverRenderBindingParser(binding, operationShape, httpBindingGenerator, structuredDataParser) + val parsedValue = + serverRenderBindingParser(binding, operationShape, httpBindingGenerator, structuredDataParser) if (parsedValue != null) { rust("if let Some(value) = ") parsedValue(this) @@ -788,17 +803,18 @@ class ServerHttpBoundProtocolTraitImplGenerator( ) } } - val err = if (ServerBuilderGenerator.hasFallibleBuilder( - inputShape, - model, - symbolProvider, - takeInUnconstrainedTypes = true, - ) - ) { - "?" - } else { - "" - } + val err = + if (ServerBuilderGenerator.hasFallibleBuilder( + inputShape, + model, + symbolProvider, + takeInUnconstrainedTypes = true, + ) + ) { + "?" + } else { + "" + } rustTemplate("input.build()$err", *codegenScope) } @@ -816,11 +832,12 @@ class ServerHttpBoundProtocolTraitImplGenerator( rust("#T($body)", structuredDataParser.payloadParser(binding.member)) } val errorSymbol = getDeserializePayloadErrorSymbol(binding) - val deserializer = httpBindingGenerator.generateDeserializePayloadFn( - binding, - errorSymbol, - structuredHandler = structureShapeHandler, - ) + val deserializer = + httpBindingGenerator.generateDeserializePayloadFn( + binding, + errorSymbol, + structuredHandler = structureShapeHandler, + ) return writable { if (binding.member.isStreaming(model)) { rustTemplate( @@ -857,7 +874,10 @@ class ServerHttpBoundProtocolTraitImplGenerator( } } - private fun serverRenderUriPathParser(writer: RustWriter, operationShape: OperationShape) { + private fun serverRenderUriPathParser( + writer: RustWriter, + operationShape: OperationShape, + ) { val pathBindings = httpBindingResolver.requestBindings(operationShape).filter { it.location == HttpLocation.LABEL @@ -879,31 +899,37 @@ class ServerHttpBoundProtocolTraitImplGenerator( } else { "" } - val labeledNames = segments - .mapIndexed { index, segment -> - if (segment.isLabel) { "m$index" } else { "_" } - } - .joinToString(prefix = (if (segments.size > 1) "(" else ""), separator = ",", postfix = (if (segments.size > 1) ")" else "")) - val nomParser = segments - .map { segment -> - if (segment.isGreedyLabel) { - "#{Nom}::combinator::rest::<_, #{Nom}::error::Error<&str>>" - } else if (segment.isLabel) { - """#{Nom}::branch::alt::<_, _, #{Nom}::error::Error<&str>, _>((#{Nom}::bytes::complete::take_until("/"), #{Nom}::combinator::rest))""" - } else { - """#{Nom}::bytes::complete::tag::<_, _, #{Nom}::error::Error<&str>>("${segment.content}")""" + val labeledNames = + segments + .mapIndexed { index, segment -> + if (segment.isLabel) { + "m$index" + } else { + "_" + } } - } - .joinToString( - // TODO(https://github.com/smithy-lang/smithy-rs/issues/1289): Note we're limited to 21 labels because of `tuple`. - prefix = if (segments.size > 1) "#{Nom}::sequence::tuple::<_, _, #{Nom}::error::Error<&str>, _>((" else "", - postfix = if (segments.size > 1) "))" else "", - transform = { parser -> - """ - #{Nom}::sequence::preceded(#{Nom}::bytes::complete::tag("/"), $parser) - """.trimIndent() - }, - ) + .joinToString(prefix = (if (segments.size > 1) "(" else ""), separator = ",", postfix = (if (segments.size > 1) ")" else "")) + val nomParser = + segments + .map { segment -> + if (segment.isGreedyLabel) { + "#{Nom}::combinator::rest::<_, #{Nom}::error::Error<&str>>" + } else if (segment.isLabel) { + """#{Nom}::branch::alt::<_, _, #{Nom}::error::Error<&str>, _>((#{Nom}::bytes::complete::take_until("/"), #{Nom}::combinator::rest))""" + } else { + """#{Nom}::bytes::complete::tag::<_, _, #{Nom}::error::Error<&str>>("${segment.content}")""" + } + } + .joinToString( + // TODO(https://github.com/smithy-lang/smithy-rs/issues/1289): Note we're limited to 21 labels because of `tuple`. + prefix = if (segments.size > 1) "#{Nom}::sequence::tuple::<_, _, #{Nom}::error::Error<&str>, _>((" else "", + postfix = if (segments.size > 1) "))" else "", + transform = { parser -> + """ + #{Nom}::sequence::preceded(#{Nom}::bytes::complete::tag("/"), $parser) + """.trimIndent() + }, + ) with(writer) { rustTemplate("let input_string = uri.path();") if (greedyLabelIndex >= 0 && greedyLabelIndex + 1 < httpTrait.uri.segments.size) { @@ -948,7 +974,9 @@ class ServerHttpBoundProtocolTraitImplGenerator( // * a map of list of string; or // * a map of set of string. enum class QueryParamsTargetMapValueType { - STRING, LIST, SET + STRING, + LIST, + SET, } private fun queryParamsTargetMapValueType(targetMapValue: Shape): QueryParamsTargetMapValueType = @@ -967,7 +995,10 @@ class ServerHttpBoundProtocolTraitImplGenerator( ) } - private fun serverRenderQueryStringParser(writer: RustWriter, operationShape: OperationShape) { + private fun serverRenderQueryStringParser( + writer: RustWriter, + operationShape: OperationShape, + ) { val queryBindings = httpBindingResolver.requestBindings(operationShape).filter { it.location == HttpLocation.QUERY @@ -1156,8 +1187,13 @@ class ServerHttpBoundProtocolTraitImplGenerator( } } - private fun serverRenderHeaderParser(writer: RustWriter, binding: HttpBindingDescriptor, operationShape: OperationShape) { - val httpBindingGenerator = ServerRequestBindingGenerator(protocol, codegenContext, operationShape, additionalHttpBindingCustomizations) + private fun serverRenderHeaderParser( + writer: RustWriter, + binding: HttpBindingDescriptor, + operationShape: OperationShape, + ) { + val httpBindingGenerator = + ServerRequestBindingGenerator(protocol, codegenContext, operationShape, additionalHttpBindingCustomizations) val deserializer = httpBindingGenerator.generateDeserializeHeaderFn(binding) writer.rustTemplate( """ @@ -1168,7 +1204,11 @@ class ServerHttpBoundProtocolTraitImplGenerator( ) } - private fun serverRenderPrefixHeadersParser(writer: RustWriter, binding: HttpBindingDescriptor, operationShape: OperationShape) { + private fun serverRenderPrefixHeadersParser( + writer: RustWriter, + binding: HttpBindingDescriptor, + operationShape: OperationShape, + ) { check(binding.location == HttpLocation.PREFIX_HEADERS) val httpBindingGenerator = ServerRequestBindingGenerator(protocol, codegenContext, operationShape) @@ -1182,7 +1222,10 @@ class ServerHttpBoundProtocolTraitImplGenerator( ) } - private fun generateParseStrFn(binding: HttpBindingDescriptor, percentDecoding: Boolean): RuntimeType { + private fun generateParseStrFn( + binding: HttpBindingDescriptor, + percentDecoding: Boolean, + ): RuntimeType { val output = unconstrainedShapeSymbolProvider.toSymbol(binding.member) return protocolFunctions.deserializeFn(binding.member) { fnName -> rustBlockTemplate( diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerProtocolLoader.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerProtocolLoader.kt index a72ad201c0d..ae87ec5723b 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerProtocolLoader.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerProtocolLoader.kt @@ -21,56 +21,64 @@ import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenContext import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.ServerProtocolGenerator class StreamPayloadSerializerCustomization() : ServerHttpBoundProtocolCustomization() { - override fun section(section: ServerHttpBoundProtocolSection): Writable = when (section) { - is ServerHttpBoundProtocolSection.WrapStreamPayload -> writable { - if (section.params.shape.isOutputEventStream(section.params.codegenContext.model)) { - // Event stream payload, of type `aws_smithy_http::event_stream::MessageStreamAdapter`, already - // implements the `Stream` trait, so no need to wrap it in the new-type. - section.params.payloadGenerator.generatePayload(this, section.params.shapeName, section.params.shape) - } else { - // Otherwise, the stream payload is `aws_smithy_types::byte_stream::ByteStream`. We wrap it in the - // new-type to enable the `Stream` trait. - withBlockTemplate( - "#{FuturesStreamCompatByteStream}::new(", - ")", - "FuturesStreamCompatByteStream" to RuntimeType.futuresStreamCompatByteStream(section.params.codegenContext.runtimeConfig), - ) { - section.params.payloadGenerator.generatePayload( - this, - section.params.shapeName, - section.params.shape, - ) + override fun section(section: ServerHttpBoundProtocolSection): Writable = + when (section) { + is ServerHttpBoundProtocolSection.WrapStreamPayload -> + writable { + if (section.params.shape.isOutputEventStream(section.params.codegenContext.model)) { + // Event stream payload, of type `aws_smithy_http::event_stream::MessageStreamAdapter`, already + // implements the `Stream` trait, so no need to wrap it in the new-type. + section.params.payloadGenerator.generatePayload(this, section.params.shapeName, section.params.shape) + } else { + // Otherwise, the stream payload is `aws_smithy_types::byte_stream::ByteStream`. We wrap it in the + // new-type to enable the `Stream` trait. + withBlockTemplate( + "#{FuturesStreamCompatByteStream}::new(", + ")", + "FuturesStreamCompatByteStream" to RuntimeType.futuresStreamCompatByteStream(section.params.codegenContext.runtimeConfig), + ) { + section.params.payloadGenerator.generatePayload( + this, + section.params.shapeName, + section.params.shape, + ) + } + } } - } - } - else -> emptySection - } + else -> emptySection + } } class ServerProtocolLoader(supportedProtocols: ProtocolMap) : ProtocolLoader(supportedProtocols) { - companion object { - val DefaultProtocols = mapOf( - RestJson1Trait.ID to ServerRestJsonFactory( - additionalServerHttpBoundProtocolCustomizations = listOf( - StreamPayloadSerializerCustomization(), - ), - ), - RestXmlTrait.ID to ServerRestXmlFactory( - additionalServerHttpBoundProtocolCustomizations = listOf( - StreamPayloadSerializerCustomization(), - ), - ), - AwsJson1_0Trait.ID to ServerAwsJsonFactory( - AwsJsonVersion.Json10, - additionalServerHttpBoundProtocolCustomizations = listOf(StreamPayloadSerializerCustomization()), - ), - AwsJson1_1Trait.ID to ServerAwsJsonFactory( - AwsJsonVersion.Json11, - additionalServerHttpBoundProtocolCustomizations = listOf(StreamPayloadSerializerCustomization()), - ), - ) + val DefaultProtocols = + mapOf( + RestJson1Trait.ID to + ServerRestJsonFactory( + additionalServerHttpBoundProtocolCustomizations = + listOf( + StreamPayloadSerializerCustomization(), + ), + ), + RestXmlTrait.ID to + ServerRestXmlFactory( + additionalServerHttpBoundProtocolCustomizations = + listOf( + StreamPayloadSerializerCustomization(), + ), + ), + AwsJson1_0Trait.ID to + ServerAwsJsonFactory( + AwsJsonVersion.Json10, + additionalServerHttpBoundProtocolCustomizations = listOf(StreamPayloadSerializerCustomization()), + ), + AwsJson1_1Trait.ID to + ServerAwsJsonFactory( + AwsJsonVersion.Json11, + additionalServerHttpBoundProtocolCustomizations = listOf(StreamPayloadSerializerCustomization()), + ), + ) } } diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestJson.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestJson.kt index ddf1ca08c33..5810081df52 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestJson.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestJson.kt @@ -28,7 +28,8 @@ class ServerRestJsonFactory( private val additionalServerHttpBoundProtocolCustomizations: List = listOf(), private val additionalHttpBindingCustomizations: List = listOf(), ) : ProtocolGeneratorFactory { - override fun protocol(codegenContext: ServerCodegenContext): Protocol = ServerRestJsonProtocol(codegenContext, additionalParserCustomizations) + override fun protocol(codegenContext: ServerCodegenContext): Protocol = + ServerRestJsonProtocol(codegenContext, additionalParserCustomizations) override fun buildProtocolGenerator(codegenContext: ServerCodegenContext): ServerHttpBoundProtocolGenerator = ServerHttpBoundProtocolGenerator( @@ -43,12 +44,12 @@ class ServerRestJsonFactory( override fun support(): ProtocolSupport { return ProtocolSupport( - /* Client support */ + // Client support requestSerialization = false, requestBodySerialization = false, responseDeserialization = false, errorDeserialization = false, - /* Server support */ + // Server support requestDeserialization = true, requestBodyDeserialization = true, responseSerialization = true, @@ -65,9 +66,10 @@ class ServerRestJsonSerializerGenerator( codegenContext, httpBindingResolver, ::restJsonFieldName, - customizations = listOf( - BeforeIteratingOverMapOrCollectionJsonCustomization(codegenContext), - BeforeSerializingMemberJsonCustomization(codegenContext), - ), + customizations = + listOf( + BeforeIteratingOverMapOrCollectionJsonCustomization(codegenContext), + BeforeSerializingMemberJsonCustomization(codegenContext), + ), ), ) : StructuredDataSerializerGenerator by jsonSerializerGenerator diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestXmlFactory.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestXmlFactory.kt index 9207c56046e..7ef7566a6f2 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestXmlFactory.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestXmlFactory.kt @@ -29,12 +29,12 @@ class ServerRestXmlFactory( override fun support(): ProtocolSupport { return ProtocolSupport( - /* Client support */ + // Client support requestSerialization = false, requestBodySerialization = false, responseDeserialization = false, errorDeserialization = false, - /* Server support */ + // Server support requestDeserialization = true, requestBodyDeserialization = true, responseSerialization = true, diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerCodegenIntegrationTest.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerCodegenIntegrationTest.kt index fc83f1392b0..8c0254904e8 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerCodegenIntegrationTest.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerCodegenIntegrationTest.kt @@ -27,16 +27,20 @@ fun serverIntegrationTest( test: (ServerCodegenContext, RustCrate) -> Unit = { _, _ -> }, ): Path { fun invokeRustCodegenPlugin(ctx: PluginContext) { - val codegenDecorator = object : ServerCodegenDecorator { - override val name: String = "Add tests" - override val order: Byte = 0 - - override fun classpathDiscoverable(): Boolean = false - - override fun extras(codegenContext: ServerCodegenContext, rustCrate: RustCrate) { - test(codegenContext, rustCrate) + val codegenDecorator = + object : ServerCodegenDecorator { + override val name: String = "Add tests" + override val order: Byte = 0 + + override fun classpathDiscoverable(): Boolean = false + + override fun extras( + codegenContext: ServerCodegenContext, + rustCrate: RustCrate, + ) { + test(codegenContext, rustCrate) + } } - } RustServerCodegenPlugin().executeWithDecorator(ctx, codegenDecorator, *additionalDecorators.toTypedArray()) } return codegenIntegrationTest(model, params, invokePlugin = ::invokeRustCodegenPlugin) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerTestHelpers.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerTestHelpers.kt index f161282242a..03643d80a80 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerTestHelpers.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/testutil/ServerTestHelpers.kt @@ -35,38 +35,40 @@ import software.amazon.smithy.rust.codegen.server.smithy.generators.protocol.Ser import software.amazon.smithy.rust.codegen.server.smithy.protocols.ServerProtocolLoader // These are the settings we default to if the user does not override them in their `smithy-build.json`. -val ServerTestRustSymbolProviderConfig = RustSymbolProviderConfig( - runtimeConfig = TestRuntimeConfig, - renameExceptions = false, - nullabilityCheckMode = NullableIndex.CheckMode.SERVER, - moduleProvider = ServerModuleProvider, -) +val ServerTestRustSymbolProviderConfig = + RustSymbolProviderConfig( + runtimeConfig = TestRuntimeConfig, + renameExceptions = false, + nullabilityCheckMode = NullableIndex.CheckMode.SERVER, + moduleProvider = ServerModuleProvider, + ) private fun testServiceShapeFor(model: Model) = model.serviceShapes.firstOrNull() ?: ServiceShape.builder().version("test").id("test#Service").build() -fun serverTestSymbolProvider(model: Model, serviceShape: ServiceShape? = null) = - serverTestSymbolProviders(model, serviceShape).symbolProvider +fun serverTestSymbolProvider( + model: Model, + serviceShape: ServiceShape? = null, +) = serverTestSymbolProviders(model, serviceShape).symbolProvider fun serverTestSymbolProviders( model: Model, serviceShape: ServiceShape? = null, settings: ServerRustSettings? = null, decorators: List = emptyList(), -) = - ServerSymbolProviders.from( - serverTestRustSettings(), - model, - serviceShape ?: testServiceShapeFor(model), - ServerTestRustSymbolProviderConfig, - ( - settings ?: serverTestRustSettings( - (serviceShape ?: testServiceShapeFor(model)).id, - ) - ).codegenConfig.publicConstrainedTypes, - CombinedServerCodegenDecorator(decorators), - RustServerCodegenPlugin::baseSymbolProvider, - ) +) = ServerSymbolProviders.from( + serverTestRustSettings(), + model, + serviceShape ?: testServiceShapeFor(model), + ServerTestRustSymbolProviderConfig, + ( + settings ?: serverTestRustSettings( + (serviceShape ?: testServiceShapeFor(model)).id, + ) + ).codegenConfig.publicConstrainedTypes, + CombinedServerCodegenDecorator(decorators), + RustServerCodegenPlugin::baseSymbolProvider, +) fun serverTestRustSettings( service: ShapeId = ShapeId.from("notrelevant#notrelevant"), @@ -103,15 +105,16 @@ fun serverTestCodegenContext( ): ServerCodegenContext { val service = serviceShape ?: testServiceShapeFor(model) val protocol = protocolShapeId ?: ShapeId.from("test#Protocol") - val serverSymbolProviders = ServerSymbolProviders.from( - settings, - model, - service, - ServerTestRustSymbolProviderConfig, - settings.codegenConfig.publicConstrainedTypes, - CombinedServerCodegenDecorator(decorators), - RustServerCodegenPlugin::baseSymbolProvider, - ) + val serverSymbolProviders = + ServerSymbolProviders.from( + settings, + model, + service, + ServerTestRustSymbolProviderConfig, + settings.codegenConfig.publicConstrainedTypes, + CombinedServerCodegenDecorator(decorators), + RustServerCodegenPlugin::baseSymbolProvider, + ) return ServerCodegenContext( model, @@ -148,12 +151,13 @@ fun StructureShape.serverRenderWithModelBuilder( val serverCodegenContext = serverTestCodegenContext(model) // Note that this always uses `ServerBuilderGenerator` and _not_ `ServerBuilderGeneratorWithoutPublicConstrainedTypes`, // regardless of the `publicConstrainedTypes` setting. - val modelBuilder = ServerBuilderGenerator( - serverCodegenContext, - this, - SmithyValidationExceptionConversionGenerator(serverCodegenContext), - protocol ?: loadServerProtocol(model), - ) + val modelBuilder = + ServerBuilderGenerator( + serverCodegenContext, + this, + SmithyValidationExceptionConversionGenerator(serverCodegenContext), + protocol ?: loadServerProtocol(model), + ) modelBuilder.render(rustCrate, writer) writer.implBlock(symbolProvider.toSymbol(this)) { modelBuilder.renderConvenienceMethod(this) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/traits/ConstraintViolationRustBoxTrait.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/traits/ConstraintViolationRustBoxTrait.kt index 9aee2b884ef..73574328897 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/traits/ConstraintViolationRustBoxTrait.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/traits/ConstraintViolationRustBoxTrait.kt @@ -19,6 +19,7 @@ import software.amazon.smithy.model.traits.Trait */ class ConstraintViolationRustBoxTrait : Trait { val ID = ShapeId.from("software.amazon.smithy.rust.codegen.smithy.rust.synthetic#constraintViolationBox") + override fun toNode(): Node = Node.objectNode() override fun toShapeId(): ShapeId = ID diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/traits/ShapeReachableFromOperationInputTagTrait.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/traits/ShapeReachableFromOperationInputTagTrait.kt index d3684687fe3..b44dc44b840 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/traits/ShapeReachableFromOperationInputTagTrait.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/traits/ShapeReachableFromOperationInputTagTrait.kt @@ -35,19 +35,27 @@ class ShapeReachableFromOperationInputTagTrait : AnnotationTrait(ID, Node.object } } -private fun isShapeReachableFromOperationInput(shape: Shape) = when (shape) { - is StructureShape, is UnionShape, is MapShape, is ListShape, is StringShape, is IntegerShape, is ShortShape, is LongShape, is ByteShape, is BlobShape -> { - shape.hasTrait() - } +private fun isShapeReachableFromOperationInput(shape: Shape) = + when (shape) { + is StructureShape, is UnionShape, is MapShape, is ListShape, is StringShape, is IntegerShape, is ShortShape, is LongShape, is ByteShape, is BlobShape -> { + shape.hasTrait() + } - else -> PANIC("this method does not support shape type ${shape.type}") -} + else -> PANIC("this method does not support shape type ${shape.type}") + } fun StringShape.isReachableFromOperationInput() = isShapeReachableFromOperationInput(this) + fun StructureShape.isReachableFromOperationInput() = isShapeReachableFromOperationInput(this) + fun CollectionShape.isReachableFromOperationInput() = isShapeReachableFromOperationInput(this) + fun UnionShape.isReachableFromOperationInput() = isShapeReachableFromOperationInput(this) + fun MapShape.isReachableFromOperationInput() = isShapeReachableFromOperationInput(this) + fun IntegerShape.isReachableFromOperationInput() = isShapeReachableFromOperationInput(this) + fun NumberShape.isReachableFromOperationInput() = isShapeReachableFromOperationInput(this) + fun BlobShape.isReachableFromOperationInput() = isShapeReachableFromOperationInput(this) diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/AttachValidationExceptionToConstrainedOperationInputsInAllowList.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/AttachValidationExceptionToConstrainedOperationInputsInAllowList.kt index 93bc55df128..18baaadf221 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/AttachValidationExceptionToConstrainedOperationInputsInAllowList.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/AttachValidationExceptionToConstrainedOperationInputsInAllowList.kt @@ -40,7 +40,6 @@ object AttachValidationExceptionToConstrainedOperationInputsInAllowList { ShapeId.from("aws.protocoltests.json#JsonProtocol"), ShapeId.from("com.amazonaws.s3#AmazonS3"), ShapeId.from("com.amazonaws.ebs#Ebs"), - // These are only loaded in the classpath and need this model transformer, but we don't generate server // SDKs for them. Here they are for reference. // ShapeId.from("aws.protocoltests.restxml#RestXml"), @@ -52,16 +51,17 @@ object AttachValidationExceptionToConstrainedOperationInputsInAllowList { fun transform(model: Model): Model { val walker = DirectedWalker(model) - val operationsWithConstrainedInputWithoutValidationException = model.serviceShapes - .filter { sherviceShapeIdAllowList.contains(it.toShapeId()) } - .flatMap { it.operations } - .map { model.expectShape(it, OperationShape::class.java) } - .filter { operationShape -> - // Walk the shapes reachable via this operation input. - walker.walkShapes(operationShape.inputShape(model)) - .any { it is SetShape || it is EnumShape || it.hasConstraintTrait() } - } - .filter { !it.errors.contains(SmithyValidationExceptionConversionGenerator.SHAPE_ID) } + val operationsWithConstrainedInputWithoutValidationException = + model.serviceShapes + .filter { sherviceShapeIdAllowList.contains(it.toShapeId()) } + .flatMap { it.operations } + .map { model.expectShape(it, OperationShape::class.java) } + .filter { operationShape -> + // Walk the shapes reachable via this operation input. + walker.walkShapes(operationShape.inputShape(model)) + .any { it is SetShape || it is EnumShape || it.hasConstraintTrait() } + } + .filter { !it.errors.contains(SmithyValidationExceptionConversionGenerator.SHAPE_ID) } return ModelTransformer.create().mapShapes(model) { shape -> if (shape is OperationShape && operationsWithConstrainedInputWithoutValidationException.contains(shape)) { diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/ConstrainedMemberTransform.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/ConstrainedMemberTransform.kt index 3ab99ce64db..c3540b273a0 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/ConstrainedMemberTransform.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/ConstrainedMemberTransform.kt @@ -26,7 +26,7 @@ import software.amazon.smithy.rust.codegen.server.smithy.allConstraintTraits import software.amazon.smithy.rust.codegen.server.smithy.traits.SyntheticStructureFromConstrainedMemberTrait import software.amazon.smithy.utils.ToSmithyBuilder import java.lang.IllegalStateException -import java.util.* +import java.util.Locale /** * Transforms all member shapes that have constraints on them into equivalent non-constrained @@ -69,8 +69,7 @@ object ConstrainedMemberTransform { private val memberConstraintTraitsToOverride = allConstraintTraits - RequiredTrait::class.java - private fun Shape.hasMemberConstraintTrait() = - memberConstraintTraitsToOverride.any(this::hasTrait) + private fun Shape.hasMemberConstraintTrait() = memberConstraintTraitsToOverride.any(this::hasTrait) fun transform(model: Model): Model { val additionalNames = HashSet() @@ -81,20 +80,21 @@ object ConstrainedMemberTransform { // convert them into non-constrained members and then pass them to the transformer. // The transformer will add new shapes, and will replace existing member shapes' target // with the newly added shapes. - val transformations = model.operationShapes - .flatMap { listOfNotNull(it.input.orNull(), it.output.orNull()) + it.errors } - .mapNotNull { model.expectShape(it).asStructureShape().orElse(null) } - .filter { it.hasTrait(SyntheticInputTrait.ID) || it.hasTrait(SyntheticOutputTrait.ID) } - .flatMap { walker.walkShapes(it) } - .filter { it is StructureShape || it is ListShape || it is UnionShape || it is MapShape } - .flatMap { it.constrainedMembers() } - .mapNotNull { - val transformation = it.makeNonConstrained(model, additionalNames) - // Keep record of new names that have been generated to ensure none of them regenerated. - additionalNames.add(transformation.newShape.id) - - transformation - } + val transformations = + model.operationShapes + .flatMap { listOfNotNull(it.input.orNull(), it.output.orNull()) + it.errors } + .mapNotNull { model.expectShape(it).asStructureShape().orElse(null) } + .filter { it.hasTrait(SyntheticInputTrait.ID) || it.hasTrait(SyntheticOutputTrait.ID) } + .flatMap { walker.walkShapes(it) } + .filter { it is StructureShape || it is ListShape || it is UnionShape || it is MapShape } + .flatMap { it.constrainedMembers() } + .mapNotNull { + val transformation = it.makeNonConstrained(model, additionalNames) + // Keep record of new names that have been generated to ensure none of them regenerated. + additionalNames.add(transformation.newShape.id) + + transformation + } return applyTransformations(model, transformations) } @@ -108,15 +108,16 @@ object ConstrainedMemberTransform { ): Model { val modelBuilder = model.toBuilder() - val memberShapesToReplace = transformations.map { - // Add the new shape to the model. - modelBuilder.addShape(it.newShape) + val memberShapesToReplace = + transformations.map { + // Add the new shape to the model. + modelBuilder.addShape(it.newShape) - it.memberToChange.toBuilder() - .target(it.newShape.id) - .traits(it.traitsToKeep) - .build() - } + it.memberToChange.toBuilder() + .target(it.newShape.id) + .traits(it.traitsToKeep) + .build() + } // Change all original constrained member shapes with the new standalone shapes. return ModelTransformer.create() @@ -140,14 +141,14 @@ object ConstrainedMemberTransform { memberShape: ShapeId, ): ShapeId { val structName = memberShape.name - val memberName = memberShape.member.orElse(null) - .replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } + val memberName = + memberShape.member.orElse(null) + .replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } fun makeStructName(suffix: String = "") = ShapeId.from("${memberShape.namespace}#${structName}${memberName}$suffix") - fun structNameIsUnique(newName: ShapeId) = - model.getShape(newName).isEmpty && !additionalNames.contains(newName) + fun structNameIsUnique(newName: ShapeId) = model.getShape(newName).isEmpty && !additionalNames.contains(newName) fun generateUniqueName(): ShapeId { // Ensure the name does not already exist in the model, else make it unique @@ -173,10 +174,11 @@ object ConstrainedMemberTransform { model: Model, additionalNames: MutableSet, ): MemberShapeTransformation { - val (memberConstraintTraits, otherTraits) = this.allTraits.values - .partition { - memberConstraintTraitsToOverride.contains(it.javaClass) - } + val (memberConstraintTraits, otherTraits) = + this.allTraits.values + .partition { + memberConstraintTraitsToOverride.contains(it.javaClass) + } check(memberConstraintTraits.isNotEmpty()) { "There must at least be one member constraint on the shape" @@ -211,9 +213,10 @@ object ConstrainedMemberTransform { // Create a new unique standalone shape that will be added to the model later on val shapeId = overriddenShapeId(model, additionalNames, this.id) - val standaloneShape = builder.id(shapeId) - .traits(newTraits) - .build() + val standaloneShape = + builder.id(shapeId) + .traits(newTraits) + .build() // Since the new shape has not been added to the model as yet, the current // memberShape's target cannot be changed to the new shape. diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/RecursiveConstraintViolationBoxer.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/RecursiveConstraintViolationBoxer.kt index fc938aab7a1..56df1b4e606 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/RecursiveConstraintViolationBoxer.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/RecursiveConstraintViolationBoxer.kt @@ -65,10 +65,11 @@ object RecursiveConstraintViolationBoxer { * * [0] https://github.com/smithy-lang/smithy-rs/pull/2040 */ - fun transform(model: Model): Model = RecursiveShapeBoxer( - containsIndirectionPredicate = ::constraintViolationLoopContainsIndirection, - boxShapeFn = ::addConstraintViolationRustBoxTrait, - ).transform(model) + fun transform(model: Model): Model = + RecursiveShapeBoxer( + containsIndirectionPredicate = ::constraintViolationLoopContainsIndirection, + boxShapeFn = ::addConstraintViolationRustBoxTrait, + ).transform(model) private fun constraintViolationLoopContainsIndirection(loop: Collection): Boolean = loop.find { it.hasTrait() } != null diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/ShapesReachableFromOperationInputTagger.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/ShapesReachableFromOperationInputTagger.kt index 74cfda8f7ed..11615995798 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/ShapesReachableFromOperationInputTagger.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/ShapesReachableFromOperationInputTagger.kt @@ -45,31 +45,34 @@ import software.amazon.smithy.rust.codegen.server.smithy.traits.ShapeReachableFr */ object ShapesReachableFromOperationInputTagger { fun transform(model: Model): Model { - val inputShapes = model.operationShapes.map { - model.expectShape(it.inputShape, StructureShape::class.java) - } + val inputShapes = + model.operationShapes.map { + model.expectShape(it.inputShape, StructureShape::class.java) + } val walker = DirectedWalker(model) - val shapesReachableFromOperationInputs = inputShapes - .flatMap { walker.walkShapes(it) } - .toSet() + val shapesReachableFromOperationInputs = + inputShapes + .flatMap { walker.walkShapes(it) } + .toSet() return ModelTransformer.create().mapShapes(model) { shape -> when (shape) { is StructureShape, is UnionShape, is ListShape, is MapShape, is StringShape, is IntegerShape, is ShortShape, is LongShape, is ByteShape, is BlobShape -> { if (shapesReachableFromOperationInputs.contains(shape)) { - val builder = when (shape) { - is StructureShape -> shape.toBuilder() - is UnionShape -> shape.toBuilder() - is ListShape -> shape.toBuilder() - is MapShape -> shape.toBuilder() - is StringShape -> shape.toBuilder() - is IntegerShape -> shape.toBuilder() - is ShortShape -> shape.toBuilder() - is LongShape -> shape.toBuilder() - is ByteShape -> shape.toBuilder() - is BlobShape -> shape.toBuilder() - else -> UNREACHABLE("the `when` is exhaustive") - } + val builder = + when (shape) { + is StructureShape -> shape.toBuilder() + is UnionShape -> shape.toBuilder() + is ListShape -> shape.toBuilder() + is MapShape -> shape.toBuilder() + is StringShape -> shape.toBuilder() + is IntegerShape -> shape.toBuilder() + is ShortShape -> shape.toBuilder() + is LongShape -> shape.toBuilder() + is ByteShape -> shape.toBuilder() + is BlobShape -> shape.toBuilder() + else -> UNREACHABLE("the `when` is exhaustive") + } builder.addTrait(ShapeReachableFromOperationInputTagTrait()).build() } else { shape diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintsMemberShapeTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintsMemberShapeTest.kt index f5b619ea747..b97328eb8d7 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintsMemberShapeTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ConstraintsMemberShapeTest.kt @@ -37,7 +37,8 @@ import java.io.File import java.nio.file.Path class ConstraintsMemberShapeTest { - private val outputModelOnly = """ + private val outputModelOnly = + """ namespace constrainedMemberShape use aws.protocols#restJson1 @@ -158,7 +159,7 @@ class ConstraintsMemberShapeTest { string PatternString @range(min: 0, max:1000) integer RangedInteger - """.asSmithyModel() + """.asSmithyModel() private fun loadModel(model: Model): Model = ConstrainedMemberTransform.transform(OperationNormalizer.transform(model)) @@ -283,15 +284,20 @@ class ConstraintsMemberShapeTest { ) } - private fun runServerCodeGen(model: Model, dirToUse: File? = null, writable: Writable): Path { + private fun runServerCodeGen( + model: Model, + dirToUse: File? = null, + writable: Writable, + ): Path { val runtimeConfig = - RuntimeConfig(runtimeCrateLocation = RuntimeCrateLocation.Path(File("../rust-runtime").absolutePath)) + RuntimeConfig(runtimeCrateLocation = RuntimeCrateLocation.path(File("../rust-runtime").absolutePath)) - val (context, dir) = generatePluginContext( - model, - runtimeConfig = runtimeConfig, - overrideTestDir = dirToUse, - ) + val (context, dir) = + generatePluginContext( + model, + runtimeConfig = runtimeConfig, + overrideTestDir = dirToUse, + ) val codegenDecorator = CombinedServerCodegenDecorator.fromClasspath( context, @@ -305,12 +311,13 @@ class ConstraintsMemberShapeTest { val codegenContext = serverTestCodegenContext(model) val settings = ServerRustSettings.from(context.model, context.settings) - val rustCrate = RustCrate( - context.fileManifest, - codegenContext.symbolProvider, - settings.codegenConfig, - codegenContext.expectModuleDocProvider(), - ) + val rustCrate = + RustCrate( + context.fileManifest, + codegenContext.symbolProvider, + settings.codegenConfig, + codegenContext.expectModuleDocProvider(), + ) // We cannot write to the lib anymore as the RustWriter overwrites it, so writing code directly to check.rs // and then adding a `mod check;` to the lib.rs @@ -328,64 +335,65 @@ class ConstraintsMemberShapeTest { @Test fun `generate code and check member constrained shapes are in the right modules`() { - val dir = runServerCodeGen(outputModelOnly) { - fun RustWriter.testTypeExistsInBuilderModule(typeName: String) { - unitTest( - "builder_module_has_${typeName.toSnakeCase()}", - """ - #[allow(unused_imports)] use crate::output::operation_using_get_output::$typeName; - """, - ) - } - - // All directly constrained members of the output structure should be in the builder module - setOf( - "ConstrainedLong", - "ConstrainedByte", - "ConstrainedShort", - "ConstrainedInteger", - "ConstrainedString", - "RequiredConstrainedString", - "RequiredConstrainedLong", - "RequiredConstrainedByte", - "RequiredConstrainedInteger", - "RequiredConstrainedShort", - "ConstrainedPatternString", - ).forEach(::testTypeExistsInBuilderModule) - - fun Set.generateUseStatements(prefix: String) = - this.joinToString(separator = "\n") { - "#[allow(unused_imports)] use $prefix::$it;" + val dir = + runServerCodeGen(outputModelOnly) { + fun RustWriter.testTypeExistsInBuilderModule(typeName: String) { + unitTest( + "builder_module_has_${typeName.toSnakeCase()}", + """ + #[allow(unused_imports)] use crate::output::operation_using_get_output::$typeName; + """, + ) } - unitTest( - "map_overridden_enum", + // All directly constrained members of the output structure should be in the builder module setOf( - "Value", - "value::ConstraintViolation as ValueCV", - "Key", - "key::ConstraintViolation as KeyCV", - ).generateUseStatements("crate::model::pattern_map_override"), - ) + "ConstrainedLong", + "ConstrainedByte", + "ConstrainedShort", + "ConstrainedInteger", + "ConstrainedString", + "RequiredConstrainedString", + "RequiredConstrainedLong", + "RequiredConstrainedByte", + "RequiredConstrainedInteger", + "RequiredConstrainedShort", + "ConstrainedPatternString", + ).forEach(::testTypeExistsInBuilderModule) + + fun Set.generateUseStatements(prefix: String) = + this.joinToString(separator = "\n") { + "#[allow(unused_imports)] use $prefix::$it;" + } - unitTest( - "union_overridden_enum", - setOf( - "First", - "first::ConstraintViolation as FirstCV", - "Second", - "second::ConstraintViolation as SecondCV", - ).generateUseStatements("crate::model::pattern_union_override"), - ) + unitTest( + "map_overridden_enum", + setOf( + "Value", + "value::ConstraintViolation as ValueCV", + "Key", + "key::ConstraintViolation as KeyCV", + ).generateUseStatements("crate::model::pattern_map_override"), + ) - unitTest( - "list_overridden_enum", - setOf( - "Member", - "member::ConstraintViolation as MemberCV", - ).generateUseStatements("crate::model::pattern_string_list_override"), - ) - } + unitTest( + "union_overridden_enum", + setOf( + "First", + "first::ConstraintViolation as FirstCV", + "Second", + "second::ConstraintViolation as SecondCV", + ).generateUseStatements("crate::model::pattern_union_override"), + ) + + unitTest( + "list_overridden_enum", + setOf( + "Member", + "member::ConstraintViolation as MemberCV", + ).generateUseStatements("crate::model::pattern_string_list_override"), + ) + } val env = mapOf("RUSTFLAGS" to "-A dead_code") "cargo test".runCommand(dir, env) @@ -424,8 +432,9 @@ class ConstraintsMemberShapeTest { memberTargetShape.id.name shouldNotBe beforeTransformMemberShape.target.name // Target shape's name should match the expected name - val expectedName = memberShape.container.name.substringAfter('#') + - memberShape.memberName.substringBefore('#').toPascalCase() + val expectedName = + memberShape.container.name.substringAfter('#') + + memberShape.memberName.substringBefore('#').toPascalCase() memberTargetShape.id.name shouldBe expectedName @@ -438,19 +447,21 @@ class ConstraintsMemberShapeTest { val leftOutConstraintTrait = beforeTransformConstraintTraits - newShapeConstrainedTraits assert( - leftOutConstraintTrait.isEmpty() || leftOutConstraintTrait.all { - it.toShapeId() == RequiredTrait.ID - }, + leftOutConstraintTrait.isEmpty() || + leftOutConstraintTrait.all { + it.toShapeId() == RequiredTrait.ID + }, ) { lazyMessage } // In case the target shape has some more constraints, which the member shape did not override, // then those still need to apply on the new standalone shape that has been defined. - val leftOverTraits = originalTargetShape.allTraits.values - .filter { beforeOverridingTrait -> - beforeTransformConstraintTraits.none { - beforeOverridingTrait.toShapeId() == it.toShapeId() + val leftOverTraits = + originalTargetShape.allTraits.values + .filter { beforeOverridingTrait -> + beforeTransformConstraintTraits.none { + beforeOverridingTrait.toShapeId() == it.toShapeId() + } } - } val allNewShapeTraits = memberTargetShape.allTraits.values.toList() assert((leftOverTraits + newShapeConstrainedTraits).all { it in allNewShapeTraits }) { lazyMessage } } diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/CustomShapeSymbolProviderTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/CustomShapeSymbolProviderTest.kt index ea5d63ab2c0..f4a21fd0094 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/CustomShapeSymbolProviderTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/CustomShapeSymbolProviderTest.kt @@ -40,20 +40,23 @@ class CustomShapeSymbolProviderTest { """.asSmithyModel(smithyVersion = "2.0") private val serviceShape = baseModel.lookup("test#TestService") private val rustType = RustType.Opaque("fake-type") - private val symbol = Symbol.builder() - .name("fake-symbol") - .rustType(rustType) - .build() - private val model = ModelTransformer.create() - .mapShapes(baseModel) { - if (it is MemberShape) { - it.toBuilder().addTrait(SyntheticCustomShapeTrait(ShapeId.from("some#id"), symbol)).build() - } else { - it + private val symbol = + Symbol.builder() + .name("fake-symbol") + .rustType(rustType) + .build() + private val model = + ModelTransformer.create() + .mapShapes(baseModel) { + if (it is MemberShape) { + it.toBuilder().addTrait(SyntheticCustomShapeTrait(ShapeId.from("some#id"), symbol)).build() + } else { + it + } } - } - private val symbolProvider = serverTestSymbolProvider(baseModel, serviceShape) - .let { CustomShapeSymbolProvider(it) } + private val symbolProvider = + serverTestSymbolProvider(baseModel, serviceShape) + .let { CustomShapeSymbolProvider(it) } @Test fun `override with custom symbol`() { diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/DeriveEqAndHashSymbolMetadataProviderTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/DeriveEqAndHashSymbolMetadataProviderTest.kt index 5f2dea66e2d..360a8fe6061 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/DeriveEqAndHashSymbolMetadataProviderTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/DeriveEqAndHashSymbolMetadataProviderTest.kt @@ -170,44 +170,48 @@ internal class DeriveEqAndHashSymbolMetadataProviderTest { } """.asSmithyModel(smithyVersion = "2.0") private val serviceShape = model.lookup("test#TestService") - private val deriveEqAndHashSymbolMetadataProvider = serverTestSymbolProvider(model, serviceShape) - .let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf()) } - .let { DeriveEqAndHashSymbolMetadataProvider(it) } + private val deriveEqAndHashSymbolMetadataProvider = + serverTestSymbolProvider(model, serviceShape) + .let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf()) } + .let { DeriveEqAndHashSymbolMetadataProvider(it) } companion object { @JvmStatic fun getShapes(): Stream { - val shapesWithNeitherEqNorHash = listOf( - "test#StreamingOperationInputOutput", - "test#EventStreamOperationInputOutput", - "test#StreamingUnion", - "test#BlobStream", - "test#TestInputOutput", - "test#HasFloat", - "test#HasDouble", - "test#HasDocument", - "test#ContainsFloat", - "test#ContainsDouble", - "test#ContainsDocument", - ) - - val shapesWithEqAndHash = listOf( - "test#EqAndHashStruct", - "test#EqAndHashUnion", - "test#Enum", - "test#HasList", - ) - - val shapesWithOnlyEq = listOf( - "test#HasListWithMap", - "test#HasMap", - ) + val shapesWithNeitherEqNorHash = + listOf( + "test#StreamingOperationInputOutput", + "test#EventStreamOperationInputOutput", + "test#StreamingUnion", + "test#BlobStream", + "test#TestInputOutput", + "test#HasFloat", + "test#HasDouble", + "test#HasDocument", + "test#ContainsFloat", + "test#ContainsDouble", + "test#ContainsDocument", + ) + + val shapesWithEqAndHash = + listOf( + "test#EqAndHashStruct", + "test#EqAndHashUnion", + "test#Enum", + "test#HasList", + ) + + val shapesWithOnlyEq = + listOf( + "test#HasListWithMap", + "test#HasMap", + ) return ( shapesWithNeitherEqNorHash.map { Arguments.of(it, emptyList()) } + shapesWithEqAndHash.map { Arguments.of(it, listOf(RuntimeType.Eq, RuntimeType.Hash)) } + shapesWithOnlyEq.map { Arguments.of(it, listOf(RuntimeType.Eq)) } - ).stream() + ).stream() } } diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PatternTraitEscapedSpecialCharsValidatorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PatternTraitEscapedSpecialCharsValidatorTest.kt index 7a54849c208..5395d63f07b 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PatternTraitEscapedSpecialCharsValidatorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PatternTraitEscapedSpecialCharsValidatorTest.kt @@ -17,84 +17,90 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel class PatternTraitEscapedSpecialCharsValidatorTest { @Test fun `should error out with a suggestion if non-escaped special chars used inside @pattern`() { - val exception = shouldThrow { - """ - namespace test - - @pattern("\t") - string MyString - """.asSmithyModel(smithyVersion = "2") - } + val exception = + shouldThrow { + """ + namespace test + + @pattern("\t") + string MyString + """.asSmithyModel(smithyVersion = "2") + } val events = exception.validationEvents.filter { it.severity == Severity.ERROR } events shouldHaveSize 1 events[0].shapeId.get() shouldBe ShapeId.from("test#MyString") - events[0].message shouldBe """ + events[0].message shouldBe + """ Non-escaped special characters used inside `@pattern`. You must escape them: `@pattern("\\t")`. See https://github.com/smithy-lang/smithy-rs/issues/2508 for more details. - """.trimIndent() + """.trimIndent() } @Test fun `should suggest escaping spacial characters properly`() { - val exception = shouldThrow { - """ - namespace test - - @pattern("[.\n\\r]+") - string MyString - """.asSmithyModel(smithyVersion = "2") - } + val exception = + shouldThrow { + """ + namespace test + + @pattern("[.\n\\r]+") + string MyString + """.asSmithyModel(smithyVersion = "2") + } val events = exception.validationEvents.filter { it.severity == Severity.ERROR } events shouldHaveSize 1 events[0].shapeId.get() shouldBe ShapeId.from("test#MyString") - events[0].message shouldBe """ + events[0].message shouldBe + """ Non-escaped special characters used inside `@pattern`. You must escape them: `@pattern("[.\\n\\r]+")`. See https://github.com/smithy-lang/smithy-rs/issues/2508 for more details. - """.trimIndent() + """.trimIndent() } @Test fun `should report all non-escaped special characters`() { - val exception = shouldThrow { - """ - namespace test + val exception = + shouldThrow { + """ + namespace test - @pattern("\b") - string MyString + @pattern("\b") + string MyString - @pattern("^\n$") - string MyString2 + @pattern("^\n$") + string MyString2 - @pattern("^[\n]+$") - string MyString3 + @pattern("^[\n]+$") + string MyString3 - @pattern("^[\r\t]$") - string MyString4 - """.asSmithyModel(smithyVersion = "2") - } + @pattern("^[\r\t]$") + string MyString4 + """.asSmithyModel(smithyVersion = "2") + } val events = exception.validationEvents.filter { it.severity == Severity.ERROR } events shouldHaveSize 4 } @Test fun `should report errors on string members`() { - val exception = shouldThrow { - """ - namespace test - - @pattern("\t") - string MyString - - structure MyStructure { - @pattern("\b") - field: String + val exception = + shouldThrow { + """ + namespace test + + @pattern("\t") + string MyString + + structure MyStructure { + @pattern("\b") + field: String + } + """.asSmithyModel(smithyVersion = "2") } - """.asSmithyModel(smithyVersion = "2") - } val events = exception.validationEvents.filter { it.severity == Severity.ERROR } events shouldHaveSize 2 diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PubCrateConstrainedShapeSymbolProviderTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PubCrateConstrainedShapeSymbolProviderTest.kt index 8d07a5959af..0c223f884bb 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PubCrateConstrainedShapeSymbolProviderTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/PubCrateConstrainedShapeSymbolProviderTest.kt @@ -21,7 +21,8 @@ import software.amazon.smithy.rust.codegen.core.util.lookup import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestSymbolProviders class PubCrateConstrainedShapeSymbolProviderTest { - private val model = """ + private val model = + """ $baseModelString structure NonTransitivelyConstrainedStructureShape { @@ -46,7 +47,7 @@ class PubCrateConstrainedShapeSymbolProviderTest { union Union { structure: Structure } - """.asSmithyModel() + """.asSmithyModel() private val serverTestSymbolProviders = serverTestSymbolProviders(model) private val symbolProvider = serverTestSymbolProviders.symbolProvider @@ -74,10 +75,11 @@ class PubCrateConstrainedShapeSymbolProviderTest { val transitivelyConstrainedCollectionType = pubCrateConstrainedShapeSymbolProvider.toSymbol(transitivelyConstrainedCollectionShape).rustType() - transitivelyConstrainedCollectionType shouldBe RustType.Opaque( - "TransitivelyConstrainedCollectionConstrained", - "crate::constrained::transitively_constrained_collection_constrained", - ) + transitivelyConstrainedCollectionType shouldBe + RustType.Opaque( + "TransitivelyConstrainedCollectionConstrained", + "crate::constrained::transitively_constrained_collection_constrained", + ) } @Test @@ -86,10 +88,11 @@ class PubCrateConstrainedShapeSymbolProviderTest { val transitivelyConstrainedMapType = pubCrateConstrainedShapeSymbolProvider.toSymbol(transitivelyConstrainedMapShape).rustType() - transitivelyConstrainedMapType shouldBe RustType.Opaque( - "TransitivelyConstrainedMapConstrained", - "crate::constrained::transitively_constrained_map_constrained", - ) + transitivelyConstrainedMapType shouldBe + RustType.Opaque( + "TransitivelyConstrainedMapConstrained", + "crate::constrained::transitively_constrained_map_constrained", + ) } @Test @@ -97,12 +100,13 @@ class PubCrateConstrainedShapeSymbolProviderTest { val memberShape = model.lookup("test#StructureWithMemberTargetingAggregateShape\$member") val memberType = pubCrateConstrainedShapeSymbolProvider.toSymbol(memberShape).rustType() - memberType shouldBe RustType.Option( - RustType.Opaque( - "TransitivelyConstrainedCollectionConstrained", - "crate::constrained::transitively_constrained_collection_constrained", - ), - ) + memberType shouldBe + RustType.Option( + RustType.Opaque( + "TransitivelyConstrainedCollectionConstrained", + "crate::constrained::transitively_constrained_collection_constrained", + ), + ) } @Test diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RecursiveConstraintViolationsTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RecursiveConstraintViolationsTest.kt index 7467d0d76ff..432ad64fde4 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RecursiveConstraintViolationsTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RecursiveConstraintViolationsTest.kt @@ -16,7 +16,6 @@ import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverIntegrat import java.util.stream.Stream internal class RecursiveConstraintViolationsTest { - data class TestCase( /** The test name is only used in the generated report, to easily identify a failing test. **/ val testName: String, @@ -49,7 +48,10 @@ internal class RecursiveConstraintViolationsTest { } """ - private fun recursiveListModel(sparse: Boolean, listPrefix: String = ""): Pair = + private fun recursiveListModel( + sparse: Boolean, + listPrefix: String = "", + ): Pair = """ $baseModel @@ -57,18 +59,26 @@ internal class RecursiveConstraintViolationsTest { list: ${listPrefix}List } - ${ if (sparse) { "@sparse" } else { "" } } + ${ if (sparse) { + "@sparse" + } else { + "" + } } @length(min: 69) list ${listPrefix}List { member: Recursive } - """.asSmithyModel() to if ("${listPrefix}List" < "Recursive") { - "com.amazonaws.recursiveconstraintviolations#${listPrefix}List\$member" - } else { - "com.amazonaws.recursiveconstraintviolations#Recursive\$list" - } + """.asSmithyModel() to + if ("${listPrefix}List" < "Recursive") { + "com.amazonaws.recursiveconstraintviolations#${listPrefix}List\$member" + } else { + "com.amazonaws.recursiveconstraintviolations#Recursive\$list" + } - private fun recursiveMapModel(sparse: Boolean, mapPrefix: String = ""): Pair = + private fun recursiveMapModel( + sparse: Boolean, + mapPrefix: String = "", + ): Pair = """ $baseModel @@ -76,17 +86,22 @@ internal class RecursiveConstraintViolationsTest { map: ${mapPrefix}Map } - ${ if (sparse) { "@sparse" } else { "" } } + ${ if (sparse) { + "@sparse" + } else { + "" + } } @length(min: 69) map ${mapPrefix}Map { key: String, value: Recursive } - """.asSmithyModel() to if ("${mapPrefix}Map" < "Recursive") { - "com.amazonaws.recursiveconstraintviolations#${mapPrefix}Map\$value" - } else { - "com.amazonaws.recursiveconstraintviolations#Recursive\$map" - } + """.asSmithyModel() to + if ("${mapPrefix}Map" < "Recursive") { + "com.amazonaws.recursiveconstraintviolations#${mapPrefix}Map\$value" + } else { + "com.amazonaws.recursiveconstraintviolations#Recursive\$map" + } private fun recursiveUnionModel(unionPrefix: String = ""): Pair = """ @@ -137,34 +152,37 @@ internal class RecursiveConstraintViolationsTest { } override fun provideArguments(context: ExtensionContext?): Stream { - val listModels = listOf(false, true).flatMap { isSparse -> - listOf("", "ZZZ").map { listPrefix -> - val (model, shapeIdWithConstraintViolationRustBoxTrait) = recursiveListModel(isSparse, listPrefix) - var testName = "${ if (isSparse) "sparse" else "non-sparse" } recursive list" - if (listPrefix.isNotEmpty()) { - testName += " with shape name prefix $listPrefix" + val listModels = + listOf(false, true).flatMap { isSparse -> + listOf("", "ZZZ").map { listPrefix -> + val (model, shapeIdWithConstraintViolationRustBoxTrait) = recursiveListModel(isSparse, listPrefix) + var testName = "${ if (isSparse) "sparse" else "non-sparse" } recursive list" + if (listPrefix.isNotEmpty()) { + testName += " with shape name prefix $listPrefix" + } + TestCase(testName, model, shapeIdWithConstraintViolationRustBoxTrait) } - TestCase(testName, model, shapeIdWithConstraintViolationRustBoxTrait) } - } - val mapModels = listOf(false, true).flatMap { isSparse -> - listOf("", "ZZZ").map { mapPrefix -> - val (model, shapeIdWithConstraintViolationRustBoxTrait) = recursiveMapModel(isSparse, mapPrefix) - var testName = "${ if (isSparse) "sparse" else "non-sparse" } recursive map" - if (mapPrefix.isNotEmpty()) { - testName += " with shape name prefix $mapPrefix" + val mapModels = + listOf(false, true).flatMap { isSparse -> + listOf("", "ZZZ").map { mapPrefix -> + val (model, shapeIdWithConstraintViolationRustBoxTrait) = recursiveMapModel(isSparse, mapPrefix) + var testName = "${ if (isSparse) "sparse" else "non-sparse" } recursive map" + if (mapPrefix.isNotEmpty()) { + testName += " with shape name prefix $mapPrefix" + } + TestCase(testName, model, shapeIdWithConstraintViolationRustBoxTrait) } - TestCase(testName, model, shapeIdWithConstraintViolationRustBoxTrait) } - } - val unionModels = listOf("", "ZZZ").map { unionPrefix -> - val (model, shapeIdWithConstraintViolationRustBoxTrait) = recursiveUnionModel(unionPrefix) - var testName = "recursive union" - if (unionPrefix.isNotEmpty()) { - testName += " with shape name prefix $unionPrefix" + val unionModels = + listOf("", "ZZZ").map { unionPrefix -> + val (model, shapeIdWithConstraintViolationRustBoxTrait) = recursiveUnionModel(unionPrefix) + var testName = "recursive union" + if (unionPrefix.isNotEmpty()) { + testName += " with shape name prefix $unionPrefix" + } + TestCase(testName, model, shapeIdWithConstraintViolationRustBoxTrait) } - TestCase(testName, model, shapeIdWithConstraintViolationRustBoxTrait) - } return listOf(listModels, mapModels, unionModels) .flatten() .map { Arguments.of(it) }.stream() diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriterTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriterTest.kt index d4358aa4c03..5dcb4b3cf85 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriterTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/RustCrateInlineModuleComposingWriterTest.kt @@ -29,7 +29,8 @@ import java.io.File class RustCrateInlineModuleComposingWriterTest { private val rustCrate: RustCrate private val codegenContext: ServerCodegenContext - private val model: Model = """ + private val model: Model = + """ ${'$'}version: "2.0" namespace test @@ -56,27 +57,32 @@ class RustCrateInlineModuleComposingWriterTest { @pattern("^[a-m]+${'$'}") string PatternString - """.trimIndent().asSmithyModel() + """.trimIndent().asSmithyModel() init { codegenContext = serverTestCodegenContext(model) val runtimeConfig = - RuntimeConfig(runtimeCrateLocation = RuntimeCrateLocation.Path(File("../rust-runtime").absolutePath)) + RuntimeConfig(runtimeCrateLocation = RuntimeCrateLocation.path(File("../rust-runtime").absolutePath)) - val (context, _) = generatePluginContext( - model, - runtimeConfig = runtimeConfig, - ) + val (context, _) = + generatePluginContext( + model, + runtimeConfig = runtimeConfig, + ) val settings = ServerRustSettings.from(context.model, context.settings) - rustCrate = RustCrate( - context.fileManifest, - codegenContext.symbolProvider, - settings.codegenConfig, - codegenContext.expectModuleDocProvider(), - ) + rustCrate = + RustCrate( + context.fileManifest, + codegenContext.symbolProvider, + settings.codegenConfig, + codegenContext.expectModuleDocProvider(), + ) } - private fun createTestInlineModule(parentModule: RustModule, moduleName: String): RustModule.LeafModule = + private fun createTestInlineModule( + parentModule: RustModule, + moduleName: String, + ): RustModule.LeafModule = RustModule.new( moduleName, visibility = Visibility.PUBLIC, @@ -92,13 +98,19 @@ class RustCrateInlineModuleComposingWriterTest { inline = true, ) - private fun helloWorld(writer: RustWriter, moduleName: String) { + private fun helloWorld( + writer: RustWriter, + moduleName: String, + ) { writer.rustBlock("pub fn hello_world()") { writer.comment("Module $moduleName") } } - private fun byeWorld(writer: RustWriter, moduleName: String) { + private fun byeWorld( + writer: RustWriter, + moduleName: String, + ) { writer.rustBlock("pub fn bye_world()") { writer.comment("Module $moduleName") writer.rust("""println!("from inside $moduleName");""") @@ -152,12 +164,13 @@ class RustCrateInlineModuleComposingWriterTest { // crate::output::h::i::hello_world(); val testProject = TestWorkspace.testProject(serverTestSymbolProvider(model)) - val modules = hashMapOf( - "a" to createTestOrphanInlineModule("a"), - "d" to createTestOrphanInlineModule("d"), - "e" to createTestOrphanInlineModule("e"), - "i" to createTestOrphanInlineModule("i"), - ) + val modules = + hashMapOf( + "a" to createTestOrphanInlineModule("a"), + "d" to createTestOrphanInlineModule("d"), + "e" to createTestOrphanInlineModule("e"), + "i" to createTestOrphanInlineModule("i"), + ) modules["b"] = createTestInlineModule(ServerRustModule.Model, "b") modules["c"] = createTestInlineModule(modules["b"]!!, "c") diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitorTest.kt index 942e5f76170..54c3606fa11 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitorTest.kt @@ -18,7 +18,8 @@ import kotlin.io.path.writeText class ServerCodegenVisitorTest { @Test fun `baseline transform verify mixins removed`() { - val model = """ + val model = + """ namespace com.example use aws.protocols#awsJson1_0 @@ -43,7 +44,7 @@ class ServerCodegenVisitorTest { ] { greeting: String } - """.asSmithyModel(smithyVersion = "2.0") + """.asSmithyModel(smithyVersion = "2.0") val (ctx, testDir) = generatePluginContext(model) testDir.resolve("src/main.rs").writeText("fn main() {}") val codegenDecorator = diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraintsAreNotUsedTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraintsAreNotUsedTest.kt index a140322e361..72279a7a205 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraintsAreNotUsedTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ValidateUnsupportedConstraintsAreNotUsedTest.kt @@ -37,7 +37,10 @@ internal class ValidateUnsupportedConstraintsAreNotUsedTest { } """ - private fun validateModel(model: Model, serverCodegenConfig: ServerCodegenConfig = ServerCodegenConfig()): ValidationResult { + private fun validateModel( + model: Model, + serverCodegenConfig: ServerCodegenConfig = ServerCodegenConfig(), + ): ValidationResult { val service = model.serviceShapes.first() return validateUnsupportedConstraints(model, service, serverCodegenConfig) } @@ -54,16 +57,18 @@ internal class ValidateUnsupportedConstraintsAreNotUsedTest { } """.asSmithyModel() val service = model.lookup("test#TestService") - val validationResult = validateOperationsWithConstrainedInputHaveValidationExceptionAttached( - model, - service, - SmithyValidationExceptionConversionGenerator.SHAPE_ID, - ) + val validationResult = + validateOperationsWithConstrainedInputHaveValidationExceptionAttached( + model, + service, + SmithyValidationExceptionConversionGenerator.SHAPE_ID, + ) validationResult.messages shouldHaveSize 1 // Asserts the exact message, to ensure the formatting is appropriate. - validationResult.messages[0].message shouldBe """ + validationResult.messages[0].message shouldBe + """ Operation test#TestOperation takes in input that is constrained (https://awslabs.github.io/smithy/2.0/spec/constraint-traits.html), and as such can fail with a validation exception. You must model this behavior in the operation shape in your model file. ```smithy use smithy.framework#ValidationException @@ -73,7 +78,7 @@ internal class ValidateUnsupportedConstraintsAreNotUsedTest { errors: [..., ValidationException] // <-- Add this. } ``` - """.trimIndent() + """.trimIndent() } private val constraintTraitOnStreamingBlobShapeModel = @@ -95,10 +100,11 @@ internal class ValidateUnsupportedConstraintsAreNotUsedTest { val validationResult = validateModel(constraintTraitOnStreamingBlobShapeModel) validationResult.messages shouldHaveSize 1 - validationResult.messages[0].message shouldContain """ + validationResult.messages[0].message shouldContain + """ The blob shape `test#StreamingBlob` has both the `smithy.api#length` and `smithy.api#streaming` constraint traits attached. It is unclear what the semantics for streaming blob shapes are. - """.trimIndent().replace("\n", " ") + """.trimIndent().replace("\n", " ") } private val constrainedShapesInEventStreamModel = @@ -183,25 +189,27 @@ internal class ValidateUnsupportedConstraintsAreNotUsedTest { The map shape `test#Map` is reachable from the list shape `test#UniqueItemsList`, which has the `@uniqueItems` trait attached. """.trimIndent().replace("\n", " ") - ) + ) } @Test fun `it should abort when a map shape is reachable from a uniqueItems list shape, despite opting into ignoreUnsupportedConstraintTraits`() { - val validationResult = validateModel( - mapShapeReachableFromUniqueItemsListShapeModel, - ServerCodegenConfig().copy(ignoreUnsupportedConstraints = true), - ) + val validationResult = + validateModel( + mapShapeReachableFromUniqueItemsListShapeModel, + ServerCodegenConfig().copy(ignoreUnsupportedConstraints = true), + ) validationResult.shouldAbort shouldBe true } @Test fun `it should abort when constraint traits in event streams are used, despite opting into ignoreUnsupportedConstraintTraits`() { - val validationResult = validateModel( - EventStreamNormalizer.transform(constrainedShapesInEventStreamModel), - ServerCodegenConfig().copy(ignoreUnsupportedConstraints = true), - ) + val validationResult = + validateModel( + EventStreamNormalizer.transform(constrainedShapesInEventStreamModel), + ServerCodegenConfig().copy(ignoreUnsupportedConstraints = true), + ) validationResult.shouldAbort shouldBe true } @@ -216,10 +224,11 @@ internal class ValidateUnsupportedConstraintsAreNotUsedTest { @Test fun `it should not abort when ignoreUnsupportedConstraints is true and unsupported constraints are used`() { - val validationResult = validateModel( - constraintTraitOnStreamingBlobShapeModel, - ServerCodegenConfig().copy(ignoreUnsupportedConstraints = true), - ) + val validationResult = + validateModel( + constraintTraitOnStreamingBlobShapeModel, + ServerCodegenConfig().copy(ignoreUnsupportedConstraints = true), + ) validationResult.messages shouldHaveAtLeastSize 1 validationResult.shouldAbort shouldBe false @@ -235,10 +244,11 @@ internal class ValidateUnsupportedConstraintsAreNotUsedTest { @Test fun `it should set log level to warn when ignoreUnsupportedConstraints is true and unsupported constraints are used`() { - val validationResult = validateModel( - constraintTraitOnStreamingBlobShapeModel, - ServerCodegenConfig().copy(ignoreUnsupportedConstraints = true), - ) + val validationResult = + validateModel( + constraintTraitOnStreamingBlobShapeModel, + ServerCodegenConfig().copy(ignoreUnsupportedConstraints = true), + ) validationResult.messages shouldHaveAtLeastSize 1 validationResult.messages.shouldForAll { it.level shouldBe Level.WARNING } @@ -246,14 +256,16 @@ internal class ValidateUnsupportedConstraintsAreNotUsedTest { @Test fun `it should abort when ignoreUnsupportedConstraints is true and all used constraints are supported`() { - val allConstraintTraitsAreSupported = File("../codegen-core/common-test-models/constraints.smithy") - .readText() - .asSmithyModel() - - val validationResult = validateModel( - allConstraintTraitsAreSupported, - ServerCodegenConfig().copy(ignoreUnsupportedConstraints = true), - ) + val allConstraintTraitsAreSupported = + File("../codegen-core/common-test-models/constraints.smithy") + .readText() + .asSmithyModel() + + val validationResult = + validateModel( + allConstraintTraitsAreSupported, + ServerCodegenConfig().copy(ignoreUnsupportedConstraints = true), + ) validationResult.messages shouldHaveSize 1 validationResult.shouldAbort shouldBe true @@ -262,6 +274,6 @@ internal class ValidateUnsupportedConstraintsAreNotUsedTest { The `ignoreUnsupportedConstraints` flag in the `codegen` configuration is set to `true`, but it has no effect. All the constraint traits used in the model are well-supported, please remove this flag. """.trimIndent().replace("\n", " ") - ) + ) } } diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/AdditionalErrorsDecoratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/AdditionalErrorsDecoratorTest.kt index d7783c7ac10..8fc655da042 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/AdditionalErrorsDecoratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/AdditionalErrorsDecoratorTest.kt @@ -15,7 +15,8 @@ import software.amazon.smithy.rust.codegen.core.util.lookup import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestRustSettings class AdditionalErrorsDecoratorTest { - private val baseModel = """ + private val baseModel = + """ namespace test operation Infallible { @@ -33,7 +34,7 @@ class AdditionalErrorsDecoratorTest { @error("client") structure AnError { } - """.asSmithyModel() + """.asSmithyModel() private val model = OperationNormalizer.transform(baseModel) private val service = ServiceShape.builder().id("smithy.test#Test").build() private val settings = serverTestRustSettings() diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/CustomValidationExceptionWithReasonDecoratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/CustomValidationExceptionWithReasonDecoratorTest.kt index 31b46023819..9176a7bf086 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/CustomValidationExceptionWithReasonDecoratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/CustomValidationExceptionWithReasonDecoratorTest.kt @@ -75,16 +75,18 @@ fun swapOutSmithyValidationExceptionForCustomOne(model: Model): Model { """.asSmithyModel(smithyVersion = "2.0") // Remove Smithy's `ValidationException`. - var model = ModelTransformer.create().removeShapes( - model, - listOf(model.expectShape(SmithyValidationExceptionConversionGenerator.SHAPE_ID)), - ) + var model = + ModelTransformer.create().removeShapes( + model, + listOf(model.expectShape(SmithyValidationExceptionConversionGenerator.SHAPE_ID)), + ) // Add our custom one. model = ModelTransformer.create().replaceShapes(model, customValidationExceptionModel.shapes().toList()) // Make all operations use our custom one. - val newOperationShapes = model.operationShapes.map { operationShape -> - operationShape.toBuilder().addError(ShapeId.from("com.amazonaws.constraints#ValidationException")).build() - } + val newOperationShapes = + model.operationShapes.map { operationShape -> + operationShape.toBuilder().addError(ShapeId.from("com.amazonaws.constraints#ValidationException")).build() + } return ModelTransformer.create().replaceShapes(model, newOperationShapes) } @@ -97,12 +99,13 @@ internal class CustomValidationExceptionWithReasonDecoratorTest { serverIntegrationTest( model, IntegrationTestParams( - additionalSettings = Node.objectNodeBuilder().withMember( - "codegen", - Node.objectNodeBuilder() - .withMember("experimentalCustomValidationExceptionWithReasonPleaseDoNotUse", "com.amazonaws.constraints#ValidationException") - .build(), - ).build(), + additionalSettings = + Node.objectNodeBuilder().withMember( + "codegen", + Node.objectNodeBuilder() + .withMember("experimentalCustomValidationExceptionWithReasonPleaseDoNotUse", "com.amazonaws.constraints#ValidationException") + .build(), + ).build(), ), ) } diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/PostprocessValidationExceptionNotAttachedErrorMessageDecoratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/PostprocessValidationExceptionNotAttachedErrorMessageDecoratorTest.kt index 9130d30b330..11a2f882aba 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/PostprocessValidationExceptionNotAttachedErrorMessageDecoratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/customizations/PostprocessValidationExceptionNotAttachedErrorMessageDecoratorTest.kt @@ -39,33 +39,37 @@ internal class PostprocessValidationExceptionNotAttachedErrorMessageDecoratorTes } """.asSmithyModel() - val validationExceptionNotAttachedErrorMessageDummyPostprocessorDecorator = object : ServerCodegenDecorator { - override val name: String - get() = "ValidationExceptionNotAttachedErrorMessageDummyPostprocessorDecorator" - override val order: Byte - get() = 69 + val validationExceptionNotAttachedErrorMessageDummyPostprocessorDecorator = + object : ServerCodegenDecorator { + override val name: String + get() = "ValidationExceptionNotAttachedErrorMessageDummyPostprocessorDecorator" + override val order: Byte + get() = 69 - override fun postprocessValidationExceptionNotAttachedErrorMessage(validationResult: ValidationResult): ValidationResult { - check(validationResult.messages.size == 1) + override fun postprocessValidationExceptionNotAttachedErrorMessage( + validationResult: ValidationResult, + ): ValidationResult { + check(validationResult.messages.size == 1) - val level = validationResult.messages.first().level - val message = - """ - ${validationResult.messages.first().message} + val level = validationResult.messages.first().level + val message = + """ + ${validationResult.messages.first().message} - There are three things all wise men fear: the sea in storm, a night with no moon, and the anger of a gentle man. - """ + There are three things all wise men fear: the sea in storm, a night with no moon, and the anger of a gentle man. + """ - return validationResult.copy(messages = listOf(LogMessage(level, message))) + return validationResult.copy(messages = listOf(LogMessage(level, message))) + } } - } - val exception = assertThrows { - serverIntegrationTest( - model, - additionalDecorators = listOf(validationExceptionNotAttachedErrorMessageDummyPostprocessorDecorator), - ) - } + val exception = + assertThrows { + serverIntegrationTest( + model, + additionalDecorators = listOf(validationExceptionNotAttachedErrorMessageDummyPostprocessorDecorator), + ) + } val exceptionCause = (exception.cause!! as ValidationResult) exceptionCause.messages.size shouldBe 1 exceptionCause.messages.first().message shouldContain "There are three things all wise men fear: the sea in storm, a night with no moon, and the anger of a gentle man." diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedBlobGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedBlobGeneratorTest.kt index 3a35120f839..bc73ac7f327 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedBlobGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedBlobGeneratorTest.kt @@ -32,27 +32,28 @@ class ConstrainedBlobGeneratorTest { data class TestCase(val model: Model, val validBlob: String, val invalidBlob: String) class ConstrainedBlobGeneratorTestProvider : ArgumentsProvider { - private val testCases = listOf( - // Min and max. - Triple("@length(min: 11, max: 12)", "validString", "invalidString"), - // Min equal to max. - Triple("@length(min: 11, max: 11)", "validString", "invalidString"), - // Only min. - Triple("@length(min: 11)", "validString", ""), - // Only max. - Triple("@length(max: 11)", "", "invalidString"), - ).map { - TestCase( - """ - namespace test - - ${it.first} - blob ConstrainedBlob - """.asSmithyModel(), - "aws_smithy_types::Blob::new(Vec::from(${it.second.dq()}))", - "aws_smithy_types::Blob::new(Vec::from(${it.third.dq()}))", - ) - } + private val testCases = + listOf( + // Min and max. + Triple("@length(min: 11, max: 12)", "validString", "invalidString"), + // Min equal to max. + Triple("@length(min: 11, max: 11)", "validString", "invalidString"), + // Only min. + Triple("@length(min: 11)", "validString", ""), + // Only max. + Triple("@length(max: 11)", "", "invalidString"), + ).map { + TestCase( + """ + namespace test + + ${it.first} + blob ConstrainedBlob + """.asSmithyModel(), + "aws_smithy_types::Blob::new(Vec::from(${it.second.dq()}))", + "aws_smithy_types::Blob::new(Vec::from(${it.third.dq()}))", + ) + } override fun provideArguments(context: ExtensionContext?): Stream = testCases.map { Arguments.of(it) }.stream() @@ -118,12 +119,13 @@ class ConstrainedBlobGeneratorTest { @Test fun `type should not be constructable without using a constructor`() { - val model = """ + val model = + """ namespace test @length(min: 1, max: 70) blob ConstrainedBlob - """.asSmithyModel() + """.asSmithyModel() val constrainedBlobShape = model.lookup("test#ConstrainedBlob") val codegenContext = serverTestCodegenContext(model) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedCollectionGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedCollectionGeneratorTest.kt index 444d75d2ad5..23158df233b 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedCollectionGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedCollectionGeneratorTest.kt @@ -70,90 +70,99 @@ class ConstrainedCollectionGeneratorTest { } """.asSmithyModel().let(ShapesReachableFromOperationInputTagger::transform) - private val lengthTraitTestCases = listOf( - // Min and max. - Triple("@length(min: 11, max: 12)", 11, 13), - // Min equal to max. - Triple("@length(min: 11, max: 11)", 11, 12), - // Only min. - Triple("@length(min: 11)", 15, 10), - // Only max. - Triple("@length(max: 11)", 11, 12), - ).map { - // Generate lists of strings of the specified length with consecutive items "0", "1", ... - val validList = List(it.second, Int::toString) - val invalidList = List(it.third, Int::toString) - - Triple(it.first, ArrayNode.fromStrings(validList), ArrayNode.fromStrings(invalidList)) - }.map { (trait, validList, invalidList) -> - TestCase( - model = generateModel(trait), - validLists = listOf(validList), - invalidLists = listOf(InvalidList(invalidList, expectedErrorFn = null)), - ) - } - - private fun constraintViolationForDuplicateIndices(duplicateIndices: List): - ((constraintViolation: Symbol, originalValueBindingName: String) -> Writable) { - fun ret(constraintViolation: Symbol, originalValueBindingName: String): Writable = writable { - // Public documentation for the unique items constraint violation states that callers should not - // rely on the order of the elements in `duplicate_indices`. However, the algorithm is deterministic, - // so we can internally assert the order. If the algorithm changes, the test cases will need to be - // adjusted. - rustTemplate( - """ - #{ConstraintViolation}::UniqueItems { - duplicate_indices: vec![${duplicateIndices.joinToString(", ")}], - original: $originalValueBindingName, - } - """, - "ConstraintViolation" to constraintViolation, + private val lengthTraitTestCases = + listOf( + // Min and max. + Triple("@length(min: 11, max: 12)", 11, 13), + // Min equal to max. + Triple("@length(min: 11, max: 11)", 11, 12), + // Only min. + Triple("@length(min: 11)", 15, 10), + // Only max. + Triple("@length(max: 11)", 11, 12), + ).map { + // Generate lists of strings of the specified length with consecutive items "0", "1", ... + val validList = List(it.second, Int::toString) + val invalidList = List(it.third, Int::toString) + + Triple(it.first, ArrayNode.fromStrings(validList), ArrayNode.fromStrings(invalidList)) + }.map { (trait, validList, invalidList) -> + TestCase( + model = generateModel(trait), + validLists = listOf(validList), + invalidLists = listOf(InvalidList(invalidList, expectedErrorFn = null)), ) } + private fun constraintViolationForDuplicateIndices( + duplicateIndices: List, + ): ((constraintViolation: Symbol, originalValueBindingName: String) -> Writable) { + fun ret( + constraintViolation: Symbol, + originalValueBindingName: String, + ): Writable = + writable { + // Public documentation for the unique items constraint violation states that callers should not + // rely on the order of the elements in `duplicate_indices`. However, the algorithm is deterministic, + // so we can internally assert the order. If the algorithm changes, the test cases will need to be + // adjusted. + rustTemplate( + """ + #{ConstraintViolation}::UniqueItems { + duplicate_indices: vec![${duplicateIndices.joinToString(", ")}], + original: $originalValueBindingName, + } + """, + "ConstraintViolation" to constraintViolation, + ) + } + return ::ret } - private val uniqueItemsTraitTestCases = listOf( - // We only need one test case, since `@uniqueItems` is not parameterizable. - TestCase( - model = generateModel("@uniqueItems"), - validLists = listOf( - ArrayNode.fromStrings(), - ArrayNode.fromStrings("0", "1"), - ArrayNode.fromStrings("a", "b", "a2"), - ArrayNode.fromStrings((0..69).map(Int::toString).toList()), - ), - invalidLists = listOf( - // Two elements, both duplicate. - InvalidList( - node = ArrayNode.fromStrings("0", "0"), - expectedErrorFn = constraintViolationForDuplicateIndices(listOf(0, 1)), - ), - // Two duplicate items, one at the beginning, one at the end. - InvalidList( - node = ArrayNode.fromStrings("0", "1", "2", "3", "4", "5", "0"), - expectedErrorFn = constraintViolationForDuplicateIndices(listOf(0, 6)), - ), - // Several duplicate items, all the same. - InvalidList( - node = ArrayNode.fromStrings("0", "1", "0", "0", "4", "0", "6", "7"), - expectedErrorFn = constraintViolationForDuplicateIndices(listOf(0, 2, 3, 5)), - ), - // Several equivalence classes. - InvalidList( - node = ArrayNode.fromStrings("0", "1", "0", "2", "1", "0", "2", "7", "2"), - // Note how the duplicate indices are not ordered. - expectedErrorFn = constraintViolationForDuplicateIndices(listOf(0, 1, 2, 3, 6, 5, 4, 8)), - ), - // The worst case: a fairly large number of elements, all duplicate. - InvalidList( - node = ArrayNode.fromStrings(generateSequence { "69" }.take(69).toList()), - expectedErrorFn = constraintViolationForDuplicateIndices((0..68).toList()), - ), + private val uniqueItemsTraitTestCases = + listOf( + // We only need one test case, since `@uniqueItems` is not parameterizable. + TestCase( + model = generateModel("@uniqueItems"), + validLists = + listOf( + ArrayNode.fromStrings(), + ArrayNode.fromStrings("0", "1"), + ArrayNode.fromStrings("a", "b", "a2"), + ArrayNode.fromStrings((0..69).map(Int::toString).toList()), + ), + invalidLists = + listOf( + // Two elements, both duplicate. + InvalidList( + node = ArrayNode.fromStrings("0", "0"), + expectedErrorFn = constraintViolationForDuplicateIndices(listOf(0, 1)), + ), + // Two duplicate items, one at the beginning, one at the end. + InvalidList( + node = ArrayNode.fromStrings("0", "1", "2", "3", "4", "5", "0"), + expectedErrorFn = constraintViolationForDuplicateIndices(listOf(0, 6)), + ), + // Several duplicate items, all the same. + InvalidList( + node = ArrayNode.fromStrings("0", "1", "0", "0", "4", "0", "6", "7"), + expectedErrorFn = constraintViolationForDuplicateIndices(listOf(0, 2, 3, 5)), + ), + // Several equivalence classes. + InvalidList( + node = ArrayNode.fromStrings("0", "1", "0", "2", "1", "0", "2", "7", "2"), + // Note how the duplicate indices are not ordered. + expectedErrorFn = constraintViolationForDuplicateIndices(listOf(0, 1, 2, 3, 6, 5, 4, 8)), + ), + // The worst case: a fairly large number of elements, all duplicate. + InvalidList( + node = ArrayNode.fromStrings(generateSequence { "69" }.take(69).toList()), + expectedErrorFn = constraintViolationForDuplicateIndices((0..68).toList()), + ), + ), ), - ), - ) + ) override fun provideArguments(context: ExtensionContext?): Stream = (lengthTraitTestCases + uniqueItemsTraitTestCases).map { Arguments.of(it) }.stream() @@ -170,11 +179,12 @@ class ConstrainedCollectionGeneratorTest { val project = TestWorkspace.testProject(codegenContext.symbolProvider) for (shape in listOf(constrainedListShape, constrainedSetShape)) { - val shapeName = when (shape) { - is SetShape -> "set" - is ListShape -> "list" - else -> UNREACHABLE("Shape is either list or set.") - } + val shapeName = + when (shape) { + is SetShape -> "set" + is ListShape -> "list" + else -> UNREACHABLE("Shape is either list or set.") + } project.withModule(ServerRustModule.Model) { render(codegenContext, this, shape) @@ -226,29 +236,31 @@ class ConstrainedCollectionGeneratorTest { } unitTest( name = "${shapeNameIdx}_try_from_fail", - block = writable { - rust( - """ - let $shapeNameIdx = $buildInvalidFnName(); - let constrained_res: Result <$typeName, _> = $shapeNameIdx.clone().try_into(); - """, - ) - - invalidList.expectedErrorFn?.also { expectedErrorFn -> - val expectedErrorWritable = expectedErrorFn( - codegenContext.constraintViolationSymbolProvider.toSymbol(shape), - shapeNameIdx, + block = + writable { + rust( + """ + let $shapeNameIdx = $buildInvalidFnName(); + let constrained_res: Result <$typeName, _> = $shapeNameIdx.clone().try_into(); + """, ) - rust("let err = constrained_res.unwrap_err();") - withBlock("let expected_err = ", ";") { - rustTemplate("#{ExpectedError:W}", "ExpectedError" to expectedErrorWritable) + invalidList.expectedErrorFn?.also { expectedErrorFn -> + val expectedErrorWritable = + expectedErrorFn( + codegenContext.constraintViolationSymbolProvider.toSymbol(shape), + shapeNameIdx, + ) + + rust("let err = constrained_res.unwrap_err();") + withBlock("let expected_err = ", ";") { + rustTemplate("#{ExpectedError:W}", "ExpectedError" to expectedErrorWritable) + } + rust("assert_eq!(err, expected_err);") + } ?: run { + rust("constrained_res.unwrap_err();") } - rust("assert_eq!(err, expected_err);") - } ?: run { - rust("constrained_res.unwrap_err();") - } - }, + }, ) } } diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGeneratorTest.kt index d475ccbd37e..ae050460a48 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedMapGeneratorTest.kt @@ -31,38 +31,38 @@ import software.amazon.smithy.rust.codegen.server.smithy.transformers.ShapesReac import java.util.stream.Stream class ConstrainedMapGeneratorTest { - data class TestCase(val model: Model, val validMap: ObjectNode, val invalidMap: ObjectNode) class ConstrainedMapGeneratorTestProvider : ArgumentsProvider { - private val testCases = listOf( - // Min and max. - Triple("@length(min: 11, max: 12)", 11, 13), - // Min equal to max. - Triple("@length(min: 11, max: 11)", 11, 12), - // Only min. - Triple("@length(min: 11)", 15, 10), - // Only max. - Triple("@length(max: 11)", 11, 12), - ).map { - val validStringMap = List(it.second) { index -> index.toString() to "value" }.toMap() - val inValidStringMap = List(it.third) { index -> index.toString() to "value" }.toMap() - Triple(it.first, ObjectNode.fromStringMap(validStringMap), ObjectNode.fromStringMap(inValidStringMap)) - }.map { (trait, validMap, invalidMap) -> - TestCase( - """ - namespace test - - $trait - map ConstrainedMap { - key: String, - value: String - } - """.asSmithyModel().let(ShapesReachableFromOperationInputTagger::transform), - validMap, - invalidMap, - ) - } + private val testCases = + listOf( + // Min and max. + Triple("@length(min: 11, max: 12)", 11, 13), + // Min equal to max. + Triple("@length(min: 11, max: 11)", 11, 12), + // Only min. + Triple("@length(min: 11)", 15, 10), + // Only max. + Triple("@length(max: 11)", 11, 12), + ).map { + val validStringMap = List(it.second) { index -> index.toString() to "value" }.toMap() + val inValidStringMap = List(it.third) { index -> index.toString() to "value" }.toMap() + Triple(it.first, ObjectNode.fromStringMap(validStringMap), ObjectNode.fromStringMap(inValidStringMap)) + }.map { (trait, validMap, invalidMap) -> + TestCase( + """ + namespace test + + $trait + map ConstrainedMap { + key: String, + value: String + } + """.asSmithyModel().let(ShapesReachableFromOperationInputTagger::transform), + validMap, + invalidMap, + ) + } override fun provideArguments(context: ExtensionContext?): Stream = testCases.map { Arguments.of(it) }.stream() @@ -129,7 +129,8 @@ class ConstrainedMapGeneratorTest { @Test fun `type should not be constructable without using a constructor`() { - val model = """ + val model = + """ namespace test @length(min: 1, max: 69) @@ -137,7 +138,7 @@ class ConstrainedMapGeneratorTest { key: String, value: String } - """.asSmithyModel().let(ShapesReachableFromOperationInputTagger::transform) + """.asSmithyModel().let(ShapesReachableFromOperationInputTagger::transform) val constrainedMapShape = model.lookup("test#ConstrainedMap") val writer = RustWriter.forModule(ServerRustModule.Model.name) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedNumberGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedNumberGeneratorTest.kt index 3a34c7753cc..9e19265e592 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedNumberGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedNumberGeneratorTest.kt @@ -26,8 +26,8 @@ import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestCode import java.util.stream.Stream class ConstrainedNumberGeneratorTest { - data class TestCaseInputs(val constraintAnnotation: String, val validValue: Int, val invalidValue: Int) + data class TestCase(val model: Model, val validValue: Int, val invalidValue: Int, val shapeName: String) class ConstrainedNumberGeneratorTestProvider : ArgumentsProvider { @@ -129,12 +129,13 @@ class ConstrainedNumberGeneratorTest { @ArgumentsSource(NoStructuralConstructorTestProvider::class) fun `type should not be constructable without using a constructor`(args: Triple) { val (smithyType, shapeName, rustType) = args - val model = """ + val model = + """ namespace test @range(min: -1, max: 5) $smithyType $shapeName - """.asSmithyModel() + """.asSmithyModel() val constrainedShape = model.lookup("test#$shapeName") val codegenContext = serverTestCodegenContext(model) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGeneratorTest.kt index 5e2f828e1b4..bdc89c00782 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ConstrainedStringGeneratorTest.kt @@ -32,42 +32,44 @@ class ConstrainedStringGeneratorTest { data class TestCase(val model: Model, val validString: String, val invalidString: String) class ConstrainedStringGeneratorTestProvider : ArgumentsProvider { - private val testCases = listOf( - // Min and max. - Triple("@length(min: 11, max: 12)", "validString", "invalidString"), - // Min equal to max. - Triple("@length(min: 11, max: 11)", "validString", "invalidString"), - // Only min. - Triple("@length(min: 11)", "validString", ""), - // Only max. - Triple("@length(max: 11)", "", "invalidString"), - // Count Unicode scalar values, not `.len()`. - Triple( - "@length(min: 3, max: 3)", - "👍👍👍", // These three emojis are three Unicode scalar values. - "👍👍👍👍", - ), - Triple("@pattern(\"^[a-z]+$\")", "valid", "123 invalid"), - Triple( - """ - @length(min: 3, max: 10) - @pattern("^a string$") - """, - "a string", "an invalid string", - ), - Triple("@pattern(\"123\")", "some pattern 123 in the middle", "no pattern at all"), - ).map { - TestCase( - """ - namespace test - - ${it.first} - string ConstrainedString - """.asSmithyModel(), - it.second, - it.third, - ) - } + private val testCases = + listOf( + // Min and max. + Triple("@length(min: 11, max: 12)", "validString", "invalidString"), + // Min equal to max. + Triple("@length(min: 11, max: 11)", "validString", "invalidString"), + // Only min. + Triple("@length(min: 11)", "validString", ""), + // Only max. + Triple("@length(max: 11)", "", "invalidString"), + // Count Unicode scalar values, not `.len()`. + Triple( + "@length(min: 3, max: 3)", + // These three emojis are three Unicode scalar values. + "👍👍👍", + "👍👍👍👍", + ), + Triple("@pattern(\"^[a-z]+$\")", "valid", "123 invalid"), + Triple( + """ + @length(min: 3, max: 10) + @pattern("^a string$") + """, + "a string", "an invalid string", + ), + Triple("@pattern(\"123\")", "some pattern 123 in the middle", "no pattern at all"), + ).map { + TestCase( + """ + namespace test + + ${it.first} + string ConstrainedString + """.asSmithyModel(), + it.second, + it.third, + ) + } override fun provideArguments(context: ExtensionContext?): Stream = testCases.map { Arguments.of(it) }.stream() @@ -132,12 +134,13 @@ class ConstrainedStringGeneratorTest { @Test fun `type should not be constructable without using a constructor`() { - val model = """ + val model = + """ namespace test @length(min: 1, max: 69) string ConstrainedString - """.asSmithyModel() + """.asSmithyModel() val constrainedStringShape = model.lookup("test#ConstrainedString") val codegenContext = serverTestCodegenContext(model) @@ -158,7 +161,8 @@ class ConstrainedStringGeneratorTest { @Test fun `Display implementation`() { - val model = """ + val model = + """ namespace test @length(min: 1, max: 69) @@ -167,7 +171,7 @@ class ConstrainedStringGeneratorTest { @sensitive @length(min: 1, max: 78) string SensitiveConstrainedString - """.asSmithyModel() + """.asSmithyModel() val constrainedStringShape = model.lookup("test#ConstrainedString") val sensitiveConstrainedStringShape = model.lookup("test#SensitiveConstrainedString") @@ -216,12 +220,13 @@ class ConstrainedStringGeneratorTest { @Test fun `A regex that is accepted by Smithy but not by the regex crate causes tests to fail`() { - val model = """ + val model = + """ namespace test @pattern("import (?!static).+") string PatternStringWithLookahead - """.asSmithyModel() + """.asSmithyModel() val constrainedStringShape = model.lookup("test#PatternStringWithLookahead") val codegenContext = serverTestCodegenContext(model) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderConstraintViolationsTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderConstraintViolationsTest.kt index f36976e715e..329f75699ea 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderConstraintViolationsTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderConstraintViolationsTest.kt @@ -10,14 +10,14 @@ import software.amazon.smithy.rust.codegen.core.testutil.asSmithyModel import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverIntegrationTest class ServerBuilderConstraintViolationsTest { - // This test exists not to regress on [this](https://github.com/smithy-lang/smithy-rs/issues/2343) issue. // We generated constraint violation variants, pointing to a structure (StructWithInnerDefault below), // but the structure was not constrained, because the structure's member have a default value // and default values are validated at generation time from the model. @Test fun `it should not generate constraint violations for members with a default value`() { - val model = """ + val model = + """ namespace test use aws.protocols#restJson1 @@ -43,7 +43,7 @@ class ServerBuilderConstraintViolationsTest { @default(false) inner: PrimitiveBoolean } - """.asSmithyModel(smithyVersion = "2") + """.asSmithyModel(smithyVersion = "2") serverIntegrationTest(model) } } diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderDefaultValuesTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderDefaultValuesTest.kt index 966426f948d..e0a20542851 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderDefaultValuesTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderDefaultValuesTest.kt @@ -43,52 +43,54 @@ import java.util.stream.Stream @TestInstance(TestInstance.Lifecycle.PER_CLASS) class ServerBuilderDefaultValuesTest { // When defaults are used, the model will be generated with these in the `@default` trait. - private val defaultValues = mapOf( - "Boolean" to "true", - "String" to "foo".dq(), - "Byte" to "5", - "Short" to "55", - "Integer" to "555", - "Long" to "5555", - "Float" to "0.5", - "Double" to "0.55", - "Timestamp" to "1985-04-12T23:20:50.52Z".dq(), - // "BigInteger" to "55555", "BigDecimal" to "0.555", // TODO(https://github.com/smithy-lang/smithy-rs/issues/312) - "StringList" to "[]", - "IntegerMap" to "{}", - "Language" to "en".dq(), - "DocumentBoolean" to "true", - "DocumentString" to "foo".dq(), - "DocumentNumberPosInt" to "100", - "DocumentNumberNegInt" to "-100", - "DocumentNumberFloat" to "0.1", - "DocumentList" to "[]", - "DocumentMap" to "{}", - ) + private val defaultValues = + mapOf( + "Boolean" to "true", + "String" to "foo".dq(), + "Byte" to "5", + "Short" to "55", + "Integer" to "555", + "Long" to "5555", + "Float" to "0.5", + "Double" to "0.55", + "Timestamp" to "1985-04-12T23:20:50.52Z".dq(), + // "BigInteger" to "55555", "BigDecimal" to "0.555", // TODO(https://github.com/smithy-lang/smithy-rs/issues/312) + "StringList" to "[]", + "IntegerMap" to "{}", + "Language" to "en".dq(), + "DocumentBoolean" to "true", + "DocumentString" to "foo".dq(), + "DocumentNumberPosInt" to "100", + "DocumentNumberNegInt" to "-100", + "DocumentNumberFloat" to "0.1", + "DocumentList" to "[]", + "DocumentMap" to "{}", + ) // When the test applies values to validate we honor custom values, use these (different) values. - private val customValues = mapOf( - "Boolean" to "false", - "String" to "bar".dq(), - "Byte" to "6", - "Short" to "66", - "Integer" to "666", - "Long" to "6666", - "Float" to "0.6", - "Double" to "0.66", - "Timestamp" to "2022-11-25T17:30:50.00Z".dq(), - // "BigInteger" to "55555", "BigDecimal" to "0.555", // TODO(https://github.com/smithy-lang/smithy-rs/issues/312) - "StringList" to "[]", - "IntegerMap" to "{}", - "Language" to "fr".dq(), - "DocumentBoolean" to "false", - "DocumentString" to "bar".dq(), - "DocumentNumberPosInt" to "1000", - "DocumentNumberNegInt" to "-1000", - "DocumentNumberFloat" to "0.01", - "DocumentList" to "[]", - "DocumentMap" to "{}", - ) + private val customValues = + mapOf( + "Boolean" to "false", + "String" to "bar".dq(), + "Byte" to "6", + "Short" to "66", + "Integer" to "666", + "Long" to "6666", + "Float" to "0.6", + "Double" to "0.66", + "Timestamp" to "2022-11-25T17:30:50.00Z".dq(), + // "BigInteger" to "55555", "BigDecimal" to "0.555", // TODO(https://github.com/smithy-lang/smithy-rs/issues/312) + "StringList" to "[]", + "IntegerMap" to "{}", + "Language" to "fr".dq(), + "DocumentBoolean" to "false", + "DocumentString" to "bar".dq(), + "DocumentNumberPosInt" to "1000", + "DocumentNumberNegInt" to "-1000", + "DocumentNumberFloat" to "0.01", + "DocumentList" to "[]", + "DocumentMap" to "{}", + ) @ParameterizedTest(name = "(#{index}) Server builders and default values. Params = requiredTrait: {0}, nullDefault: {1}, applyDefaultValues: {2}, builderGeneratorKind: {3}, assertValues: {4}") @MethodSource("testParameters") @@ -116,34 +118,37 @@ class ServerBuilderDefaultValuesTest { } val rustValues = setupRustValuesForTest(assertValues) - val setters = if (applyDefaultValues) { - structSetters(rustValues, nullDefault && !requiredTrait) - } else { - writable { } - } + val setters = + if (applyDefaultValues) { + structSetters(rustValues, nullDefault && !requiredTrait) + } else { + writable { } + } val unwrapBuilder = if (nullDefault && requiredTrait && applyDefaultValues) ".unwrap()" else "" unitTest( name = "generates_default_required_values", - block = writable { - rustTemplate( - """ - let my_struct = MyStruct::builder() - #{Setters:W} - .build() - $unwrapBuilder; - - #{Assertions:W} - """, - "Assertions" to assertions( - rustValues, - applyDefaultValues, - nullDefault, - requiredTrait, - applyDefaultValues, - ), - "Setters" to setters, - ) - }, + block = + writable { + rustTemplate( + """ + let my_struct = MyStruct::builder() + #{Setters:W} + .build() + $unwrapBuilder; + + #{Assertions:W} + """, + "Assertions" to + assertions( + rustValues, + applyDefaultValues, + nullDefault, + requiredTrait, + applyDefaultValues, + ), + "Setters" to setters, + ) + }, ) } @@ -153,39 +158,49 @@ class ServerBuilderDefaultValuesTest { } private fun setupRustValuesForTest(valuesMap: Map): Map { - return valuesMap + mapOf( - "Byte" to "${valuesMap["Byte"]}i8", - "Short" to "${valuesMap["Short"]}i16", - "Integer" to "${valuesMap["Integer"]}i32", - "Long" to "${valuesMap["Long"]}i64", - "Float" to "${valuesMap["Float"]}f32", - "Double" to "${valuesMap["Double"]}f64", - "Language" to "crate::model::Language::${valuesMap["Language"]!!.replace(""""""", "").toPascalCase()}", - "Timestamp" to """aws_smithy_types::DateTime::from_str(${valuesMap["Timestamp"]}, aws_smithy_types::date_time::Format::DateTime).unwrap()""", - // These must be empty - "StringList" to "Vec::::new()", - "IntegerMap" to "std::collections::HashMap::::new()", - "DocumentList" to "Vec::::new()", - "DocumentMap" to "std::collections::HashMap::::new()", - ) + valuesMap - .filter { it.value?.startsWith("Document") ?: false } - .map { it.key to "${it.value}.into()" } + return valuesMap + + mapOf( + "Byte" to "${valuesMap["Byte"]}i8", + "Short" to "${valuesMap["Short"]}i16", + "Integer" to "${valuesMap["Integer"]}i32", + "Long" to "${valuesMap["Long"]}i64", + "Float" to "${valuesMap["Float"]}f32", + "Double" to "${valuesMap["Double"]}f64", + "Language" to "crate::model::Language::${valuesMap["Language"]!!.replace(""""""", "").toPascalCase()}", + "Timestamp" to """aws_smithy_types::DateTime::from_str(${valuesMap["Timestamp"]}, aws_smithy_types::date_time::Format::DateTime).unwrap()""", + // These must be empty + "StringList" to "Vec::::new()", + "IntegerMap" to "std::collections::HashMap::::new()", + "DocumentList" to "Vec::::new()", + "DocumentMap" to "std::collections::HashMap::::new()", + ) + + valuesMap + .filter { it.value?.startsWith("Document") ?: false } + .map { it.key to "${it.value}.into()" } } - private fun writeServerBuilderGeneratorWithoutPublicConstrainedTypes(rustCrate: RustCrate, writer: RustWriter, model: Model, symbolProvider: RustSymbolProvider) { + private fun writeServerBuilderGeneratorWithoutPublicConstrainedTypes( + rustCrate: RustCrate, + writer: RustWriter, + model: Model, + symbolProvider: RustSymbolProvider, + ) { val struct = model.lookup("com.test#MyStruct") - val codegenContext = serverTestCodegenContext( - model, - settings = serverTestRustSettings( - codegenConfig = ServerCodegenConfig(publicConstrainedTypes = false), - ), - ) - val builderGenerator = ServerBuilderGeneratorWithoutPublicConstrainedTypes( - codegenContext, - struct, - SmithyValidationExceptionConversionGenerator(codegenContext), - ServerRestJsonProtocol(codegenContext), - ) + val codegenContext = + serverTestCodegenContext( + model, + settings = + serverTestRustSettings( + codegenConfig = ServerCodegenConfig(publicConstrainedTypes = false), + ), + ) + val builderGenerator = + ServerBuilderGeneratorWithoutPublicConstrainedTypes( + codegenContext, + struct, + SmithyValidationExceptionConversionGenerator(codegenContext), + ServerRestJsonProtocol(codegenContext), + ) writer.implBlock(symbolProvider.toSymbol(struct)) { builderGenerator.renderConvenienceMethod(writer) @@ -200,15 +215,21 @@ class ServerBuilderDefaultValuesTest { StructureGenerator(model, symbolProvider, writer, struct, emptyList(), codegenContext.structSettings()).render() } - private fun writeServerBuilderGenerator(rustCrate: RustCrate, writer: RustWriter, model: Model, symbolProvider: RustSymbolProvider) { + private fun writeServerBuilderGenerator( + rustCrate: RustCrate, + writer: RustWriter, + model: Model, + symbolProvider: RustSymbolProvider, + ) { val struct = model.lookup("com.test#MyStruct") val codegenContext = serverTestCodegenContext(model) - val builderGenerator = ServerBuilderGenerator( - codegenContext, - struct, - SmithyValidationExceptionConversionGenerator(codegenContext), - ServerRestJsonProtocol(codegenContext), - ) + val builderGenerator = + ServerBuilderGenerator( + codegenContext, + struct, + SmithyValidationExceptionConversionGenerator(codegenContext), + ServerRestJsonProtocol(codegenContext), + ) writer.implBlock(symbolProvider.toSymbol(struct)) { builderGenerator.renderConvenienceMethod(writer) @@ -223,7 +244,10 @@ class ServerBuilderDefaultValuesTest { StructureGenerator(model, symbolProvider, writer, struct, emptyList(), codegenContext.structSettings()).render() } - private fun structSetters(values: Map, optional: Boolean) = writable { + private fun structSetters( + values: Map, + optional: Boolean, + ) = writable { for ((key, value) in values) { withBlock(".${key.toSnakeCase()}(", ")") { conditionalBlock("Some(", ")", optional) { @@ -259,27 +283,30 @@ class ServerBuilderDefaultValuesTest { if (!hasSetValues) { rust("assert!($member.is_none());") } else { - val actual = writable { - rust(member) - if (!requiredTrait && !(hasDefaults && !hasNullValues)) { - rust(".unwrap()") + val actual = + writable { + rust(member) + if (!requiredTrait && !(hasDefaults && !hasNullValues)) { + rust(".unwrap()") + } } - } - val expected = writable { - val expected = if (key == "DocumentNull") { - "aws_smithy_types::Document::Null" - } else if (key == "DocumentString") { - "String::from($value).into()" - } else if (key.startsWith("DocumentNumber")) { - val type = key.replace("DocumentNumber", "") - "aws_smithy_types::Document::Number(aws_smithy_types::Number::$type($value))" - } else if (key.startsWith("Document")) { - "$value.into()" - } else { - "$value" + val expected = + writable { + val expected = + if (key == "DocumentNull") { + "aws_smithy_types::Document::Null" + } else if (key == "DocumentString") { + "String::from($value).into()" + } else if (key.startsWith("DocumentNumber")) { + val type = key.replace("DocumentNumber", "") + "aws_smithy_types::Document::Number(aws_smithy_types::Number::$type($value))" + } else if (key.startsWith("Document")) { + "$value.into()" + } else { + "$value" + } + rust(expected) } - rust(expected) - } rustTemplate("assert_eq!(#{Actual:W}, #{Expected:W});", "Actual" to actual, "Expected" to expected) } } @@ -293,19 +320,21 @@ class ServerBuilderDefaultValuesTest { ): Model { val requiredOrNot = if (requiredTrait) "@required" else "" - val members = values.entries.joinToString(", ") { - val value = if (applyDefaultValues) { - "= ${it.value}" - } else if (nullDefault) { - "= null" - } else { - "" + val members = + values.entries.joinToString(", ") { + val value = + if (applyDefaultValues) { + "= ${it.value}" + } else if (nullDefault) { + "= null" + } else { + "" + } + """ + $requiredOrNot + ${it.key.toPascalCase()}: ${it.key} $value + """ } - """ - $requiredOrNot - ${it.key.toPascalCase()}: ${it.key} $value - """ - } val model = """ namespace com.test @@ -352,26 +381,22 @@ class ServerBuilderDefaultValuesTest { } private fun testParameters(): Stream { - val builderGeneratorKindList = listOf( - BuilderGeneratorKind.SERVER_BUILDER_GENERATOR, - BuilderGeneratorKind.SERVER_BUILDER_GENERATOR_WITHOUT_PUBLIC_CONSTRAINED_TYPES, - ) + val builderGeneratorKindList = + listOf( + BuilderGeneratorKind.SERVER_BUILDER_GENERATOR, + BuilderGeneratorKind.SERVER_BUILDER_GENERATOR_WITHOUT_PUBLIC_CONSTRAINED_TYPES, + ) return Stream.of( TestConfig(defaultValues, requiredTrait = false, nullDefault = true, applyDefaultValues = true), TestConfig(defaultValues, requiredTrait = false, nullDefault = true, applyDefaultValues = false), - TestConfig(customValues, requiredTrait = false, nullDefault = true, applyDefaultValues = true), TestConfig(customValues, requiredTrait = false, nullDefault = true, applyDefaultValues = false), - TestConfig(defaultValues, requiredTrait = true, nullDefault = true, applyDefaultValues = true), TestConfig(customValues, requiredTrait = true, nullDefault = true, applyDefaultValues = true), - TestConfig(defaultValues, requiredTrait = false, nullDefault = false, applyDefaultValues = true), TestConfig(defaultValues, requiredTrait = false, nullDefault = false, applyDefaultValues = false), - TestConfig(customValues, requiredTrait = false, nullDefault = false, applyDefaultValues = true), TestConfig(customValues, requiredTrait = false, nullDefault = false, applyDefaultValues = false), - TestConfig(defaultValues, requiredTrait = true, nullDefault = false, applyDefaultValues = true), TestConfig(customValues, requiredTrait = true, nullDefault = false, applyDefaultValues = true), ).flatMap { (assertValues, requiredTrait, nullDefault, applyDefaultValues) -> diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorTest.kt index 27e45c373c1..ef20b24fb92 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerBuilderGeneratorTest.kt @@ -24,7 +24,8 @@ import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestCode class ServerBuilderGeneratorTest { @Test fun `it respects the sensitive trait in Debug impl`() { - val model = """ + val model = + """ namespace test @sensitive string SecretKey @@ -37,7 +38,7 @@ class ServerBuilderGeneratorTest { password: Password, secretKey: SecretKey } - """.asSmithyModel() + """.asSmithyModel() val codegenContext = serverTestCodegenContext(model) val project = TestWorkspace.testProject() @@ -46,12 +47,13 @@ class ServerBuilderGeneratorTest { val shape = model.lookup("test#Credentials") StructureGenerator(model, codegenContext.symbolProvider, writer, shape, emptyList(), codegenContext.structSettings()).render() - val builderGenerator = ServerBuilderGenerator( - codegenContext, - shape, - SmithyValidationExceptionConversionGenerator(codegenContext), - ServerRestJsonProtocol(codegenContext), - ) + val builderGenerator = + ServerBuilderGenerator( + codegenContext, + shape, + SmithyValidationExceptionConversionGenerator(codegenContext), + ServerRestJsonProtocol(codegenContext), + ) builderGenerator.render(project, writer) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGeneratorTest.kt index bffb82bb408..32361060328 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerEnumGeneratorTest.kt @@ -16,7 +16,8 @@ import software.amazon.smithy.rust.codegen.server.smithy.customizations.SmithyVa import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestCodegenContext class ServerEnumGeneratorTest { - private val model = """ + private val model = + """ namespace test @enum([ { @@ -33,7 +34,7 @@ class ServerEnumGeneratorTest { }, ]) string InstanceType - """.asSmithyModel() + """.asSmithyModel() private val codegenContext = serverTestCodegenContext(model) private val writer = RustWriter.forModule("model") diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerHttpSensitivityGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerHttpSensitivityGeneratorTest.kt index a90acec6e48..0cddbd246a3 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerHttpSensitivityGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerHttpSensitivityGeneratorTest.kt @@ -22,14 +22,16 @@ import software.amazon.smithy.rust.codegen.server.smithy.ServerCargoDependency import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestSymbolProvider class ServerHttpSensitivityGeneratorTest { - private val codegenScope = arrayOf( - "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(TestRuntimeConfig).toType(), - "Http" to CargoDependency.Http.toType(), - ) + private val codegenScope = + arrayOf( + "SmithyHttpServer" to ServerCargoDependency.smithyHttpServer(TestRuntimeConfig).toType(), + "Http" to CargoDependency.Http.toType(), + ) @Test fun `query closure`() { - val model = """ + val model = + """ namespace test operation Secret { @@ -48,7 +50,7 @@ class ServerHttpSensitivityGeneratorTest { @httpQuery("query_b") queryB: SensitiveString } - """.asSmithyModel() + """.asSmithyModel() val operation = model.operationShapes.toList()[0] val generator = ServerHttpSensitivityGenerator(model, operation, TestRuntimeConfig) @@ -77,7 +79,8 @@ class ServerHttpSensitivityGeneratorTest { @Test fun `query params closure`() { - val model = """ + val model = + """ namespace test operation Secret { @@ -95,7 +98,7 @@ class ServerHttpSensitivityGeneratorTest { @httpQueryParams() params: StringMap, } - """.asSmithyModel() + """.asSmithyModel() val operation = model.operationShapes.toList()[0] val generator = ServerHttpSensitivityGenerator(model, operation, TestRuntimeConfig) @@ -123,7 +126,8 @@ class ServerHttpSensitivityGeneratorTest { @Test fun `query params key closure`() { - val model = """ + val model = + """ namespace test operation Secret { @@ -144,7 +148,7 @@ class ServerHttpSensitivityGeneratorTest { value: String } - """.asSmithyModel() + """.asSmithyModel() val operation = model.operationShapes.toList()[0] val generator = ServerHttpSensitivityGenerator(model, operation, TestRuntimeConfig) @@ -171,7 +175,8 @@ class ServerHttpSensitivityGeneratorTest { @Test fun `query params value closure`() { - val model = """ + val model = + """ namespace test operation Secret { @@ -192,7 +197,7 @@ class ServerHttpSensitivityGeneratorTest { value: SensitiveValue } - """.asSmithyModel() + """.asSmithyModel() val operation = model.operationShapes.toList()[0] val generator = ServerHttpSensitivityGenerator(model, operation, TestRuntimeConfig) @@ -219,7 +224,8 @@ class ServerHttpSensitivityGeneratorTest { @Test fun `query params none`() { - val model = """ + val model = + """ namespace test operation Secret { @@ -237,7 +243,7 @@ class ServerHttpSensitivityGeneratorTest { value: String } - """.asSmithyModel() + """.asSmithyModel() val operation = model.operationShapes.toList()[0] val generator = ServerHttpSensitivityGenerator(model, operation, TestRuntimeConfig) @@ -250,7 +256,8 @@ class ServerHttpSensitivityGeneratorTest { @Test fun `header closure`() { - val model = """ + val model = + """ namespace test operation Secret { @@ -269,7 +276,7 @@ class ServerHttpSensitivityGeneratorTest { @httpHeader("header-b") headerB: SensitiveString } - """.asSmithyModel() + """.asSmithyModel() val operation = model.operationShapes.toList()[0] val generator = ServerHttpSensitivityGenerator(model, operation, TestRuntimeConfig) @@ -299,7 +306,8 @@ class ServerHttpSensitivityGeneratorTest { @Test fun `prefix header closure`() { - val model = """ + val model = + """ namespace test operation Secret { @@ -318,7 +326,7 @@ class ServerHttpSensitivityGeneratorTest { value: String } - """.asSmithyModel() + """.asSmithyModel() val operation = model.operationShapes.toList()[0] val generator = ServerHttpSensitivityGenerator(model, operation, TestRuntimeConfig) @@ -349,7 +357,8 @@ class ServerHttpSensitivityGeneratorTest { @Test fun `prefix header none`() { - val model = """ + val model = + """ namespace test operation Secret { @@ -367,7 +376,7 @@ class ServerHttpSensitivityGeneratorTest { value: String } - """.asSmithyModel() + """.asSmithyModel() val operation = model.operationShapes.toList()[0] val generator = ServerHttpSensitivityGenerator(model, operation, TestRuntimeConfig) @@ -379,7 +388,8 @@ class ServerHttpSensitivityGeneratorTest { @Test fun `prefix headers key closure`() { - val model = """ + val model = + """ namespace test operation Secret { @@ -399,7 +409,7 @@ class ServerHttpSensitivityGeneratorTest { value: String } - """.asSmithyModel() + """.asSmithyModel() val operation = model.operationShapes.toList()[0] val generator = ServerHttpSensitivityGenerator(model, operation, TestRuntimeConfig) @@ -432,7 +442,8 @@ class ServerHttpSensitivityGeneratorTest { @Test fun `prefix headers value closure`() { - val model = """ + val model = + """ namespace test operation Secret { @@ -452,7 +463,7 @@ class ServerHttpSensitivityGeneratorTest { key: String, value: SensitiveValue } - """.asSmithyModel() + """.asSmithyModel() val operation = model.operationShapes.toList()[0] val generator = ServerHttpSensitivityGenerator(model, operation, TestRuntimeConfig) @@ -486,7 +497,8 @@ class ServerHttpSensitivityGeneratorTest { @Test fun `uri closure`() { - val model = """ + val model = + """ namespace test @http(method: "GET", uri: "/secret/{labelA}/{labelB}") @@ -505,7 +517,7 @@ class ServerHttpSensitivityGeneratorTest { @httpLabel labelB: SensitiveString, } - """.asSmithyModel() + """.asSmithyModel() val operation = model.operationShapes.toList()[0] val generator = ServerHttpSensitivityGenerator(model, operation, TestRuntimeConfig) @@ -535,7 +547,8 @@ class ServerHttpSensitivityGeneratorTest { @Test fun `uri greedy`() { - val model = """ + val model = + """ namespace test @http(method: "GET", uri: "/secret/{labelA}/{labelB+}/labelC") @@ -554,7 +567,7 @@ class ServerHttpSensitivityGeneratorTest { @httpLabel labelB: SensitiveString, } - """.asSmithyModel() + """.asSmithyModel() val operation = model.operationShapes.toList()[0] val generator = ServerHttpSensitivityGenerator(model, operation, TestRuntimeConfig) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiatorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiatorTest.kt index 5a6f9791518..1a1f9f01eab 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiatorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerInstantiatorTest.kt @@ -39,7 +39,8 @@ import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestCode class ServerInstantiatorTest { // This model started off from the one in `InstantiatorTest.kt` from `codegen-core`. - private val model = """ + private val model = + """ namespace com.test use smithy.framework#ValidationException @@ -136,7 +137,9 @@ class ServerInstantiatorTest { }, ]) string NamedEnum - """.asSmithyModel().let { RecursiveShapeBoxer().transform(it) } + """.asSmithyModel().let { + RecursiveShapeBoxer().transform(it) + } private val codegenContext = serverTestCodegenContext(model) private val symbolProvider = codegenContext.symbolProvider @@ -269,17 +272,19 @@ class ServerInstantiatorTest { UnionGenerator(model, symbolProvider, this, nestedUnion).render() unitTest("writable_for_shapes") { - val sut = ServerInstantiator( - codegenContext, - customWritable = object : Instantiator.CustomWritable { - override fun generate(shape: Shape): Writable? = - if (model.lookup("com.test#NestedStruct\$num") == shape) { - writable("40 + 2") - } else { - null - } - }, - ) + val sut = + ServerInstantiator( + codegenContext, + customWritable = + object : Instantiator.CustomWritable { + override fun generate(shape: Shape): Writable? = + if (model.lookup("com.test#NestedStruct\$num") == shape) { + writable("40 + 2") + } else { + null + } + }, + ) val data = Node.parse("""{ "str": "hello", "num": 1 }""") withBlock("let result = ", ";") { sut.render(this, model.lookup("com.test#NestedStruct"), data as ObjectNode) @@ -294,39 +299,43 @@ class ServerInstantiatorTest { unitTest("writable_for_nested_inner_members") { val map = model.lookup("com.test#Inner\$map") - val sut = ServerInstantiator( - codegenContext, - customWritable = object : Instantiator.CustomWritable { - private var n: Int = 0 - override fun generate(shape: Shape): Writable? = - if (shape != map) { - null - } else if (n != 2) { - n += 1 - null - } else { - n += 1 - writable("None") - } - }, - ) - val data = Node.parse( - """ - { - "map": { - "k1": { - "map": { - "k2": { - "map": { - "never": {} + val sut = + ServerInstantiator( + codegenContext, + customWritable = + object : Instantiator.CustomWritable { + private var n: Int = 0 + + override fun generate(shape: Shape): Writable? = + if (shape != map) { + null + } else if (n != 2) { + n += 1 + null + } else { + n += 1 + writable("None") + } + }, + ) + val data = + Node.parse( + """ + { + "map": { + "k1": { + "map": { + "k2": { + "map": { + "never": {} + } } } } } } - } - """, - ) + """, + ) withBlock("let result = ", ";") { sut.render(this, inner, data as ObjectNode) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationErrorGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationErrorGeneratorTest.kt index a73466277a8..8f0cc80dcb5 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationErrorGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServerOperationErrorGeneratorTest.kt @@ -19,7 +19,8 @@ import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverRenderWi import software.amazon.smithy.rust.codegen.server.smithy.testutil.serverTestSymbolProvider class ServerOperationErrorGeneratorTest { - private val baseModel = """ + private val baseModel = + """ namespace error use aws.protocols#restJson1 @@ -52,7 +53,7 @@ class ServerOperationErrorGeneratorTest { @error("server") @deprecated structure Deprecated { } - """.asSmithyModel() + """.asSmithyModel() private val model = OperationNormalizer.transform(baseModel) private val symbolProvider = serverTestSymbolProvider(model) diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServiceConfigGeneratorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServiceConfigGeneratorTest.kt index c2c568b291c..fcb61ae53a2 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServiceConfigGeneratorTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/ServiceConfigGeneratorTest.kt @@ -5,7 +5,10 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.string.shouldContain import org.junit.jupiter.api.Test +import software.amazon.smithy.codegen.core.CodegenException import software.amazon.smithy.rust.codegen.core.rustlang.rust import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.rustlang.writable @@ -24,62 +27,70 @@ internal class ServiceConfigGeneratorTest { fun `it should inject an aws_auth method that configures an HTTP plugin and a model plugin`() { val model = File("../codegen-core/common-test-models/simple.smithy").readText().asSmithyModel() - val decorator = object : ServerCodegenDecorator { - override val name: String - get() = "AWSAuth pre-applied middleware decorator" - override val order: Byte - get() = -69 + val decorator = + object : ServerCodegenDecorator { + override val name: String + get() = "AWSAuth pre-applied middleware decorator" + override val order: Byte + get() = -69 - override fun configMethods(codegenContext: ServerCodegenContext): List { - val smithyHttpServer = ServerCargoDependency.smithyHttpServer(codegenContext.runtimeConfig).toType() - val codegenScope = arrayOf( - "SmithyHttpServer" to smithyHttpServer, - ) - return listOf( - ConfigMethod( - name = "aws_auth", - docs = "Docs", - params = listOf( - Binding("auth_spec", RuntimeType.String), - Binding("authorizer", RuntimeType.U64), - ), - errorType = RuntimeType.std.resolve("io::Error"), - initializer = Initializer( - code = writable { - rustTemplate( - """ - if authorizer != 69 { - return Err(std::io::Error::new(std::io::ErrorKind::Other, "failure 1")); - } - - if auth_spec.len() != 69 { - return Err(std::io::Error::new(std::io::ErrorKind::Other, "failure 2")); - } - let authn_plugin = #{SmithyHttpServer}::plugin::IdentityPlugin; - let authz_plugin = #{SmithyHttpServer}::plugin::IdentityPlugin; - """, - *codegenScope, - ) - }, - layerBindings = emptyList(), - httpPluginBindings = listOf( - Binding( - "authn_plugin", - smithyHttpServer.resolve("plugin::IdentityPlugin"), + override fun configMethods(codegenContext: ServerCodegenContext): List { + val smithyHttpServer = ServerCargoDependency.smithyHttpServer(codegenContext.runtimeConfig).toType() + val codegenScope = + arrayOf( + "SmithyHttpServer" to smithyHttpServer, + ) + return listOf( + ConfigMethod( + name = "aws_auth", + docs = "Docs", + params = + listOf( + Binding.Concrete("auth_spec", RuntimeType.String), + Binding.Concrete("authorizer", RuntimeType.U64), + Binding.Generic("generic_list", RuntimeType("::std::vec::Vec"), setOf("T")), ), - ), - modelPluginBindings = listOf( - Binding( - "authz_plugin", - smithyHttpServer.resolve("plugin::IdentityPlugin"), + errorType = RuntimeType.std.resolve("io::Error"), + initializer = + Initializer( + code = + writable { + rustTemplate( + """ + if authorizer != 69 { + return Err(std::io::Error::new(std::io::ErrorKind::Other, "failure 1")); + } + + if auth_spec.len() != 69 && generic_list.len() != 69 { + return Err(std::io::Error::new(std::io::ErrorKind::Other, "failure 2")); + } + let authn_plugin = #{SmithyHttpServer}::plugin::IdentityPlugin; + let authz_plugin = #{SmithyHttpServer}::plugin::IdentityPlugin; + """, + *codegenScope, + ) + }, + layerBindings = emptyList(), + httpPluginBindings = + listOf( + Binding.Concrete( + "authn_plugin", + smithyHttpServer.resolve("plugin::IdentityPlugin"), + ), + ), + modelPluginBindings = + listOf( + Binding.Concrete( + "authz_plugin", + smithyHttpServer.resolve("plugin::IdentityPlugin"), + ), + ), ), - ), + isRequired = true, ), - isRequired = true, - ), - ) + ) + } } - } serverIntegrationTest(model, additionalDecorators = listOf(decorator)) { _, rustCrate -> rustCrate.testModule { @@ -101,7 +112,7 @@ internal class ServiceConfigGeneratorTest { // One model plugin has been applied. PluginStack, > = SimpleServiceConfig::builder() - .aws_auth("a".repeat(69).to_owned(), 69) + .aws_auth("a".repeat(69).to_owned(), 69, vec![69]) .expect("failed to configure aws_auth") .build() .unwrap(); @@ -113,7 +124,7 @@ internal class ServiceConfigGeneratorTest { rust( """ let actual_err = SimpleServiceConfig::builder() - .aws_auth("a".to_owned(), 69) + .aws_auth("a".to_owned(), 69, vec![69]) .unwrap_err(); let expected = std::io::Error::new(std::io::ErrorKind::Other, "failure 2").to_string(); assert_eq!(actual_err.to_string(), expected); @@ -125,7 +136,7 @@ internal class ServiceConfigGeneratorTest { rust( """ let actual_err = SimpleServiceConfig::builder() - .aws_auth("a".repeat(69).to_owned(), 6969) + .aws_auth("a".repeat(69).to_owned(), 6969, vec!["69"]) .unwrap_err(); let expected = std::io::Error::new(std::io::ErrorKind::Other, "failure 1").to_string(); assert_eq!(actual_err.to_string(), expected); @@ -147,50 +158,55 @@ internal class ServiceConfigGeneratorTest { } @Test - fun `it should inject an method that applies three non-required layers`() { + fun `it should inject a method that applies three non-required layers`() { val model = File("../codegen-core/common-test-models/simple.smithy").readText().asSmithyModel() - val decorator = object : ServerCodegenDecorator { - override val name: String - get() = "ApplyThreeNonRequiredLayers" - override val order: Byte - get() = 69 + val decorator = + object : ServerCodegenDecorator { + override val name: String + get() = "ApplyThreeNonRequiredLayers" + override val order: Byte + get() = 69 - override fun configMethods(codegenContext: ServerCodegenContext): List { - val identityLayer = RuntimeType.Tower.resolve("layer::util::Identity") - val codegenScope = arrayOf( - "Identity" to identityLayer, - ) - return listOf( - ConfigMethod( - name = "three_non_required_layers", - docs = "Docs", - params = emptyList(), - errorType = null, - initializer = Initializer( - code = writable { - rustTemplate( - """ - let layer1 = #{Identity}::new(); - let layer2 = #{Identity}::new(); - let layer3 = #{Identity}::new(); - """, - *codegenScope, - ) - }, - layerBindings = listOf( - Binding("layer1", identityLayer), - Binding("layer2", identityLayer), - Binding("layer3", identityLayer), - ), - httpPluginBindings = emptyList(), - modelPluginBindings = emptyList(), + override fun configMethods(codegenContext: ServerCodegenContext): List { + val identityLayer = RuntimeType.Tower.resolve("layer::util::Identity") + val codegenScope = + arrayOf( + "Identity" to identityLayer, + ) + return listOf( + ConfigMethod( + name = "three_non_required_layers", + docs = "Docs", + params = emptyList(), + errorType = null, + initializer = + Initializer( + code = + writable { + rustTemplate( + """ + let layer1 = #{Identity}::new(); + let layer2 = #{Identity}::new(); + let layer3 = #{Identity}::new(); + """, + *codegenScope, + ) + }, + layerBindings = + listOf( + Binding.Concrete("layer1", identityLayer), + Binding.Concrete("layer2", identityLayer), + Binding.Concrete("layer3", identityLayer), + ), + httpPluginBindings = emptyList(), + modelPluginBindings = emptyList(), + ), + isRequired = false, ), - isRequired = false, - ), - ) + ) + } } - } serverIntegrationTest(model, additionalDecorators = listOf(decorator)) { _, rustCrate -> rustCrate.testModule { @@ -228,4 +244,50 @@ internal class ServiceConfigGeneratorTest { } } } + + @Test + fun `it should throw an exception if a generic binding using L, H, or M is used`() { + val model = File("../codegen-core/common-test-models/simple.smithy").readText().asSmithyModel() + + val decorator = + object : ServerCodegenDecorator { + override val name: String + get() = "InvalidGenericBindingsDecorator" + override val order: Byte + get() = 69 + + override fun configMethods(codegenContext: ServerCodegenContext): List { + val identityLayer = RuntimeType.Tower.resolve("layer::util::Identity") + return listOf( + ConfigMethod( + name = "invalid_generic_bindings", + docs = "Docs", + params = + listOf( + Binding.Generic("param1_bad", identityLayer, setOf("L")), + Binding.Generic("param2_bad", identityLayer, setOf("H")), + Binding.Generic("param3_bad", identityLayer, setOf("M")), + Binding.Generic("param4_ok", identityLayer, setOf("N")), + ), + errorType = null, + initializer = + Initializer( + code = writable {}, + layerBindings = emptyList(), + httpPluginBindings = emptyList(), + modelPluginBindings = emptyList(), + ), + isRequired = false, + ), + ) + } + } + + val codegenException = + shouldThrow { + serverIntegrationTest(model, additionalDecorators = listOf(decorator)) { _, _ -> } + } + + codegenException.message.shouldContain("Injected config method `invalid_generic_bindings` has generic bindings that use `L`, `H`, or `M` to refer to the generic types. This is not allowed. Invalid generic bindings:") + } } diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/RecursiveConstraintViolationBoxerTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/RecursiveConstraintViolationBoxerTest.kt index 622d3806039..3fe7cc75db7 100644 --- a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/RecursiveConstraintViolationBoxerTest.kt +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/transformers/RecursiveConstraintViolationBoxerTest.kt @@ -20,9 +20,10 @@ internal class RecursiveConstraintViolationBoxerTest { fun `recursive constraint violation boxer test`(testCase: RecursiveConstraintViolationsTest.TestCase) { val transformed = RecursiveConstraintViolationBoxer.transform(testCase.model) - val shapesWithConstraintViolationRustBoxTrait = transformed.shapes().filter { - it.hasTrait() - }.toList() + val shapesWithConstraintViolationRustBoxTrait = + transformed.shapes().filter { + it.hasTrait() + }.toList() // Only the provided member shape should have the trait attached. shapesWithConstraintViolationRustBoxTrait shouldBe diff --git a/codegen-server/typescript/build.gradle.kts b/codegen-server/typescript/build.gradle.kts index 81f543c2220..1e67077d7a2 100644 --- a/codegen-server/typescript/build.gradle.kts +++ b/codegen-server/typescript/build.gradle.kts @@ -29,7 +29,12 @@ dependencies { implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion") } -tasks.compileKotlin { kotlinOptions.jvmTarget = "1.8" } +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + +tasks.compileKotlin { kotlinOptions.jvmTarget = "11" } // Reusable license copySpec val licenseSpec = copySpec { @@ -60,7 +65,7 @@ if (isTestingEnabled.toBoolean()) { testImplementation("io.kotest:kotest-assertions-core-jvm:$kotestVersion") } - tasks.compileTestKotlin { kotlinOptions.jvmTarget = "1.8" } + tasks.compileTestKotlin { kotlinOptions.jvmTarget = "11" } tasks.test { useJUnitPlatform() diff --git a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/RustServerCodegenTsPlugin.kt b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/RustServerCodegenTsPlugin.kt index 10aafec81bb..5cbf3732f9c 100644 --- a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/RustServerCodegenTsPlugin.kt +++ b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/RustServerCodegenTsPlugin.kt @@ -78,28 +78,27 @@ class RustServerCodegenTsPlugin : SmithyBuildPlugin { constrainedTypes: Boolean = true, includeConstrainedShapeProvider: Boolean = true, codegenDecorator: ServerCodegenDecorator, - ) = - TsServerSymbolVisitor(settings, model, serviceShape = serviceShape, config = rustSymbolProviderConfig) - // Generate public constrained types for directly constrained shapes. - // In the Typescript server project, this is only done to generate constrained types for simple shapes (e.g. - // a `string` shape with the `length` trait), but these always remain `pub(crate)`. - .let { - if (includeConstrainedShapeProvider) ConstrainedShapeSymbolProvider(it, serviceShape, constrainedTypes) else it - } - // Generate different types for EventStream shapes (e.g. transcribe streaming) - .let { EventStreamSymbolProvider(rustSymbolProviderConfig.runtimeConfig, it, CodegenTarget.SERVER) } - // Add Rust attributes (like `#[derive(PartialEq)]`) to generated shapes - .let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf()) } - // Constrained shapes generate newtypes that need the same derives we place on types generated from aggregate shapes. - .let { ConstrainedShapeSymbolMetadataProvider(it, constrainedTypes) } - // Streaming shapes need different derives (e.g. they cannot derive Eq) - .let { TsStreamingShapeMetadataProvider(it) } - // Derive `Eq` and `Hash` if possible. - .let { DeriveEqAndHashSymbolMetadataProvider(it) } - // Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot - // be the name of an operation input - .let { RustReservedWordSymbolProvider(it, ServerReservedWords) } - // Allows decorators to inject a custom symbol provider - .let { codegenDecorator.symbolProvider(it) } + ) = TsServerSymbolVisitor(settings, model, serviceShape = serviceShape, config = rustSymbolProviderConfig) + // Generate public constrained types for directly constrained shapes. + // In the Typescript server project, this is only done to generate constrained types for simple shapes (e.g. + // a `string` shape with the `length` trait), but these always remain `pub(crate)`. + .let { + if (includeConstrainedShapeProvider) ConstrainedShapeSymbolProvider(it, serviceShape, constrainedTypes) else it + } + // Generate different types for EventStream shapes (e.g. transcribe streaming) + .let { EventStreamSymbolProvider(rustSymbolProviderConfig.runtimeConfig, it, CodegenTarget.SERVER) } + // Add Rust attributes (like `#[derive(PartialEq)]`) to generated shapes + .let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf()) } + // Constrained shapes generate newtypes that need the same derives we place on types generated from aggregate shapes. + .let { ConstrainedShapeSymbolMetadataProvider(it, constrainedTypes) } + // Streaming shapes need different derives (e.g. they cannot derive Eq) + .let { TsStreamingShapeMetadataProvider(it) } + // Derive `Eq` and `Hash` if possible. + .let { DeriveEqAndHashSymbolMetadataProvider(it) } + // Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot + // be the name of an operation input + .let { RustReservedWordSymbolProvider(it, ServerReservedWords) } + // Allows decorators to inject a custom symbol provider + .let { codegenDecorator.symbolProvider(it) } } } diff --git a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/TsServerCargoDependency.kt b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/TsServerCargoDependency.kt index 5c3b4c22093..c23a59433b0 100644 --- a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/TsServerCargoDependency.kt +++ b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/TsServerCargoDependency.kt @@ -23,11 +23,14 @@ object TsServerCargoDependency { val Tracing: CargoDependency = CargoDependency("tracing", CratesIo("0.1")) val Tower: CargoDependency = CargoDependency("tower", CratesIo("0.4")) val TowerHttp: CargoDependency = CargoDependency("tower-http", CratesIo("0.3"), features = setOf("trace")) - val Hyper: CargoDependency = CargoDependency("hyper", CratesIo("0.14.12"), features = setOf("server", "http1", "http2", "tcp", "stream")) + val Hyper: CargoDependency = + CargoDependency("hyper", CratesIo("0.14.12"), features = setOf("server", "http1", "http2", "tcp", "stream")) val NumCpus: CargoDependency = CargoDependency("num_cpus", CratesIo("1.13")) val ParkingLot: CargoDependency = CargoDependency("parking_lot", CratesIo("0.12")) val Socket2: CargoDependency = CargoDependency("socket2", CratesIo("0.4")) fun smithyHttpServer(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-http-server") - fun smithyHttpServerTs(runtimeConfig: RuntimeConfig) = runtimeConfig.smithyRuntimeCrate("smithy-http-server-typescript") + + fun smithyHttpServerTs(runtimeConfig: RuntimeConfig) = + runtimeConfig.smithyRuntimeCrate("smithy-http-server-typescript") } diff --git a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/TsServerCodegenVisitor.kt b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/TsServerCodegenVisitor.kt index b1513b1be35..d47ed0b09a8 100644 --- a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/TsServerCodegenVisitor.kt +++ b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/TsServerCodegenVisitor.kt @@ -49,7 +49,6 @@ class TsServerCodegenVisitor( context: PluginContext, private val codegenDecorator: ServerCodegenDecorator, ) : ServerCodegenVisitor(context, codegenDecorator) { - init { val symbolVisitorConfig = RustSymbolProviderConfig( @@ -84,17 +83,19 @@ class TsServerCodegenVisitor( publicConstrainedTypes: Boolean, includeConstraintShapeProvider: Boolean, codegenDecorator: ServerCodegenDecorator, - ) = RustServerCodegenTsPlugin.baseSymbolProvider(settings, model, serviceShape, rustSymbolProviderConfig, publicConstrainedTypes, includeConstraintShapeProvider, codegenDecorator) - - val serverSymbolProviders = ServerSymbolProviders.from( - settings, - model, - service, - symbolVisitorConfig, - settings.codegenConfig.publicConstrainedTypes, - codegenDecorator, - ::baseSymbolProviderFactory, - ) + ) = + RustServerCodegenTsPlugin.baseSymbolProvider(settings, model, serviceShape, rustSymbolProviderConfig, publicConstrainedTypes, includeConstraintShapeProvider, codegenDecorator) + + val serverSymbolProviders = + ServerSymbolProviders.from( + settings, + model, + service, + symbolVisitorConfig, + settings.codegenConfig.publicConstrainedTypes, + codegenDecorator, + ::baseSymbolProviderFactory, + ) // Override `codegenContext` which carries the various symbol providers. codegenContext = @@ -111,18 +112,21 @@ class TsServerCodegenVisitor( serverSymbolProviders.pubCrateConstrainedShapeSymbolProvider, ) - codegenContext = codegenContext.copy( - moduleDocProvider = codegenDecorator.moduleDocumentationCustomization( - codegenContext, - TsServerModuleDocProvider(ServerModuleDocProvider(codegenContext)), - ), - ) + codegenContext = + codegenContext.copy( + moduleDocProvider = + codegenDecorator.moduleDocumentationCustomization( + codegenContext, + TsServerModuleDocProvider(ServerModuleDocProvider(codegenContext)), + ), + ) // Override `rustCrate` which carries the symbolProvider. - rustCrate = RustCrate( - context.fileManifest, codegenContext.symbolProvider, settings.codegenConfig, - codegenContext.expectModuleDocProvider(), - ) + rustCrate = + RustCrate( + context.fileManifest, codegenContext.symbolProvider, settings.codegenConfig, + codegenContext.expectModuleDocProvider(), + ) // Override `protocolGenerator` which carries the symbolProvider. protocolGenerator = protocolGeneratorFactory.buildProtocolGenerator(codegenContext) } @@ -164,8 +168,10 @@ class TsServerCodegenVisitor( * Although raw strings require no code generation, enums are actually [EnumTrait] applied to string shapes. */ override fun stringShape(shape: StringShape) { - fun tsServerEnumGeneratorFactory(codegenContext: ServerCodegenContext, shape: StringShape) = - TsServerEnumGenerator(codegenContext, shape, validationExceptionConversionGenerator) + fun tsServerEnumGeneratorFactory( + codegenContext: ServerCodegenContext, + shape: StringShape, + ) = TsServerEnumGenerator(codegenContext, shape, validationExceptionConversionGenerator) stringShape(shape, ::tsServerEnumGeneratorFactory) } diff --git a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/TsServerSymbolProvider.kt b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/TsServerSymbolProvider.kt index a7ca74d064c..cc042767db9 100644 --- a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/TsServerSymbolProvider.kt +++ b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/TsServerSymbolProvider.kt @@ -120,6 +120,7 @@ class TsStreamingShapeMetadataProvider(private val base: RustSymbolProvider) : S } override fun memberMeta(memberShape: MemberShape) = base.toSymbol(memberShape).expectRustMetadata() + override fun enumMeta(stringShape: StringShape): RustMetadata = RustMetadata( setOf(RuntimeType.Eq, RuntimeType.Ord, RuntimeType.PartialEq, RuntimeType.PartialOrd, RuntimeType.Debug), @@ -128,8 +129,12 @@ class TsStreamingShapeMetadataProvider(private val base: RustSymbolProvider) : S ) override fun listMeta(listShape: ListShape) = base.toSymbol(listShape).expectRustMetadata() + override fun mapMeta(mapShape: MapShape) = base.toSymbol(mapShape).expectRustMetadata() + override fun stringMeta(stringShape: StringShape) = base.toSymbol(stringShape).expectRustMetadata() + override fun numberMeta(numberShape: NumberShape) = base.toSymbol(numberShape).expectRustMetadata() + override fun blobMeta(blobShape: BlobShape) = base.toSymbol(blobShape).expectRustMetadata() } diff --git a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/customizations/TsServerCodegenDecorator.kt b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/customizations/TsServerCodegenDecorator.kt index 885bac4a9a0..00e42d7d511 100644 --- a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/customizations/TsServerCodegenDecorator.kt +++ b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/customizations/TsServerCodegenDecorator.kt @@ -25,13 +25,12 @@ class CdylibManifestDecorator : ServerCodegenDecorator { override val name: String = "CdylibDecorator" override val order: Byte = 0 - override fun crateManifestCustomizations( - codegenContext: ServerCodegenContext, - ): ManifestCustomizations = + override fun crateManifestCustomizations(codegenContext: ServerCodegenContext): ManifestCustomizations = mapOf( - "lib" to mapOf( - "crate-type" to listOf("cdylib"), - ), + "lib" to + mapOf( + "crate-type" to listOf("cdylib"), + ), ) } @@ -40,7 +39,10 @@ class NapiBuildRsDecorator : ServerCodegenDecorator { override val order: Byte = 0 private val napi_build = TsServerCargoDependency.NapiBuild.toType() - override fun extras(codegenContext: ServerCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ServerCodegenContext, + rustCrate: RustCrate, + ) { rustCrate.withFile("build.rs") { rustTemplate( """ @@ -58,7 +60,10 @@ class NapiPackageJsonDecorator : ServerCodegenDecorator { override val name: String = "NapiPackageJsonDecorator" override val order: Byte = 0 - override fun extras(codegenContext: ServerCodegenContext, rustCrate: RustCrate) { + override fun extras( + codegenContext: ServerCodegenContext, + rustCrate: RustCrate, + ) { val name = codegenContext.settings.moduleName.toSnakeCase() val version = codegenContext.settings.moduleVersion @@ -99,16 +104,17 @@ class NapiPackageJsonDecorator : ServerCodegenDecorator { } } -val DECORATORS = arrayOf( - /** - * Add the [InternalServerError] error to all operations. - * This is done because the Typescript interpreter can raise eceptions during execution. - */ - AddInternalServerErrorToAllOperationsDecorator(), - // Add the [lib] section to Cargo.toml to configure the generation of the shared library. - CdylibManifestDecorator(), - // Add the build.rs file needed to generate Typescript code. - NapiBuildRsDecorator(), - // Add the napi package.json. - NapiPackageJsonDecorator(), -) +val DECORATORS = + arrayOf( + /* + * Add the [InternalServerError] error to all operations. + * This is done because the Typescript interpreter can raise eceptions during execution. + */ + AddInternalServerErrorToAllOperationsDecorator(), + // Add the [lib] section to Cargo.toml to configure the generation of the shared library. + CdylibManifestDecorator(), + // Add the build.rs file needed to generate Typescript code. + NapiBuildRsDecorator(), + // Add the napi package.json. + NapiPackageJsonDecorator(), + ) diff --git a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/generators/TsApplicationGenerator.kt b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/generators/TsApplicationGenerator.kt index 92e346fa918..7809c9562c1 100644 --- a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/generators/TsApplicationGenerator.kt +++ b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/generators/TsApplicationGenerator.kt @@ -29,11 +29,12 @@ class TsApplicationGenerator( private val protocol: ServerProtocol, ) { private val index = TopDownIndex.of(codegenContext.model) - private val operations = index.getContainedOperations(codegenContext.serviceShape).toSortedSet( - compareBy { - it.id - }, - ).toList() + private val operations = + index.getContainedOperations(codegenContext.serviceShape).toSortedSet( + compareBy { + it.id + }, + ).toList() private val symbolProvider = codegenContext.symbolProvider private val libName = codegenContext.settings.moduleName.toSnakeCase() private val runtimeConfig = codegenContext.runtimeConfig @@ -263,7 +264,8 @@ class TsApplicationGenerator( writer.rustBlock("impl TsSocket") { writer.rustTemplate( - """pub fn to_raw_socket(&self) -> #{napi}::Result<#{socket2}::Socket> { + """ + pub fn to_raw_socket(&self) -> #{napi}::Result<#{socket2}::Socket> { self.0 .try_clone() .map_err(|e| #{napi}::Error::from_reason(e.to_string())) @@ -277,7 +279,8 @@ class TsApplicationGenerator( private fun renderServer(writer: RustWriter) { writer.rustBlockTemplate( - """pub fn start_hyper_worker( + """ + pub fn start_hyper_worker( socket: &TsSocket, app: #{tower}::util::BoxCloneService< #{http}::Request<#{SmithyServer}::body::Body>, diff --git a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/generators/TsServerEnumGenerator.kt b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/generators/TsServerEnumGenerator.kt index f12ebb5ef68..aef08a3484b 100644 --- a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/generators/TsServerEnumGenerator.kt +++ b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/generators/TsServerEnumGenerator.kt @@ -28,9 +28,10 @@ class TsConstrainedEnum( ) : ConstrainedEnum(codegenContext, shape, validationExceptionConversionGenerator) { private val napiDerive = TsServerCargoDependency.NapiDerive.toType() - override fun additionalEnumImpls(context: EnumGeneratorContext): Writable = writable { - this.rust("use napi::bindgen_prelude::ToNapiValue;") - } + override fun additionalEnumImpls(context: EnumGeneratorContext): Writable = + writable { + this.rust("use napi::bindgen_prelude::ToNapiValue;") + } override fun additionalEnumAttributes(context: EnumGeneratorContext): List = listOf(Attribute(napiDerive.resolve("napi"))) @@ -41,12 +42,12 @@ class TsServerEnumGenerator( shape: StringShape, validationExceptionConversionGenerator: ValidationExceptionConversionGenerator, ) : EnumGenerator( - codegenContext.model, - codegenContext.symbolProvider, - shape, - TsConstrainedEnum( - codegenContext, + codegenContext.model, + codegenContext.symbolProvider, shape, - validationExceptionConversionGenerator, - ), -) + TsConstrainedEnum( + codegenContext, + shape, + validationExceptionConversionGenerator, + ), + ) diff --git a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/generators/TsServerStructureGenerator.kt b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/generators/TsServerStructureGenerator.kt index cf08892bc9b..9bdf53db1a5 100644 --- a/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/generators/TsServerStructureGenerator.kt +++ b/codegen-server/typescript/src/main/kotlin/software/amazon/smithy/rust/codegen/server/typescript/smithy/generators/TsServerStructureGenerator.kt @@ -29,15 +29,15 @@ class TsServerStructureGenerator( private val writer: RustWriter, private val shape: StructureShape, ) : StructureGenerator(model, symbolProvider, writer, shape, listOf(), StructSettings(flattenVecAccessors = false)) { - private val napiDerive = TsServerCargoDependency.NapiDerive.toType() override fun renderStructure() { - val flavour = if (shape.hasTrait()) { - "constructor" - } else { - "object" - } + val flavour = + if (shape.hasTrait()) { + "constructor" + } else { + "object" + } Attribute( writable { rustInlineTemplate( diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 9d38f8d778c..d92869a661d 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -1,5 +1,6 @@ # Without this configuration, the workspace will be read from `rust-runtime`, causing the build to fail. [workspace] +resolver = "2" members = [ "pokemon-service-common", "pokemon-service", diff --git a/examples/pokemon-service-client-usage/Cargo.toml b/examples/pokemon-service-client-usage/Cargo.toml index dc1acaeaf42..290c8d80cb5 100644 --- a/examples/pokemon-service-client-usage/Cargo.toml +++ b/examples/pokemon-service-client-usage/Cargo.toml @@ -24,6 +24,8 @@ aws-smithy-types = { path = "../../rust-runtime/aws-smithy-types/" } # Required for `HyperClientBuilder` in `client-connector` example. aws-smithy-runtime = { path = "../../rust-runtime/aws-smithy-runtime/", features=["test-util"] } +# Required for `Metadata` in `custom-header-using-interceptor` example. +aws-smithy-runtime-api = { path = "../../rust-runtime/aws-smithy-runtime-api/", features=["client"] } hyper = { version = "0.14.25", features = ["client", "full"] } diff --git a/examples/pokemon-service-client-usage/examples/custom-header-using-interceptor.rs b/examples/pokemon-service-client-usage/examples/custom-header-using-interceptor.rs index 997cce306e3..00878beb5eb 100644 --- a/examples/pokemon-service-client-usage/examples/custom-header-using-interceptor.rs +++ b/examples/pokemon-service-client-usage/examples/custom-header-using-interceptor.rs @@ -14,6 +14,7 @@ /// use std::{collections::HashMap, time::Duration}; +use aws_smithy_runtime_api::client::orchestrator::Metadata; use pokemon_service_client::config::{ConfigBag, Intercept}; use pokemon_service_client::Client as PokemonClient; use pokemon_service_client::{ @@ -77,9 +78,7 @@ impl Intercept for TtlHeaderInterceptor { cfg: &mut ConfigBag, ) -> Result<(), BoxError> { // Metadata in the ConfigBag has the operation name. - let metadata = cfg - .load::() - .expect("metadata should exist"); + let metadata = cfg.load::().expect("metadata should exist"); let operation_name = metadata.name(); // Get operation specific or default HeaderValue to set for the header key. diff --git a/examples/pokemon-service-client-usage/examples/response-header-interceptor.rs b/examples/pokemon-service-client-usage/examples/response-header-interceptor.rs index a1ec2501979..7f153873705 100644 --- a/examples/pokemon-service-client-usage/examples/response-header-interceptor.rs +++ b/examples/pokemon-service-client-usage/examples/response-header-interceptor.rs @@ -2,6 +2,7 @@ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 */ +use aws_smithy_runtime_api::client::orchestrator::Metadata; /// This example demonstrates how response headers can be examined before they are deserialized /// into the output type. /// @@ -88,9 +89,7 @@ impl Intercept for ResponseHeaderLoggingInterceptor { cfg: &mut ConfigBag, ) -> Result<(), BoxError> { // `Metadata` in the `ConfigBag` has the operation name in it. - let metadata = cfg - .load::() - .expect("metadata should exist"); + let metadata = cfg.load::().expect("metadata should exist"); let operation_name = metadata.name().to_string(); // Get the server side request ID and set it in the RequestID data type diff --git a/examples/pokemon-service-tls/Cargo.toml b/examples/pokemon-service-tls/Cargo.toml index 566afcfc0a7..850f40f3e63 100644 --- a/examples/pokemon-service-tls/Cargo.toml +++ b/examples/pokemon-service-tls/Cargo.toml @@ -10,12 +10,13 @@ description = "A smithy Rust service to retrieve information about Pokémon." clap = { version = "4.1.11", features = ["derive"] } hyper = { version = "0.14.26", features = ["server"] } tokio = "1.26.0" +tracing = "0.1" # These dependencies are only required for the `pokemon-service-tls` program. tls-listener = { version = "0.7.0", features = ["rustls", "hyper-h2"] } tokio-rustls = "0.24.0" rustls-pemfile = "1.0.2" -futures-util = { version = "0.3.27", default-features = false } +futures-util = { version = "0.3.29", default-features = false } # Local paths aws-smithy-http-server = { path = "../../rust-runtime/aws-smithy-http-server" } diff --git a/examples/pokemon-service-tls/src/main.rs b/examples/pokemon-service-tls/src/main.rs index 45d6964686b..b536b9f436b 100644 --- a/examples/pokemon-service-tls/src/main.rs +++ b/examples/pokemon-service-tls/src/main.rs @@ -24,7 +24,9 @@ use std::{fs::File, future, io::BufReader, net::SocketAddr, sync::Arc}; -use aws_smithy_http_server::AddExtensionLayer; +use aws_smithy_http_server::{ + request::connect_info::ConnectInfo, routing::Connected, AddExtensionLayer, +}; use clap::Parser; use futures_util::stream::StreamExt; use tokio_rustls::{ @@ -33,10 +35,10 @@ use tokio_rustls::{ }; use pokemon_service_common::{ - capture_pokemon, check_health, do_nothing, get_pokemon_species, get_server_statistics, - get_storage, setup_tracing, stream_pokemon_radio, State, + capture_pokemon, check_health, get_pokemon_species, get_server_statistics, get_storage, + setup_tracing, stream_pokemon_radio, State, }; -use pokemon_service_server_sdk::{PokemonService, PokemonServiceConfig}; +use pokemon_service_server_sdk::{input, output, PokemonService, PokemonServiceConfig}; use pokemon_service_tls::{DEFAULT_ADDRESS, DEFAULT_PORT, DEFAULT_TEST_CERT, DEFAULT_TEST_KEY}; #[derive(Parser, Debug)] @@ -56,6 +58,46 @@ struct Args { tls_key_path: String, } +/// Information derived from the TLS connection. +#[derive(Debug, Clone)] +pub struct TlsConnectInfo { + /// The remote peer address of this connection. + pub socket_addr: SocketAddr, + + /// The set of TLS certificates presented by the peer in this connection. + pub certs: Option>>, +} + +impl Connected<&tokio_rustls::server::TlsStream> + for TlsConnectInfo +{ + fn connect_info( + target: &tokio_rustls::server::TlsStream, + ) -> Self { + let (addr_stream, session) = target.get_ref(); + let socket_addr = addr_stream.remote_addr(); + + let certs = session + .peer_certificates() + .map(|certs| Arc::new(certs.to_vec())); + + TlsConnectInfo { socket_addr, certs } + } +} + +/// Empty operation used to showcase how we can get access to information derived from the TLS +/// connection in. +pub async fn do_nothing_with_tls_connect_info( + _input: input::DoNothingInput, + ConnectInfo(tls_connect_info): ConnectInfo, +) -> output::DoNothingOutput { + // Logging these might pose a security concern! You probably don't want to do this in + // production. + tracing::debug!(?tls_connect_info.certs, "peer TLS certificates"); + + output::DoNothingOutput {} +} + #[tokio::main] pub async fn main() { let args = Args::parse(); @@ -73,7 +115,7 @@ pub async fn main() { .get_storage(get_storage) .get_server_statistics(get_server_statistics) .capture_pokemon(capture_pokemon) - .do_nothing(do_nothing) + .do_nothing(do_nothing_with_tls_connect_info) .check_health(check_health) .stream_pokemon_radio(stream_pokemon_radio) .build() @@ -96,8 +138,11 @@ pub async fn main() { future::ready(true) } }); - let server = hyper::Server::builder(hyper::server::accept::from_stream(listener)) - .serve(app.into_make_service()); + // Using `into_make_service_with_connect_info`, rather than `into_make_service`, to adjoin the `TlsConnectInfo` + // connection info. + let make_app = app.into_make_service_with_connect_info::(); + let server = + hyper::Server::builder(hyper::server::accept::from_stream(listener)).serve(make_app); if let Err(err) = server.await { eprintln!("server error: {}", err); } diff --git a/examples/pokemon-service-tls/tests/custom_connectors.rs b/examples/pokemon-service-tls/tests/custom_connectors.rs index 12c82d55cbc..a65881afe10 100644 --- a/examples/pokemon-service-tls/tests/custom_connectors.rs +++ b/examples/pokemon-service-tls/tests/custom_connectors.rs @@ -7,23 +7,23 @@ pub mod common; use serial_test::serial; -#[tokio::test] -#[serial] // This test invokes an operation with a client that can only send HTTP2 requests and whose TLS // implementation is backed by `rustls`. -async fn test_check_health_http2_rustls_connector() { +#[tokio::test] +#[serial] +async fn test_do_nothing_http2_rustls_connector() { let _child = common::run_server().await; let client = common::client_http2_only(); - let _check_health = client.check_health().send().await.unwrap(); + let _check_health = client.do_nothing().send().await.unwrap(); } +// This test invokes an operation with a client whose TLS implementation is backed by `native_tls`. #[tokio::test] #[serial] -// This test invokes an operation with a client whose TLS implementation is backed by `native_tls`. -async fn test_check_health_native_tls_connector() { +async fn test_do_nothing_native_tls_connector() { let _child = common::run_server().await; let client = common::native_tls_client(); - let _check_health = client.check_health().send().await.unwrap(); + let _check_health = client.do_nothing().send().await.unwrap(); } diff --git a/examples/python/pokemon_service.py b/examples/python/pokemon_service.py index 8eb1255f877..1bcb6e0658b 100644 --- a/examples/python/pokemon_service.py +++ b/examples/python/pokemon_service.py @@ -179,6 +179,8 @@ async def check_content_type_header(request: Request, next: Next) -> Response: if content_type in ["application/json", "application/vnd.amazon.eventstream"]: logging.debug("found valid `%s` content type", content_type) else: + # Note that dumping all headers may log sensitive information! You + # probably don't want to do this in production. logging.warning( "invalid content type %s, dumping headers: %s", content_type, diff --git a/gradle.properties b/gradle.properties index ed4fedc5e4a..d0dce9a7814 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ # # Rust MSRV (entered into the generated README) -rust.msrv=1.70.0 +rust.msrv=1.72.1 # To enable debug, swap out the two lines below. # When changing this value, be sure to run `./gradlew --stop` to kill the Gradle daemon. @@ -12,23 +12,23 @@ rust.msrv=1.70.0 org.gradle.jvmargs=-Xmx1024M # Version number to use for the generated stable runtime crates -smithy.rs.runtime.crate.stable.version=1.0.3 +smithy.rs.runtime.crate.stable.version=1.1.3 # Version number to use for the generated unstable runtime crates -smithy.rs.runtime.crate.unstable.version=0.60.0 +smithy.rs.runtime.crate.unstable.version=0.60.3 kotlin.code.style=official # codegen smithyGradlePluginVersion=0.7.0 -smithyVersion=1.40.0 +smithyVersion=1.43.0 # kotlin -kotlinVersion=1.7.21 +kotlinVersion=1.9.20 # testing/utility -ktlintVersion=0.48.2 -kotestVersion=5.2.3 +ktlintVersion=1.0.1 +kotestVersion=5.8.0 # Avoid registering dependencies/plugins/tasks that are only used for testing purposes isTestingEnabled=true diff --git a/rust-runtime/Cargo.toml b/rust-runtime/Cargo.toml index 52cf0a5ed25..142b1370504 100644 --- a/rust-runtime/Cargo.toml +++ b/rust-runtime/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "inlineable", "aws-smithy-async", @@ -17,5 +18,6 @@ members = [ "aws-smithy-runtime-api", "aws-smithy-types", "aws-smithy-types-convert", + "aws-smithy-mocks-experimental", "aws-smithy-xml", ] diff --git a/rust-runtime/aws-smithy-async/Cargo.toml b/rust-runtime/aws-smithy-async/Cargo.toml index 6e1a5f3c436..d08a8ee5744 100644 --- a/rust-runtime/aws-smithy-async/Cargo.toml +++ b/rust-runtime/aws-smithy-async/Cargo.toml @@ -14,7 +14,7 @@ test-util = ["rt-tokio"] [dependencies] pin-project-lite = "0.2" tokio = { version = "1.23.1", features = ["sync"] } -futures-util = { version = "0.3.16", default-features = false } +futures-util = { version = "0.3.29", default-features = false } [dev-dependencies] pin-utils = "0.1" @@ -29,6 +29,7 @@ normal = ["futures-util"] [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-async/src/future/pagination_stream.rs b/rust-runtime/aws-smithy-async/src/future/pagination_stream.rs index a5454108af7..d8a0a8999f7 100644 --- a/rust-runtime/aws-smithy-async/src/future/pagination_stream.rs +++ b/rust-runtime/aws-smithy-async/src/future/pagination_stream.rs @@ -8,6 +8,8 @@ use crate::future::pagination_stream::collect::sealed::Collectable; use std::future::Future; use std::pin::Pin; +use std::task::{Context, Poll}; + pub mod collect; pub mod fn_stream; use fn_stream::FnStream; @@ -60,6 +62,11 @@ impl PaginationStream { self.0.next().await } + /// Poll an item from the stream + pub fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll> { + Pin::new(&mut self.0).poll_next(cx) + } + /// Consumes this stream and gathers elements into a collection. pub async fn collect>(self) -> T { self.0.collect().await diff --git a/rust-runtime/aws-smithy-checksums/Cargo.toml b/rust-runtime/aws-smithy-checksums/Cargo.toml index 2485412d72d..46c912efd41 100644 --- a/rust-runtime/aws-smithy-checksums/Cargo.toml +++ b/rust-runtime/aws-smithy-checksums/Cargo.toml @@ -16,7 +16,7 @@ repository = "https://github.com/smithy-lang/smithy-rs" aws-smithy-http = { path = "../aws-smithy-http" } aws-smithy-types = { path = "../aws-smithy-types" } bytes = "1" -crc32c = "0.6" +crc32c = "0.6.2" crc32fast = "1.3" hex = "0.4.3" http = "0.2.8" @@ -36,5 +36,6 @@ tracing-test = "0.2.1" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-client/Cargo.toml b/rust-runtime/aws-smithy-client/Cargo.toml index a480618b617..3f6b50b5bdd 100644 --- a/rust-runtime/aws-smithy-client/Cargo.toml +++ b/rust-runtime/aws-smithy-client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aws-smithy-client" -version = "0.0.0-smithy-rs-head" +version = "0.60.3" authors = ["AWS Rust SDK Team ", "Russell Cohen "] description = "This crate is no longer used by smithy-rs and is deprecated." edition = "2021" @@ -10,5 +10,6 @@ repository = "https://github.com/smithy-lang/smithy-rs" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-eventstream/Cargo.toml b/rust-runtime/aws-smithy-eventstream/Cargo.toml index 6923fb9d7a1..b6979af34ee 100644 --- a/rust-runtime/aws-smithy-eventstream/Cargo.toml +++ b/rust-runtime/aws-smithy-eventstream/Cargo.toml @@ -23,5 +23,6 @@ bytes-utils = "0.1" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-eventstream/src/frame.rs b/rust-runtime/aws-smithy-eventstream/src/frame.rs index eb2bb1707c5..390df4f2601 100644 --- a/rust-runtime/aws-smithy-eventstream/src/frame.rs +++ b/rust-runtime/aws-smithy-eventstream/src/frame.rs @@ -154,7 +154,7 @@ impl SignMessage for NoOpSigner { } } -/// Converts a Smithy modeled Event Stream type into a [`Message`](Message). +/// Converts a Smithy modeled Event Stream type into a [`Message`]. pub trait MarshallMessage: fmt::Debug { /// Smithy modeled input type to convert from. type Input; @@ -169,7 +169,7 @@ pub enum UnmarshalledMessage { Error(E), } -/// Converts an Event Stream [`Message`](Message) into a Smithy modeled type. +/// Converts an Event Stream [`Message`] into a Smithy modeled type. pub trait UnmarshallMessage: fmt::Debug { /// Smithy modeled type to convert into. type Output; diff --git a/rust-runtime/aws-smithy-http-auth/Cargo.toml b/rust-runtime/aws-smithy-http-auth/Cargo.toml index 67de7ed7e1e..84fc294d66d 100644 --- a/rust-runtime/aws-smithy-http-auth/Cargo.toml +++ b/rust-runtime/aws-smithy-http-auth/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aws-smithy-http-auth" -version = "0.0.0-smithy-rs-head" +version = "0.60.3" authors = [ "AWS Rust SDK Team ", "Eduardo Rodrigues <16357187+eduardomourar@users.noreply.github.com>", @@ -15,5 +15,6 @@ repository = "https://github.com/smithy-lang/smithy-rs" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-http-server-python/Cargo.toml b/rust-runtime/aws-smithy-http-server-python/Cargo.toml index 188d5f5af2d..5ec48888978 100644 --- a/rust-runtime/aws-smithy-http-server-python/Cargo.toml +++ b/rust-runtime/aws-smithy-http-server-python/Cargo.toml @@ -43,7 +43,7 @@ tracing-appender = { version = "0.2.2"} [dev-dependencies] pretty_assertions = "1" -futures-util = { version = "0.3.16", default-features = false } +futures-util = { version = "0.3.29", default-features = false } tower-test = "0.4" tokio-test = "0.4" pyo3-asyncio = { version = "0.18.0", features = ["testing", "attributes", "tokio-runtime", "unstable-streams"] } @@ -66,5 +66,6 @@ harness = false [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-http-server-typescript/Cargo.toml b/rust-runtime/aws-smithy-http-server-typescript/Cargo.toml index ba1fa436df2..d46eaf9da8c 100644 --- a/rust-runtime/aws-smithy-http-server-typescript/Cargo.toml +++ b/rust-runtime/aws-smithy-http-server-typescript/Cargo.toml @@ -19,5 +19,6 @@ publish = false [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-http-server/Cargo.toml b/rust-runtime/aws-smithy-http-server/Cargo.toml index fbfcd899989..7aa80defa75 100644 --- a/rust-runtime/aws-smithy-http-server/Cargo.toml +++ b/rust-runtime/aws-smithy-http-server/Cargo.toml @@ -18,14 +18,14 @@ unredacted-logging = [] request-id = ["dep:uuid"] [dependencies] -async-trait = "0.1" +async-trait = "0.1.74" aws-smithy-http = { path = "../aws-smithy-http", features = ["rt-tokio"] } aws-smithy-json = { path = "../aws-smithy-json" } aws-smithy-runtime-api = { path = "../aws-smithy-runtime-api", features = ["http-02x"] } aws-smithy-types = { path = "../aws-smithy-types", features = ["http-body-0-4-x", "hyper-0-14-x"] } aws-smithy-xml = { path = "../aws-smithy-xml" } bytes = "1.1" -futures-util = { version = "0.3.16", default-features = false } +futures-util = { version = "0.3.29", default-features = false } http = "0.2" http-body = "0.4" hyper = { version = "0.14.26", features = ["server", "http1", "http2", "tcp", "stream"] } @@ -38,6 +38,7 @@ regex = "1.5.5" serde_urlencoded = "0.7" thiserror = "1.0.40" tokio = { version = "1.23.1", features = ["full"] } +tokio-rustls = "0.24" tower = { version = "0.4.11", features = ["util", "make"], default-features = false } tower-http = { version = "0.3", features = ["add-extension", "map-response-body"] } tracing = "0.1.35" @@ -49,5 +50,6 @@ pretty_assertions = "1" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-http-server/src/instrumentation/plugin.rs b/rust-runtime/aws-smithy-http-server/src/instrumentation/plugin.rs index f2dcca9cac1..4e8c0a66ca4 100644 --- a/rust-runtime/aws-smithy-http-server/src/instrumentation/plugin.rs +++ b/rust-runtime/aws-smithy-http-server/src/instrumentation/plugin.rs @@ -32,7 +32,7 @@ impl HttpMarker for InstrumentPlugin {} /// An extension trait for applying [`InstrumentPlugin`]. pub trait InstrumentExt { /// Applies an [`InstrumentOperation`] to every operation, respecting the [@sensitive] trait given on the input and - /// output models. See [`InstrumentOperation`](super::InstrumentOperation) for more information. + /// output models. See [`InstrumentOperation`] for more information. /// /// [@sensitive]: https://awslabs.github.io/smithy/2.0/spec/documentation-traits.html#sensitive-trait fn instrument(self) -> HttpPlugins>; diff --git a/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/headers.rs b/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/headers.rs index 57e65eb4199..479820b5645 100644 --- a/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/headers.rs +++ b/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/headers.rs @@ -164,7 +164,7 @@ mod tests { impl Debug for TestDebugMap { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { - f.debug_map().entries(self.0.into_iter()).finish() + f.debug_map().entries(self.0).finish() } } diff --git a/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/request.rs b/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/request.rs index 87dfdcb8498..710eedb161d 100644 --- a/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/request.rs +++ b/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/request.rs @@ -17,7 +17,7 @@ use super::{ }; /// Allows the modification the requests URIs [`Display`](std::fmt::Display) and headers -/// [`Debug`](std::fmt::Debug) to accommodate sensitivity. +/// [`Debug`] to accommodate sensitivity. /// /// This enjoys [`MakeFmt`] for [`&HeaderMap`](HeaderMap) and [`&Uri`](http::Uri). #[derive(Clone)] diff --git a/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/response.rs b/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/response.rs index 6d2212ab091..77d3652678c 100644 --- a/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/response.rs +++ b/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/response.rs @@ -17,7 +17,7 @@ use super::{ }; /// Allows the modification the responses status code [`Display`](std::fmt::Display) and headers -/// [`Debug`](std::fmt::Debug) to accommodate sensitivity. +/// [`Debug`] to accommodate sensitivity. /// /// This enjoys [`MakeFmt`] for [`&HeaderMap`](HeaderMap) and [`StatusCode`](http::StatusCode). #[derive(Clone)] diff --git a/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/uri/label.rs b/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/uri/label.rs index f5f99746fad..54bfd969f25 100644 --- a/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/uri/label.rs +++ b/rust-runtime/aws-smithy-http-server/src/instrumentation/sensitivity/uri/label.rs @@ -81,6 +81,8 @@ where if let Some(greedy_label) = &self.greedy_label { // Calculate the byte index of the start of the greedy label and whether it was reached while writing the // normal labels. + // TODO(clippy): Switch from fold to try_fold + #[allow(clippy::manual_try_fold)] let (greedy_start, greedy_hit) = self .path .split('/') diff --git a/rust-runtime/aws-smithy-http-server/src/instrumentation/service.rs b/rust-runtime/aws-smithy-http-server/src/instrumentation/service.rs index 21f211bc06c..f1878abaeac 100644 --- a/rust-runtime/aws-smithy-http-server/src/instrumentation/service.rs +++ b/rust-runtime/aws-smithy-http-server/src/instrumentation/service.rs @@ -77,9 +77,9 @@ where } } -/// A middleware [`Service`](tower::Service) responsible for: +/// A middleware [`Service`] responsible for: /// - Opening a [`tracing::debug_span`] for the lifetime of the request, which includes the operation name, the -/// [`Uri`](http::Uri), and the request headers. +/// [`Uri`], and the request headers. /// - A [`tracing::debug`] during response, which includes the response status code and headers. /// /// The [`Display`](std::fmt::Display) and [`Debug`] of the request and response components can be modified using diff --git a/rust-runtime/aws-smithy-http-server/src/plugin/mod.rs b/rust-runtime/aws-smithy-http-server/src/plugin/mod.rs index 533dbee00ed..bfd45df0b08 100644 --- a/rust-runtime/aws-smithy-http-server/src/plugin/mod.rs +++ b/rust-runtime/aws-smithy-http-server/src/plugin/mod.rs @@ -269,8 +269,7 @@ impl<'a, Pl> HttpMarker for &'a Pl where Pl: HttpMarker {} /// model plugins are _operation-specific_: somewhere in the type signature of their definition, /// they'll rely on a particular operation shape's types. It is therefore important that you scope /// application of model plugins to the operations they are meant to work on, via -/// [`Scoped`](crate::plugin::Scoped) or -/// [`filter_by_operation`](crate::plugin::filter_by_operation). +/// [`Scoped`] or [`filter_by_operation`]. /// /// Below is an example implementation of a model plugin that can only be applied to the /// `CheckHealth` operation: note how in the `Service` trait implementation, we require access to diff --git a/rust-runtime/aws-smithy-http-tower/Cargo.toml b/rust-runtime/aws-smithy-http-tower/Cargo.toml index f661b1283b5..3393b642e52 100644 --- a/rust-runtime/aws-smithy-http-tower/Cargo.toml +++ b/rust-runtime/aws-smithy-http-tower/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aws-smithy-http-tower" -version = "0.0.0-smithy-rs-head" +version = "0.60.3" authors = ["AWS Rust SDK Team ", "Russell Cohen "] description = "This crate is no longer used by smithy-rs and is deprecated." edition = "2021" @@ -10,5 +10,6 @@ repository = "https://github.com/smithy-lang/smithy-rs" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-http/Cargo.toml b/rust-runtime/aws-smithy-http/Cargo.toml index 2517342b794..a0e661862ef 100644 --- a/rust-runtime/aws-smithy-http/Cargo.toml +++ b/rust-runtime/aws-smithy-http/Cargo.toml @@ -29,11 +29,11 @@ pin-utils = "0.1.0" tracing = "0.1" # For an adapter to enable the `Stream` trait for `aws_smithy_types::byte_stream::ByteStream` -futures-core = "0.3.14" +futures-core = "0.3.29" [dev-dependencies] async-stream = "0.3" -futures-util = { version = "0.3.16", default-features = false } +futures-util = { version = "0.3.29", default-features = false } hyper = { version = "0.14.26", features = ["stream"] } proptest = "1" tokio = { version = "1.23.1", features = [ @@ -45,5 +45,6 @@ tokio = { version = "1.23.1", features = [ [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-http/src/endpoint.rs b/rust-runtime/aws-smithy-http/src/endpoint.rs index ce7c79900f3..e4c478bd69f 100644 --- a/rust-runtime/aws-smithy-http/src/endpoint.rs +++ b/rust-runtime/aws-smithy-http/src/endpoint.rs @@ -5,58 +5,41 @@ //! Code for resolving an endpoint (URI) that a request should be sent to +#![allow(deprecated)] + +use crate::endpoint::error::InvalidEndpointError; +use http::uri::{Authority, Uri}; use std::borrow::Cow; -use std::fmt::Debug; use std::result::Result as StdResult; use std::str::FromStr; -use http::uri::{Authority, Uri}; - -use aws_smithy_types::config_bag::{Storable, StoreReplace}; -pub use error::ResolveEndpointError; - -use crate::endpoint::error::InvalidEndpointError; - pub mod error; +pub use error::ResolveEndpointError; /// An endpoint-resolution-specific Result. Contains either an [`Endpoint`](aws_smithy_types::endpoint::Endpoint) or a [`ResolveEndpointError`]. +#[deprecated(since = "0.60.1", note = "Was never used.")] pub type Result = std::result::Result; /// A special type that adds support for services that have special URL-prefixing rules. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct EndpointPrefix(String); -impl EndpointPrefix { - /// Create a new endpoint prefix from an `impl Into`. If the prefix argument is invalid, - /// a [`InvalidEndpointError`] will be returned. - pub fn new(prefix: impl Into) -> StdResult { - let prefix = prefix.into(); - match Authority::from_str(&prefix) { - Ok(_) => Ok(EndpointPrefix(prefix)), - Err(err) => Err(InvalidEndpointError::failed_to_construct_authority( - prefix, err, - )), - } - } - - /// Get the `str` representation of this `EndpointPrefix`. - pub fn as_str(&self) -> &str { - &self.0 - } -} - -impl Storable for EndpointPrefix { - type Storer = StoreReplace; -} +#[deprecated( + since = "0.60.1", + note = "Use aws_smithy_runtime_api::client::endpoint::EndpointPrefix instead." +)] +pub type EndpointPrefix = aws_smithy_runtime_api::client::endpoint::EndpointPrefix; /// Apply `endpoint` to `uri` /// /// This method mutates `uri` by setting the `endpoint` on it +#[deprecated( + since = "0.60.1", + note = "Use aws_smithy_runtime::client::endpoint::apply_endpoint instead." +)] pub fn apply_endpoint( uri: &mut Uri, endpoint: &Uri, prefix: Option<&EndpointPrefix>, ) -> StdResult<(), InvalidEndpointError> { - let prefix = prefix.map(|p| p.0.as_str()).unwrap_or(""); + let prefix = prefix.map(EndpointPrefix::as_str).unwrap_or(""); let authority = endpoint .authority() .as_ref() diff --git a/rust-runtime/aws-smithy-http/src/header.rs b/rust-runtime/aws-smithy-http/src/header.rs index 558fe13e014..4b2ebc75c52 100644 --- a/rust-runtime/aws-smithy-http/src/header.rs +++ b/rust-runtime/aws-smithy-http/src/header.rs @@ -303,7 +303,7 @@ pub fn quote_header_value<'a>(value: impl Into>) -> Cow<'a, str> { } } -/// Given two [`HeaderMap`][HeaderMap]s, merge them together and return the merged `HeaderMap`. If the +/// Given two [`HeaderMap`]s, merge them together and return the merged `HeaderMap`. If the /// two `HeaderMap`s share any keys, values from the right `HeaderMap` be appended to the left `HeaderMap`. pub fn append_merge_header_maps( mut lhs: HeaderMap, diff --git a/rust-runtime/aws-smithy-http/src/operation.rs b/rust-runtime/aws-smithy-http/src/operation.rs index cba50828712..39f42d95365 100644 --- a/rust-runtime/aws-smithy-http/src/operation.rs +++ b/rust-runtime/aws-smithy-http/src/operation.rs @@ -3,42 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -//! Types for representing the interaction between a service an a client, referred to as an "operation" in smithy. -//! Clients "send" operations to services, which are composed of 1 or more HTTP requests. - -use aws_smithy_types::config_bag::{Storable, StoreReplace}; -use std::borrow::Cow; +//! Deprecated metadata type. /// Metadata added to the [`ConfigBag`](aws_smithy_types::config_bag::ConfigBag) that identifies the API being called. -#[derive(Clone, Debug)] -pub struct Metadata { - operation: Cow<'static, str>, - service: Cow<'static, str>, -} - -impl Metadata { - /// Returns the operation name. - pub fn name(&self) -> &str { - &self.operation - } - - /// Returns the service name. - pub fn service(&self) -> &str { - &self.service - } - - /// Creates [`Metadata`]. - pub fn new( - operation: impl Into>, - service: impl Into>, - ) -> Self { - Metadata { - operation: operation.into(), - service: service.into(), - } - } -} - -impl Storable for Metadata { - type Storer = StoreReplace; -} +#[deprecated( + since = "0.60.2", + note = "Use aws_smithy_runtime_api::client::orchestrator::Metadata instead." +)] +pub type Metadata = aws_smithy_runtime_api::client::orchestrator::Metadata; diff --git a/rust-runtime/aws-smithy-json/Cargo.toml b/rust-runtime/aws-smithy-json/Cargo.toml index 44745d6c44a..37614c1c8ec 100644 --- a/rust-runtime/aws-smithy-json/Cargo.toml +++ b/rust-runtime/aws-smithy-json/Cargo.toml @@ -17,5 +17,6 @@ serde_json = "1.0" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-json/src/escape.rs b/rust-runtime/aws-smithy-json/src/escape.rs index e09402abd95..fb8ee35c3e1 100644 --- a/rust-runtime/aws-smithy-json/src/escape.rs +++ b/rust-runtime/aws-smithy-json/src/escape.rs @@ -225,10 +225,10 @@ mod test { assert_eq!("foo", escape_string("foo").as_ref()); assert_eq!("foo\\r\\n", escape_string("foo\r\n").as_ref()); assert_eq!("foo\\r\\nbar", escape_string("foo\r\nbar").as_ref()); - assert_eq!(r#"foo\\bar"#, escape_string(r#"foo\bar"#).as_ref()); - assert_eq!(r#"\\foobar"#, escape_string(r#"\foobar"#).as_ref()); + assert_eq!(r"foo\\bar", escape_string(r"foo\bar").as_ref()); + assert_eq!(r"\\foobar", escape_string(r"\foobar").as_ref()); assert_eq!( - r#"\bf\fo\to\r\n"#, + r"\bf\fo\to\r\n", escape_string("\u{08}f\u{0C}o\to\r\n").as_ref() ); assert_eq!("\\\"test\\\"", escape_string("\"test\"").as_ref()); @@ -247,7 +247,7 @@ mod test { fn unescape() { assert_eq!( "\x08f\x0Co\to\r\n", - unescape_string(r#"\bf\fo\to\r\n"#).unwrap() + unescape_string(r"\bf\fo\to\r\n").unwrap() ); assert_eq!("\"test\"", unescape_string(r#"\"test\""#).unwrap()); assert_eq!("\x00", unescape_string("\\u0000").unwrap()); diff --git a/rust-runtime/aws-smithy-mocks-experimental/Cargo.toml b/rust-runtime/aws-smithy-mocks-experimental/Cargo.toml new file mode 100644 index 00000000000..ef06256e5d2 --- /dev/null +++ b/rust-runtime/aws-smithy-mocks-experimental/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "aws-smithy-mocks-experimental" +version = "0.1.0" +authors = ["AWS Rust SDK Team "] +description = "Experimental testing utilities for smithy-rs generated clients" +edition = "2021" +license = "Apache-2.0" +repository = "https://github.com/smithy-lang/smithy-rs" + +[dependencies] +aws-smithy-types = "1" +aws-smithy-runtime-api = { version = "1", features = ["client", "http-02x"] } + +[dev-dependencies] +aws-sdk-s3 = { version = "1", features = ["test-util"] } +tokio = { version = "1", features = ["full"]} + +[package.metadata.docs.rs] +all-features = true +targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] +rustdoc-args = ["--cfg", "docsrs"] +# End of docs.rs metadata + +[[example]] +name = "s3-getobject-mocks" +doc-scrape-examples = true diff --git a/rust-runtime/aws-smithy-mocks-experimental/LICENSE b/rust-runtime/aws-smithy-mocks-experimental/LICENSE new file mode 100644 index 00000000000..67db8588217 --- /dev/null +++ b/rust-runtime/aws-smithy-mocks-experimental/LICENSE @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/rust-runtime/aws-smithy-mocks-experimental/README.md b/rust-runtime/aws-smithy-mocks-experimental/README.md new file mode 100644 index 00000000000..0c4ca12d309 --- /dev/null +++ b/rust-runtime/aws-smithy-mocks-experimental/README.md @@ -0,0 +1,7 @@ +# aws-smithy-mocks + +Experiment for mocking Smithy Clients using interceptors. See [`tests/get-object-mocks.rs`](tests/get-object-mocks.rs) for example usage. + + +This crate is part of the [AWS SDK for Rust](https://awslabs.github.io/aws-sdk-rust/) and the [smithy-rs](https://github.com/smithy-lang/smithy-rs) code generator. + diff --git a/rust-runtime/aws-smithy-mocks-experimental/examples/s3-getobject-mocks.rs b/rust-runtime/aws-smithy-mocks-experimental/examples/s3-getobject-mocks.rs new file mode 100644 index 00000000000..9aa0a622e59 --- /dev/null +++ b/rust-runtime/aws-smithy-mocks-experimental/examples/s3-getobject-mocks.rs @@ -0,0 +1,112 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Example of mocking a simple wrapper around S3 + +#[tokio::main] +async fn main() { + // this is an example of writing tests, see the tests +} + +use aws_sdk_s3::operation::get_object::GetObjectError; +use aws_sdk_s3::Client; +use std::error::Error; + +pub struct MyFileRetriever { + s3_client: Client, +} + +impl MyFileRetriever { + pub async fn get_file(&self, path: &str) -> Result, Box> { + let response = match self + .s3_client + .get_object() + .bucket("test-bucket") + .key(path) + .send() + .await + .map_err(|e| e.into_service_error()) + { + Ok(response) => response, + Err(GetObjectError::NoSuchKey(_)) => return Ok(None), + e @ Err(_) => e?, + }; + let contents = response.body.collect().await?.to_vec(); + let contents = String::from_utf8(contents)?; + Ok(Some(contents)) + } +} + +// intentionally not cfg(test) so that rustdoc can find this +mod test { + use aws_sdk_s3::config::Region; + use aws_sdk_s3::operation::get_object::{GetObjectError, GetObjectOutput}; + use aws_sdk_s3::types::error::NoSuchKey; + use aws_sdk_s3::Client; + use aws_smithy_mocks_experimental::{mock, MockResponseInterceptor}; + use aws_smithy_runtime_api::client::orchestrator::HttpResponse; + use aws_smithy_runtime_api::http::StatusCode; + use aws_smithy_types::body::SdkBody; + use aws_smithy_types::byte_stream::ByteStream; + + #[allow(dead_code)] + fn mocked_client(file_contents: impl AsRef<[u8]>) -> Client { + let file_contents = file_contents.as_ref().to_vec(); + let get_object_happy_path = mock!(Client::get_object) + .match_requests(|req| { + req.bucket() == Some("test-bucket") && req.key() == Some("test-key") + }) + .then_output(move || { + GetObjectOutput::builder() + .body(ByteStream::from(file_contents.clone())) + .build() + }); + // fallback error + let get_object_error_path = mock!(Client::get_object) + .then_error(|| GetObjectError::NoSuchKey(NoSuchKey::builder().build())); + let hinted_500_error = mock!(Client::get_object) + .match_requests(|req| req.key() == Some("500")) + .then_http_response(|| { + HttpResponse::new( + StatusCode::try_from(500).unwrap(), + SdkBody::from("internal server error"), + ) + }); + let mock_response_interceptor = MockResponseInterceptor::new() + .with_rule(&get_object_happy_path) + .with_rule(&hinted_500_error) + .with_rule(&get_object_error_path); + Client::from_conf( + aws_sdk_s3::Config::builder() + .with_test_defaults() + .region(Region::from_static("us-east-1")) + .interceptor(mock_response_interceptor) + .build(), + ) + } + + #[tokio::test] + async fn loads_file() { + let client = super::MyFileRetriever { + s3_client: mocked_client(b"12345-abcde"), + }; + assert_eq!( + client.get_file("test-key").await.unwrap().as_deref(), + Some("12345-abcde") + ); + assert_eq!(client.get_file("different-key").await.unwrap(), None) + } + + #[tokio::test] + async fn returns_error_on_invalid_utf8() { + let client = super::MyFileRetriever { + s3_client: mocked_client(&vec![0xFF, 0xFE]), + }; + client + .get_file("test-key") + .await + .expect_err("invalid UTF-8"); + } +} diff --git a/rust-runtime/aws-smithy-mocks-experimental/src/lib.rs b/rust-runtime/aws-smithy-mocks-experimental/src/lib.rs new file mode 100644 index 00000000000..2cedc429b7b --- /dev/null +++ b/rust-runtime/aws-smithy-mocks-experimental/src/lib.rs @@ -0,0 +1,337 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Automatically managed default lints */ +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +/* End of automatically managed default lints */ +use std::collections::VecDeque; +use std::fmt::{Debug, Formatter}; +use std::future::Future; +use std::marker::PhantomData; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::{Arc, Mutex}; + +use aws_smithy_runtime_api::box_error::BoxError; +use aws_smithy_runtime_api::client::interceptors::context::{ + BeforeDeserializationInterceptorContextMut, BeforeSerializationInterceptorContextMut, Error, + FinalizerInterceptorContextMut, Input, Output, +}; +use aws_smithy_runtime_api::client::interceptors::Intercept; +use aws_smithy_runtime_api::client::orchestrator::{HttpResponse, OrchestratorError}; +use aws_smithy_runtime_api::client::result::SdkError; +use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents; +use aws_smithy_runtime_api::http::{Response, StatusCode}; +use aws_smithy_types::body::SdkBody; +use aws_smithy_types::config_bag::{ConfigBag, Storable, StoreReplace}; + +// why do we need a macro for this? +// We want customers to be able to provide an ergonomic way to say the method they're looking for, +// `Client::list_buckets`, e.g. But there isn't enough information on that type to recover everything. +// This macro commits a small amount of crimes to recover that type information so we can construct +// a rule that can intercept these operations. + +/// `mock!` macro that produces a [`RuleBuilder`] from a client invocation +/// +/// See the `examples` folder of this crate for fully worked examples. +/// +/// # Examples +/// **Mock and return a success response**: +/// ```rust +/// use aws_sdk_s3::operation::get_object::GetObjectOutput; +/// use aws_sdk_s3::Client; +/// use aws_smithy_types::byte_stream::ByteStream; +/// use aws_smithy_mocks_experimental::mock; +/// let get_object_happy_path = mock!(Client::get_object) +/// .match_requests(|req|req.bucket() == Some("test-bucket") && req.key() == Some("test-key")) +/// .then_output(||GetObjectOutput::builder().body(ByteStream::from_static(b"12345-abcde")).build()); +/// ``` +/// +/// **Mock and return an error**: +/// ```rust +/// use aws_sdk_s3::operation::get_object::GetObjectError; +/// use aws_sdk_s3::types::error::NoSuchKey; +/// use aws_sdk_s3::Client; +/// use aws_smithy_mocks_experimental::mock; +/// let get_object_error_path = mock!(Client::get_object) +/// .then_error(||GetObjectError::NoSuchKey(NoSuchKey::builder().build())); +/// ``` +#[macro_export] +macro_rules! mock { + ($operation: expr) => { + #[allow(unreachable_code)] + { + $crate::RuleBuilder::new( + // We don't actually want to run this code, so we put it in a closure. The closure + // has the types we want which makes this whole thing type-safe (and the IDE can even + // figure out the right input/output types in inference!) + // The code generated here is: + // `Client::list_buckets(todo!())` + || $operation(todo!()).as_input().clone().build().unwrap(), + || $operation(todo!()).send(), + ) + } + }; +} + +type MatchFn = Arc bool + Send + Sync>; +type OutputFn = Arc Result> + Send + Sync>; + +impl Debug for MockResponseInterceptor { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{} rules", self.rules.lock().unwrap().len()) + } +} + +#[derive(Clone)] +enum MockOutput { + HttpResponse(Arc Result + Send + Sync>), + ModeledResponse(OutputFn), +} + +/// Interceptor which produces mock responses based on a list of rules +pub struct MockResponseInterceptor { + rules: Arc>>, + enforce_order: bool, + must_match: bool, +} + +impl Default for MockResponseInterceptor { + fn default() -> Self { + Self::new() + } +} + +pub struct RuleBuilder { + _ty: PhantomData<(I, O, E)>, + input_filter: MatchFn, +} + +impl RuleBuilder +where + I: Send + Sync + Debug + 'static, + O: Send + Sync + Debug + 'static, + E: Send + Sync + Debug + std::error::Error + 'static, +{ + /// Creates a new [`RuleBuilder`]. This is normally constructed with the [`mock!`] macro + pub fn new(_input_hint: impl Fn() -> I, _output_hint: impl Fn() -> F) -> Self + where + F: Future>>, + { + Self { + _ty: Default::default(), + input_filter: Arc::new(|i: &Input| i.downcast_ref::().is_some()), + } + } + + /// Add an additional filter to constrain which inputs match this rule. + /// + /// For examples, see the examples directory of this repository. + pub fn match_requests(mut self, filter: impl Fn(&I) -> bool + Send + Sync + 'static) -> Self { + self.input_filter = Arc::new(move |i: &Input| match i.downcast_ref::() { + Some(typed_input) => filter(typed_input), + _ => false, + }); + self + } + + /// If the rule matches, then return a specific HTTP response. + /// + /// This is the recommended way of testing error behavior. + pub fn then_http_response( + self, + response: impl Fn() -> HttpResponse + Send + Sync + 'static, + ) -> Rule { + Rule::new( + self.input_filter, + MockOutput::HttpResponse(Arc::new(move || Ok(response()))), + ) + } + + /// If a rule matches, then return a specific output + pub fn then_output(self, output: impl Fn() -> O + Send + Sync + 'static) -> Rule { + Rule::new( + self.input_filter, + MockOutput::ModeledResponse(Arc::new(move || Ok(Output::erase(output())))), + ) + } + + /// If a rule matches, then return a specific error + /// + /// Although this _basically_ works, using `then_http_response` is strongly recommended to + /// create a higher fidelity mock. Error handling is quite complex in practice and returning errors + /// directly often will not perfectly capture the way the error is actually returned to the SDK. + pub fn then_error(self, output: impl Fn() -> E + Send + Sync + 'static) -> Rule { + Rule::new( + self.input_filter, + MockOutput::ModeledResponse(Arc::new(move || { + Err(OrchestratorError::operation(Error::erase(output()))) + })), + ) + } +} + +#[derive(Clone)] +pub struct Rule { + matcher: MatchFn, + output: MockOutput, + used_count: Arc, +} + +impl Debug for Rule { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "Rule") + } +} + +impl Rule { + fn new(matcher: MatchFn, output: MockOutput) -> Self { + Self { + matcher, + output, + used_count: Default::default(), + } + } + fn record_usage(&self) { + self.used_count.fetch_add(1, Ordering::Relaxed); + } + + /// Returns the number of times this rule has been hit. + pub fn num_calls(&self) -> usize { + self.used_count.load(Ordering::Relaxed) + } +} + +#[derive(Debug)] +struct ActiveRule(Rule); +impl Storable for ActiveRule { + type Storer = StoreReplace; +} + +impl MockResponseInterceptor { + pub fn new() -> Self { + Self { + rules: Default::default(), + enforce_order: false, + must_match: true, + } + } + /// Add a rule to the Interceptor + /// + /// Rules are matched in order—this rule will only apply if all previous rules do not match. + pub fn with_rule(self, rule: &Rule) -> Self { + self.rules.lock().unwrap().push_back(rule.clone()); + self + } + + /// Require that rules are matched in order. + /// + /// If a rule matches out of order, the interceptor will panic. + pub fn enforce_order(mut self) -> Self { + self.enforce_order = true; + self + } + + pub fn allow_passthrough(mut self) -> Self { + self.must_match = false; + self + } +} + +impl Intercept for MockResponseInterceptor { + fn name(&self) -> &'static str { + "test" + } + + fn modify_before_serialization( + &self, + context: &mut BeforeSerializationInterceptorContextMut<'_>, + _runtime_components: &RuntimeComponents, + cfg: &mut ConfigBag, + ) -> Result<(), BoxError> { + let mut rules = self.rules.lock().unwrap(); + let rule = match self.enforce_order { + true => { + let rule = rules + .pop_front() + .expect("no more rules but a new request was received"); + if !(rule.matcher)(context.input()) { + panic!( + "In order matching was enforced but the next rule did not match {:?}", + context.input() + ); + } + Some(rule) + } + false => rules + .iter() + .find(|rule| (rule.matcher)(context.input())) + .cloned(), + }; + match rule { + Some(rule) => { + cfg.interceptor_state().store_put(ActiveRule(rule.clone())); + } + None => { + if self.must_match { + panic!( + "must_match was enabled but no rules matches {:?}", + context.input() + ); + } + } + } + Ok(()) + } + + fn modify_before_deserialization( + &self, + context: &mut BeforeDeserializationInterceptorContextMut<'_>, + _runtime_components: &RuntimeComponents, + cfg: &mut ConfigBag, + ) -> Result<(), BoxError> { + if let Some(rule) = cfg.load::() { + let rule = &rule.0; + let result = match &rule.output { + MockOutput::HttpResponse(output_fn) => output_fn(), + _ => return Ok(()), + }; + rule.record_usage(); + + match result { + Ok(http_response) => *context.response_mut() = http_response, + Err(e) => context + .inner_mut() + .set_output_or_error(Err(OrchestratorError::response(e))), + } + } + Ok(()) + } + + fn modify_before_attempt_completion( + &self, + context: &mut FinalizerInterceptorContextMut<'_>, + _runtime_components: &RuntimeComponents, + _cfg: &mut ConfigBag, + ) -> Result<(), BoxError> { + if let Some(rule) = _cfg.load::() { + let rule = &rule.0; + let result = match &rule.output { + MockOutput::ModeledResponse(output_fn) => output_fn(), + _ => return Ok(()), + }; + + rule.record_usage(); + if result.is_err() { + // the orchestrator will panic of no response is present + context.inner_mut().set_response(Response::new( + StatusCode::try_from(500).unwrap(), + SdkBody::from("stubbed error response"), + )) + } + context.inner_mut().set_output_or_error(result); + } + Ok(()) + } +} diff --git a/rust-runtime/aws-smithy-mocks-experimental/tests/get-object-mocks.rs b/rust-runtime/aws-smithy-mocks-experimental/tests/get-object-mocks.rs new file mode 100644 index 00000000000..fb7010ca3d6 --- /dev/null +++ b/rust-runtime/aws-smithy-mocks-experimental/tests/get-object-mocks.rs @@ -0,0 +1,98 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use aws_sdk_s3::config::Region; +use aws_sdk_s3::operation::get_object::{GetObjectError, GetObjectOutput}; +use aws_sdk_s3::operation::list_buckets::ListBucketsError; +use aws_sdk_s3::{Client, Config}; +use aws_smithy_runtime_api::client::orchestrator::HttpResponse; +use aws_smithy_runtime_api::http::StatusCode; +use aws_smithy_types::body::SdkBody; +use aws_smithy_types::byte_stream::ByteStream; +use aws_smithy_types::error::metadata::ProvideErrorMetadata; +use aws_smithy_types::error::ErrorMetadata; + +use aws_smithy_mocks_experimental::{mock, MockResponseInterceptor}; + +const S3_NO_SUCH_KEY: &'static str = r#" + + NoSuchKey + The resource you requested does not exist + /mybucket/myfoto.jpg + 4442587FB7D0A2F9 +"#; + +#[tokio::test] +async fn create_mock_s3_get_object() { + let s3_404 = mock!(Client::get_object) + .match_requests(|inp| { + inp.bucket() == Some("test-bucket") && inp.key() != Some("correct-key") + }) + .then_http_response(|| { + HttpResponse::new( + StatusCode::try_from(400).unwrap(), + SdkBody::from(S3_NO_SUCH_KEY), + ) + }); + + let s3_real_object = mock!(Client::get_object) + .match_requests(|inp| { + inp.bucket() == Some("test-bucket") && inp.key() == Some("correct-key") + }) + .then_output(|| { + GetObjectOutput::builder() + .body(ByteStream::from_static(b"test-test-test")) + .build() + }); + + let modeled_error = mock!(Client::list_buckets).then_error(|| { + ListBucketsError::generic(ErrorMetadata::builder().code("InvalidAccessKey").build()) + }); + + let get_object_mocks = MockResponseInterceptor::new() + .with_rule(&s3_404) + .with_rule(&s3_real_object) + .with_rule(&modeled_error) + .enforce_order(); + + let s3 = aws_sdk_s3::Client::from_conf( + Config::builder() + .with_test_defaults() + .region(Region::new("us-east-1")) + .interceptor(get_object_mocks) + .build(), + ); + + let error = s3 + .get_object() + .bucket("test-bucket") + .key("foo") + .send() + .await + .expect_err("404"); + assert!(matches!( + error.into_service_error(), + GetObjectError::NoSuchKey(_) + )); + assert_eq!(s3_404.num_calls(), 1); + + let data = s3 + .get_object() + .bucket("test-bucket") + .key("correct-key") + .send() + .await + .expect("success response") + .body + .collect() + .await + .expect("successful read") + .to_vec(); + assert_eq!(data, b"test-test-test"); + assert_eq!(s3_real_object.num_calls(), 1); + + let err = s3.list_buckets().send().await.expect_err("bad access key"); + assert_eq!(err.code(), Some("InvalidAccessKey")); +} diff --git a/rust-runtime/aws-smithy-protocol-test/Cargo.toml b/rust-runtime/aws-smithy-protocol-test/Cargo.toml index ad120f78775..270afec98f0 100644 --- a/rust-runtime/aws-smithy-protocol-test/Cargo.toml +++ b/rust-runtime/aws-smithy-protocol-test/Cargo.toml @@ -22,5 +22,6 @@ aws-smithy-runtime-api = { path = "../aws-smithy-runtime-api", features = ["clie [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-query/Cargo.toml b/rust-runtime/aws-smithy-query/Cargo.toml index 552c024feb3..e83cf402df4 100644 --- a/rust-runtime/aws-smithy-query/Cargo.toml +++ b/rust-runtime/aws-smithy-query/Cargo.toml @@ -14,5 +14,6 @@ urlencoding = "2.1" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-runtime-api/Cargo.toml b/rust-runtime/aws-smithy-runtime-api/Cargo.toml index 93f88c0cd68..aed9bc45e28 100644 --- a/rust-runtime/aws-smithy-runtime-api/Cargo.toml +++ b/rust-runtime/aws-smithy-runtime-api/Cargo.toml @@ -33,6 +33,7 @@ tokio = { version = "1.25", features = ["macros", "rt", "rt-multi-thread"] } [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/connection.rs b/rust-runtime/aws-smithy-runtime-api/src/client/connection.rs index 293e27dcb80..63925ec882a 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/client/connection.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/client/connection.rs @@ -218,12 +218,12 @@ mod tests { }) .build(); - assert_eq!(connection_metadata.is_proxied, true); + assert!(connection_metadata.is_proxied); assert_eq!(connection_metadata.remote_addr(), Some(TEST_SOCKET_ADDR)); assert_eq!(connection_metadata.local_addr(), Some(TEST_SOCKET_ADDR)); - assert_eq!(*mutable_flag.lock().unwrap(), false); + assert!(!(*mutable_flag.lock().unwrap())); connection_metadata.poison(); - assert_eq!(*mutable_flag.lock().unwrap(), true); + assert!(*mutable_flag.lock().unwrap()); } #[test] diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/endpoint.rs b/rust-runtime/aws-smithy-runtime-api/src/client/endpoint.rs index 13e9880a4a5..3114d55f499 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/client/endpoint.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/client/endpoint.rs @@ -11,7 +11,10 @@ use crate::impl_shared_conversions; use aws_smithy_types::config_bag::{Storable, StoreReplace}; use aws_smithy_types::endpoint::Endpoint; use aws_smithy_types::type_erasure::TypeErasedBox; +use error::InvalidEndpointError; +use http::uri::Authority; use std::fmt; +use std::str::FromStr; use std::sync::Arc; new_type_future! { @@ -71,3 +74,156 @@ impl ResolveEndpoint for SharedEndpointResolver { impl ValidateConfig for SharedEndpointResolver {} impl_shared_conversions!(convert SharedEndpointResolver from ResolveEndpoint using SharedEndpointResolver::new); + +/// A special type that adds support for services that have special URL-prefixing rules. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct EndpointPrefix(String); +impl EndpointPrefix { + /// Create a new endpoint prefix from an `impl Into`. If the prefix argument is invalid, + /// a [`InvalidEndpointError`] will be returned. + pub fn new(prefix: impl Into) -> Result { + let prefix = prefix.into(); + match Authority::from_str(&prefix) { + Ok(_) => Ok(EndpointPrefix(prefix)), + Err(err) => Err(InvalidEndpointError::failed_to_construct_authority( + prefix, err, + )), + } + } + + /// Get the `str` representation of this `EndpointPrefix`. + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl Storable for EndpointPrefix { + type Storer = StoreReplace; +} + +/// Errors related to endpoint resolution and validation +pub mod error { + use crate::box_error::BoxError; + use std::error::Error as StdError; + use std::fmt; + + /// Endpoint resolution failed + #[derive(Debug)] + pub struct ResolveEndpointError { + message: String, + source: Option, + } + + impl ResolveEndpointError { + /// Create an [`ResolveEndpointError`] with a message + pub fn message(message: impl Into) -> Self { + Self { + message: message.into(), + source: None, + } + } + + /// Add a source to the error + pub fn with_source(self, source: Option) -> Self { + Self { source, ..self } + } + + /// Create a [`ResolveEndpointError`] from a message and a source + pub fn from_source(message: impl Into, source: impl Into) -> Self { + Self::message(message).with_source(Some(source.into())) + } + } + + impl fmt::Display for ResolveEndpointError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.message) + } + } + + impl StdError for ResolveEndpointError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + self.source.as_ref().map(|err| err.as_ref() as _) + } + } + + #[derive(Debug)] + pub(super) enum InvalidEndpointErrorKind { + EndpointMustHaveScheme, + FailedToConstructAuthority { authority: String, source: BoxError }, + FailedToConstructUri { source: BoxError }, + } + + /// An error that occurs when an endpoint is found to be invalid. This usually occurs due to an + /// incomplete URI. + #[derive(Debug)] + pub struct InvalidEndpointError { + pub(super) kind: InvalidEndpointErrorKind, + } + + impl InvalidEndpointError { + /// Construct a build error for a missing scheme + pub fn endpoint_must_have_scheme() -> Self { + Self { + kind: InvalidEndpointErrorKind::EndpointMustHaveScheme, + } + } + + /// Construct a build error for an invalid authority + pub fn failed_to_construct_authority( + authority: impl Into, + source: impl Into>, + ) -> Self { + Self { + kind: InvalidEndpointErrorKind::FailedToConstructAuthority { + authority: authority.into(), + source: source.into(), + }, + } + } + + /// Construct a build error for an invalid URI + pub fn failed_to_construct_uri( + source: impl Into>, + ) -> Self { + Self { + kind: InvalidEndpointErrorKind::FailedToConstructUri { + source: source.into(), + }, + } + } + } + + impl From for InvalidEndpointError { + fn from(kind: InvalidEndpointErrorKind) -> Self { + Self { kind } + } + } + + impl fmt::Display for InvalidEndpointError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use InvalidEndpointErrorKind as ErrorKind; + match &self.kind { + ErrorKind::EndpointMustHaveScheme => write!(f, "endpoint must contain a valid scheme"), + ErrorKind::FailedToConstructAuthority { authority, source: _ } => write!( + f, + "endpoint must contain a valid authority when combined with endpoint prefix: {authority}" + ), + ErrorKind::FailedToConstructUri { .. } => write!(f, "failed to construct URI"), + } + } + } + + impl StdError for InvalidEndpointError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + use InvalidEndpointErrorKind as ErrorKind; + match &self.kind { + ErrorKind::FailedToConstructUri { source } => Some(source.as_ref()), + ErrorKind::FailedToConstructAuthority { + authority: _, + source, + } => Some(source.as_ref()), + ErrorKind::EndpointMustHaveScheme => None, + } + } + } +} diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs b/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs index 3632029e7b1..f0e972675ad 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs @@ -4,7 +4,6 @@ */ use crate::box_error::BoxError; -use crate::client::auth::AuthSchemeId; use crate::client::runtime_components::sealed::ValidateConfig; use crate::client::runtime_components::{RuntimeComponents, RuntimeComponentsBuilder}; use crate::impl_shared_conversions; @@ -108,6 +107,8 @@ impl ResolveCachedIdentity for SharedIdentityCache { } } +impl ValidateConfig for SharedIdentityResolver {} + impl ValidateConfig for SharedIdentityCache { fn validate_base_client_config( &self, @@ -197,38 +198,6 @@ impl ResolveIdentity for SharedIdentityResolver { impl_shared_conversions!(convert SharedIdentityResolver from ResolveIdentity using SharedIdentityResolver::new); -/// An identity resolver paired with an auth scheme ID that it resolves for. -#[derive(Clone, Debug)] -pub(crate) struct ConfiguredIdentityResolver { - auth_scheme: AuthSchemeId, - identity_resolver: SharedIdentityResolver, -} - -impl ConfiguredIdentityResolver { - /// Creates a new [`ConfiguredIdentityResolver`] from the given auth scheme and identity resolver. - pub(crate) fn new( - auth_scheme: AuthSchemeId, - identity_resolver: SharedIdentityResolver, - ) -> Self { - Self { - auth_scheme, - identity_resolver, - } - } - - /// Returns the auth scheme ID. - pub(crate) fn scheme_id(&self) -> AuthSchemeId { - self.auth_scheme - } - - /// Returns the identity resolver. - pub(crate) fn identity_resolver(&self) -> SharedIdentityResolver { - self.identity_resolver.clone() - } -} - -impl ValidateConfig for ConfiguredIdentityResolver {} - /// An identity that can be used for authentication. /// /// The [`Identity`] is a container for any arbitrary identity data that may be used diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/interceptors.rs b/rust-runtime/aws-smithy-runtime-api/src/client/interceptors.rs index e4fde15ad47..fcd107a4185 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/client/interceptors.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/client/interceptors.rs @@ -838,7 +838,7 @@ where /// Disable an interceptor with a given cause pub fn disable_interceptor(cause: &'static str) -> DisableInterceptor { DisableInterceptor { - _t: PhantomData::default(), + _t: PhantomData, cause, } } diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/orchestrator.rs b/rust-runtime/aws-smithy-runtime-api/src/client/orchestrator.rs index 873b8a1cc3b..ffad2dbf171 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/client/orchestrator.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/client/orchestrator.rs @@ -23,6 +23,7 @@ use crate::client::interceptors::InterceptorError; use crate::client::result::{ConnectorError, SdkError}; use aws_smithy_types::config_bag::{Storable, StoreReplace}; use bytes::Bytes; +use std::borrow::Cow; use std::error::Error as StdError; use std::fmt; @@ -287,3 +288,37 @@ impl From for OrchestratorError { Self::operation(err) } } + +/// Metadata added to the [`ConfigBag`](aws_smithy_types::config_bag::ConfigBag) that identifies the API being called. +#[derive(Clone, Debug)] +pub struct Metadata { + operation: Cow<'static, str>, + service: Cow<'static, str>, +} + +impl Metadata { + /// Returns the operation name. + pub fn name(&self) -> &str { + &self.operation + } + + /// Returns the service name. + pub fn service(&self) -> &str { + &self.service + } + + /// Creates [`Metadata`]. + pub fn new( + operation: impl Into>, + service: impl Into>, + ) -> Self { + Metadata { + operation: operation.into(), + service: service.into(), + } + } +} + +impl Storable for Metadata { + type Storer = StoreReplace; +} diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/result.rs b/rust-runtime/aws-smithy-runtime-api/src/client/result.rs index 09797c21b9a..84dde1e3c3b 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/client/result.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/client/result.rs @@ -56,7 +56,7 @@ pub mod builders { source_only_error_builder!(TimeoutError, TimeoutErrorBuilder, BoxError); source_only_error_builder!(DispatchFailure, DispatchFailureBuilder, ConnectorError); - /// Builder for [`ResponseError`](super::ResponseError). + /// Builder for [`ResponseError`]. #[derive(Debug)] pub struct ResponseErrorBuilder { source: Option, @@ -111,7 +111,7 @@ pub mod builders { } } - /// Builder for [`ServiceError`](super::ServiceError). + /// Builder for [`ServiceError`]. #[derive(Debug)] pub struct ServiceErrorBuilder { source: Option, @@ -314,7 +314,7 @@ pub trait CreateUnhandledError { /// When logging an error from the SDK, it is recommended that you either wrap the error in /// [`DisplayErrorContext`](aws_smithy_types::error::display::DisplayErrorContext), use another /// error reporter library that visits the error's cause/source chain, or call -/// [`Error::source`](std::error::Error::source) for more details about the underlying cause. +/// [`Error::source`] for more details about the underlying cause. #[non_exhaustive] #[derive(Debug)] pub enum SdkError { @@ -412,6 +412,36 @@ impl SdkError { } } + /// Returns a reference underlying service error `E` if there is one + /// + /// # Examples + /// ```no_run + /// # use aws_smithy_runtime_api::client::result::SdkError; + /// # #[derive(Debug)] enum GetObjectError { NoSuchKey(()), Other(()) } + /// # impl std::fmt::Display for GetObjectError { + /// # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { unimplemented!() } + /// # } + /// # impl std::error::Error for GetObjectError {} + /// # impl GetObjectError { + /// # fn is_not_found(&self) -> bool { true } + /// # } + /// # fn example() -> Result<(), GetObjectError> { + /// # let sdk_err = SdkError::service_error(GetObjectError::NoSuchKey(()), ()); + /// if sdk_err.as_service_error().map(|e|e.is_not_found()) == Some(true) { + /// println!("the object doesn't exist"); + /// // return None, or handle this error specifically + /// } + /// // ... handle other error cases, happy path, etc. + /// # Ok(()) + /// # } + /// ``` + pub fn as_service_error(&self) -> Option<&E> { + match self { + Self::ServiceError(err) => Some(&err.source), + _ => None, + } + } + /// Converts this error into its error source. /// /// If there is no error source, then `Err(Self)` is returned. diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs index a6b2744bc5e..dc9f65d56ac 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs @@ -8,8 +8,7 @@ //! Runtime components are trait implementations that are _always_ used by the orchestrator. //! There are other trait implementations that can be configured for a client, but if they //! aren't directly and always used by the orchestrator, then they are placed in the -//! [`ConfigBag`](aws_smithy_types::config_bag::ConfigBag) instead of in -//! [`RuntimeComponents`](RuntimeComponents). +//! [`ConfigBag`] instead of in [`RuntimeComponents`]. use crate::box_error::BoxError; use crate::client::auth::{ @@ -19,8 +18,7 @@ use crate::client::auth::{ use crate::client::endpoint::{ResolveEndpoint, SharedEndpointResolver}; use crate::client::http::{HttpClient, SharedHttpClient}; use crate::client::identity::{ - ConfiguredIdentityResolver, ResolveCachedIdentity, ResolveIdentity, SharedIdentityCache, - SharedIdentityResolver, + ResolveCachedIdentity, ResolveIdentity, SharedIdentityCache, SharedIdentityResolver, }; use crate::client::interceptors::{Intercept, SharedInterceptor}; use crate::client::retries::classifiers::{ClassifyRetry, SharedRetryClassifier}; @@ -30,6 +28,7 @@ use crate::shared::IntoShared; use aws_smithy_async::rt::sleep::{AsyncSleep, SharedAsyncSleep}; use aws_smithy_async::time::{SharedTimeSource, TimeSource}; use aws_smithy_types::config_bag::ConfigBag; +use std::collections::HashMap; use std::fmt; use std::sync::Arc; @@ -178,6 +177,13 @@ macro_rules! merge { $self.$name.extend($other.$name.iter().cloned()); } }; + (OptionalAuthSchemeMap $other:ident . $name:ident => $self:ident ) => { + if let Some(m) = &$other.$name { + let mut us = $self.$name.unwrap_or_default(); + us.extend(m.iter().map(|(k, v)| (k.clone(), v.clone()))); + $self.$name = Some(us); + } + }; } /// Internal to `declare_runtime_components!`. /// @@ -198,6 +204,18 @@ macro_rules! builder_field_value { (Vec $self:ident . $name:ident) => { $self.$name }; + (OptionalAuthSchemeMap $self:ident . $name:ident atLeastOneRequired) => {{ + match $self.$name { + Some(map) => map, + None => { + return Err(BuildError(concat!( + "at least one `", + stringify!($name), + "` runtime component is required" + ))); + } + } + }}; (Vec $self:ident . $name:ident atLeastOneRequired) => {{ if $self.$name.is_empty() { return Err(BuildError(concat!( @@ -226,6 +244,7 @@ macro_rules! runtime_component_field_type { (Vec $inner_type:ident atLeastOneRequired) => { Vec> }; + (OptionalAuthSchemeMap $inner_type: ident atLeastOneRequired) => { AuthSchemeMap> }; } /// Internal to `declare_runtime_components!`. /// @@ -239,8 +258,14 @@ macro_rules! empty_builder_value { (Vec) => { Vec::new() }; + (OptionalAuthSchemeMap) => { + None + }; } +type OptionalAuthSchemeMap = Option>; +type AuthSchemeMap = HashMap; + /// Macro to define the structs for both `RuntimeComponents` and `RuntimeComponentsBuilder`. /// /// This is a macro in order to keep the fields consistent between the two, and to automatically @@ -335,7 +360,7 @@ declare_runtime_components! { identity_cache: Option, #[atLeastOneRequired] - identity_resolvers: Vec, + identity_resolvers: OptionalAuthSchemeMap, interceptors: Vec, @@ -430,7 +455,12 @@ impl RuntimeComponents { } }; (Vec: $field:expr) => { - for entry in &$field { + for entry in $field { + ValidateConfig::validate_final_config(&entry.value, self, cfg)?; + } + }; + (Map: $field:expr) => { + for entry in $field.values() { ValidateConfig::validate_final_config(&entry.value, self, cfg)?; } }; @@ -442,10 +472,10 @@ impl RuntimeComponents { } validate!(Option: self.http_client); validate!(Required: self.endpoint_resolver); - validate!(Vec: self.auth_schemes); + validate!(Vec: &self.auth_schemes); validate!(Required: self.identity_cache); - validate!(Vec: self.identity_resolvers); - validate!(Vec: self.interceptors); + validate!(Map: self.identity_resolvers); + validate!(Vec: &self.interceptors); validate!(Required: self.retry_strategy); Ok(()) } @@ -571,11 +601,7 @@ impl RuntimeComponentsBuilder { scheme_id: AuthSchemeId, identity_resolver: impl ResolveIdentity + 'static, ) -> &mut Self { - self.identity_resolvers.push(Tracked::new( - self.builder_name, - ConfiguredIdentityResolver::new(scheme_id, identity_resolver.into_shared()), - )); - self + self.set_identity_resolver(scheme_id, identity_resolver) } /// Sets the identity resolver for a given `scheme_id`. @@ -587,21 +613,12 @@ impl RuntimeComponentsBuilder { scheme_id: AuthSchemeId, identity_resolver: impl ResolveIdentity + 'static, ) -> &mut Self { - let tracked = Tracked::new( - self.builder_name, - ConfiguredIdentityResolver::new(scheme_id, identity_resolver.into_shared()), + let mut resolvers = self.identity_resolvers.take().unwrap_or_default(); + resolvers.insert( + scheme_id, + Tracked::new(self.builder_name, identity_resolver.into_shared()), ); - - if let Some(s) = self - .identity_resolvers - .iter_mut() - .find(|s| s.value.scheme_id() == scheme_id) - { - *s = tracked; - } else { - self.identity_resolvers.push(tracked); - } - + self.identity_resolvers = Some(resolvers); self } @@ -808,7 +825,7 @@ impl RuntimeComponentsBuilder { pub fn validate_base_client_config(&self, cfg: &ConfigBag) -> Result<(), BoxError> { macro_rules! validate { ($field:expr) => { - for entry in &$field { + for entry in $field { ValidateConfig::validate_base_client_config(&entry.value, self, cfg)?; } }; @@ -818,13 +835,15 @@ impl RuntimeComponentsBuilder { for validator in self.config_validators() { validator.validate_base_client_config(self, cfg)?; } - validate!(self.http_client); - validate!(self.endpoint_resolver); - validate!(self.auth_schemes); - validate!(self.identity_cache); - validate!(self.identity_resolvers); - validate!(self.interceptors); - validate!(self.retry_strategy); + validate!(&self.http_client); + validate!(&self.endpoint_resolver); + validate!(&self.auth_schemes); + validate!(&self.identity_cache); + if let Some(resolvers) = &self.identity_resolvers { + validate!(resolvers.values()) + } + validate!(&self.interceptors); + validate!(&self.retry_strategy); Ok(()) } @@ -1011,9 +1030,8 @@ pub trait GetIdentityResolver: Send + Sync { impl GetIdentityResolver for RuntimeComponents { fn identity_resolver(&self, scheme_id: AuthSchemeId) -> Option { self.identity_resolvers - .iter() - .find(|s| s.value.scheme_id() == scheme_id) - .map(|s| s.value.identity_resolver()) + .get(&scheme_id) + .map(|s| s.value.clone()) } } diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_plugin.rs b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_plugin.rs index 53812097f7a..85d71d635b1 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_plugin.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_plugin.rs @@ -86,7 +86,7 @@ pub trait RuntimePlugin: Debug + Send + Sync { None } - /// Returns a [`RuntimeComponentsBuilder`](RuntimeComponentsBuilder) to incorporate into the final runtime components. + /// Returns a [`RuntimeComponentsBuilder`] to incorporate into the final runtime components. /// /// The order of runtime plugins determines which runtime components "win". Components set by later runtime plugins will /// override those set by earlier runtime plugins. diff --git a/rust-runtime/aws-smithy-runtime-api/src/lib.rs b/rust-runtime/aws-smithy-runtime-api/src/lib.rs index 92ddf65464a..3be2088da65 100644 --- a/rust-runtime/aws-smithy-runtime-api/src/lib.rs +++ b/rust-runtime/aws-smithy-runtime-api/src/lib.rs @@ -24,7 +24,7 @@ //! generated clients, then please file an issue on [smithy-rs](https://github.com/smithy-lang/smithy-rs) //! as we likely missed re-exporting one of the APIs. //! -//! All client-specific code is in the [`client`](crate::client) root level module +//! All client-specific code is in the [`client`] root level module //! to leave room for smithy-rs server APIs in the future. /// A boxed error that is `Send` and `Sync`. diff --git a/rust-runtime/aws-smithy-runtime/Cargo.toml b/rust-runtime/aws-smithy-runtime/Cargo.toml index d9ebaea92b0..fc08e13ea4c 100644 --- a/rust-runtime/aws-smithy-runtime/Cargo.toml +++ b/rust-runtime/aws-smithy-runtime/Cargo.toml @@ -48,7 +48,7 @@ approx = "0.5.1" aws-smithy-async = { path = "../aws-smithy-async", features = ["rt-tokio", "test-util"] } aws-smithy-runtime-api = { path = "../aws-smithy-runtime-api", features = ["test-util"] } aws-smithy-types = { path = "../aws-smithy-types", features = ["test-util"] } -futures-util = "0.3.28" +futures-util = "0.3.29" pretty_assertions = "1.4.0" tokio = { version = "1.25", features = ["macros", "rt", "rt-multi-thread", "test-util", "full"] } tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } @@ -58,8 +58,14 @@ hyper_0_14 = { package = "hyper", version = "0.14.27",features = ["client", "ser [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata [package.metadata.smithy-rs-release-tooling] stable = true + +# aws-smithy-http is used by the http-auth feature, which is not turned on by the SDK at all. +# Without ignoring it, the `check-aws-sdk-smoketest-docs-clippy-udeps` CI script fails. +[package.metadata.cargo-udeps.ignore] +normal = ["aws-smithy-http"] diff --git a/rust-runtime/aws-smithy-runtime/src/client.rs b/rust-runtime/aws-smithy-runtime/src/client.rs index 10591578fce..bb3a85ad3d9 100644 --- a/rust-runtime/aws-smithy-runtime/src/client.rs +++ b/rust-runtime/aws-smithy-runtime/src/client.rs @@ -10,6 +10,8 @@ pub mod defaults; pub mod dns; +pub mod endpoint; + /// Built-in Smithy HTTP clients and connectors. /// /// See the [module docs in `aws-smithy-runtime-api`](aws_smithy_runtime_api::client::http) diff --git a/rust-runtime/aws-smithy-runtime/src/client/endpoint.rs b/rust-runtime/aws-smithy-runtime/src/client/endpoint.rs new file mode 100644 index 00000000000..b6110499e20 --- /dev/null +++ b/rust-runtime/aws-smithy-runtime/src/client/endpoint.rs @@ -0,0 +1,65 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Code for applying endpoints to a request. + +use aws_smithy_runtime_api::client::endpoint::{error::InvalidEndpointError, EndpointPrefix}; +use http::uri::{Authority, Uri}; +use std::borrow::Cow; +use std::result::Result as StdResult; +use std::str::FromStr; + +/// Apply `endpoint` to `uri` +/// +/// This method mutates `uri` by setting the `endpoint` on it +pub fn apply_endpoint( + uri: &mut Uri, + endpoint: &Uri, + prefix: Option<&EndpointPrefix>, +) -> StdResult<(), InvalidEndpointError> { + let prefix = prefix.map(EndpointPrefix::as_str).unwrap_or(""); + let authority = endpoint + .authority() + .as_ref() + .map(|auth| auth.as_str()) + .unwrap_or(""); + let authority = if !prefix.is_empty() { + Cow::Owned(format!("{}{}", prefix, authority)) + } else { + Cow::Borrowed(authority) + }; + let authority = Authority::from_str(&authority).map_err(|err| { + InvalidEndpointError::failed_to_construct_authority(authority.into_owned(), err) + })?; + let scheme = *endpoint + .scheme() + .as_ref() + .ok_or_else(InvalidEndpointError::endpoint_must_have_scheme)?; + let new_uri = Uri::builder() + .authority(authority) + .scheme(scheme.clone()) + .path_and_query(merge_paths(endpoint, uri).as_ref()) + .build() + .map_err(InvalidEndpointError::failed_to_construct_uri)?; + *uri = new_uri; + Ok(()) +} + +fn merge_paths<'a>(endpoint: &'a Uri, uri: &'a Uri) -> Cow<'a, str> { + if let Some(query) = endpoint.path_and_query().and_then(|pq| pq.query()) { + tracing::warn!(query = %query, "query specified in endpoint will be ignored during endpoint resolution"); + } + let endpoint_path = endpoint.path(); + let uri_path_and_query = uri.path_and_query().map(|pq| pq.as_str()).unwrap_or(""); + if endpoint_path.is_empty() { + Cow::Borrowed(uri_path_and_query) + } else { + let ep_no_slash = endpoint_path.strip_suffix('/').unwrap_or(endpoint_path); + let uri_path_no_slash = uri_path_and_query + .strip_prefix('/') + .unwrap_or(uri_path_and_query); + Cow::Owned(format!("{}/{}", ep_no_slash, uri_path_no_slash)) + } +} diff --git a/rust-runtime/aws-smithy-runtime/src/client/http/hyper_014.rs b/rust-runtime/aws-smithy-runtime/src/client/http/hyper_014.rs index e5aabaf81d0..95bcd0d1825 100644 --- a/rust-runtime/aws-smithy-runtime/src/client/http/hyper_014.rs +++ b/rust-runtime/aws-smithy-runtime/src/client/http/hyper_014.rs @@ -953,7 +953,7 @@ mod timeout_middleware { #[tokio::test] async fn http_read_timeout_works() { - let tcp_connector = NeverReplies::default(); + let tcp_connector = NeverReplies; let connector_settings = HttpConnectorSettings::builder() .connect_timeout(Duration::from_secs(1)) .read_timeout(Duration::from_secs(2)) diff --git a/rust-runtime/aws-smithy-runtime/src/client/http/test_util.rs b/rust-runtime/aws-smithy-runtime/src/client/http/test_util.rs index c05b3dca543..a1c4250fb2f 100644 --- a/rust-runtime/aws-smithy-runtime/src/client/http/test_util.rs +++ b/rust-runtime/aws-smithy-runtime/src/client/http/test_util.rs @@ -6,11 +6,11 @@ //! Various fake/mock clients for testing. //! //! Each test client is useful for different test use cases: -//! - [`capture_request`](capture_request::capture_request): If you don't care what the -//! response is, but just want to check that the serialized request is what you expect, -//! then use `capture_request`. Or, alternatively, if you don't care what the request -//! is, but want to always respond with a given response, then capture request can also -//! be useful since you can optionally give it a response to return. +//! - [`capture_request()`]: If you don't care what the response is, but just want to +//! check that the serialized request is what you expect, then use `capture_request`. +//! Or, alternatively, if you don't care what the request is, but want to always +//! respond with a given response, then capture request can also be useful since +//! you can optionally give it a response to return. #![cfg_attr( feature = "connector-hyper-0-14-x", doc = "- [`dvr`]: If you want to record real-world traffic and then replay it later, then DVR's" diff --git a/rust-runtime/aws-smithy-runtime/src/client/http/test_util/capture_request.rs b/rust-runtime/aws-smithy-runtime/src/client/http/test_util/capture_request.rs index 43d54152dba..86b5fc8f5fd 100644 --- a/rust-runtime/aws-smithy-runtime/src/client/http/test_util/capture_request.rs +++ b/rust-runtime/aws-smithy-runtime/src/client/http/test_util/capture_request.rs @@ -49,7 +49,7 @@ impl HttpClient for CaptureRequestHandler { } } -/// Receiver for [`CaptureRequestHandler`](CaptureRequestHandler) +/// Receiver for [`CaptureRequestHandler`]. #[derive(Debug)] pub struct CaptureRequestReceiver { receiver: oneshot::Receiver, diff --git a/rust-runtime/aws-smithy-runtime/src/client/http/test_util/dvr.rs b/rust-runtime/aws-smithy-runtime/src/client/http/test_util/dvr.rs index c5f10961db2..9136b725587 100644 --- a/rust-runtime/aws-smithy-runtime/src/client/http/test_util/dvr.rs +++ b/rust-runtime/aws-smithy-runtime/src/client/http/test_util/dvr.rs @@ -25,7 +25,7 @@ pub use replay::ReplayingClient; /// A complete traffic recording /// -/// A traffic recording can be replayed with [`RecordingClient`](RecordingClient) +/// A traffic recording can be replayed with [`RecordingClient`]. #[derive(Debug, Serialize, Deserialize)] pub struct NetworkTraffic { events: Vec, @@ -232,7 +232,7 @@ pub enum BodyData { } impl BodyData { - /// Convert [`BodyData`](BodyData) into Bytes + /// Convert [`BodyData`] into Bytes. pub fn into_bytes(self) -> Vec { match self { BodyData::Utf8(string) => string.into_bytes(), @@ -240,7 +240,7 @@ impl BodyData { } } - /// Copy [`BodyData`](BodyData) into a `Vec` + /// Copy [`BodyData`] into a `Vec`. pub fn copy_to_vec(&self) -> Vec { match self { BodyData::Utf8(string) => string.as_bytes().into(), diff --git a/rust-runtime/aws-smithy-runtime/src/client/http/test_util/dvr/record.rs b/rust-runtime/aws-smithy-runtime/src/client/http/test_util/dvr/record.rs index 7d03163a1c3..db0fb671a19 100644 --- a/rust-runtime/aws-smithy-runtime/src/client/http/test_util/dvr/record.rs +++ b/rust-runtime/aws-smithy-runtime/src/client/http/test_util/dvr/record.rs @@ -31,7 +31,7 @@ pub struct RecordingClient { pub(crate) inner: SharedHttpConnector, } -#[cfg(all(feature = "tls-rustls"))] +#[cfg(feature = "tls-rustls")] impl RecordingClient { /// Construct a recording connection wrapping a default HTTPS implementation without any timeouts. pub fn https() -> Self { diff --git a/rust-runtime/aws-smithy-runtime/src/client/orchestrator/endpoints.rs b/rust-runtime/aws-smithy-runtime/src/client/orchestrator/endpoints.rs index 85b70ac5c49..eb09694b399 100644 --- a/rust-runtime/aws-smithy-runtime/src/client/orchestrator/endpoints.rs +++ b/rust-runtime/aws-smithy-runtime/src/client/orchestrator/endpoints.rs @@ -3,15 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -use aws_smithy_http::endpoint::error::ResolveEndpointError; -use aws_smithy_http::endpoint::EndpointPrefix; -use aws_smithy_runtime_api::box_error::BoxError; use aws_smithy_runtime_api::client::endpoint::{ - EndpointFuture, EndpointResolverParams, ResolveEndpoint, + error::ResolveEndpointError, EndpointFuture, EndpointResolverParams, ResolveEndpoint, }; use aws_smithy_runtime_api::client::interceptors::context::InterceptorContext; use aws_smithy_runtime_api::client::orchestrator::HttpRequest; use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents; +use aws_smithy_runtime_api::{box_error::BoxError, client::endpoint::EndpointPrefix}; use aws_smithy_types::config_bag::ConfigBag; use aws_smithy_types::endpoint::Endpoint; use http::header::HeaderName; @@ -149,9 +147,7 @@ fn apply_endpoint( #[cfg(test)] mod test { - use aws_smithy_http::endpoint::EndpointPrefix; - use aws_smithy_runtime_api::client::orchestrator::HttpRequest; - use aws_smithy_types::endpoint::Endpoint; + use super::*; #[test] fn test_apply_endpoint() { diff --git a/rust-runtime/aws-smithy-runtime/src/test_util/assertions.rs b/rust-runtime/aws-smithy-runtime/src/test_util/assertions.rs index de35c053b4f..7cd8dfac690 100644 --- a/rust-runtime/aws-smithy-runtime/src/test_util/assertions.rs +++ b/rust-runtime/aws-smithy-runtime/src/test_util/assertions.rs @@ -29,7 +29,7 @@ macro_rules! assert_str_contains { mod tests { use std::panic::{catch_unwind, UnwindSafe}; - fn expect_panic(f: impl FnOnce() -> () + UnwindSafe) -> String { + fn expect_panic(f: impl FnOnce() + UnwindSafe) -> String { *catch_unwind(f) .expect_err("it should fail") .downcast::() diff --git a/rust-runtime/aws-smithy-types-convert/Cargo.toml b/rust-runtime/aws-smithy-types-convert/Cargo.toml index e205cf446ff..3b988899990 100644 --- a/rust-runtime/aws-smithy-types-convert/Cargo.toml +++ b/rust-runtime/aws-smithy-types-convert/Cargo.toml @@ -10,14 +10,18 @@ repository = "https://github.com/smithy-lang/smithy-rs" [features] convert-chrono = ["aws-smithy-types", "chrono"] convert-time = ["aws-smithy-types", "time"] +convert-streams = ["aws-smithy-async", "futures-core"] [dependencies] aws-smithy-types = { path = "../aws-smithy-types", optional = true } +aws-smithy-async = {path = "../aws-smithy-async", optional = true} chrono = { version = "0.4.26", optional = true, default-features = false, features = ["std"] } time = { version = "0.3.4", optional = true } +futures-core = { version = "0.3.0", optional = true } [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-types-convert/README.md b/rust-runtime/aws-smithy-types-convert/README.md index 8fa07cac82e..9d5719df4da 100644 --- a/rust-runtime/aws-smithy-types-convert/README.md +++ b/rust-runtime/aws-smithy-types-convert/README.md @@ -21,5 +21,5 @@ _Note:_ Conversions to and from [`SystemTime`](https://doc.rust-lang.org/std/tim into [`aws-smithy-types`](https://docs.rs/aws-smithy-types/0.30.0-alpha/aws_smithy_types/date_time/struct.DateTime.html#impl-From%3CSystemTime%3E). -This crate is part of the [AWS SDK for Rust](https://awslabs.github.io/aws-sdk-rust/) and the [smithy-rs](https://github.com/smithy-lang/smithy-rs) code generator. In most cases, it should not be used directly. +This crate is part of the [AWS SDK for Rust](https://awslabs.github.io/aws-sdk-rust/) and the [smithy-rs](https://github.com/smithy-lang/smithy-rs) code generator. diff --git a/rust-runtime/aws-smithy-types-convert/external-types.toml b/rust-runtime/aws-smithy-types-convert/external-types.toml index aca8b6962e5..ab9b0fe6a43 100644 --- a/rust-runtime/aws-smithy-types-convert/external-types.toml +++ b/rust-runtime/aws-smithy-types-convert/external-types.toml @@ -4,4 +4,6 @@ allowed_external_types = [ "chrono::offset::fixed::FixedOffset", "chrono::offset::utc::Utc", "time::offset_date_time::OffsetDateTime", + "aws_smithy_async::future::pagination_stream::PaginationStream", + "futures_core::stream::Stream", ] diff --git a/rust-runtime/aws-smithy-types-convert/src/lib.rs b/rust-runtime/aws-smithy-types-convert/src/lib.rs index bd7ae8a7848..1283c0f53f8 100644 --- a/rust-runtime/aws-smithy-types-convert/src/lib.rs +++ b/rust-runtime/aws-smithy-types-convert/src/lib.rs @@ -18,3 +18,6 @@ #[cfg(any(feature = "convert-time", feature = "convert-chrono"))] pub mod date_time; + +#[cfg(feature = "convert-streams")] +pub mod stream; diff --git a/rust-runtime/aws-smithy-types-convert/src/stream.rs b/rust-runtime/aws-smithy-types-convert/src/stream.rs new file mode 100644 index 00000000000..3dbf5a789ad --- /dev/null +++ b/rust-runtime/aws-smithy-types-convert/src/stream.rs @@ -0,0 +1,62 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Conversions from Stream-like structs to implementors of `futures::Stream` + +use futures_core::Stream; +use std::pin::Pin; +use std::task::{Context, Poll}; + +use aws_smithy_async::future::pagination_stream::PaginationStream; + +/// Stream implementor wrapping `PaginationStream` +pub struct PaginationStreamImplStream { + pagination_stream: PaginationStream, +} + +impl PaginationStreamImplStream { + /// Create a new Stream object wrapping a `PaginationStream` + pub fn new(pagination_stream: PaginationStream) -> Self { + PaginationStreamImplStream { pagination_stream } + } +} + +impl Stream for PaginationStreamImplStream { + type Item = Item; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.pagination_stream.poll_next(cx) + } +} + +/// Trait to convert PaginationStream into implementor of `Stream` +pub trait PaginationStreamExt { + /// Convert PaginationStream into implementor of `Stream` + /// + /// # Example + /// ```no_run + /// # use aws_smithy_async::future::pagination_stream::PaginationStream; + /// use aws_smithy_types_convert::stream::PaginationStreamExt; + /// // Assuming you have obtained a pagination stream, by something like: + /// // ``` + /// // let pagination_stream = s3_client + /// // .list_objects_v2() + /// // .bucket(bucket) + /// // .into_paginator() + /// // .send(); + /// // ``` + /// # let pagination_stream: PaginationStream = unimplemented!(); + /// let futures_stream = pagination_stream.into_stream_03x(); + /// ``` + fn into_stream_03x(self) -> PaginationStreamImplStream; +} + +impl PaginationStreamExt for PaginationStream { + fn into_stream_03x(self) -> PaginationStreamImplStream { + PaginationStreamImplStream { + pagination_stream: self, + } + } +} diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index a46f9924fa4..4d50bff2262 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -13,6 +13,7 @@ repository = "https://github.com/smithy-lang/smithy-rs" [features] byte-stream-poll-next = [] http-body-0-4-x = ["dep:http-body-0-4"] +http-body-1-x = ["dep:http-body-1-0", "dep:http-body-util", "dep:http-body-0-4", "dep:http-1x"] hyper-0-14-x = ["dep:hyper-0-14"] rt-tokio = [ "dep:http-body-0-4", @@ -32,7 +33,10 @@ base64-simd = "0.8" bytes = "1" bytes-utils = "0.1" http = "0.2.3" +http-1x = { package = "http", version = "1", optional = true } http-body-0-4 = { package = "http-body", version = "0.4.4", optional = true } +http-body-1-0 = { package = "http-body", version = "1", optional = true } +http-body-util = { version = "0.1.0", optional = true } hyper-0-14 = { package = "hyper", version = "0.14.26", optional = true } itoa = "1.0.0" num-integer = "0.1.44" @@ -42,7 +46,7 @@ ryu = "1.0.5" time = { version = "0.3.4", features = ["parsing"] } # ByteStream internals -futures-core = "0.3.14" +futures-core = "0.3.29" tokio = { version = "1.23.1", optional = true } tokio-util = { version = "0.7", optional = true } @@ -68,6 +72,7 @@ tempfile = "3.2.0" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/aws-smithy-types/additional-ci b/rust-runtime/aws-smithy-types/additional-ci index 2d9305d5103..7ce1a378ac5 100755 --- a/rust-runtime/aws-smithy-types/additional-ci +++ b/rust-runtime/aws-smithy-types/additional-ci @@ -12,3 +12,6 @@ cargo tree -d --edges normal --all-features echo "### Checking whether the features are properly feature-gated" ! cargo tree -e no-dev | grep serde + +echo "### Checking feature powerset" +cargo hack check --feature-powerset --exclude-all-features diff --git a/rust-runtime/aws-smithy-types/src/blob.rs b/rust-runtime/aws-smithy-types/src/blob.rs index ec8c7e6e374..eebdd60ca21 100644 --- a/rust-runtime/aws-smithy-types/src/blob.rs +++ b/rust-runtime/aws-smithy-types/src/blob.rs @@ -42,7 +42,7 @@ mod serde_serialize { S: serde::Serializer, { if serializer.is_human_readable() { - serializer.serialize_str(&base64::encode(&self.inner)) + serializer.serialize_str(&crate::base64::encode(&self.inner)) } else { serializer.serialize_bytes(&self.inner) } diff --git a/rust-runtime/aws-smithy-types/src/body.rs b/rust-runtime/aws-smithy-types/src/body.rs index 33e5912a935..97985243870 100644 --- a/rust-runtime/aws-smithy-types/src/body.rs +++ b/rust-runtime/aws-smithy-types/src/body.rs @@ -19,6 +19,8 @@ use std::task::{Context, Poll}; /// The name has a suffix `_x` to avoid name collision with a third-party `http-body-0-4`. #[cfg(feature = "http-body-0-4-x")] pub mod http_body_0_4_x; +#[cfg(feature = "http-body-1-x")] +pub mod http_body_1_x; /// A generic, boxed error that's `Send` and `Sync` pub type Error = Box; @@ -55,7 +57,13 @@ impl Debug for SdkBody { /// A boxed generic HTTP body that, when consumed, will result in [`Bytes`] or an [`Error`]. enum BoxBody { - #[cfg(feature = "http-body-0-4-x")] + // This is enabled by the **dependency**, not the feature. This allows us to construct it + // whenever we have the dependency and keep the APIs private + #[cfg(any( + feature = "http-body-0-4-x", + feature = "http-body-1-x", + feature = "rt-tokio" + ))] HttpBody04(http_body_0_4::combinators::BoxBody), } @@ -162,6 +170,27 @@ impl SdkBody { } } + #[cfg(any( + feature = "http-body-0-4-x", + feature = "http-body-1-x", + feature = "rt-tokio" + ))] + pub(crate) fn from_body_0_4_internal(body: T) -> Self + where + T: http_body_0_4::Body + Send + Sync + 'static, + E: Into + 'static, + { + Self { + inner: Inner::Dyn { + inner: BoxBody::HttpBody04(http_body_0_4::combinators::BoxBody::new( + body.map_err(Into::into), + )), + }, + rebuild: None, + bytes_contents: None, + } + } + #[cfg(feature = "http-body-0-4-x")] pub(crate) fn poll_next_trailers( self: Pin<&mut Self>, diff --git a/rust-runtime/aws-smithy-types/src/body/http_body_0_4_x.rs b/rust-runtime/aws-smithy-types/src/body/http_body_0_4_x.rs index a6719d1fa2d..d4eae4cf4cc 100644 --- a/rust-runtime/aws-smithy-types/src/body/http_body_0_4_x.rs +++ b/rust-runtime/aws-smithy-types/src/body/http_body_0_4_x.rs @@ -3,11 +3,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -use crate::body::{BoxBody, Error, Inner, SdkBody}; -use bytes::Bytes; use std::pin::Pin; use std::task::{Context, Poll}; +use bytes::Bytes; + +use crate::body::{Error, SdkBody}; + impl SdkBody { /// Construct an `SdkBody` from a type that implements [`http_body_0_4::Body`](http_body_0_4::Body). /// @@ -17,15 +19,7 @@ impl SdkBody { T: http_body_0_4::Body + Send + Sync + 'static, E: Into + 'static, { - Self { - inner: Inner::Dyn { - inner: BoxBody::HttpBody04(http_body_0_4::combinators::BoxBody::new( - body.map_err(Into::into), - )), - }, - rebuild: None, - bytes_contents: None, - } + SdkBody::from_body_0_4_internal(body) } } diff --git a/rust-runtime/aws-smithy-types/src/body/http_body_1_x.rs b/rust-runtime/aws-smithy-types/src/body/http_body_1_x.rs new file mode 100644 index 00000000000..6b3278d9875 --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/body/http_body_1_x.rs @@ -0,0 +1,267 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Adapters to use http-body 1.0 bodies with SdkBody & ByteStream + +use std::pin::Pin; +use std::task::{ready, Context, Poll}; + +use bytes::Bytes; +use http_body_util::BodyExt; +use pin_project_lite::pin_project; + +use crate::body::{Error, SdkBody}; + +impl SdkBody { + /// Construct an `SdkBody` from a type that implements [`http_body_1_0::Body`](http_body_1_0::Body). + pub fn from_body_1_x(body: T) -> Self + where + T: http_body_1_0::Body + Send + Sync + 'static, + E: Into + 'static, + { + SdkBody::from_body_0_4_internal(Http1toHttp04::new(body.map_err(Into::into))) + } +} + +pin_project! { + struct Http1toHttp04 { + #[pin] + inner: B, + trailers: Option, + } +} + +impl Http1toHttp04 { + fn new(inner: B) -> Self { + Self { + inner, + trailers: None, + } + } +} + +impl http_body_0_4::Body for Http1toHttp04 +where + B: http_body_1_0::Body, +{ + type Data = B::Data; + type Error = B::Error; + + fn poll_data( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll>> { + loop { + let this = self.as_mut().project(); + match ready!(this.inner.poll_frame(cx)) { + Some(Ok(frame)) => { + let frame = match frame.into_data() { + Ok(data) => return Poll::Ready(Some(Ok(data))), + Err(frame) => frame, + }; + // when we get a trailers frame, store the trailers for the next poll + if let Ok(trailers) = frame.into_trailers() { + this.trailers.replace(trailers); + return Poll::Ready(None); + }; + // if the frame type was unknown, discard it. the next one might be something + // useful + } + Some(Err(e)) => return Poll::Ready(Some(Err(e))), + None => return Poll::Ready(None), + } + } + } + + fn poll_trailers( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll, Self::Error>> { + // all of the polling happens in poll_data, once we get to the trailers we've actually + // already read everything + let this = self.project(); + match this.trailers.take() { + Some(headers) => Poll::Ready(Ok(Some(convert_header_map(headers)))), + None => Poll::Ready(Ok(None)), + } + } + + fn is_end_stream(&self) -> bool { + self.inner.is_end_stream() + } + + fn size_hint(&self) -> http_body_0_4::SizeHint { + let mut size_hint = http_body_0_4::SizeHint::new(); + let inner_hint = self.inner.size_hint(); + if let Some(exact) = inner_hint.exact() { + size_hint.set_exact(exact); + } else { + size_hint.set_lower(inner_hint.lower()); + if let Some(upper) = inner_hint.upper() { + size_hint.set_upper(upper); + } + } + size_hint + } +} + +fn convert_header_map(input: http_1x::HeaderMap) -> http::HeaderMap { + let mut map = http::HeaderMap::with_capacity(input.capacity()); + let mut mem: Option = None; + for (k, v) in input.into_iter() { + let name = k.or_else(|| mem.clone()).unwrap(); + map.append( + http::HeaderName::from_bytes(name.as_str().as_bytes()).expect("already validated"), + http::HeaderValue::from_bytes(v.as_bytes()).expect("already validated"), + ); + mem = Some(name); + } + map +} + +#[cfg(test)] +mod test { + use std::collections::VecDeque; + use std::pin::Pin; + use std::task::{Context, Poll}; + + use bytes::Bytes; + use http::header::{CONTENT_LENGTH as CL0, CONTENT_TYPE as CT0}; + use http_1x::header::{CONTENT_LENGTH as CL1, CONTENT_TYPE as CT1}; + use http_1x::{HeaderMap, HeaderName, HeaderValue}; + use http_body_1_0::Frame; + + use crate::body::http_body_1_x::convert_header_map; + use crate::body::{Error, SdkBody}; + use crate::byte_stream::ByteStream; + + struct TestBody { + chunks: VecDeque, + } + + enum Chunk { + Data(&'static str), + Error(&'static str), + Trailers(HeaderMap), + } + + impl http_body_1_0::Body for TestBody { + type Data = Bytes; + type Error = Error; + + fn poll_frame( + mut self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll, Self::Error>>> { + let next = self.chunks.pop_front(); + let mk = |v: Frame| Poll::Ready(Some(Ok(v))); + + match next { + Some(Chunk::Data(s)) => mk(Frame::data(Bytes::from_static(s.as_bytes()))), + Some(Chunk::Trailers(headers)) => mk(Frame::trailers(headers)), + Some(Chunk::Error(err)) => Poll::Ready(Some(Err(err.into()))), + None => Poll::Ready(None), + } + } + } + + fn trailers() -> HeaderMap { + let mut map = HeaderMap::new(); + map.insert( + HeaderName::from_static("x-test"), + HeaderValue::from_static("x-test-value"), + ); + map.append( + HeaderName::from_static("x-test"), + HeaderValue::from_static("x-test-value-2"), + ); + map.append( + HeaderName::from_static("y-test"), + HeaderValue::from_static("y-test-value-2"), + ); + map + } + + #[tokio::test] + async fn test_body_with_trailers() { + let body = TestBody { + chunks: vec![ + Chunk::Data("123"), + Chunk::Data("456"), + Chunk::Data("789"), + Chunk::Trailers(trailers()), + ] + .into(), + }; + let body = SdkBody::from_body_1_x(body); + let data = ByteStream::new(body); + assert_eq!(data.collect().await.unwrap().to_vec(), b"123456789"); + } + + #[tokio::test] + async fn test_read_trailers() { + let body = TestBody { + chunks: vec![ + Chunk::Data("123"), + Chunk::Data("456"), + Chunk::Data("789"), + Chunk::Trailers(trailers()), + ] + .into(), + }; + let mut body = SdkBody::from_body_1_x(body); + while let Some(_data) = http_body_0_4::Body::data(&mut body).await {} + assert_eq!( + http_body_0_4::Body::trailers(&mut body).await.unwrap(), + Some(convert_header_map(trailers())) + ); + } + + #[tokio::test] + async fn test_errors() { + let body = TestBody { + chunks: vec![ + Chunk::Data("123"), + Chunk::Data("456"), + Chunk::Data("789"), + Chunk::Error("errors!"), + ] + .into(), + }; + + let body = SdkBody::from_body_1_x(body); + let body = ByteStream::new(body); + body.collect().await.expect_err("body returned an error"); + } + #[tokio::test] + async fn test_no_trailers() { + let body = TestBody { + chunks: vec![Chunk::Data("123"), Chunk::Data("456"), Chunk::Data("789")].into(), + }; + + let body = SdkBody::from_body_1_x(body); + let body = ByteStream::new(body); + assert_eq!(body.collect().await.unwrap().to_vec(), b"123456789"); + } + + #[test] + fn test_convert_headers() { + let mut http1_headermap = http_1x::HeaderMap::new(); + http1_headermap.append(CT1, HeaderValue::from_static("a")); + http1_headermap.append(CT1, HeaderValue::from_static("b")); + http1_headermap.append(CT1, HeaderValue::from_static("c")); + + http1_headermap.insert(CL1, HeaderValue::from_static("1234")); + + let mut expect = http::HeaderMap::new(); + expect.append(CT0, http::HeaderValue::from_static("a")); + expect.append(CT0, http::HeaderValue::from_static("b")); + expect.append(CT0, http::HeaderValue::from_static("c")); + + expect.insert(CL0, http::HeaderValue::from_static("1234")); + + assert_eq!(convert_header_map(http1_headermap), expect); + } +} diff --git a/rust-runtime/aws-smithy-types/src/byte_stream.rs b/rust-runtime/aws-smithy-types/src/byte_stream.rs index 2721b1b6b21..b6123ee2fff 100644 --- a/rust-runtime/aws-smithy-types/src/byte_stream.rs +++ b/rust-runtime/aws-smithy-types/src/byte_stream.rs @@ -5,8 +5,9 @@ //! ByteStream Abstractions //! -//! When the SDK returns streaming binary data, the inner Http Body is wrapped in [ByteStream](crate::byte_stream::ByteStream). ByteStream provides misuse-resistant -//! primitives to make it easier to handle common patterns with streaming data. +//! When the SDK returns streaming binary data, the inner Http Body is +//! wrapped in [`ByteStream`]. ByteStream provides misuse-resistant primitives +//! to make it easier to handle common patterns with streaming data. //! //! # Examples //! @@ -148,6 +149,8 @@ pub use self::bytestream_util::FsBuilder; /// The name has a suffix `_x` to avoid name collision with a third-party `http-body-0-4`. #[cfg(feature = "http-body-0-4-x")] pub mod http_body_0_4_x; +#[cfg(feature = "http-body-1-x")] +pub mod http_body_1_x; pin_project! { /// Stream of binary data @@ -343,8 +346,10 @@ impl ByteStream { self.inner.collect().await.map_err(Error::streaming) } - /// Returns a [`FsBuilder`](crate::byte_stream::FsBuilder), allowing you to build a `ByteStream` with - /// full control over how the file is read (eg. specifying the length of the file or the size of the buffer used to read the file). + /// Returns a [`FsBuilder`], allowing you to build a `ByteStream` with + /// full control over how the file is read (eg. specifying the length of + /// the file or the size of the buffer used to read the file). + /// /// ```no_run /// # #[cfg(feature = "rt-tokio")] /// # { @@ -382,8 +387,7 @@ impl ByteStream { /// Furthermore, a partial write MAY seek in the file and resume from the previous location. /// /// Note: If you want more control, such as specifying the size of the buffer used to read the file - /// or the length of the file, use a [`FsBuilder`](crate::byte_stream::FsBuilder) as returned - /// from `ByteStream::read_from` + /// or the length of the file, use a [`FsBuilder`] as returned from `ByteStream::read_from`. /// /// # Examples /// ```no_run @@ -462,7 +466,7 @@ impl From for ByteStream { } } -/// Construct a retryable ByteStream from [`bytes::Bytes`](bytes::Bytes) +/// Construct a retryable ByteStream from [`bytes::Bytes`]. impl From for ByteStream { fn from(input: Bytes) -> Self { ByteStream::new(SdkBody::from(input)) @@ -471,8 +475,7 @@ impl From for ByteStream { /// Construct a retryable ByteStream from a `Vec`. /// -/// This will convert the `Vec` into [`bytes::Bytes`](bytes::Bytes) to enable efficient -/// retries. +/// This will convert the `Vec` into [`bytes::Bytes`] to enable efficient retries. impl From> for ByteStream { fn from(input: Vec) -> Self { Self::from(Bytes::from(input)) @@ -481,15 +484,15 @@ impl From> for ByteStream { /// Non-contiguous Binary Data Storage /// -/// When data is read from the network, it is read in a sequence of chunks that are not in -/// contiguous memory. [`AggregatedBytes`](crate::byte_stream::AggregatedBytes) provides a view of -/// this data via [`impl Buf`](bytes::Buf) or it can be copied into contiguous storage with +/// When data is read from the network, it is read in a sequence of chunks that are +/// not in contiguous memory. [`AggregatedBytes`] provides a view of this data via +/// [`impl Buf`](bytes::Buf) or it can be copied into contiguous storage with /// [`.into_bytes()`](crate::byte_stream::AggregatedBytes::into_bytes). #[derive(Debug, Clone)] pub struct AggregatedBytes(SegmentedBuf); impl AggregatedBytes { - /// Convert this buffer into [`Bytes`](bytes::Bytes) + /// Convert this buffer into [`Bytes`]. /// /// # Why does this consume `self`? /// Technically, [`copy_to_bytes`](bytes::Buf::copy_to_bytes) can be called without ownership of self. However, since this diff --git a/rust-runtime/aws-smithy-types/src/byte_stream/bytestream_util.rs b/rust-runtime/aws-smithy-types/src/byte_stream/bytestream_util.rs index 39965c90c56..8a8feda0c2a 100644 --- a/rust-runtime/aws-smithy-types/src/byte_stream/bytestream_util.rs +++ b/rust-runtime/aws-smithy-types/src/byte_stream/bytestream_util.rs @@ -47,7 +47,7 @@ impl PathBody { state: State::Loaded(ReaderStream::with_capacity(file.take(length), buffer_size)), length, buffer_size, - /// The file used to create this `PathBody` should have already had an offset applied + // The file used to create this `PathBody` should have already had an offset applied offset: None, } } @@ -163,7 +163,7 @@ impl FsBuilder { self } - /// Returns a [`ByteStream`](ByteStream) from this builder. + /// Returns a [`ByteStream`] from this builder. pub async fn build(self) -> Result { if self.path.is_some() && self.file.is_some() { panic!("The 'file' and 'path' options on an FsBuilder are mutually exclusive but both were set. Please set only one") @@ -193,7 +193,7 @@ impl FsBuilder { let body_loader = move || { // If an offset was provided, seeking will be handled in `PathBody::poll_data` each // time the file is loaded. - SdkBody::from_body_0_4(PathBody::from_path( + SdkBody::from_body_0_4_internal(PathBody::from_path( path.clone(), length, buffer_size, @@ -208,7 +208,8 @@ impl FsBuilder { let _s = file.seek(io::SeekFrom::Start(offset)).await?; } - let body = SdkBody::from_body_0_4(PathBody::from_file(file, length, buffer_size)); + let body = + SdkBody::from_body_0_4_internal(PathBody::from_file(file, length, buffer_size)); Ok(ByteStream::new(body)) } else { diff --git a/rust-runtime/aws-smithy-types/src/byte_stream/http_body_1_x.rs b/rust-runtime/aws-smithy-types/src/byte_stream/http_body_1_x.rs new file mode 100644 index 00000000000..bff8b201ebb --- /dev/null +++ b/rust-runtime/aws-smithy-types/src/byte_stream/http_body_1_x.rs @@ -0,0 +1,21 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Adapters to use http-body 1.0 bodies with SdkBody & ByteStream + +use crate::body::SdkBody; +use crate::byte_stream::ByteStream; +use bytes::Bytes; + +impl ByteStream { + /// Construct a `ByteStream` from a type that implements [`http_body_1_0::Body`](http_body_1_0::Body). + pub fn from_body_1_x(body: T) -> Self + where + T: http_body_1_0::Body + Send + Sync + 'static, + E: Into + 'static, + { + ByteStream::new(SdkBody::from_body_1_x(body)) + } +} diff --git a/rust-runtime/aws-smithy-types/src/config_bag.rs b/rust-runtime/aws-smithy-types/src/config_bag.rs index f2bcc01d4c7..79365244685 100644 --- a/rust-runtime/aws-smithy-types/src/config_bag.rs +++ b/rust-runtime/aws-smithy-types/src/config_bag.rs @@ -589,7 +589,11 @@ impl ConfigBag { // this code looks weird to satisfy the borrow checker—we can't keep the result of `get_mut` // alive (even in a returned branch) and then call `store_put`. So: drop the borrow immediately // store, the value, then pull it right back - if matches!(self.interceptor_state.get_mut::>(), None) { + if self + .interceptor_state + .get_mut::>() + .is_none() + { let new_item = match self.tail.iter().find_map(|b| b.load::()) { Some(item) => item.clone(), None => return None, @@ -710,7 +714,7 @@ impl ConfigBag { pub fn sourced_get(&self) -> T::ReturnedType<'_> { let stored_type_iter = ItemIter { inner: self.layers(), - t: PhantomData::default(), + t: PhantomData, }; T::merge_iter(stored_type_iter) } diff --git a/rust-runtime/aws-smithy-types/src/date_time/mod.rs b/rust-runtime/aws-smithy-types/src/date_time/mod.rs index 9466036bfac..bfcbfb22e34 100644 --- a/rust-runtime/aws-smithy-types/src/date_time/mod.rs +++ b/rust-runtime/aws-smithy-types/src/date_time/mod.rs @@ -39,7 +39,7 @@ const NANOS_PER_SECOND_U32: u32 = 1_000_000_000; /// DateTime in time represented as seconds and sub-second nanos since /// the Unix epoch (January 1, 1970 at midnight UTC/GMT). /// -/// This type can be converted to/from the standard library's [`SystemTime`](std::time::SystemTime): +/// This type can be converted to/from the standard library's [`SystemTime`]: /// ```rust /// # fn doc_fn() -> Result<(), aws_smithy_types::date_time::ConversionError> { /// # use aws_smithy_types::date_time::DateTime; diff --git a/rust-runtime/aws-smithy-types/src/primitive.rs b/rust-runtime/aws-smithy-types/src/primitive.rs index 79294cd0667..91e4d8e153f 100644 --- a/rust-runtime/aws-smithy-types/src/primitive.rs +++ b/rust-runtime/aws-smithy-types/src/primitive.rs @@ -11,9 +11,9 @@ //! - Positive infinity should be serialized as `Infinity` //! - Negative infinity should be serialized as `-Infinity` //! -//! This module defines the [`Parse`](Parse) trait which +//! This module defines the [`Parse`] trait which //! enables parsing primitive values (numbers & booleans) that follow -//! these rules and [`Encoder`](Encoder), a struct that enables +//! these rules and [`Encoder`], a struct that enables //! allocation-free serialization. //! //! # Examples diff --git a/rust-runtime/aws-smithy-xml/Cargo.toml b/rust-runtime/aws-smithy-xml/Cargo.toml index 49d86196c24..6833a957d3c 100644 --- a/rust-runtime/aws-smithy-xml/Cargo.toml +++ b/rust-runtime/aws-smithy-xml/Cargo.toml @@ -18,5 +18,6 @@ proptest = "1" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/build.gradle.kts b/rust-runtime/build.gradle.kts index 8c2fd8c054b..aab8b483944 100644 --- a/rust-runtime/build.gradle.kts +++ b/rust-runtime/build.gradle.kts @@ -13,6 +13,11 @@ group = "software.amazon.rustruntime" version = "0.0.3" +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + tasks.jar { from("./") { include("inlineable/src/") diff --git a/rust-runtime/inlineable/Cargo.toml b/rust-runtime/inlineable/Cargo.toml index a32e8da5c87..aca6e8af0f7 100644 --- a/rust-runtime/inlineable/Cargo.toml +++ b/rust-runtime/inlineable/Cargo.toml @@ -18,7 +18,7 @@ default = ["gated-tests"] [dependencies] -async-trait = "0.1" +async-trait = "0.1.74" aws-smithy-http = { path = "../aws-smithy-http", features = ["event-stream"] } aws-smithy-http-server = { path = "../aws-smithy-http-server" } aws-smithy-json = { path = "../aws-smithy-json" } @@ -27,7 +27,7 @@ aws-smithy-types = { path = "../aws-smithy-types" } aws-smithy-xml = { path = "../aws-smithy-xml" } bytes = "1" fastrand = "2.0.0" -futures-util = "0.3" +futures-util = "0.3.29" http = "0.2.1" md-5 = "0.10.0" once_cell = "1.16.0" @@ -43,5 +43,6 @@ proptest = "1" [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] # End of docs.rs metadata diff --git a/rust-runtime/inlineable/src/endpoint_lib/s3.rs b/rust-runtime/inlineable/src/endpoint_lib/s3.rs index 3bf692c6b7d..8198a11ca83 100644 --- a/rust-runtime/inlineable/src/endpoint_lib/s3.rs +++ b/rust-runtime/inlineable/src/endpoint_lib/s3.rs @@ -13,7 +13,7 @@ static VIRTUAL_HOSTABLE_SEGMENT: Lazy = static IPV4: Lazy = Lazy::new(|| Regex::new("^(\\d+\\.){3}\\d+$").unwrap()); -static DOTS_AND_DASHES: Lazy = Lazy::new(|| Regex::new(r#"^.*((\.-)|(-\.)).*$"#).unwrap()); +static DOTS_AND_DASHES: Lazy = Lazy::new(|| Regex::new(r"^.*((\.-)|(-\.)).*$").unwrap()); /// Evaluates whether a string is a DNS-compatible bucket name that can be used with virtual hosted-style addressing. pub(crate) fn is_virtual_hostable_s3_bucket( diff --git a/rust-runtime/inlineable/src/endpoint_lib/substring.rs b/rust-runtime/inlineable/src/endpoint_lib/substring.rs index 27142e118ed..2082a2c7f53 100644 --- a/rust-runtime/inlineable/src/endpoint_lib/substring.rs +++ b/rust-runtime/inlineable/src/endpoint_lib/substring.rs @@ -100,7 +100,7 @@ mod test { } #[test] - fn substring_correct_length(s in r#"[\x00-\xFF]*"#, start in 0..10usize, stop in 0..10usize, reverse in proptest::bool::ANY) { + fn substring_correct_length(s in r"[\x00-\xFF]*", start in 0..10usize, stop in 0..10usize, reverse in proptest::bool::ANY) { prop_assume!(start < s.len()); prop_assume!(stop < s.len()); prop_assume!(start < stop); diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 22048ac5bba..7eb23c42c2a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.70.0" +channel = "1.72.1" diff --git a/tools/ci-build/Dockerfile b/tools/ci-build/Dockerfile index bf776eeac3d..f6ce29bf047 100644 --- a/tools/ci-build/Dockerfile +++ b/tools/ci-build/Dockerfile @@ -6,8 +6,8 @@ # This is the base Docker build image used by CI ARG base_image=public.ecr.aws/amazonlinux/amazonlinux:2023 -ARG rust_stable_version=1.70.0 -ARG rust_nightly_version=nightly-2023-05-31 +ARG rust_stable_version=1.72.1 +ARG rust_nightly_version=nightly-2023-10-10 FROM ${base_image} AS bare_base_image RUN yum -y updateinfo @@ -82,10 +82,11 @@ RUN set -eux; \ cd smithy-rs; \ git checkout ${smithy_rs_commit_hash}; \ fi; \ - cargo install --locked --path tools/ci-build/publisher; \ cargo install --locked --path tools/ci-build/changelogger; \ cargo install --locked --path tools/ci-build/crate-hasher; \ cargo install --locked --path tools/ci-build/difftags; \ + cargo install --locked --path tools/ci-build/publisher; \ + cargo install --locked --path tools/ci-build/runtime-versioner; \ cargo install --locked --path tools/ci-build/sdk-lints; \ cargo install --locked --path tools/ci-build/sdk-versioner; \ chmod g+rw -R /opt/cargo/registry @@ -95,7 +96,7 @@ ARG cargo_deny_version=0.13.5 RUN cargo install cargo-deny --locked --version ${cargo_deny_version} FROM install_rust AS cargo_udeps -ARG cargo_udeps_version=0.1.35 +ARG cargo_udeps_version=0.1.42 ARG rust_nightly_version RUN cargo +${rust_nightly_version} install cargo-udeps --locked --version ${cargo_udeps_version} @@ -104,11 +105,11 @@ ARG cargo_hack_version=0.5.23 RUN cargo install cargo-hack --locked --version ${cargo_hack_version} FROM install_rust AS cargo_minimal_versions -ARG cargo_minimal_versions_version=0.1.8 +ARG cargo_minimal_versions_version=0.1.19 RUN cargo install cargo-minimal-versions --locked --version ${cargo_minimal_versions_version} FROM install_rust AS cargo_check_external_types -ARG cargo_check_external_types_version=0.1.7 +ARG cargo_check_external_types_version=0.1.8 RUN cargo install cargo-check-external-types --locked --version ${cargo_check_external_types_version} FROM install_rust AS maturin @@ -138,13 +139,11 @@ RUN cargo install cargo-semver-checks --locked --version ${cargo_semver_checks_v FROM install_rust AS cargo_mdbook ARG cargo_mdbook_version=0.4.30 -ARG rust_nightly_version -RUN cargo +${rust_nightly_version} -Z sparse-registry install mdbook --locked --version ${cargo_mdbook_version} +RUN cargo install mdbook --locked --version ${cargo_mdbook_version} FROM install_rust AS cargo_mdbook_mermaid ARG cargo_mdbook_mermaid_version=0.12.6 -ARG rust_nightly_version -RUN cargo +${rust_nightly_version} -Z sparse-registry install mdbook-mermaid --locked --version ${cargo_mdbook_mermaid_version} +RUN cargo install mdbook-mermaid --locked --version ${cargo_mdbook_mermaid_version} # # Final image @@ -168,7 +167,8 @@ RUN set -eux; \ python3 \ python3-devel \ python3-pip \ - shadow-utils; \ + shadow-utils \ + tar; \ yum clean all; \ rm -rf /var/cache/yum; \ groupadd build; \ diff --git a/tools/ci-build/changelogger/Cargo.lock b/tools/ci-build/changelogger/Cargo.lock index 682f4e12177..c7de5cafaa9 100644 --- a/tools/ci-build/changelogger/Cargo.lock +++ b/tools/ci-build/changelogger/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -19,28 +19,28 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "async-trait" -version = "0.1.72" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] @@ -62,9 +62,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -77,9 +77,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bitflags" @@ -89,27 +89,30 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -144,7 +147,7 @@ dependencies = [ "bitflags 1.3.2", "clap_derive", "clap_lex", - "indexmap", + "indexmap 1.9.3", "once_cell", "strsim", "termcolor", @@ -175,9 +178,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -185,9 +188,18 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "deranged" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +dependencies = [ + "powerfmt", +] [[package]] name = "diff" @@ -197,39 +209,34 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] [[package]] -name = "errno" -version = "0.3.1" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "errno" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fnv" @@ -254,45 +261,45 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-core", "futures-task", @@ -302,15 +309,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -318,7 +325,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -331,6 +338,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "heck" version = "0.4.1" @@ -348,9 +361,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -376,9 +389,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" @@ -397,7 +410,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -419,9 +432,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -434,14 +447,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", ] [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itoa" @@ -451,9 +474,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -466,27 +489,27 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "mime" @@ -505,13 +528,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -544,9 +567,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -562,26 +585,26 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -598,7 +621,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] @@ -609,9 +632,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" dependencies = [ "cc", "libc", @@ -630,21 +653,21 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.5.1" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -658,6 +681,12 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "pretty_assertions" version = "1.4.0" @@ -694,36 +723,36 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", @@ -733,9 +762,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -744,15 +773,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ "base64", "bytes", @@ -775,6 +804,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tower-service", @@ -793,15 +823,15 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.4" +version = "0.38.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -816,7 +846,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -844,35 +874,35 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.176" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.176" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e7b8c5dc823e3b90651ff1d3808419cd14e5ad76de04feaf37da114e7a306f" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -893,9 +923,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -912,20 +942,31 @@ dependencies = [ "semver", "serde", "serde_json", + "thiserror", "toml", "tracing", ] [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", ] +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "strsim" version = "0.10.0" @@ -945,33 +986,54 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" -version = "3.7.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] @@ -982,23 +1044,45 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "time" -version = "0.3.23" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ + "deranged", "libc", "num_threads", + "powerfmt", "serde", "time-core", ] [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "tinyvec" @@ -1017,18 +1101,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", "mio", "pin-project-lite", - "socket2", - "windows-sys", + "socket2 0.5.5", + "windows-sys 0.48.0", ] [[package]] @@ -1043,9 +1126,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -1061,7 +1144,7 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "indexmap", + "indexmap 1.9.3", "serde", ] @@ -1073,11 +1156,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1085,41 +1167,41 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -1132,9 +1214,9 @@ dependencies = [ [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -1170,9 +1252,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1180,24 +1262,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if", "js-sys", @@ -1207,9 +1289,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1217,28 +1299,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -1262,9 +1344,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -1281,73 +1363,140 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] [[package]] diff --git a/tools/ci-build/changelogger/src/render.rs b/tools/ci-build/changelogger/src/render.rs index 5b72a253bbf..54b8a5dcbd7 100644 --- a/tools/ci-build/changelogger/src/render.rs +++ b/tools/ci-build/changelogger/src/render.rs @@ -164,6 +164,7 @@ fn to_md_link(reference: &Reference) -> String { let org_name = match reference.repo.as_str() { "smithy-rs" => "smithy-lang", "aws-sdk-rust" => "awslabs", + "aws-sdk" => "aws", repo => panic!("unrecognized repo named {repo}"), }; format!( @@ -396,6 +397,7 @@ fn render_external_contributors(entries: &[ChangelogEntry], out: &mut String) { .unwrap() .references .iter() + .filter(|r| matches!(r.repo.as_str(), "aws-sdk-rust" | "smithy-rs")) .map(to_md_link) }) .collect::>(); @@ -507,7 +509,7 @@ references = ["smithy-rs#445"] author = "external-contrib" message = "I made a change to update the code generator" meta = { breaking = false, tada = true, bug = false } -references = ["smithy-rs#446"] +references = ["smithy-rs#446", "aws-sdk#123"] [[smithy-rs]] author = "another-contrib" @@ -570,7 +572,7 @@ v0.3.0 (January 4th, 2022) - :warning: (all, [smithy-rs#445](https://github.com/smithy-lang/smithy-rs/issues/445)) I made a major change to update the code generator **New this release:** -- :tada: (all, [smithy-rs#446](https://github.com/smithy-lang/smithy-rs/issues/446), @external-contrib) I made a change to update the code generator +- :tada: (all, [smithy-rs#446](https://github.com/smithy-lang/smithy-rs/issues/446), [aws-sdk#123](https://github.com/aws/aws-sdk/issues/123), @external-contrib) I made a change to update the code generator - :tada: (all, [smithy-rs#446](https://github.com/smithy-lang/smithy-rs/issues/446), @external-contrib) I made a change to update the code generator **Update guide:** diff --git a/tools/ci-build/crate-hasher/Cargo.lock b/tools/ci-build/crate-hasher/Cargo.lock index bc931d59845..83cef645754 100644 --- a/tools/ci-build/crate-hasher/Cargo.lock +++ b/tools/ci-build/crate-hasher/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -19,28 +19,28 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "async-trait" -version = "0.1.72" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.39", ] [[package]] @@ -62,9 +62,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -83,9 +83,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "block-buffer" @@ -98,9 +98,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" dependencies = [ "memchr", "serde", @@ -108,15 +108,18 @@ dependencies = [ [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -165,9 +168,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -232,59 +235,42 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "filetime" -version = "0.2.21" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", - "windows-sys", + "redox_syscall", + "windows-sys 0.52.0", ] [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", "miniz_oxide", ] -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - [[package]] name = "generic-array" version = "0.14.7" @@ -297,21 +283,21 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "globset" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1391ab1f92ffcc08911957149833e682aa3fe252b9f45f966d2ef972274c97df" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ "aho-corasick", "bstr", - "fnv", "log", - "regex", + "regex-automata", + "regex-syntax", ] [[package]] @@ -377,27 +363,27 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "miniz_oxide" @@ -410,30 +396,30 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "os_str_bytes" -version = "6.5.1" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pretty_assertions" @@ -471,45 +457,36 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", @@ -519,9 +496,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -530,9 +507,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustc-demangle" @@ -542,15 +519,15 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.4" +version = "0.38.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -564,15 +541,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.176" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -581,9 +572,9 @@ dependencies = [ [[package]] name = "sha256" -version = "1.2.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "386f700b0c798d92ac20a53342c240ff9d58030c3b845fbaeb92eead3a774792" +checksum = "7895c8ae88588ccead14ff438b939b0c569cd619116f14b4d13fdff7b8333386" dependencies = [ "async-trait", "bytes", @@ -611,9 +602,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -622,9 +613,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec96d2ffad078296368d46ff1cb309be1c23c513b4ab0e22a45de0185275ac96" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" dependencies = [ "filetime", "libc", @@ -633,22 +624,22 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.7.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.3.5", + "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] @@ -671,11 +662,10 @@ dependencies = [ [[package]] name = "tokio" -version = "1.29.1" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ - "autocfg", "backtrace", "bytes", "pin-project-lite", @@ -683,15 +673,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "version_check" @@ -701,9 +691,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" dependencies = [ "same-file", "winapi-util", @@ -727,9 +717,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -746,71 +736,137 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "xattr" -version = "0.2.3" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" dependencies = [ "libc", ] diff --git a/tools/ci-build/crate-hasher/tests/test.rs b/tools/ci-build/crate-hasher/tests/test.rs index 98bd360bb44..1188f8bbe40 100644 --- a/tools/ci-build/crate-hasher/tests/test.rs +++ b/tools/ci-build/crate-hasher/tests/test.rs @@ -44,9 +44,9 @@ fn test_against_aws_smithy_async_with_ignored_files() -> Result<()> { let mut archive = Archive::new(tar); archive.unpack(&dir)?; - std::fs::create_dir(&dir.as_path().join("target"))?; + std::fs::create_dir(dir.as_path().join("target"))?; std::fs::write( - &dir.as_path().join("target/something"), + dir.as_path().join("target/something"), b"some data that should be excluded", )?; diff --git a/tools/ci-build/difftags/Cargo.lock b/tools/ci-build/difftags/Cargo.lock index 1bbe447c25b..29773e435a2 100644 --- a/tools/ci-build/difftags/Cargo.lock +++ b/tools/ci-build/difftags/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -130,27 +130,27 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "os_str_bytes" -version = "6.5.1" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "proc-macro-error" @@ -178,27 +178,27 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", @@ -208,9 +208,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -219,9 +219,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "strsim" @@ -242,9 +242,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] @@ -257,9 +257,9 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unidiff" @@ -273,9 +273,9 @@ dependencies = [ [[package]] name = "utf8-width" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "version_check" @@ -301,9 +301,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] diff --git a/tools/ci-build/publisher/Cargo.lock b/tools/ci-build/publisher/Cargo.lock index 7acedde3b8a..8c4ffda50ac 100644 --- a/tools/ci-build/publisher/Cargo.lock +++ b/tools/ci-build/publisher/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -19,24 +19,18 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "async-recursion" @@ -51,13 +45,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.72" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] @@ -79,9 +73,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -94,9 +88,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bitflags" @@ -106,9 +100,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "block-buffer" @@ -121,15 +115,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cargo_toml" @@ -138,14 +132,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3f9629bc6c4388ea699781dc988c2b99766d7679b151c81990b4fa1208fafd3" dependencies = [ "serde", - "toml 0.8.6", + "toml 0.8.8", ] [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -155,11 +152,10 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ - "android-tzdata", "num-traits", "serde", ] @@ -220,9 +216,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -230,15 +226,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -306,9 +302,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] @@ -321,30 +317,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fnv" @@ -369,24 +354,27 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "fs-err" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -399,9 +387,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -409,15 +397,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -426,38 +414,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -483,15 +471,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -499,7 +487,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -508,9 +496,9 @@ dependencies = [ [[package]] name = "handlebars" -version = "4.3.7" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c3372087601b532857d332f5957cbae686da52bb7810bf038c3e3c3cc2fa0d" +checksum = "faa67bab9ff362228eb3d00bd024a4965d8231bbb7921167f0cfa66c6626b225" dependencies = [ "log", "pest", @@ -528,9 +516,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heck" @@ -549,9 +537,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "hex" @@ -561,9 +549,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -589,9 +577,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" @@ -610,7 +598,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -632,9 +620,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -652,19 +640,19 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.2", + "hashbrown 0.14.3", ] [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itoa" @@ -674,9 +662,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -689,21 +677,21 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -711,9 +699,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "matchers" @@ -726,9 +714,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "mime" @@ -747,13 +735,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -786,9 +774,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -799,32 +787,32 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi 0.3.3", "libc", ] [[package]] name = "object" -version = "0.31.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -841,7 +829,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] @@ -852,9 +840,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" dependencies = [ "cc", "libc", @@ -864,9 +852,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.5.1" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "overload" @@ -886,38 +874,39 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.1" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d2d1d55045829d65aad9d389139882ad623b33b904e7c9f1b10c5b8927298e5" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" dependencies = [ + "memchr", "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.1" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f94bca7e7a599d89dea5dfa309e217e7906c3c007fb9c3299c40b10d6a315d3" +checksum = "81d78524685f5ef2a3b3bd1cafbc9fcabb036253d9b1463e726a91cd16e2dfc2" dependencies = [ "pest", "pest_generator", @@ -925,22 +914,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.1" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d490fe7e8556575ff6911e45567ab95e71617f43781e5c05490dc8d75c965c" +checksum = "68bd1206e71118b5356dae5ddc61c8b11e28b09ef6a31acbd15ea48a28e0c227" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] name = "pest_meta" -version = "2.7.1" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674c66ebb4b4d9036012091b537aae5878970d6999f81a265034d85b136b341" +checksum = "7c747191d4ad9e4a4ab9c8798f1e82a39affe7ef9648390b7e5548d18e099de6" dependencies = [ "once_cell", "pest", @@ -949,9 +938,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1001,9 +990,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] @@ -1039,32 +1028,32 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.3", - "regex-syntax 0.7.4", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -1078,13 +1067,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.8.2", ] [[package]] @@ -1095,15 +1084,15 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ "base64", "bytes", @@ -1126,6 +1115,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tower-service", @@ -1144,15 +1134,15 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.4" +version = "0.38.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1167,7 +1157,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1201,35 +1191,35 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.176" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.176" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e7b8c5dc823e3b90651ff1d3808419cd14e5ad76de04feaf37da114e7a306f" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -1259,9 +1249,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -1270,9 +1260,9 @@ dependencies = [ [[package]] name = "sha256" -version = "1.2.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "386f700b0c798d92ac20a53342c240ff9d58030c3b845fbaeb92eead3a774792" +checksum = "7895c8ae88588ccead14ff438b939b0c569cd619116f14b4d13fdff7b8333386" dependencies = [ "async-trait", "bytes", @@ -1283,9 +1273,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -1301,18 +1291,18 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "smithy-rs-tool-common" @@ -1326,6 +1316,7 @@ dependencies = [ "semver", "serde", "serde_json", + "thiserror", "tokio", "toml 0.5.11", "tracing", @@ -1333,14 +1324,24 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", ] +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "strsim" version = "0.10.0" @@ -1360,33 +1361,54 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" -version = "3.7.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] @@ -1409,22 +1431,22 @@ checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] @@ -1454,11 +1476,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", @@ -1467,20 +1488,20 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.5", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] @@ -1495,9 +1516,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -1519,9 +1540,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff9e3abce27ee2c9a37f9ad37238c1bdd4e789c84ba37df76aa4d528f5072cc" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" dependencies = [ "serde", "serde_spanned", @@ -1540,11 +1561,11 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.20.7" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", @@ -1559,11 +1580,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1571,20 +1591,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -1592,20 +1612,20 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -1621,15 +1641,15 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" @@ -1639,15 +1659,15 @@ checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -1660,15 +1680,15 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -1710,9 +1730,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1720,24 +1740,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if", "js-sys", @@ -1747,9 +1767,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1757,28 +1777,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -1802,9 +1822,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -1821,82 +1841,149 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.17" +version = "0.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" +checksum = "b67b5f0a4e7a27a64c651977932b9dc5667ca7fc31ac44b03ed37a0cf42fdfff" dependencies = [ "memchr", ] [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] [[package]] @@ -1907,6 +1994,6 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/tools/ci-build/publisher/Cargo.toml b/tools/ci-build/publisher/Cargo.toml index 9aa5909980e..ce6b7ba49de 100644 --- a/tools/ci-build/publisher/Cargo.toml +++ b/tools/ci-build/publisher/Cargo.toml @@ -16,7 +16,7 @@ opt-level = 0 [dependencies] anyhow = "1.0" async-recursion = "0.3.2" -async-trait = "0.1.51" +async-trait = "0.1.74" cargo_toml = "0.16.3" clap = { version = "~3.1.18", features = ["derive"] } crates_io_api = "0.7.3" @@ -29,7 +29,7 @@ semver = "1.0" serde = { version = "1", features = ["derive"] } serde_json = "1" sha256 = "1" -smithy-rs-tool-common = { version = "0.1", path = "../smithy-rs-tool-common", features = ["async-shell"] } +smithy-rs-tool-common = { version = "0.1", path = "../smithy-rs-tool-common", features = ["async"] } tempfile = "3.3.0" thiserror = "1.0" tokio = { version = "1.20.1", features = ["full"] } diff --git a/tools/ci-build/publisher/src/cargo/get_owners.rs b/tools/ci-build/publisher/src/cargo/get_owners.rs index 1857cd4c5c3..b549738a1d2 100644 --- a/tools/ci-build/publisher/src/cargo/get_owners.rs +++ b/tools/ci-build/publisher/src/cargo/get_owners.rs @@ -33,7 +33,7 @@ impl ShellOperation for GetOwners { let mut result = Vec::new(); let (stdout, _) = output_text(&output); - let line_re = Regex::new(r#"^([\w\d\-_:]+)\s+\([\w\d\s\-_]+\)$"#).unwrap(); + let line_re = Regex::new(r"^([\w\d\-_:]+)\s+\([\w\d\s\-_]+\)$").unwrap(); for line in stdout.lines() { if let Some(captures) = line_re.captures(line) { let user_id = captures.get(1).unwrap().as_str(); diff --git a/tools/ci-build/publisher/src/lib.rs b/tools/ci-build/publisher/src/lib.rs index 5e677b0a242..632e7b5b04b 100644 --- a/tools/ci-build/publisher/src/lib.rs +++ b/tools/ci-build/publisher/src/lib.rs @@ -14,6 +14,6 @@ pub mod cargo; pub mod fs; pub mod package; pub mod publish; -pub mod retry; pub mod sort; pub mod subcommand; +pub mod yank; diff --git a/tools/ci-build/publisher/src/package.rs b/tools/ci-build/publisher/src/package.rs index 7efff2725ec..4fb572a687f 100644 --- a/tools/ci-build/publisher/src/package.rs +++ b/tools/ci-build/publisher/src/package.rs @@ -239,10 +239,9 @@ fn read_package(path: &Path, manifest_bytes: &[u8]) -> Result> { }; let mut local_dependencies = BTreeSet::new(); - local_dependencies.extend(read_dependencies(path, &manifest.dependencies)?.into_iter()); - local_dependencies.extend(read_dependencies(path, &manifest.dev_dependencies)?.into_iter()); - local_dependencies - .extend(read_dependencies(path, &manifest.build_dependencies)?.into_iter()); + local_dependencies.extend(read_dependencies(path, &manifest.dependencies)?); + local_dependencies.extend(read_dependencies(path, &manifest.dev_dependencies)?); + local_dependencies.extend(read_dependencies(path, &manifest.build_dependencies)?); Ok(Some(Package::new( handle, path, diff --git a/tools/ci-build/publisher/src/publish.rs b/tools/ci-build/publisher/src/publish.rs index 59d4d48b565..151f00ac518 100644 --- a/tools/ci-build/publisher/src/publish.rs +++ b/tools/ci-build/publisher/src/publish.rs @@ -5,9 +5,9 @@ use crate::cargo; use crate::package::PackageHandle; -use crate::retry::{run_with_retry, BoxError, ErrorClass}; use crates_io_api::{AsyncClient, Error}; use once_cell::sync::Lazy; +use smithy_rs_tool_common::retry::{run_with_retry, BoxError, ErrorClass}; use smithy_rs_tool_common::shell::ShellOperation; use std::path::Path; use std::time::Duration; diff --git a/tools/ci-build/publisher/src/subcommand/fix_manifests.rs b/tools/ci-build/publisher/src/subcommand/fix_manifests.rs index a22c47f5901..78814cdad50 100644 --- a/tools/ci-build/publisher/src/subcommand/fix_manifests.rs +++ b/tools/ci-build/publisher/src/subcommand/fix_manifests.rs @@ -16,7 +16,6 @@ use anyhow::{bail, Context, Result}; use clap::Parser; use semver::Version; use smithy_rs_tool_common::ci::running_in_ci; -use smithy_rs_tool_common::package::PackageStability; use std::collections::BTreeMap; use std::ffi::OsStr; use std::path::{Path, PathBuf}; @@ -40,17 +39,15 @@ pub struct FixManifestsArgs { /// Checks manifests rather than fixing them #[clap(long)] check: bool, - /// Disable expected version number validation. This should only be used - /// when SDK crates are being generated with independent version numbers. + /// UNUSED. Kept for backwards compatibility. Can be removed in the future when + /// the older commits that rely on it have been synced over in a SDK release. #[clap(long)] disable_version_number_validation: bool, } pub async fn subcommand_fix_manifests( FixManifestsArgs { - location, - check, - disable_version_number_validation, + location, check, .. }: &FixManifestsArgs, ) -> Result<()> { let mode = match check { @@ -61,7 +58,6 @@ pub async fn subcommand_fix_manifests( let mut manifests = read_manifests(Fs::Real, manifest_paths).await?; let versions = package_versions(&manifests)?; - validate::validate_before_fixes(&versions, *disable_version_number_validation)?; fix_manifests(Fs::Real, &versions, &mut manifests, mode).await?; validate::validate_after_fixes(location).await?; info!("Successfully fixed manifests!"); @@ -84,27 +80,6 @@ impl Manifest { ))), } } - - fn stability(&self) -> Result { - let value = self - .metadata - .get("package") - .and_then(|v| v.get("metadata")) - .and_then(|v| v.get("smithy-rs-release-tooling")) - .and_then(|v| v.get("stable")); - match value { - None => Ok(PackageStability::Unstable), - Some(value) => { - if value.as_bool().ok_or(anyhow::Error::msg(format!( - "unexpected stable setting: {value}" - )))? { - Ok(PackageStability::Stable) - } else { - Ok(PackageStability::Unstable) - } - } - } - } } struct Versions(BTreeMap); @@ -133,32 +108,11 @@ impl Versions { fn published(&self) -> VersionView { VersionView(self, FilterType::PublishedOnly) } - - fn published_crates(&self) -> impl Iterator + '_ { - self.0 - .iter() - .filter(|(_, v)| v.publish) - .map(|(k, v)| (k.as_str(), &v.version)) - } - - fn get(&self, crate_name: &str) -> Option<&Version> { - self.0.get(crate_name).map(|v| &v.version) - } - - fn stable(&self, crate_name: &str) -> Option { - match self.0.get(crate_name) { - Some(VersionWithMetadata { stability, .. }) => { - Some(*stability == PackageStability::Stable) - } - _ => None, - } - } } struct VersionWithMetadata { version: Version, publish: bool, - stability: PackageStability, } async fn read_manifests(fs: Fs, manifest_paths: Vec) -> Result> { @@ -182,7 +136,6 @@ fn package_versions(manifests: &[Manifest]) -> Result { None => continue, }; let publish = manifest.publish()?; - let stability = manifest.stability()?; let name = package .get("name") .and_then(|name| name.as_str()) @@ -196,14 +149,7 @@ fn package_versions(manifests: &[Manifest]) -> Result { anyhow::Error::msg(format!("{:?} is missing a package version", manifest.path)) })?; let version = parse_version(&manifest.path, version)?; - versions.insert( - name.into(), - VersionWithMetadata { - version, - publish, - stability, - }, - ); + versions.insert(name.into(), VersionWithMetadata { version, publish }); } Ok(Versions(versions)) } @@ -359,19 +305,16 @@ fn fix_manifest(versions: &Versions, manifest: &mut Manifest) -> Result { mod tests { use super::*; - fn make_versions<'a>( - versions: impl Iterator, - ) -> Versions { + fn make_versions<'a>(versions: impl Iterator) -> Versions { let map = versions .into_iter() - .map(|(name, version, publish, stability)| { + .map(|(name, version, publish)| { let publish = *publish; ( name.to_string(), VersionWithMetadata { - version: Version::parse(&version).unwrap(), + version: Version::parse(version).unwrap(), publish, - stability: *stability, }, ) }) @@ -405,19 +348,9 @@ mod tests { metadata, }; let versions = &[ - ( - "local_build_something", - "0.2.0", - true, - PackageStability::Unstable, - ), - ( - "local_dev_something", - "0.1.0", - false, - PackageStability::Unstable, - ), - ("local_something", "1.1.3", false, PackageStability::Stable), + ("local_build_something", "0.2.0", true), + ("local_dev_something", "0.1.0", false), + ("local_something", "1.1.3", false), ]; let versions = make_versions(versions.iter()); fix_manifest(&versions, &mut manifest).expect_err("depends on unpublished local something"); @@ -451,19 +384,9 @@ mod tests { metadata, }; let versions = &[ - ( - "local_build_something", - "0.2.0", - true, - PackageStability::Unstable, - ), - ( - "local_dev_something", - "0.1.0", - false, - PackageStability::Unstable, - ), - ("local_something", "1.1.3", true, PackageStability::Stable), + ("local_build_something", "0.2.0", true), + ("local_dev_something", "0.1.0", false), + ("local_something", "1.1.3", true), ]; let versions = make_versions(versions.iter()); @@ -522,52 +445,4 @@ mod tests { "aws-sdk-rust/examples/foo/bar/Cargo.toml" )); } - - #[test] - fn test_package_stability_from_manifest() { - fn verify_package_stability_for_manifest( - manifest: &[u8], - expected_stability: PackageStability, - ) { - let metadata = toml::from_slice(manifest).unwrap(); - let manifest = Manifest { - path: "test".into(), - metadata, - }; - assert_eq!(expected_stability, manifest.stability().unwrap()); - } - - let stable_manifest = br#" - [package] - name = "test" - version = "1.0.0" - - [package.metadata.smithy-rs-release-tooling] - stable = true - "#; - verify_package_stability_for_manifest(stable_manifest, PackageStability::Stable); - - let explicitly_unstable_manifest = br#" - [package] - name = "test" - version = "0.1.0" - - [package.metadata.smithy-rs-release-tooling] - stable = false - "#; - verify_package_stability_for_manifest( - explicitly_unstable_manifest, - PackageStability::Unstable, - ); - - let implicitly_unstable_manifest = br#" - [package] - name = "test" - version = "0.1.0" - "#; - verify_package_stability_for_manifest( - implicitly_unstable_manifest, - PackageStability::Unstable, - ); - } } diff --git a/tools/ci-build/publisher/src/subcommand/fix_manifests/validate.rs b/tools/ci-build/publisher/src/subcommand/fix_manifests/validate.rs index e9924124597..673a91770f8 100644 --- a/tools/ci-build/publisher/src/subcommand/fix_manifests/validate.rs +++ b/tools/ci-build/publisher/src/subcommand/fix_manifests/validate.rs @@ -5,62 +5,10 @@ use crate::fs::Fs; use crate::package::discover_and_validate_package_batches; -use crate::subcommand::fix_manifests::Versions; -use anyhow::{anyhow, bail, Result}; -use semver::Version; -use smithy_rs_tool_common::package::PackageCategory; +use anyhow::Result; use std::path::Path; use tracing::info; -/// Validations that run before the manifests are fixed. -/// -/// For now, this validates: -/// - `aws-smithy-` prefixed versions match `aws-` (NOT `aws-sdk-`) prefixed versions -pub(super) fn validate_before_fixes( - versions: &Versions, - disable_version_number_validation: bool, -) -> Result<()> { - // Later when we only generate independently versioned SDK crates, this flag can become permanent. - if disable_version_number_validation { - return Ok(()); - } - - info!("Pre-validation manifests..."); - - let expected_stable_runtime_version = versions - .get("aws-smithy-types") - .ok_or_else(|| anyhow!("`aws-smithy-types` crate missing"))?; - - let expected_unstable_runtime_version = versions - .get("aws-smithy-http") - .ok_or_else(|| anyhow!("`aws-smithy-http` crate missing"))?; - - for (name, version) in versions.published_crates() { - let category = PackageCategory::from_package_name(name); - if category == PackageCategory::SmithyRuntime || category == PackageCategory::AwsRuntime { - let expected_runtime_version = if let Some(true) = versions.stable(name) { - expected_stable_runtime_version - } else { - expected_unstable_runtime_version - }; - confirm_version(name, expected_runtime_version, version)?; - } - } - Ok(()) -} - -fn confirm_version(name: &str, expected: &Version, actual: &Version) -> Result<()> { - if expected != actual { - bail!( - "Crate named `{}` should be at version `{}` but is at `{}`", - name, - expected, - actual - ); - } - Ok(()) -} - /// Validations that run after fixing the manifests. /// /// These should match the validations that the `publish` subcommand runs. @@ -69,95 +17,3 @@ pub(super) async fn validate_after_fixes(location: &Path) -> Result<()> { discover_and_validate_package_batches(Fs::Real, location).await?; Ok(()) } - -#[cfg(test)] -mod test { - use super::*; - use crate::subcommand::fix_manifests::VersionWithMetadata; - use smithy_rs_tool_common::package::PackageStability; - use std::collections::BTreeMap; - use std::str::FromStr; - - fn versions(versions: &[(&'static str, &'static str, PackageStability)]) -> Versions { - let mut map = BTreeMap::new(); - for (name, version, stability) in versions { - map.insert( - (*name).into(), - VersionWithMetadata { - version: Version::from_str(version).unwrap(), - publish: true, - stability: *stability, - }, - ); - } - Versions(map) - } - - #[track_caller] - fn expect_success(version_tuples: &[(&'static str, &'static str, PackageStability)]) { - validate_before_fixes(&versions(version_tuples), false).expect("success"); - } - - #[track_caller] - fn expect_failure( - message: &str, - version_tuples: &[(&'static str, &'static str, PackageStability)], - ) { - if let Err(err) = validate_before_fixes(&versions(version_tuples), false) { - assert_eq!(message, format!("{}", err)); - } else { - panic!("Expected validation failure"); - } - } - - #[test] - fn pre_validate() { - expect_success(&[ - ("aws-config", "1.5.2", PackageStability::Stable), - ("aws-smithy-http", "0.35.1", PackageStability::Unstable), - ("aws-sdk-s3", "1.5.2", PackageStability::Stable), - ("aws-smithy-types", "1.5.2", PackageStability::Stable), - ("aws-types", "1.5.2", PackageStability::Stable), - ]); - - expect_success(&[ - ("aws-smithy-types", "1.5.2", PackageStability::Stable), - ("aws-smithy-http", "0.35.1", PackageStability::Unstable), - ]); - - expect_failure( - "Crate named `aws-smithy-runtime-api` should be at version `1.5.3` but is at `1.5.2`", - &[ - ("aws-smithy-runtime-api", "1.5.2", PackageStability::Stable), - ("aws-smithy-types", "1.5.3", PackageStability::Stable), - ("aws-smithy-http", "0.35.0", PackageStability::Unstable), - ], - ); - - expect_success(&[ - ("aws-config", "1.5.2", PackageStability::Stable), - ("aws-smithy-http", "0.35.0", PackageStability::Unstable), - ("aws-sdk-s3", "1.5.2", PackageStability::Stable), - ("aws-smithy-types", "1.5.2", PackageStability::Stable), - ("aws-types", "1.5.2", PackageStability::Stable), - ]); - - expect_failure( - "Crate named `aws-types` should be at version `1.5.3` but is at `1.5.2`", - &[ - ("aws-config", "1.5.3", PackageStability::Stable), - ("aws-sdk-s3", "1.5.3", PackageStability::Stable), - ("aws-smithy-http", "0.35.0", PackageStability::Unstable), - ("aws-smithy-types", "1.5.3", PackageStability::Stable), - ("aws-types", "1.5.2", PackageStability::Stable), - ], - ); - - expect_success(&[ - ("aws-config", "1.5.3", PackageStability::Stable), - ("aws-sdk-s3", "1.5.3", PackageStability::Stable), - ("aws-smithy-types", "1.5.3", PackageStability::Stable), - ("aws-smithy-http", "0.35.0", PackageStability::Unstable), - ]); - } -} diff --git a/tools/ci-build/publisher/src/subcommand/publish.rs b/tools/ci-build/publisher/src/subcommand/publish.rs index 4a8090de027..788f579e8d4 100644 --- a/tools/ci-build/publisher/src/subcommand/publish.rs +++ b/tools/ci-build/publisher/src/subcommand/publish.rs @@ -9,7 +9,6 @@ use crate::package::{ PackageHandle, PackageStats, }; use crate::publish::{publish, CRATES_IO_CLIENT}; -use crate::retry::{run_with_retry, BoxError, ErrorClass}; use crate::{cargo, SDK_REPO_CRATE_PATH, SDK_REPO_NAME}; use anyhow::{bail, Context, Result}; use clap::Parser; @@ -17,6 +16,7 @@ use crates_io_api::Error; use dialoguer::Confirm; use smithy_rs_tool_common::git; use smithy_rs_tool_common::package::PackageCategory; +use smithy_rs_tool_common::retry::{run_with_retry, BoxError, ErrorClass}; use smithy_rs_tool_common::shell::ShellOperation; use std::collections::HashSet; use std::path::{Path, PathBuf}; diff --git a/tools/ci-build/publisher/src/subcommand/yank_release.rs b/tools/ci-build/publisher/src/subcommand/yank_release.rs index 12b769a10ac..0b8378c2207 100644 --- a/tools/ci-build/publisher/src/subcommand/yank_release.rs +++ b/tools/ci-build/publisher/src/subcommand/yank_release.rs @@ -4,21 +4,20 @@ */ use crate::cargo; +use crate::yank::yank; use anyhow::{anyhow, bail, Context, Result}; use clap::{ArgEnum, Parser}; use dialoguer::Confirm; use smithy_rs_tool_common::package::PackageCategory; use smithy_rs_tool_common::release_tag::ReleaseTag; -use smithy_rs_tool_common::shell::ShellOperation; use smithy_rs_tool_common::versions_manifest::{Release, VersionsManifest}; use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use std::str::FromStr; -use std::sync::Arc; -use tokio::sync::Semaphore; +use std::time::Duration; use tracing::info; -const MAX_CONCURRENCY: usize = 5; +const DEFAULT_DELAY_MILLIS: usize = 1000; #[derive(Copy, Clone, Debug, ArgEnum, Eq, PartialEq, Ord, PartialOrd)] pub enum CrateSet { @@ -42,6 +41,9 @@ pub struct YankReleaseArgs { versions_toml: Option, #[clap(arg_enum)] crate_set: Option, + /// Time delay between crate yanking to avoid crates.io throttling errors. + #[clap(long)] + delay_millis: Option, } pub async fn subcommand_yank_release( @@ -49,6 +51,7 @@ pub async fn subcommand_yank_release( github_release_tag, versions_toml, crate_set, + delay_millis, }: &YankReleaseArgs, ) -> Result<()> { // Make sure cargo exists @@ -75,28 +78,16 @@ pub async fn subcommand_yank_release( // Don't proceed unless the user confirms the plan confirm_plan(&tag, &crates)?; - // Use a semaphore to only allow a few concurrent yanks - let semaphore = Arc::new(Semaphore::new(MAX_CONCURRENCY)); - info!( - "Will yank {} crates in parallel where possible.", - MAX_CONCURRENCY - ); + let delay_millis = Duration::from_millis(delay_millis.unwrap_or(DEFAULT_DELAY_MILLIS) as _); - let mut tasks = Vec::new(); + // Yank one crate at a time to try avoiding throttling errors for (crate_name, crate_version) in crates { - let permit = semaphore.clone().acquire_owned().await.unwrap(); - tasks.push(tokio::spawn(async move { - info!("Yanking `{}-{}`...", crate_name, crate_version); - let result = cargo::Yank::new(&crate_name, &crate_version).spawn().await; - drop(permit); - if result.is_ok() { - info!("Successfully yanked `{}-{}`", crate_name, crate_version); - } - result - })); - } - for task in tasks { - task.await??; + yank(&crate_name, &crate_version).await?; + + // Keep things slow to avoid getting throttled by crates.io + tokio::time::sleep(delay_millis).await; + + info!("Successfully yanked `{}-{}`", crate_name, crate_version); } Ok(()) diff --git a/tools/ci-build/publisher/src/yank.rs b/tools/ci-build/publisher/src/yank.rs new file mode 100644 index 00000000000..8535c5384a0 --- /dev/null +++ b/tools/ci-build/publisher/src/yank.rs @@ -0,0 +1,27 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::cargo; +use smithy_rs_tool_common::retry::{run_with_retry, BoxError, ErrorClass}; +use smithy_rs_tool_common::shell::ShellOperation; +use std::time::Duration; +use tracing::info; + +#[tracing::instrument] +pub async fn yank(crate_name: &str, crate_version: &str) -> anyhow::Result<()> { + info!("Yanking `{}-{}`...", crate_name, crate_version); + run_with_retry( + &format!("Yanking `{}-{}`", crate_name, crate_version), + 5, + Duration::from_secs(60), + || async { + cargo::Yank::new(crate_name, crate_version).spawn().await?; + Result::<_, BoxError>::Ok(()) + }, + |_err| ErrorClass::Retry, + ) + .await?; + Ok(()) +} diff --git a/tools/ci-build/runtime-release-dryrun/Cargo.lock b/tools/ci-build/runtime-release-dryrun/Cargo.lock new file mode 100644 index 00000000000..5d86df86e9b --- /dev/null +++ b/tools/ci-build/runtime-release-dryrun/Cargo.lock @@ -0,0 +1,353 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5840cd9093aabeabf7fd932754c435b7674520fc3ddc935c397837050f0f1e4b" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92289ffc6fb4a85d85c246ddb874c05a87a2e540fb6ad52f7ca07c8c1e1840b1" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "033f6b7a4acb1f358c742aaca805c939ee73b4c6209ae4318ec7aca81c42e646" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "console" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "indicatif" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "runtime-release-dryrun" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "indicatif", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" diff --git a/tools/ci-build/runtime-release-dryrun/Cargo.toml b/tools/ci-build/runtime-release-dryrun/Cargo.toml new file mode 100644 index 00000000000..cc4d5e35b5a --- /dev/null +++ b/tools/ci-build/runtime-release-dryrun/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "runtime-release-dryrun" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4", features = ["derive"] } +anyhow = "1.0.75" +indicatif = "0.17.7" diff --git a/tools/ci-build/runtime-release-dryrun/src/main.rs b/tools/ci-build/runtime-release-dryrun/src/main.rs new file mode 100644 index 00000000000..d10d77b9df7 --- /dev/null +++ b/tools/ci-build/runtime-release-dryrun/src/main.rs @@ -0,0 +1,182 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +// this tool is simple and works at what it does +// potential improvements: +// - support the release of rust-runtime crates +// - support patching the users system-wide ~/.cargo/config.toml + +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::time::Duration; + +use anyhow::{bail, Context, Result}; +use clap::Parser; +use indicatif::{ProgressBar, ProgressStyle}; + +#[derive(Parser, Debug)] +struct DryRunSdk { + /// Path to the aws-sdk-rust repo + #[clap(long)] + pub sdk_path: PathBuf, + + /// Tag of the aws-sdk-rust repo to dry-run against + #[clap(long)] + pub rust_sdk_tag: String, + + /// Path to the artifact produced by the release-dry run + #[clap(long)] + pub smithy_rs_release: PathBuf, +} + +#[derive(Parser, Debug)] +#[clap( + name = "runtime-release-dryrun", + about = "CLI tool to prepare the aws-sdk-rust to test the result of releasing a new set of runtime crates.", + version +)] +#[allow(clippy::enum_variant_names)] // Want the "use" prefix in the CLI subcommand names for clarity +enum Args { + /// Dry run a smithy-rs release against a rust SDK release + /// + /// You will need: + /// 1. An `aws-sdk-rust` repo with a clean working tree + /// 2. A directory containing the artifacts from a smithy-rs release dry run. This is an artifact + /// named `artifacts-generate-smithy-rs-release` from the GH action (e.g. https://github.com/smithy-lang/smithy-rs/actions/runs/7200898068) + /// 3. An `aws-sdk-rust` release tag you want to test against + /// + /// After running the tool, you might want to do something like `cargo test` in `s3`. Make sure + /// to run `cargo update` to pull in the new dependencies. Use `cargo tree` to confirm you're + /// actually consuming the new versions. + #[clap(verbatim_doc_comment)] + DryRunSdk(DryRunSdk), +} + +fn main() -> Result<()> { + let args = Args::parse(); + match args { + Args::DryRunSdk(args) => dry_run_sdk(args).map_err(|err| { + // workaround an indicatif (bug?) where one character is stripped from output on the error message + eprintln!(" "); + err + })?, + } + Ok(()) +} + +fn step(message: &'static str, step: impl FnOnce() -> Result) -> Result { + let spinner = ProgressBar::new_spinner() + .with_message(message) + .with_style(ProgressStyle::with_template("{spinner} {msg} {elapsed}").unwrap()); + spinner.enable_steady_tick(Duration::from_millis(100)); + let result = step(); + let check = match &result { + Ok(_) => "✅", + Err(_) => "❌", + }; + spinner.set_style(ProgressStyle::with_template("{msg} {elapsed}").unwrap()); + spinner.finish_with_message(format!("{check} {message}")); + result +} + +fn run(command: &mut Command) -> anyhow::Result<()> { + let status = command.output()?; + if !status.status.success() { + bail!( + "command `{:?}` failed:\n{}{}", + command, + String::from_utf8_lossy(&status.stdout), + String::from_utf8_lossy(&status.stderr) + ); + } + Ok(()) +} + +fn dry_run_sdk(args: DryRunSdk) -> Result<()> { + step("Checking out SDK tag", || { + run(Command::new("git") + .arg("checkout") + .arg(&args.rust_sdk_tag) + .current_dir(&args.sdk_path)) + .context("failed to checkout aws-sdk-rust revision")?; + Ok(()) + })?; + + // By default the SDK dependencies also include a path component. This prevents + // patching from working + step("Applying version-only dependencies", || { + run(Command::new("sdk-versioner") + .args([ + "use-version-dependencies", + "--versions-toml", + "versions.toml", + "sdk", + ]) + .current_dir(&args.sdk_path))?; + + run(Command::new("git") + .args(["checkout", "-B", "smithy-release-dryrun"]) + .current_dir(&args.sdk_path))?; + run(Command::new("git") + .args([ + "commit", + "-am", + "removing path dependencies to allow patching", + ]) + .current_dir(&args.sdk_path))?; + Ok(()) + })?; + + let patches = step("computing patches", || { + let path = Path::new(&args.smithy_rs_release).join("crates-to-publish"); + let crates_to_patch = std::fs::read_dir(&path) + .context(format!("could list crates in directory {:?}", path))? + .map(|dir| dir.unwrap().file_name()) + .map(|osstr| osstr.into_string().expect("invalid utf-8 directory")) + .collect::>(); + + let patch_sections = crates_to_patch + .iter() + .map(|crte| { + let path = Path::new(&args.smithy_rs_release) + .join("crates-to-publish") + .join(crte); + assert!( + path.exists(), + "tried to reference a crate that did not exist!" + ); + format!( + "{crte} = {{ path = '{}' }}", + path.canonicalize().unwrap().to_str().unwrap() + ) + }) + .collect::>() + .join("\n"); + Ok(format!("[patch.crates-io]\n{patch_sections}")) + })?; + + // Note: in the future we could also automatically apply this to the system wide ~/.cargo/config.toml + step("apply patches to workspace Cargo.toml", || { + let workspace_cargo_toml = Path::new(&args.sdk_path).join("Cargo.toml"); + if !workspace_cargo_toml.exists() { + bail!( + "Could not find the workspace Cargo.toml to patch {:?}", + workspace_cargo_toml + ); + } + let current_contents = std::fs::read_to_string(&workspace_cargo_toml) + .context("could not read workspace cargo.toml")?; + std::fs::write( + workspace_cargo_toml, + format!("{current_contents}\n{patches}"), + )?; + run(Command::new("git") + .args(["commit", "-am", "patching workspace Cargo.toml"]) + .current_dir(&args.sdk_path))?; + Ok(()) + })?; + println!("{:?} has been updated to build against patches. Use `cargo update` to recompute the dependencies.", &args.sdk_path); + Ok(()) +} diff --git a/tools/ci-build/runtime-versioner/Cargo.lock b/tools/ci-build/runtime-versioner/Cargo.lock new file mode 100644 index 00000000000..f73ff75a995 --- /dev/null +++ b/tools/ci-build/runtime-versioner/Cargo.lock @@ -0,0 +1,1635 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "crates-index" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1f3e3ef6d547bbf1213b3dabbf0b01a500fbd0924abf818b563a4bc2c85296c" +dependencies = [ + "hex", + "home", + "http", + "memchr", + "rustc-hash", + "semver", + "serde", + "serde_derive", + "serde_json", + "smol_str", + "thiserror", + "toml 0.8.8", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-core", + "futures-io", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "h2" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "js-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "openssl" +version = "0.10.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "proc-macro2" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "reqwest" +version = "0.11.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "runtime-versioner" +version = "0.1.0" +dependencies = [ + "anyhow", + "camino", + "clap", + "crates-index", + "reqwest", + "smithy-rs-tool-common", + "tempfile", + "test-common", + "toml 0.5.11", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + +[[package]] +name = "smithy-rs-tool-common" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "lazy_static", + "regex", + "reqwest", + "semver", + "serde", + "serde_json", + "thiserror", + "toml 0.5.11", + "tracing", +] + +[[package]] +name = "smol_str" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "test-common" +version = "0.1.0" +dependencies = [ + "camino", + "tempfile", + "test_bin", +] + +[[package]] +name = "test_bin" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7a7de15468c6e65dd7db81cf3822c1ec94c71b2a3c1a976ea8e4696c91115c" + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "pin-project-lite", + "socket2 0.5.5", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "indexmap 1.9.3", + "serde", +] + +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.1.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicode-bidi" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" + +[[package]] +name = "web-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] diff --git a/tools/ci-build/runtime-versioner/Cargo.toml b/tools/ci-build/runtime-versioner/Cargo.toml new file mode 100644 index 00000000000..15a356eb0b0 --- /dev/null +++ b/tools/ci-build/runtime-versioner/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "runtime-versioner" +version = "0.1.0" +authors = ["AWS Rust SDK Team "] +description = "Tool that manages runtime crate versions." +edition = "2021" +license = "Apache-2.0" +publish = false + +[workspace] + +[profile.release] +# prefer fast compile time over runtime performance +opt-level = 0 + +[dependencies] +anyhow = "1.0.75" +camino = "1.1.6" +clap = { version = "4.4.11", features = ["derive"] } +crates-index = "2.3.0" +reqwest = { version = "0.11.22", features = ["blocking"] } +smithy-rs-tool-common = { version = "0.1", path = "../smithy-rs-tool-common" } +tempfile = "3.9.0" +toml = { version = "0.5.8", features = ["preserve_order"] } +tracing = "0.1.40" +tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } + +[dev-dependencies] +test-common = { path = "./test-common" } diff --git a/tools/ci-build/runtime-versioner/src/audit.rs b/tools/ci-build/runtime-versioner/src/audit.rs new file mode 100644 index 00000000000..72396337237 --- /dev/null +++ b/tools/ci-build/runtime-versioner/src/audit.rs @@ -0,0 +1,259 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::{ + index::CratesIndex, + repo::Repo, + tag::{previous_release_tag, release_tags}, + util::utf8_path_buf, + Audit, +}; +use anyhow::{anyhow, bail, Context, Result}; +use camino::{Utf8Path, Utf8PathBuf}; +use smithy_rs_tool_common::{command::sync::CommandExt, release_tag::ReleaseTag}; +use std::{ + collections::{BTreeMap, BTreeSet}, + fs, + process::Command, +}; + +pub fn audit(args: Audit) -> Result<()> { + let repo = Repo::new(args.smithy_rs_path.as_deref())?; + if !args.no_fetch { + // Make sure we have the latest release tags + fetch_smithy_rs_tags(&repo)?; + } + + let release_tags = release_tags(&repo)?; + let previous_release_tag = + previous_release_tag(&repo, &release_tags, args.previous_release_tag.as_deref())?; + if release_tags.first() != Some(&previous_release_tag) { + tracing::warn!("there are newer releases since '{previous_release_tag}'"); + } + + let next_crates = discover_runtime_crates(&repo.root).context("next")?; + let previous_crates = resolve_previous_crates(&repo, previous_release_tag.as_str())?; + + let crates = augment_runtime_crates(previous_crates, next_crates, args.fake_crates_io_index)?; + let mut errors = Vec::new(); + for rt_crate in crates { + if let Err(err) = audit_crate(&repo, &previous_release_tag, rt_crate) { + errors.push(err); + } + } + if errors.is_empty() { + println!("SUCCESS"); + Ok(()) + } else { + for error in errors { + eprintln!("{error}"); + } + bail!("there are audit failures in the runtime crates") + } +} + +fn audit_crate(repo: &Repo, release_tag: &ReleaseTag, rt_crate: RuntimeCrate) -> Result<()> { + if rt_crate.changed_since_release(repo, release_tag)? { + // If this version has never been published before, then we're good. + // (This tool doesn't check semver compatibility.) + if !rt_crate.next_version_is_published() { + if let Some(previous_version) = rt_crate.previous_release_version { + tracing::info!( + "'{}' changed and was version bumped from {previous_version} to {}", + rt_crate.name, + rt_crate.next_release_version, + ); + } else { + tracing::info!( + "'{}' is a new crate (or wasn't independently versioned before) and will publish at {}", + rt_crate.name, + rt_crate.next_release_version, + ); + } + Ok(()) + } else if rt_crate.previous_release_version.as_ref() != Some(&rt_crate.next_release_version) + { + Err(anyhow!( + "{crate_name} was changed and version bumped, but the new version \ + number ({version}) has already been published to crates.io. Choose a new \ + version number.", + crate_name = rt_crate.name, + version = rt_crate.next_release_version, + )) + } else { + Err(anyhow!( + "{crate_name} changed since {release_tag} and requires a version bump", + crate_name = rt_crate.name + )) + } + } else { + // If it didn't change at all since last release, then we're good. + Ok(()) + } +} + +struct RuntimeCrate { + name: String, + path: Utf8PathBuf, + previous_release_version: Option, + next_release_version: String, + published_versions: Vec, +} + +impl RuntimeCrate { + /// True if the runtime crate's next version exists in crates.io + fn next_version_is_published(&self) -> bool { + self.published_versions + .iter() + .any(|version| self.next_release_version == *version) + } + + /// True if this runtime crate changed since the given release tag. + fn changed_since_release(&self, repo: &Repo, release_tag: &ReleaseTag) -> Result { + let status = repo + .git(["diff", "--quiet", release_tag.as_str(), self.path.as_str()]) + .status() + .with_context(|| format!("failed to git diff {}", self.name))?; + match status.code() { + Some(0) => Ok(false), + Some(1) => Ok(true), + code => bail!("unknown git diff result: {code:?}"), + } + } +} + +/// Loads version information from crates.io and attaches it to the passed in runtime crates. +fn augment_runtime_crates( + previous_crates: BTreeMap, + next_crates: BTreeMap, + fake_crates_io_index: Option, +) -> Result> { + let index = fake_crates_io_index + .map(CratesIndex::fake) + .map(Ok) + .unwrap_or_else(CratesIndex::real)?; + let all_keys: BTreeSet<_> = previous_crates.keys().chain(next_crates.keys()).collect(); + let mut result = Vec::new(); + for key in all_keys { + let previous_crate = previous_crates.get(key); + if let Some(next_crate) = next_crates.get(key) { + result.push(RuntimeCrate { + published_versions: index.published_versions(&next_crate.name)?, + name: next_crate.name.clone(), + previous_release_version: previous_crate.map(|c| c.version.clone()), + next_release_version: next_crate.version.clone(), + path: next_crate.path.clone(), + }); + } else { + tracing::warn!("runtime crate '{key}' was removed and will not be published"); + } + } + Ok(result) +} + +struct DiscoveredCrate { + name: String, + version: String, + path: Utf8PathBuf, +} + +/// Discovers runtime crates that are independently versioned. +/// For now, that just means the ones that don't have the special version number `0.0.0-smithy-rs-head`. +/// In the future, this can be simplified to just return all the runtime crates. +fn discover_runtime_crates(repo_root: &Utf8Path) -> Result> { + const ROOT_PATHS: &[&str] = &["rust-runtime", "aws/rust-runtime"]; + let mut result = BTreeMap::new(); + for &root in ROOT_PATHS { + let root = repo_root.join(root); + for entry in fs::read_dir(&root) + .context(root) + .context("failed to read dir")? + { + let entry = entry.context("failed to read dir entry")?; + if !entry.path().is_dir() { + continue; + } + let manifest_path = entry.path().join("Cargo.toml"); + if !manifest_path.exists() { + continue; + } + let manifest: toml::Value = + toml::from_slice(&fs::read(&manifest_path).context("failed to read manifest")?) + .context("failed to parse manifest")?; + let publish = manifest["package"] + .get("publish") + .and_then(|p| p.as_bool()) + .unwrap_or(true); + let version = manifest["package"]["version"] + .as_str() + .expect("version is a string"); + if publish && version != "0.0.0-smithy-rs-head" { + let name: String = entry.path().file_name().unwrap().to_string_lossy().into(); + result.insert( + name.clone(), + DiscoveredCrate { + name, + version: version.into(), + path: utf8_path_buf(entry.path()), + }, + ); + } + } + } + Ok(result) +} + +fn resolve_previous_crates( + repo: &Repo, + previous_release_tag: &str, +) -> Result> { + // We checkout to a temp path so that this can be run with a dirty working tree + // (for running in local development). + let tempdir = tempfile::tempdir()?; + let tempdir_path = Utf8Path::from_path(tempdir.path()).unwrap(); + let clone_path = tempdir_path.join("smithy-rs"); + fs::create_dir_all(&clone_path).context("failed to create temp smithy-rs repo")?; + + checkout_runtimes_to(repo, previous_release_tag, &clone_path) + .context("resolve previous crates")?; + discover_runtime_crates(&clone_path).context("resolve previous crates") +} + +/// Fetches the latest tags from smithy-rs origin. +fn fetch_smithy_rs_tags(repo: &Repo) -> Result<()> { + let output = repo + .git(["remote", "get-url", "origin"]) + .output() + .context("failed to verify origin git remote")?; + let origin_url = String::from_utf8(output.stdout) + .expect("valid utf-8") + .trim() + .to_string(); + if origin_url != "git@github.com:smithy-lang/smithy-rs.git" { + bail!("smithy-rs origin must be 'git@github.com:smithy-lang/smithy-rs.git' in order to get the latest release tags"); + } + + repo.git(["fetch", "--tags", "origin"]) + .expect_success_output("fetch tags")?; + Ok(()) +} + +fn checkout_runtimes_to(repo: &Repo, revision: &str, into: impl AsRef) -> Result<()> { + Command::new("git") + .arg("init") + .current_dir(into.as_ref()) + .expect_success_output("init")?; + let tmp_repo = Repo::new(Some(into.as_ref()))?; + tmp_repo + .git(["remote", "add", "origin", repo.root.as_str()]) + .expect_success_output("remote add origin")?; + tmp_repo + .git(["fetch", "origin", revision, "--depth", "1"]) + .expect_success_output("fetch revision")?; + tmp_repo + .git(["reset", "--hard", "FETCH_HEAD"]) + .expect_success_output("reset")?; + Ok(()) +} diff --git a/tools/ci-build/runtime-versioner/src/index.rs b/tools/ci-build/runtime-versioner/src/index.rs new file mode 100644 index 00000000000..41106ef7b7b --- /dev/null +++ b/tools/ci-build/runtime-versioner/src/index.rs @@ -0,0 +1,109 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use anyhow::{anyhow, Context, Error, Result}; +use camino::Utf8Path; +use crates_index::Crate; +use reqwest::StatusCode; +use smithy_rs_tool_common::retry::{run_with_retry_sync, ErrorClass}; +use std::fs; +use std::{collections::HashMap, time::Duration}; + +pub struct CratesIndex(Inner); + +enum Inner { + Fake(FakeIndex), + Real(crates_index::SparseIndex), +} + +impl CratesIndex { + /// Returns a real sparse crates.io index. + pub fn real() -> Result { + Ok(Self(Inner::Real( + crates_index::SparseIndex::new_cargo_default() + .context("failed to initialize the sparse crates.io index")?, + ))) + } + + /// Returns a fake crates.io index from file, panicking if loading fails. + pub fn fake(path: impl AsRef) -> Self { + Self(Inner::Fake(FakeIndex::from_file(path))) + } + + /// Retrieves the published versions for the given crate name. + pub fn published_versions(&self, crate_name: &str) -> Result> { + match &self.0 { + Inner::Fake(index) => Ok(index.crates.get(crate_name).cloned().unwrap_or_default()), + Inner::Real(index) => Ok(run_with_retry_sync( + "retrieve published versions", + 3, + Duration::from_secs(1), + || published_versions(index, crate_name), + |_err| ErrorClass::Retry, + )?), + } + } +} + +fn published_versions(index: &crates_index::SparseIndex, crate_name: &str) -> Result> { + let url = index + .crate_url(crate_name) + .expect("crate name is not empty string"); + let crate_meta: Option = reqwest::blocking::get(url) + .map_err(Error::from) + .and_then(|response| { + let status = response.status(); + response.bytes().map(|b| (status, b)).map_err(Error::from) + }) + .and_then(|(status, bytes)| match status { + status if status.is_success() => { + Crate::from_slice(&bytes).map_err(Error::from).map(Some) + } + StatusCode::NOT_FOUND => Ok(None), + status => { + let body = String::from_utf8_lossy(&bytes); + Err(anyhow!( + "request to crates.io index failed ({status}):\n{body}" + )) + } + }) + .with_context(|| format!("failed to retrieve crates.io metadata for {crate_name}"))?; + Ok(crate_meta + .map(|meta| { + meta.versions() + .iter() + .map(|v| v.version().to_string()) + .collect() + }) + .unwrap_or_default()) +} + +/// Fake crates.io index for testing +pub struct FakeIndex { + crates: HashMap>, +} + +impl FakeIndex { + fn from_file(path: impl AsRef) -> FakeIndex { + let bytes = fs::read(path.as_ref()).unwrap(); + let toml: toml::Value = toml::from_slice(&bytes).unwrap(); + let crates: HashMap> = toml["crates"] + .as_table() + .expect("missing crates table") + .into_iter() + .map(|(k, v)| { + ( + k.into(), + v.as_array() + .expect("value must be array") + .iter() + .map(|v| v.as_str().expect("must be string").to_string()) + .collect::>(), + ) + }) + .collect(); + FakeIndex { crates } + } +} diff --git a/tools/ci-build/runtime-versioner/src/main.rs b/tools/ci-build/runtime-versioner/src/main.rs new file mode 100644 index 00000000000..e09951f043f --- /dev/null +++ b/tools/ci-build/runtime-versioner/src/main.rs @@ -0,0 +1,82 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::{ + repo::Repo, + tag::{previous_release_tag, release_tags}, +}; +use anyhow::Result; +use camino::Utf8PathBuf; +use clap::Parser; +use tracing_subscriber::{filter::LevelFilter, EnvFilter}; + +mod audit; +mod index; +mod repo; +mod tag; +mod util; + +#[derive(clap::Args, Clone)] +pub struct Audit { + /// Don't `git fetch` before auditing. + #[arg(long)] + no_fetch: bool, + /// Explicitly state the previous release's tag. Discovers it if not provided. + #[arg(long)] + previous_release_tag: Option, + /// Path to smithy-rs. Defaults to current working directory. + #[arg(long)] + smithy_rs_path: Option, + /// (For testing) Path to a fake crates.io index. + #[arg(long)] + fake_crates_io_index: Option, +} + +#[derive(clap::Args, Clone)] +pub struct PreviousReleaseTag { + /// Path to smithy-rs. Defaults to current working directory. + #[arg(long)] + smithy_rs_path: Option, +} + +#[derive(clap::Parser, Clone)] +#[clap(author, version, about)] +enum Command { + /// Audit the runtime crate versions in the smithy-rs repo at HEAD + /// + /// Requires a full clone of smithy-rs. Will not work against shallow clones. + /// + /// This audits that any runtime crate that has been changed since the last + /// release has been version bumped. It's not smart enough to know if the version + /// bump is correct in semver terms, but verifies that there was at least a + /// bump. A human will still need to verify the semver correctness of that bump. + Audit(Audit), + + /// Outputs the previous release tag for the revision at HEAD. + PreviousReleaseTag(PreviousReleaseTag), +} + +fn main() -> Result<()> { + tracing_subscriber::fmt() + .with_writer(std::io::stderr) + .with_env_filter( + EnvFilter::builder() + .with_default_directive(LevelFilter::INFO.into()) + .from_env_lossy(), + ) + .init(); + + let command = Command::parse(); + match command { + Command::Audit(args) => audit::audit(args), + Command::PreviousReleaseTag(args) => { + let repo = Repo::new(args.smithy_rs_path.as_deref())?; + let tags = release_tags(&repo)?; + let tag = previous_release_tag(&repo, &tags, None)?; + println!("{tag}"); + Ok(()) + } + } +} diff --git a/tools/ci-build/runtime-versioner/src/repo.rs b/tools/ci-build/runtime-versioner/src/repo.rs new file mode 100644 index 00000000000..45290368a3d --- /dev/null +++ b/tools/ci-build/runtime-versioner/src/repo.rs @@ -0,0 +1,43 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::util::utf8_path_buf; +use anyhow::{Context, Result}; +use camino::{Utf8Path, Utf8PathBuf}; +use smithy_rs_tool_common::git::find_git_repository_root; +use std::{env, ffi::OsStr, process::Command}; + +/// Git repository +pub struct Repo { + pub root: Utf8PathBuf, +} + +impl Repo { + pub fn new(maybe_root: Option<&Utf8Path>) -> Result { + Ok(Self { + root: repo_root(maybe_root)?, + }) + } + + /// Returns a `std::process::Command` set to run git in this repo with the given args + pub fn git(&self, args: I) -> Command + where + I: IntoIterator, + S: AsRef, + { + let mut cmd = Command::new("git"); + cmd.current_dir(&self.root); + cmd.args(args); + cmd + } +} + +fn repo_root(hint: Option<&Utf8Path>) -> Result { + let cwd = utf8_path_buf(env::current_dir().context("failed to get current working directory")?); + Ok(utf8_path_buf(find_git_repository_root( + "smithy-rs", + hint.unwrap_or(&cwd), + )?)) +} diff --git a/tools/ci-build/runtime-versioner/src/tag.rs b/tools/ci-build/runtime-versioner/src/tag.rs new file mode 100644 index 00000000000..c9a88259102 --- /dev/null +++ b/tools/ci-build/runtime-versioner/src/tag.rs @@ -0,0 +1,121 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::repo::Repo; +use anyhow::{anyhow, bail, Context, Result}; +use smithy_rs_tool_common::{command::sync::CommandExt, release_tag::ReleaseTag}; +use std::str::FromStr; +use tracing::warn; + +/// Discovers and returns the tag of the previous release for the revision at HEAD. +pub fn previous_release_tag( + repo: &Repo, + release_tags: &[ReleaseTag], + release_tag_override: Option<&str>, +) -> Result { + let ancestor_tag = ancestor_tag(repo)?; + let tag_override = release_tag_override + .map(ReleaseTag::from_str) + .transpose() + .context("invalid release tag given")?; + if let Some(tag_override) = tag_override { + if !release_tags.contains(&tag_override) { + bail!("specified tag '{tag_override}' doesn't exist"); + } + if !tag_is_ancestor(repo, &tag_override)? { + bail!("specified tag '{tag_override}' is not an ancestor to HEAD"); + } + if tag_override != ancestor_tag { + warn!( + "expected previous release to be '{ancestor_tag}', \ + but '{tag_override}' was specified. Proceeding with '{tag_override}'.", + ); + } + Ok(tag_override) + } else { + Ok(ancestor_tag) + } +} + +fn ancestor_tag(repo: &Repo) -> Result { + let tag = repo + .git(["describe", "--tags"]) + .expect_success_output("find the current ancestor release tag")?; + let tag = tag.trim(); + let maybe_release_tag = ReleaseTag::from_str(tag); + let release_tag = match maybe_release_tag { + Ok(tag) => Some(tag), + Err(_) => strip_describe_tags_suffix(tag) + .map(ReleaseTag::from_str) + .transpose() + .context("failed to find ancestor release tag")?, + }; + release_tag.ok_or_else(|| anyhow!("failed to find ancestor release tag")) +} + +// `git describe --tags` appends a suffix if the current commit is not the tagged commit +// +// Function assumes the given tag is known to be suffixed. +fn strip_describe_tags_suffix(tag: &str) -> Option<&str> { + // Example release tag with suffix: release-2023-12-01-42-g885048e40 + tag.rsplitn(3, '-').nth(2) +} + +/// Returns all release tags for the repo in descending order by time. +pub fn release_tags(repo: &Repo) -> Result> { + let mut tags: Vec<_> = repo + .git(["tag"]) + .expect_success_output("find the current ancestor release tag")? + .lines() + .flat_map(|tag| match ReleaseTag::from_str(tag) { + Ok(tag) => Some(tag), + Err(_) => { + if !tag.starts_with("v0.") { + warn!("ignoring tag '{tag}': doesn't look like a release tag"); + } + None + } + }) + .collect(); + tags.sort_by(|a, b| b.cmp(a)); + Ok(tags) +} + +/// True if the given tag is an ancestor to HEAD. +fn tag_is_ancestor(repo: &Repo, tag: &ReleaseTag) -> Result { + let commit = commit_for_tag(repo, tag)?; + let status = repo + .git(["merge-base", "--is-ancestor", &commit, "HEAD"]) + .expect_status_one_of("determine if a tag is the ancestor to HEAD", [0, 1])?; + Ok(status == 0) +} + +/// Returns the commit hash for the given tag +fn commit_for_tag(repo: &Repo, tag: &ReleaseTag) -> Result { + repo.git(["rev-list", "-n1", tag.as_str()]) + .expect_success_output("retrieve commit hash for tag") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn strip_git_describe_tags_suffix() { + assert_eq!( + Some("release-2023-12-01"), + strip_describe_tags_suffix("release-2023-12-01-42-g885048e40") + ); + assert_eq!( + Some("release-2023-12-01"), + strip_describe_tags_suffix("release-2023-12-01-2-g885048e40") + ); + assert_eq!( + Some("release-2023-12-01"), + strip_describe_tags_suffix("release-2023-12-01-123-g885048e40") + ); + assert_eq!(None, strip_describe_tags_suffix("invalid")); + } +} diff --git a/tools/ci-build/runtime-versioner/src/util.rs b/tools/ci-build/runtime-versioner/src/util.rs new file mode 100644 index 00000000000..61426ab9e37 --- /dev/null +++ b/tools/ci-build/runtime-versioner/src/util.rs @@ -0,0 +1,16 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use anyhow::Context; +use camino::{Utf8Path, Utf8PathBuf}; +use std::path::Path; + +pub fn utf8_path_buf(path: impl AsRef) -> Utf8PathBuf { + let path: &Path = path.as_ref(); + <&Utf8Path>::try_from(path) + .with_context(|| format!("gross path_buf: {:?}", path)) + .unwrap() + .into() +} diff --git a/tools/ci-build/runtime-versioner/test-common/Cargo.toml b/tools/ci-build/runtime-versioner/test-common/Cargo.toml new file mode 100644 index 00000000000..e23fab820ed --- /dev/null +++ b/tools/ci-build/runtime-versioner/test-common/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "test-common" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +camino = "1.1.6" +tempfile = "3.8.1" +test_bin = "0.4.0" diff --git a/tools/ci-build/runtime-versioner/test-common/src/lib.rs b/tools/ci-build/runtime-versioner/test-common/src/lib.rs new file mode 100644 index 00000000000..7f151cb88db --- /dev/null +++ b/tools/ci-build/runtime-versioner/test-common/src/lib.rs @@ -0,0 +1,100 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use camino::{Utf8Path, Utf8PathBuf}; +use std::process::Command; +use tempfile::TempDir; + +#[derive(Debug)] +pub struct VersionerOutput { + pub status: i32, + pub stdout: String, + pub stderr: String, +} + +pub struct TestBase { + _tmp: TempDir, + pub test_data: Utf8PathBuf, + pub root: Utf8PathBuf, +} + +impl TestBase { + pub fn new(branch_name: &str) -> Self { + let tmp = TempDir::new().unwrap(); + let root = Utf8PathBuf::try_from(tmp.path().join("test_base")).unwrap(); + + let test_data = + Utf8PathBuf::try_from(std::env::current_dir().unwrap().join("test_data")).unwrap(); + let tar_path = test_data.join("test_base.git.tar.gz"); + assert!( + Command::new("tar") + .args(["xfz", tar_path.as_str()]) + .current_dir(tmp.path()) + .status() + .unwrap() + .success(), + "untarring the test_base into the temp directory failed" + ); + assert!( + Command::new("git") + .args(["clone", "test_base.git"]) + .current_dir(tmp.path()) + .status() + .unwrap() + .success(), + "cloning the test_base repo failed" + ); + assert!(root.exists(), "test_base not found after cloning"); + change_branch(&root, branch_name); + + Self { + _tmp: tmp, + test_data, + root, + } + } + + pub fn change_branch(&self, branch_name: &str) { + change_branch(&self.root, branch_name); + } + + pub fn run_versioner(&self, args: &[&str], expect_failure: bool) -> VersionerOutput { + let mut cmd = test_bin::get_test_bin("runtime-versioner"); + let cmd = cmd.args(args).current_dir(&self.root); + let output = cmd.output().expect("failed to execute runtime-versioner"); + let status = output.status.code().unwrap(); + let stdout = String::from_utf8_lossy(&output.stdout); + let stderr = String::from_utf8_lossy(&output.stderr); + println!("###\ncmd: {cmd:?}\nstatus: {status}\nstdout:\n{stdout}\nstderr:\n{stderr}\n\n"); + if expect_failure { + assert!( + !output.status.success(), + "expected runtime-versioner to fail, but it succeeded" + ); + } else { + assert!( + output.status.success(), + "expected runtime-versioner to succeed, but it failed" + ); + } + VersionerOutput { + status, + stdout: stdout.into(), + stderr: stderr.into(), + } + } +} + +fn change_branch(path: &Utf8Path, branch_name: &str) { + assert!( + Command::new("git") + .args(["checkout", branch_name]) + .current_dir(path) + .status() + .unwrap() + .success(), + "changing to the correct test_base branch failed" + ); +} diff --git a/tools/ci-build/runtime-versioner/test_data/.gitignore b/tools/ci-build/runtime-versioner/test_data/.gitignore new file mode 100644 index 00000000000..61f335ae79d --- /dev/null +++ b/tools/ci-build/runtime-versioner/test_data/.gitignore @@ -0,0 +1,2 @@ +/test_base.git/ +/test_base/ \ No newline at end of file diff --git a/tools/ci-build/runtime-versioner/test_data/Makefile b/tools/ci-build/runtime-versioner/test_data/Makefile new file mode 100644 index 00000000000..5419b47efd4 --- /dev/null +++ b/tools/ci-build/runtime-versioner/test_data/Makefile @@ -0,0 +1,22 @@ +all: + echo "Use the pack/unpack targets." + +# Unpacks test_base.git.tar.gz +# +# Note: doesn't directly clone the bare repository into a working tree, +# or otherwise it would lose all the different branches. +unpack: + rm -rf test_base + mkdir -p test_base + tar xfz test_base.git.tar.gz + mv test_base.git test_base/.git + (cd test_base && git config --unset core.bare) + (cd test_base && git reset --hard) + +# Packs test_base.git.tar.gz +pack: + git clone --bare test_base + tar cfz test_base.git.tar.gz test_base.git + rm -rf test_base.git + +.PHONY: all \ No newline at end of file diff --git a/tools/ci-build/runtime-versioner/test_data/README.md b/tools/ci-build/runtime-versioner/test_data/README.md new file mode 100644 index 00000000000..b156de76cbc --- /dev/null +++ b/tools/ci-build/runtime-versioner/test_data/README.md @@ -0,0 +1,14 @@ +Test base archive +================= + +The `test_base.git.tar.gz` is an archived test git repository that looks like a +smithy-rs repo (with only the runtime crates), with some version numbers and +release tags. + +It is a bare git repository (no working tree). To modify it, use the Makefile in +this directory to unpack it with `make unpack`. This will create a test_base directory +in test_data where you can make any changes you need to the repo. Then running +`make pack` will convert that modified repository back into the archive. + +When making new test cases that need some extensive setup, it's best to create +a test-case specific branch in the test base. \ No newline at end of file diff --git a/tools/ci-build/runtime-versioner/test_data/already_published_version.toml b/tools/ci-build/runtime-versioner/test_data/already_published_version.toml new file mode 100644 index 00000000000..0d65a32f30c --- /dev/null +++ b/tools/ci-build/runtime-versioner/test_data/already_published_version.toml @@ -0,0 +1,28 @@ +[crates] +aws-config = ["1.0.0"] +aws-endpoint = ["0.60.0"] +aws-http = ["0.60.0"] +aws-hyper = ["0.60.0"] +aws-runtime = ["1.0.0"] +aws-runtime-api = ["1.0.0"] +aws-sig-auth = ["0.60.0"] +aws-sigv4 = ["1.0.0"] +aws-smithy-async = ["1.0.1"] # Oh no, aws-smithy-async already has 1.0.1 published! +aws-smithy-checksums = ["0.60.0"] +aws-smithy-client = ["0.60.0"] +aws-smithy-eventstream = ["0.60.0"] +aws-smithy-http = ["0.60.0"] +aws-smithy-http-auth = ["0.60.0"] +aws-smithy-http-server = ["0.60.0"] +aws-smithy-http-server-python = ["0.60.0"] +aws-smithy-http-server-typescript = ["0.60.0"] +aws-smithy-http-tower = ["0.60.0"] +aws-smithy-json = ["0.60.0"] +aws-smithy-protocol-test = ["0.60.0"] +aws-smithy-query = ["0.60.0"] +aws-smithy-runtime = ["1.0.0"] +aws-smithy-runtime-api = ["1.0.0"] +aws-smithy-types = ["1.0.0"] +aws-smithy-types-convert = ["0.60.0"] +aws-smithy-xml = ["0.60.0"] +aws-types = ["1.0.0"] diff --git a/tools/ci-build/runtime-versioner/test_data/base_crates_io_index.toml b/tools/ci-build/runtime-versioner/test_data/base_crates_io_index.toml new file mode 100644 index 00000000000..70de8ec50da --- /dev/null +++ b/tools/ci-build/runtime-versioner/test_data/base_crates_io_index.toml @@ -0,0 +1,28 @@ +[crates] +aws-config = ["1.0.0"] +aws-endpoint = ["0.60.0"] +aws-http = ["0.60.0"] +aws-hyper = ["0.60.0"] +aws-runtime = ["1.0.0"] +aws-runtime-api = ["1.0.0"] +aws-sig-auth = ["0.60.0"] +aws-sigv4 = ["1.0.0"] +aws-smithy-async = ["1.0.0"] +aws-smithy-checksums = ["0.60.0"] +aws-smithy-client = ["0.60.0"] +aws-smithy-eventstream = ["0.60.0"] +aws-smithy-http = ["0.60.0"] +aws-smithy-http-auth = ["0.60.0"] +aws-smithy-http-server = ["0.60.0"] +aws-smithy-http-server-python = ["0.60.0"] +aws-smithy-http-server-typescript = ["0.60.0"] +aws-smithy-http-tower = ["0.60.0"] +aws-smithy-json = ["0.60.0"] +aws-smithy-protocol-test = ["0.60.0"] +aws-smithy-query = ["0.60.0"] +aws-smithy-runtime = ["1.0.0"] +aws-smithy-runtime-api = ["1.0.0"] +aws-smithy-types = ["1.0.0"] +aws-smithy-types-convert = ["0.60.0"] +aws-smithy-xml = ["0.60.0"] +aws-types = ["1.0.0"] diff --git a/tools/ci-build/runtime-versioner/test_data/test_base.git.tar.gz b/tools/ci-build/runtime-versioner/test_data/test_base.git.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..539485e65d1b9d318e787bedac0387791e4aa742 GIT binary patch literal 49188 zcmY&fV|blWvpunG+ji2}Y-2RGZJ*e-ZKr8$n+@8=jcq6A+Px zt)`G()2m)>Xuqr8rU$$L=ZPOo3$=0xi(Q|^-G=<0Ik&~F0F|Qkl=U-P^h$}Jt z3yw)i1-JeX3EQxK9`@aNI_QrYKUm)fnxy4DJDnX}ydAwgXTKl8cXS?zCYq&!!`1G? zmY|@(Tur6$`XMJ5Dgwcu#- zo5`@i>IH2h)XH4)3g2vhcfAFsX%T%?)`Nl6;8EgF+i9P+C(z&b0^YGc&<^@hz~Gn9 zlP~(DU+Hy{kU_>|qKjaC*1}9bFj~x4FrJLd0QnroSTlb*#}w2rj4(ocXoXbW{DG1_ z{GYy5&yf^KiZ8^h%GBucWta>Uhj$j3K|Bp&aY*I*ohpn;jOGLWEnBMp5T(N+qDtFR z!}91dV@4?xq-b$4)T&hwlID^pU7A%WH0WLW#HI#e6arDUDMUJxlL@Z2o)gTo@BLfS)cLu^PNzBP~PL9kZRk1j4>ab#3z*~zq zF=^rGK@%* zSrOYH<%W2OzZp1YQSN*@9A9{D*xsHIK%FHU&qpp0Fu%|Hhv-q`e{-fsI7FH9vlFvB zp~#F-rI{sRvoBpi1&G|zOOVFriBNkO+d5F=O5!7XQ}3ecz5=LFbfSJh$05K+*NjNf z(p0RV<2NL7kD?Qn5`_c{$?4L(A_ph|f;bTQOjSDuyU++lB4A_}sURydbRlFA0%Znx zbWv)_iq{~~0n#$55X0#*5{cEwu&D}I(Yu7mYbW=*`Gzpe)P&R(YNqIr104|G=8cz6 zjpqS~f7(3?83F3`t7E}0!8K`K%unQtLK};Wu%QZs`W3WtbcA8Mu=X@l4l>;<0Q!pX zUs;#P3!G9=g+Ue)Bopup40Uiy*2v>sRg^r&ZWWr0-;J|Z7*RqXm~?jswUOxJeN}_A z^=N}8ona~Kz)HEq0OKyh-E7qb}J~sp3GRk)Wcr=&0PK;Zc4*Y zXQLKpc?J+2a_rD?D{Da{g!M z^p<3+VMyS4E&lEj7h2BqMU`B^8}@Co#9`7!w#;OWeJ$6(TQYR0-{>Wg;pE^>{otTX zSrC#p?~4&WP38O3;wk2R%>+HwA*I)-H*vxQ3dks=6-uaR)W50C8@XXIMGZ9yr6OD- z%hIKo&!$Pl_wp|q6I_DAj$uyvj4=fSgsuY8-o5w|6G)TtmcPmwkjIyXFA+-sIMLuOidd0JtJ10P z%$ik5Qs<19vAmIAP08;W$@TvQc|vl<&`wZ@yPQpw5>4E9$dJMuBJZZOXd1KX3d@Wf z$06wGV;579rQQ6yslELo}SP@zOB{q9hfxl<}2psh05$ zgVi^UzoaVFb4mpV4g^g?k;6XBAU#e6?Mx>0CJn&8W~B8dpsKvy;u|AyBl~fauvM(| z{YoA;N4JF%2d@&TB~nnxRKP&uyjHX0mn{*&>np^#vMaM2LndJtLG$Ydee0FC`iZP7 zj_)Es%w#{QQiG3-T{q?~CCo046|n-){b|hSV)5J0mvcu{^il%JvN-aVc$pTtgZQ*O z0bt?+ErGbuW}BlD4BIwl@J#|@_9x-9Aa{(ZGgJ^7GCC0Irz+&Sq<#v{;1e!#*#W|m z3Z*z?Ue!tz8}g3VPvao_1=HqN-NS4}Sq?$S435F#B&w2{?+kPcsr|vHP%lvRQL)4p zNU%Cd@aeQ6?+T_!NsLG;As9`tq>ZafjcIsI!ZB8%zHFM z;t6v=_5x$ocyyr?ywHdkA6{(OgQzBq=Fq~~N3;Q)pc)8!*nLcPC-QimS(2uLtr|YL z9TtFZ+JM*q=1a1P-yC9^3frPq@3MY5`0*OY~J~4)tJ+uzoHoX-M87! zF%@-|@Bi8u^3d8NuP0-gxK~i0b{h3M++q%;?!K69nn!cvhDpA@l_p^kSNhVChG-u$9*hR1@z>)nNEAKVr-~=KmnAIJCO^QvM#~rdhN&wr z^*Z7;kQ6W}SavfO8pd&ySPRM}Txw{W*^*GIQq*PizF%TzU}uf5kGMnxjO~1x=zDxT zcg|EnRg7s#Gx=)3!CU8a1<9SM?G|^2*iT~uYaBpm@Vl4Wp3l~MgZ&;$#R#96s+iW4 z9gk~5pFOzw@>CA84UL9E@OI(-HhdPz&4XqakmGC4JWH^|*}FN+u5Kl`jQ^%-oVkCs*=fl?v`es47O)1dCe5zMJWyMQ3Yo zErg)C0$VJ5{hJaKR=;;&TduVYbDzG15JRdZpwc$o><{>_%st5X+J%r`wkymw}M4;=boIj>KMW{C+t#NC;?J;BL7b6vF?_bBwyI z4X6t;C>6xaP*JmmPdQa3Zcm?6PyPm5PnrPPM(5nC3scToL?e{L4nV@-PMGGR6xgAo zI`IxV3$e$B2H41^Cp>a4gi5~ob_np2yP(7g;pjr6P(8z8I0RcCg67~m=Pe_&v3N?xjq^?ysQXIofg-;psiN-kRb*cZd~_&inDn%2>b?Qnks4>7 zYPHg0*wG0l3R>Y?s~|Fh1n0`Dv+e9IX2>zbqY_SlU)EwgcQXWaPTl5$TGAu+eOnRF zvh^Oor`y?p!^_L-IA&7XM#Z$mB23AghG`N43i}a&jE#`V%m*H1fi@KlT`W^)nAtbu zK@>)vB;(1bMNlELrnIe;V8PK*c9k>@BdgEOS-uWxZr0xjM;^=@1|T6%!Y<(U5*48$ zs+u)rL#Lr~$nvgW=*mgsuOgC5B6TK?M12p@VWEZuL`tyHC(#FmCif0H?|xWoE`}Vo z70mPm1K@`95zmpng_s*7zYIg}U_zL}WxyP3=kH`pKZ@7inbS);5M{v+E_)nj2lYIz3I*q$fbt8qbi4%v0SSC*3xv94K(P9*J9Z@G z-}ZJmho8*2XO%$g#Zp}Rsijiz>>a^s2%7T(CTNoV%Acv(O?bL8VMYC!4sKxvs8id+ z^G6GqvBab-edf!_EmcU&Q|)ViK2H9}dIe|!!Ga`z<^wytj-mwN+JW}B@&KE%jQ&aH z9nxS;K~o6*7F$t*3@|EC2BSDhyi zTJHN-JGJFRv=BrZF~>jf@+kPzD%e<^Wvn)mZz|U_sDLK{atJYG`>zIhproVs!hp6EiW%EiT~&{;TROr-BoTMAt2K z;a8pbZ#a&Pg8~RKLx=NLbv!t575EMc$_TG6L-Ai#HBj>%J|cAtK42!3Vw}p zSoD?8k!PoyqvP9TvzT)P=k^FwLeZmxzEcyE!|Pp_$jk6Q2T@$pV@~rp-@Y@Og(O_3 z*tFXIjDUS2PB+*^|AMvOh6y!NLUl4~tby*^D;OF@w~yc6iG{X$w`hkl@B<2#tj9kN zVy48d%J`^ET#X=cr3U*YelztkwiL>|N$OS>*qIm{~()lkHFi5cdQIHnmk?BO53*+(=mcK|fpHHleKI|}#w zz*pvI9osX=N1kP^h!RaGn-~CtTtjEhR{L&@PLVRbC8r|Z7lj~k4!RA5R8E{gNmm?a>hUu>)z#7~M8+8xM{S&S3y zP|1}LmKqs|NHfDPP$gb84QlGdN@lq*kA+e~BLakF1W%UxKXkx*5z9cE$$1bIapO0! zw{uY}sK=IPQ4XWDY0#caSlb;~f&oYgLJDQ&MOnZDgoJy_86eLRXd$EHYl$nYj^DwI zx#5_Z6YUX$zR>j>KvgNn+%1+1G;7EtWVYL0Rt4F!Wusa&rNKk=AnVsV zUfCh+DX4DvHayaS-U{u+-M;|Ja=|8(=Yo5pBsNar zvzyK2oN;A30 zZ5)e$uVEsC%z!LxXMSocreQ40L|49Pq#1>%efuk9-^j?n3D~q7?6MuV82d9+3p2YE zUW(pD=hwi`>L0 z5R+8NCXFf>_*_zE>?iK~DEzKk83K=~Gg?QHS{4SJu%FM2)$=) z3+T1&4i@Ddb*826aa?rOFrhP{@vsvpWtnV|Sre*?5$)6TN_eA=DF-?(kf;UjvKXS8 zYH%;34R*@XR2}hK1cZWRN0iqrl07yDMV0s&2PPR&rix|SuGtCFF==0e%dD>PPhDKy zd%5?ICv;%pkcD`QGMtOJ$p;{UDF#=Y=;g4{@1QK%P~UNcVD5L1VKL-ID1fxxw`G~L zaTL%IV~5HBSP=>2t2QXeqDxbd%SxJB#e3pMd0%IU&A?cm z!4U;!Nc+%1b`V*EWotTFK`X>jW?F6?u;EUI|f%CjvuIW^7@)1&WQd zA`XJjGDR>IB5z*q!+En@Ru91mC@eTq`{z?lk=#&pUm=~P*Ucq%g9Ug?4jfh&|+?~ zb83kn52}!mqZctd3kX?=-$1Ddcc?eGJ8{>xhHpQ*k;SwX~ z0GVU69R{`_GZ6&XW#i?&G`3i5boLl5%-{#L;wJV179|A*h$V;%{ae;bqA{1@jt2Zi zJhQ3nvV|$DMT$L+J5{wRsJHj7%XL0%71+)((wCh@7G!xLZr2p^o+iuLtj9o-0E`(G zwM5CAv{>2ArV$~Mp(X}G1X3M(ELLu=85H3*UA6mET$zM0&R|Q4R{EE5WTa3N?HwS! z>nWTB&UZF$u3~Xej=r?!CPlxx>k6gFB+djA`y?SYnx1X4N7Z-iwsvr8Ni8lr+v`z}x+G*|Ta)k%#$A~XbQF4jx1b z*RQ*y-YV{aTb0Gb=170TMcV@&E3^CNS)erc)2{1yb zz~pw&*Wdzb)jH*DgINw#Oic}s+C<|C4*S%xf44l=E6r)mms?>mZJ{@&>>VknqNQV_ z71Xe&p`#^G@<a7g*N3lm-a z7KBB(N%n!`1#fh)29DpLx4W~obzyjc9bZtD*;SNGTS=B}t3m<7zkO0T*Ndbts%!R( zv5~tXIGhpaNfBYxYwpLOX)84Lk|#<+F!F;y*t%+8b;Y)@L5*XeTkxgJx?r9KODg4wKz8&hS=Jqd$lqDKE#;PnzN-rG) z%v4!DosM3PM!3=-gvzeLqxVWeU);8ZC<_biV^2^s?dF?pNCVFnwT{)UKa>TEV?Ma> z#DJdQLaGTjaN&IGCYUYlw)RMLBCUuL+nu(FWVysYY2hSBzrmdg8>KMl(jM#huYbbd zGB#{!jij6j0;Z}j2cssx$E7Lw_cs}Fu*|CCVcJ`?t!-w9 zput=ihP}5MFk)gPr-qa@VV5*1UR4W_gX>Yt>5R0m{XS=oJUF;{91Bv>@L`fzjnuR~ zK`?s0DTv6d8h5yz(EShKNbv&J^)?x_L0a z5XW=M*}L*cdp;OP;YIUBd2vK^29Rnrmq|=uG~=Uf9p$*p5`amG<0@lCQ8AeGbs^tt zdEyVCjfb{(A7NZf5+xqs)fwgf<3hg}!4Vnm?0~$~ z^kEEG7UOzDl#N20v#vsh!Nu9AlCF0$(<< zNaC>^Aum|9;DCUgCw}pl;+n5fSxa0nfYtpwWGjGB#(@%Mdpok(8=I@&3#YLX^m z?R~d8zSJ}l>sDY>hn5|pF%P9SeCKH{?<`&~>TjpN_AjTv`oRgx59;t{FcfSM`#fkq z16=Psb#)3PrgD?glU}B}V*E=uWOsy`HH1wy4Dho?X15-?UjMrw5uk#SGaNT5%M4Wv zx7oClt6-m-3N%8z1s5^70FQBh&p#Wbjf0_h0lc8kS4h?e4xgw>Y5)>U5+_{;ss`^4 zn45+J14(9bSZ)!nTBS~weECd>7%II+uIRH)TH1|lsNfwH1)0d8Z2r7beDtLq!7>)MP7#OXSaEzF$g#bQQ zP1&m{6XID>93?d+9cEWm1^2}V7A9_vI$S56kT{J9#^=~L?kje7P_p}`iWqY>FW4q# zAwg?S$(HoG&pJ(kRGP+sQz}{BQUy}MJ4=EN3FTyC_sC;1Hs>1e3y@mhnR5tZ{8+m! z`9ns0yW-Ce&iV9XyP=hRjSrsvblBrB@3$A@f$5S?<)QtX!o^^{lQMKhyi z@!^+DsQagn!*@i*imBD(rQUK$Iraog z>aOA@;TX1TfdtjTs$H^wMzHCTKdQ>#<`n~9!Dw9|m6vD`o|{1D9nkIBH21@Z{y_Tz zNYK@7va~}u05CV@6-t?sh)$q1HrCtv5GBa~z77sYd?1Bl6bxB`PD+tDg*{{sjs~DWS1T`&1PiH`KQIP(WQiO| zIM?098rNe6>1+MFUd4D84o3WuR;;d8+nn@+XaF=Rry`84TL5MUt&lG`jD!`UK}PnL zE(a7j-QmbAwMh!_2RrOKt}sBtJ(-E-2v#!$db}Q<#{eA>u)}DBXUJa_B`Gv@HWK&QV7IEZZ$w|QsIkImkFM} zJU*5jRj!gm=(hrTFeVn#-AJ9QEmy#z?|}QqDr~Djotz^NvKM1qlzmjE4vhlEFR>J# zoaDi*AXSo*Ir8_scn(?ApKnDEvU70$RGns$$ctp zLU4=6(R^pu8RFrn_=5t_O%hm`#IT97OOL~ z0}@seNJ(Ykv|n?K#m!rYA!y{%0qTX==+OV(^2|;0|B+$9`IO?%tcw-gtL?*mC)5R8 zUS3|4Wmzu}z!IsfQqTB&JJc90esu%4>!C2NV1IqJ@IbCiT6t*;v45c@t6Q6IhC{Z|@g60Q_zU#G26rkd3BOG+F{Bp6 zW?*C&x*QGhPMF02fR+3^)q{P$2;wXKjhwZDp7Hl9Tot*BhpyyfinaI>OxMx6%%Pc7 zQ3H4*UAL5}H$KbvVO7eA2+5gv?K9OJA5pKZ7Jd19>ztt+vrf$8gTHynRWQGtD{}dB zTi{a(jyCTGbpV88PIZIIs?vSb)O7LcW1&7U)}!XTGGdHM;~SI&n$Hj*e`_YFb_H+H zm5N-V2${mPaJ0~uW3S^2<@n5>9j=Y-7?xEnSw=5>6N%ZkKi{z2W?>$TzIGu97&`rh zh`HSCs6uw1<2^fK(I*fH!#atkfExHpn5FwI^d9RzBbzHutlZ4x%kf|sk86yZtNY>L zftr7P_5B!FSOis%p<~|xN81#3=9WJ#)V01&CPw{_h2iM%4Kg z5E+h&p%S6{oFQNJYcbknD-|c57Pps0DkEr4xt>Jg8V3E?5$y-Ovw)AYoq(XkQ}9GV z@v{abLRB&rE37uXdhyjZrP}2A!C|aK6OT}pSffJ=^0u{)a&GdM$sg2VC5aU(T6Fif zaK~yzSA*i47m}+E(h}_b_)reyGo5al8WINHDiWS&jU4#Fe`(gn{sEk+jQYZJ=YbPS z=ZH$0VzzY8=;ez+PDs-(_vSdUaLO}58Dh=t`@Y{Dj!!z5x;bpy%4{E~GnFgK69y13 z3ul(U$@Z%^Hd6(6Bp2X%XGwi4=!$eKo9hZHP^DX-Q<6!ajM z+Szfh+C&|kcS86#lI!$)ze#y3?Kyhbm~XB(rTv91cjx<(E z4f$}PB4;}#%k}iwn~Z9dSHX1EJJs(@)E1o!%&=6)CShr~H2sk;qZ7z)6H;wM4O)e8 z;D$?N@3lXpJV!|T#JT&vdivyFj>AKxo?s{_a*XOy_tN=ZmhdjV@f^h@pH#;Ya=24v zdFi0t{l#C59kvbxPcG>uQ%Z+fx=O#~*5h)|$5QJJYx6HTt#WK51*?}ee31YXbXE@H zFmn@RAefCNeIHC-L!E=Ks|oQBMaM7;Nq(q`Phr=cq=cV5=MJkLfoF7pzE9!TS^6jb zv&&?;HYMIg_lI`c7rojUFXm%i7%?avd>miRqU69*grJa1Q^1ZfwQ<7)nixaiX&3D) z%3{LkW;81Q?sU>|9^F0yTfCVqp@4H-5JQnZcfS-y4E=O*clt~U#u$HyM8k@ofLsJs zHev5FeqT;j`AUll2t9~4Yl=vQv{t?vc`v90zNxezdx&i;!A>>L}zc;dc;b{z-0C41ij(!Nv1sU zRpzzTM4)#fLxa+BSuKa@J6rpMo%0MTLesw}1$XG`He+7I&tTU}w4B-LohYU%;?Lri zYio;)!=sDu*#)@$(a_mRH>-EpU=;9Y)0o)3+u>m%Qm=$cUGayi=%IYJ+mbzW_|iqY z*m}${s)KcSvdqP}vyG>aasAV2{EtvQU^11aD?=y5ee+#eN_yy&{@QI!q~zr&^$eOm z@KnQ_K?v)FUdq&m)7T(s)Y2A>yJTs^Qo7O}Fjh1|>}DC-#l%gC2kFv~ph9?UVE~k% zAGX-V=vmllu`!iqpze_15ic{+-I#8kK?xPOR^hp_6>w(fA6x@n*=ghU-Gsu{~%u08+_pCw@u|db)CXz zNx8KC?y!~#EZ*M$59;CAQ<84JytxGwp##MSZ~FaJ8=j3CvZ&fN!7OPKhMwv~Gn^^@ z-?-hmHXbTJXf&X9`< zKCQu0gIiXb4SAdNV_U!}P7RtdFQE6pl#|X&;?acltL*myjs~%J)2|znt={;tsu zuIYL2%8ZCmdW>e^PYD<<8103I4jdb{0H%5mHKT8OCp!Ya->_lgae!bTn^C~ws<-2! zk@U8pqrcZi^yPqeq}Uwr3-3Fg!Xz2^N6A=!(s=7`Kf40xS=%|55d5hK;imzPasAaF?n_%r47 zWoiIWtS)H%9UQLl*_-E4j`z=k_2|pR-jU2DFk~6_C&D|z&=ES+L5@#I zam@Ge-^pHR*cSPD)xvghpF2@q=kWdDoV9W-3HM>a;Q%cS@(HNchlw|3;R;bWt$EF_ zFA?G!vnPxtQEZ+r$U0Z;p&+pKW|&))M3Oy?el0T-_)Gvua}FMOOk> zySp{l&C%@E4-53)Z~lPxT4W>R3&-^g&nQS+x_!@MVyxy9ue%GE4@%A@{n6H+e%UIC>lM-jCM?(YnF}7u|7=YH!m<>Z9r{)Lt2z>LmK^i?O{nBuph) zi8ZN=8%EXgYZE>B5rI8T6f{E9z>5k91Rg)>%e=scmci~6zwq0*u3Q-x?cU>KLVq5& zKTpHs8D9SH&EhYid}IYE{DCDS|N3jG-yFQ~TkqD9=EwDXE71_}17&n9w;uKI_*|!C zth&p3ZNWj!Z_~eir=X&x#R|!K)U7m}6eXTN51(z#_?$Igi_1p1)Lbjz?S1_8A?@qn z>?!5!Nvv}lr+upxL3p+sc{7>Q&YkthB{}i78haY3N4cN{;#aWQYP}RP!@L5^DJ9CN zM}#m2$6X}8MM=Asi%|}Yign$DD^v&3sb0VIFOMruj^BKOCA585PeWHmevrvA<#d-O8W(sAYuz`| z<+7{hy^1Rr-9+}H8oNxM@pX^3TPQ9cI4voR?sXrwL~pBn%y%R%l&XCK9I`;_pYHaj3H5xZI7B7Ne{TE! zbXzT*eOw!^WNs7$a=_TNzt2sVM+dUDc#YXVxssARdjC^@I9kj_`>|d}VR-(=^tI8k z#n10|EN4XO-S(@Gqn}~zd@0X1Yer(ScTMK%8#8}_r|Vw%Si49=KAFmTJ2Ts%xc+=? z-}GKQ9{5%NZj7gYwY2ASMG#aql7wLZo9XvMj;&7!0@Cn^HmELc`k4@abWw5>JKdiSRJ&eyXy4lK{MCCtN_ALSH zf7}lLx^P>yY0cC2izRXVX?q+h>`51p$xZxb^Ekz6Sn`GL_hV|bLuA87?V_nkg^k24 zX=9~8+#-PlNpJf(>)OPa*mwVBV z7NZPjI{~HN-rbQkjDn}}C_#9?{|k=tz%iZ%0&D&POMY`^svem)33!;_`= zU+uN}xj^6Xvbx&A$tQv}11dve(uRxC?q9Ya1*h*WWZ%uspZQMvnNAV@OgW`P?)B3I zfjiYYrHauNs3Bprhf*h{{UsRHF@+!!VuMx4sevOPxO1mnU_n;mdw<*A_7H<5m@V;H z8??QEhopD@?dpy8RQ|$ESY`vC#N)}z$aRT~qIkSssh%i;#j_O#JcB^-=l*jSJ;uYOyzF$_=hppbRhvdu zWT@xx&>$}xnb#ZO6}XzjSdPcCJ({T1@Z3iiutr^SvQTA*ycYfN`c&InBdM2prtVdM zWw!<9aR|>i`LZ{9q-IxQ!1+6v`TO^^tN1oj|C-Y_u+|<%vv%c!KIS4Awg0U9Hu){h zkPI#F*4Dl2*LW-hlt|-uu$ZTKA9t<%N#JIqb>tdQ&2&%D-*hP6HrJL1?aJ5v?~c#e zVb{5*J%z)fWy{_e%dn#`KHvS|HPR3sDUrKXL0})wAA66Fe5iB(zk4+z`Gjb_%})=- z@~u?44)$%XimexDsGghdjW$krTB&AVxqd*-!E}(QI`_?QxcmNGet7qJjHOW4TF%Sk zU+6vWlMd~@`7r2=+%j+@5n)t)y?o0Ea|0RjMacH4aB2M2^3vDoEVeTpFKp;t?>MzMMEFXSVED^pJtT7Y(1BhgU@(cFZ~h8Y z8}KS@^qcd?xG!7(#98aFfEtFYZS@VK{e5>QipD>G&%8WTgKypv()oP_i+P+L$FI~y z@b0$%dTFV04S^Tcc0Sn3^XPUM!uVOqoy*0b?M3sbQt9_GX_Oh%72x&h51qjiFJzHS z*oP@#NRjb2FjJbuIxvK%7dQ>*d79~T*;#2;)njvX26)Uh^c$X9(bcU7aH1J$9XV!_;hd$YLucqytUwLRznTwrDUb&td^jq zk@8Q_V8FnDhC7M{Rwowz1-ieJ-GY;DL?Qd)!APZ97yTZeS{%_pkkQ%At7>Rtp+8v+ z8EBc4wz~UYmp4C?&->4`HL0ue?-$>LFE2LUqce^4+`AU{R1uGcM!plgcWu78dmzgT zqGRK7)0i&hEejw?&^?^DUX|}&Z}Ghq%*54hyTzVT<^IS75ZRkzr>AmgxVxfBznWxxKH-(kaG=33X?$xE6RoL5C4p|{8QUU-YqISQlb+|A!jwpm}VtTC5v{r+FS zyr7)izv$N}dU&KRYcBm*Vy6@r3ul=^_)gav6t;P0dXXAYJ!*rz9617#? zpTPURc5}}y;-B;^2Dp6+?G~8CW@IjX>SD0mf4WC^TS$kCH1kM?Hwtuxq09w0s>CSg z7PXDWr2j;^e{%RLd<#=3m_(-d`ugk(r(USscJpwUT&QUAojlF=nXQZM(dbtD9qm1x zeyBgC|5^JKyw|_ff2}?CsQnBC;<)KHg|u!s%*GFV(VQ2)=x%esDk!u3+X*x8D6$Q# z08Tok&=igX6XG7Nw(3lpv%r3 z!#n}ocBaC$GTCkNF8IyfO7-UW}KesvFpkiJ8<+OD><_$>~qithCK_rJ1t@f|+K zx^sOE+%^5@S2dwN7W#jYZ`anm58R)McVE|uonQOs{bPL!^6&LWgt-{`ABPS(J>sg% z6ZZ4g_EAf!R{l3$gj-zKX_NtA)JX}xxezd0Z2SI(H89^F9W6T(_|}ZxqUbzjbKNlC=h0Ut4rdr!5@_jjl7|9p!f(V5@9* z1{{gt7@*BfsBjfBVh30V=d4_wZSi)_za-}?E_Xz|(EE@GD%W$rRTvM(^&Y$sDLRt+ z88-~~p-OhK`J{^QQ&dJN7g*IHAmi)hfBfP>p~=niQyJ<>+o+lP^bio2661AtthT8h>6@f25Mz1jn4IO>C$X9IaXX_7sU-h3TCOqeLIhg9V3^+XH ztlVzu*j(AFPYcvWzOKf4@3@uxt$oI8dE%R+C&9V|QrXy@@`Ja!6Z2H*%wj(XHGU^E z=p8-=tkbRB(cRc#CCo2xc#C$3A6OE4J{Ljc8hPXjE$ov7_T<}5r&%a|{5BFiAMm@( ze$aVWX);^>mxS&IcC`9cIfLW>68OYL5)6mW+eW=$uYW-Xe{4%-lxqSsLE2|2@uEb1 z7v4U1ly`cPTbF+I8!;>2w+33Pj?9_*4H5mpscC4>YX4`^aiBmy7#~le)3sQGTyuhd zLlhG{h=EvlCrbV?-~1`u_y+L`^shK{oz@+0pEtavfD~M{o7s)NP+M)N*Dh()Zu}?H z>>c+xA409CWmzn^B((g}vbFbXNGx%9EQmGQf~N2)!^gR$mE!P^PNYvfW2T*-*YImg zI+tSI&wj@$_3{dPZ_(Y1I~vo@(7yB1_0pfa%i6Z}m ziG=u^GrlSU>COwAb~ndi)|T|HxP@bdsN(SJrvEYHuUbs^O+}JcTrBkkh^Pcu8^!*1 z+a$Fo`r-c$v9g>aJ~ig(q@|$?N_crNwy-}zl1^P;`$8O5m`AWgXN6)CAlhexkPIcPO;ge_Q2)YtHuv|6|f#SFftiScqs(Z;C?{$ zny8&s-B$1?VecH<50>A0^M%dd&~ohZ8j6A#g{oE3F<7PtnJ`>`01-uscM!t-qvOWY zoy|D~lxNc6JBTS{;RAQv1SnZ$A1m)g$L+yx6K|qofZxyk?1=SXzNfi8Fq6aWyMC*- z=dT>Rqn_(D)=qb=>%Omam0H3%9v%D5%_WaL{S=qKvupLfh$#7=y!bz#PmYGDWqpnD z6=}QmD<633M}#(&Ajf75_ixZ({ba&uihvShFx?Q@8uXY7=?bhjvhU#4m%^%dvg^|S zK%C#Vq931}D8ozD=}7zOlW*PqIj&y-_*UF+oAu;JPVT$+#5-GR-^Pd9)!(v~_FC%s zn|C|U*=r=hg1im9CeUbklk~MMIgfgT-s#ax?%R~>G>H-yP#;k0oVP~ z@=EBTgASw4#ROht)S7APQ($!8MnVA4H@R#t# zce~$XBMjrB%$&%H_~>T><|QT{C$E8X2Y8y>cjbquFXf5BAE$-9{F%2Cc`q|7d$Tu1 zuXh6eZCr&c`(0luH(uZJf58`y1ZeW0gxKcoDEp>A1Wc~Pc$$?)XfypU!O{oLXG(Vs zLlh~j+(8Pyp-WdtqfAHx5Q@bxIZIG$#dH7}KhaClI;iCU$XJ##|Dt@mr{pk^bg^lDoi{7C>q>U+o zF$dSfb`X_@$;$fg&Lvy}wQQK|3z*{w*fa&E#a#a^xGB*YFnR8w%dX@VGTh@P(srZ2 z^;+Zn9^0M~wwnbHHqJws{Xx3|=pC)}{dYeZzK$4~=phgzv5*ej7)AH<B7tcaUG=l^L@zxv0iCZL~GQ|1rR*}h6m<=LB7aXqP>EeRoW*Hjf~U+KP+ ze247G85sYuFX0_zITJ_+WEEl?Y>f_=d*K% zb;exG{{c%tw7)9W*}pB|?^XOQhiV*pIC-kyjm&`;$Mm^8er26=)fubUbw8i!U2ORy zhG?(xmio@d?*}VmE)C>2YQJa|Ic73;d1`u>n5R=(OZ} z@w!%V&%WtPX1w&!Gvn@?u3tYfXHN21f2U4cG=7(7erXah``8SA$Xb)ARSV;@m9Jad zJ5@dSe#w-y>y-q1Uk80$y{o~beIqaS*%i9#@UgZ#RvsS_RVl9Qb48aqC*#KMe)+AB zx8``$#`Bi9x4(TP@zT7CHO7wXM6PZ|$2%?UO1=16J*iEjod-vk9Jxt8#JlRjzsIIr z?Pu6tJK^tV_U(2JxOhP2{-$GK<8$*C@2#~orN)4^LnkDk?K1P$geXFBvv%XgZ<=*V z5bVh+v$IwQPj5vfr`dB`Rc1MMs`6-5NcZ09HCun|E~`<=+rHAk#oOxM?9y$s?osUg zw0b)d&S}2HXV0%ZZPm`MVTLkm$G1J=(x`drJiA6OJJuBk+;5?tlYIBerk(ZEhOZy* zm(e6_|FJ$L;vV%m_C_|VzuvBxalGHY1z-8&gJvib zZe})rI_E!4DKwHl3`wIfiv?dFDsOwM^~q0WUXg@A5Lf z_1iwT)(sm!v2tR<)rU)b{=#-2Ssa)6tx}omJ6Ow`G^>~q-Q3M_`Dd}Q+|8I4+FBpd z{m*9(+&E}Ujg>;((>f*2VNU!ZyZbGf;GWhXK6UK)0PSUtUGj@>)prHf|GPz1RoeXt z6NqXht4%#M>(0f!)jwjQ5}%%I-gKs;=Tonp{T4oW`Jq$v$PNp+`?6{!OIH_f<+yx< zH?Hn;)OB*{TN4fmYu#PyS+R#NM>*v{^_2_vwe93<3TRt@Se5n%r!0$K+O+)LOAS9& z9`K}M{SMC-Jl!#T&g|$X;WuhtIy!CF=cS+C^UEg;>RydI?q*n}QpG+5gg)8%P3!4Y z@6?C!*UFDwUtvdL*ra<0tE_rmy}#S*MHiooF4ZklspV(Ww7(TCYWfG&coK7E%l!>i zS2Er$ys|2AVbu9Pou>FCTnd=;{*i9i$d5+;*UVyWcPzGTT4{p3l@(bu!D7f zy>Fndl6K3%R}0&&JALlMr~MHJ8>a=cXY8*#X~j~W-O-2pCudxWJ(+nhBqA|pRH@a< zOW9?j^^Kkv+i|1Cjh-*VC$r9g1RaR724jO~TvmM$Y?@!T+N|UJYD?A) z8XDcDF_&)*>h1cV)Rj|P=B(pxO4-=7^P6=oPHfA% zu{Hi;>tP-noUg{64r<|kf^V0WQuAoyl^YT6%l(&YipRz-s(GP%^jl5s0}gg=u0BuH zh2Ht_J|fg^dFHCD_b=bq{ZP_r(14wgOw-2i)z9Ko^UMCk_}a3Ly`zJ2QpaLdJ9OT@ zSG4GO#~Kyq)fiS{UHu17W-a80na*wBW>6l#y`{39!7gxV5MyZ)Z|L00WBS?o+P90Z z|9ZlQNo~14Wu!w)lJY(7@Y#2Vl=3cH?`(5y&->s#yNaEU-{BN+tlFeD7yfeC)v)L2 z2TF&P{15jdV-{y;`@Mf{S~KVD$$^Ii*!2!0d)&O$lv&nWyFq+>@Apfe<~lEUb?)xw8Q<-@Zd`*&rq|OPdhMM4d1>3yRTnJ?zOi}U<}dF~pALHvv1{Grg>lNt3oASt zT)NGXM;=Y?U(j6-Zne3Sy#2VBXWC8`xvo1K_v+KE9ty`hU#h%#d+%%vBWd)@XK6Qj zyj|iHcI^APA*VAkk|Gz^$UfbGxDfWz{!m8w8huu@e$>0w?qVh8rYuiu2-bO`w{`)i z(r_RS3=t;zo%Lw?8>ySitF7++<0WWINTuukYH&Et=i$vFDiC&5w9W4=0=T@^w|$sC&_G^w}#9uDop6W>8Dko0GHVoWEYL z;e7Rtvpz}3cDAmiUz~j@#nEX%x&$oV$Wqe@0Isfha_q%2Pimj74V@~*hZpOr; zw@c1h*}Lj@&Xne-vmU1PxVrm(`NPA@kK2FrTEe_;hc9J?vqEpZbSVCHfUwKD{--)l zS`mId*+sf?xx7+^x0AxxeXcrW$$z|(7(_xLK$Ae)y?!2JsokWU3hcb8JSK>af2aLJU*lAbh_MW?^o{2lOCsp1}K4)rm zzYU6FkqcXvzcVV{U6?X&m-q0)Lnkj_&AE9d;nR&1Z#uPatl09`&MjRJGCPLab?I1T z9@DRD)8Xs<^_!p1e!8n+!!O4oFP41WsiCn+kFCD%uZ~StG`cT~TF|%d>42}?0mZgV zORwI6Cw$pBy~55DH(qB;S|5vzT<$Tem}Gya_l&uQkGpPd)(NiNB6bh$7uEA+8BV-+ z6x803q=3vD4z%~qx@B6eZ9F5h4>5@6Fr-nxri(CTP$kjg-2=8Y_I$P>uHVN=aUWiP zT0bR7hxe>Pl%7$x%jRKg49$*7IxZR3TRuuUsU*?$uQ~&!nkvTBz30SJkH*HtsQf3& z!sZ)WDQ32xQn%~k2eqpV+MV6Tl-%C5;@12z@z~2*` z23+QJm^h{*H@xw*)c6^agoZQ!mL1;q!9FbN6i4u8?mdS&T)VLGrC;nVCrnq@U3vNC zzSI*F(`B`*$J9-)J!t*&W3~5;AG<#M%e~?kCtesnEG=C#aCQRQ^JS?KZO46u$|Pk% zrXDP;U-rjQPwPilnJ^3}llU=<<->7yOj?|^K~#agkIeSk9QEFSx1e9Zf24MU%u>(un(&O@(8$V%7TU#k2; z-Jx!$PJh2|SA1!ki6_z?aN~lQLqe8~dtB)iZ~wY(D~Akq4W1C-w=VGVk)$3GN7`f_ zet!DvJv*o1Mh)VlYoDHYu1jkUyRvrlrWO@5GcTsy?ddS@_C8jPmDi;;IyGOi_PWty z$?UMFl0h5zrfvc8gt%6tBN8Il4tXeVEhDA*5Y-q_UL#tF<+jBrtblRh3OP;G99D8~z z=1R3v!RuQQ9?Im_omQ>5)Uw-!THG!t_(N4b$--;BDlTO_Tz2hjh1BzP?dwF~an7|G5!&ooYZ|gTKeo(djf|N$dUJ7Q(U8=^HH+{G<^To$bx{KSDPx~DhVbK2N zbNgf0YV4~G|H1~{md37p^*O7~f?*{)9UT9qQfNr>=v`xm3~e1hVdo^poK$&YO6<`o zq5MSryWXzqx$fNu?|kjqWwLs+LepCleZuREOVoyI3-`rjw_2N`elcPFf#Dfxp05`_ zT-a>bG~+qD?y;BeEyy}kHEy)OOVdxa+qJmgZsv&3<(z@`J-(?$331&Eao_aCd`ERX zS%1gZ(!1;e90o04Q93@APy0BlcV=cjFizQ?9nfUpy^z;0Pb~{HA*(4NIKq_-Tdx=j|gRi4RW4jPJvoO1GRlp?mm>S*dfTO`UOEH*UdG?8J+bZT|LX zU+mbL5qrnhP3qRjwMn}G|6@%vI%J(Ht_ zN=LiA>CAY|f77m()A1w6#@Dzrb?tZ;_YTsgVJ2d=fZwV|Yk&V@L*I9PliBa^`$vM$ z4aaVJIKa?Je!Cajv2n{QqiTr^2Djab-#)iWF+AwipzH>(9eaA`A5q)XS%*yGb_-9O2+qdV{nw{|M32W2s zo?GRbYmZL!wD-(jl-%5>Q&;7_N=bg)9sVJQIgdVp? zbo=XsVUf0>T2VZ^6|i$1;y;@6kjGOJYhmVe)p^jE6oFK3-&*B$uGbw=EQ?z(ed0;G^yf_hEKy4k?M zVY*zJ^X9?uGKXut`aahvy5VH~WUlM}HW2~N|6Ln@TEu9~Q& z>o!f?mOki(|KYYiBhwe2&PuJebG|IO?eY?hW+m-EE=f6-+E04KaBjBCefCd?sJ6~Y zw5Yg6!(6-jWygjrV?i&_s}^5*{HkJ9bvTJg z!bWpa9w-*yPvIDqSv9J64?U5^3R)Ty>m%Cx)=w`=zI>K9_w?;a^UogWl^pnK)rkt~ z$m4q6uB+=Wd`O#Q98R~hzazA6%&I=_8*DWiO1x7z7`_doRR z7M|KOcxumup+P++O`LOh!j+v-Ju(iyHjEgxbIR!|8%qvt80vO#`Rax1u#J+fF6-wG z^L~{6B5P*tCoR^buU1?-iuK&ws-0t*IpN7ot5zAcnb5u)J8S3u#!qIoZFm3kfMQSU zw0oU7__5E?fo(P1#LMS&@fq{#XD>ScsOF6iV?w<4x7oerO4HSIBKme<^0L0)Kes3% zK}q0+n7*}pwJx(9zHT~9oS%2%#_?CPMLn~($Nc49q5O)bFJ3g|vO9d(8vTk_StQOF z_cel(WIql=S-VF5ldN5x{%O`Ozp2BY-zq-r|8e$?QI>7Xw(v^Zwr!i0sI+a{uC#62 zww+m7X`|A%?X1+Rz0bMtd-t`y&;H*1w_2NX#flLTvqz6HW5gnJ&jKO>Y<~7bWJA=G zZvdlSMcGMnvPn+n$lN|1yWZKa#lmzaVt`bEVIZRX4cbFSxBaEf_KII8{X( zCFx~g0{n#?6qo}&C;GzjjD4qaG4OG<20p(WwrYow0lt=CNBm7LD7YC6yYV_SOYyG# zFj4-sNOzUS+V`K&FZcxGoc@ipxwz$Q_0Q2E@9@(onvM!LmRQiv%>S&L(h_#_UrQTN z{@`nsY&hC(hcHvK(bnfWI2QlJ{s*`%1;M@eYjIzD)!g29`ujaxHp`UIlK)k3b+#gfPZ(=n0$YeS;%?^&U*?rKHS8~ zx0LR^--h?cSDXJqT;>Yy@ZVTYH5T!{%la3^Wq@Jz=)xg8P@&e?KV|qFtiOqo=ae>u ze(tZ1ZcaZ?uEtEu-^z?<%l|k+$W%Q$*{@^ka=`u$&A+Y>$Vd#-& zrQ5D2JKiKCpQ{N}C>Bs|IT>$Ub%r6;uq9xASctqtpDW&q1T;N zZ_h|ky9WFSzI|q`{tpj(X%ql?6V}MzaF2m+n`ECDZhTh^HEiS?3=Fq+%bC`HG(irE zj>29tL68I_ymR^Ly4zbLeIlf9ITED+^b2t){)TE#wg~M9KHup3p!qg_oU>QDOu~Go z|7W`~Rbk`(wY2N5c+QKsMy2rUkbB*qrM=i{_y`P4|2aaeS#W&+Mz@=R>EAYTy*Ts6 zVc4XjWPX4AX`B!agh+{sLB`THj2i_h`FQl^vC~&C`X*rPGajrC3@E|E-LC#WdC$N9 zKKQ>1-@oBM2{Ne1|E(am=mKgOyuEA1NqO#FR7XQDaa=eHhf;4TYibi|{a3$Y^3Dfo zI~c)QY8SJ`>ur@~;OG?8sph{E{AEE7 zK6TX$%+a7Gp==YrzxhD3=&EA})(EBj_ucJbNd%!M;5mrDvz!GWKd3)BWz$o6q1a*!mz#PrZFF?=ZHy5$ot)P8acq26Nl}urOi0C z*VRx-Zs(4KZ172m8iDYp_;}g<=Q!8x#o_-Ow7KBYlWXb|Dy^B3lxY_GHPk0FtMd;} zGz>Bp@n1_T`|wf~?;2(D___=i0nGlSCGq5Z zs5clYXpf!mP~pN#7}bf)tyRBFb>rRKQM0vtc_gZSS&(K@yDUP|Ic!;t!#08dVFRH~ zsAlZnLPo}E2$2k}APA^VPU+MpG65G0aXgroOM)2c@X6ZFh-MroM!)1Kvi|w{-@wg@ z&dJ8Y+1!K9(Z$x;!o~zZSl5gWR2ymRK-3Mz@FphdgMHNX2OILR6NEbk@uT>yCMRI{ zGyAuiaeS!r>dVmpn>j~%H?Of@E2k|KN%yez3Q@qQNinorbVIAPU#{GP*~|0B%Im)F zC*A;8!C2z~{SAP1(0&ZO$z^gqo-Tf@+N+U1mb|u#{(~>t2k^N6T3j2^jV@`AQ^3Hg z6@&|}z`}(|xBYS8KlsAe9vAL!!1~up^RBjk;qr7p-WrZ!=dYUeUdDeoWLlJt`}{W$ zc95N_@M(IrQ=>$as65t7gVn71nD(FHHQ*X&>~DC`+pkfdop}xpn)f2;UE>d??z=_= z=Kox=S%%@@6@&hN!1mYeROI^qKgMYQ!ai}1N`e0hz5eoO4gld9A@6?z6@P6PZA|RX z|A}4xI_(&mV;}vWb_vPFvF5*c*YmCA3SBacZ462~Jb707zwNTHD0NiZc{oOg>6>1< zCNuY@Cb^>r=qkj;`AfTmcs3^TufH_BdQtUf&yUhRis{5NT>w}>5WD{;yKa9Sed)Hi zvi}3(@i!C;KM5=0zu6^KHXsw0kHmE!y%rYQOa9WbK6q&bl=hGITV%a|x8Kfa_wgK@ zy|-OQOPOk$qqi9jG4%!`0ZjCe-;f0d=Kpym_J`gkiiU&y=@L^sy|r4T3;U|Rk`Mr^N1T)^porhtojJ~* z>K#xWw%t8ecQvOJC|emi+{S<-F?+he$M?v%**l%#rt0mLNZbo})?{`!gItVX>0 zZzyOWz_m6~u;lqmcoU+s_o9Bolj$t*U-XW&=il^BsMe&PE}U>Q+CN50=AO57*hzyd z695Q?#oGGo-{v5K2TG*)I>}paWTcW_RI(PR;t&kLCqcOE#&XZHi4~9=V1ylf@`A2x zox?#yLB_#BhH1^_-d|l>?3fQnZgqQq#6;8<5@|60ynQ>mIA){9mk_6S4u8>3uoG%? zoE0Vm4@&-(_8Zg-X%R!xh#!;8kW&0nOE!KQhyZE4t{~JI-~xNVsK-vFRNIQj#T<&z z=7M;l6C7W>9JGA9iV^VGV?GZ8OV26ms9g^_3DU0O=5A1Xkt$z{nqsd*Xs&@O?&y49 z=|I(R9v54P?8I^x$i6n9Le?8jyEYA0V69`b0)iBOJ6^} z?C(mT2^HOLy@MQ*RQl5z9Z?4dbT7tBdeSN}fTLJwtPX+9$yHb#rBNE9TZHA;DH>PJ zp9&4-rB95*Iu=1Av-)2N(Q4uC_1{23jZ;<{+UsgDrVRgxxTd(3L`Oed4R_>b{+jbG zJt~h8K8FRA7K|Sr-dpZVc~p~R?J;R{3u~zXr+8Qe78nw{y-7h@sMWF8bf=WyvSeWT zHLe^HWLqV=NfNL@rIpAaBzAat(FM>T(?lYi&|x#-8PNo{vrKvgKS95l z=AiVG=sL+S>wF=#Y*&FPZwU_8KvP)GN!a!~ysUo}gg#|0QN{S;v3dwL7iJY%WQ^Nv zOc&|#n*F2U-3z#S9|hL)yC~I{4mjD9@DdISL(W49(2|hi$C`XX0#j|`iV6R%P|yqO z@2B9Lc^M<9n5UkDGa7J6x)xqz*3@uTwmE~)ur#Q15$zNW(tL&s2gMU2iIwi}n|Kjl z{K1JO+IJqk&%rBn^}#`v@U#5DZ|=k|%cSfEE-&f@T-kQ8)(WHPT;{9&=g5 z881x&K;OicH%h(RBS#|f*;2pr;=^A@9W*W5nf~oJhgDC-qqs011XO*{?vPTqVak+?Fm-ZNGum;8`(Uf;GmSx!Bl7&1EhwGgUtd05Un zTibg^iySFp7?qFrwt8j=Pdg4Kv5!w7Qx{XLE3m2u8}lCnFSd=>+DYB~+Fyh(`Ie-H zK)OlG8>}&uCYHto&l4ESb8^aJ7{O4|fvhr8DDI^Th969Me^8%Dw9gRx@9f4PU|Z?& zw@*A>tMRI{^Yt<=9e{9}WqtQ%afxp<6W^xbx5cCdLsQ>qe)-0M@#TH05Fwdt-R3(@NJyC?+}ppFyaK7{$Dzm-dVtO{KytI47`rf!>#| zU4ZLQrJi!0q=(&Df$pWNECT}MbZ128&JmyN;W2uZ&1R%_nT*}{Tq>Gxkz26t$Pj2^ z#?cB*3y`$DR&T;&G$?I4SCdAY)_;uDKjeZL3xMG=mFEypl%5xv<(IZFq3L2r{c-`{ z7ak)V_~}FxX`fHqL6DOe54EgsAQvCoz9rziRS#k9==pf0m-^(Zw<%pyv$f^h*8XAt z`EkB+5DNjKZj0ZJjn_{*7%6XV5fh6EOBRT}^a<2+hXHXw5a#TjWum|**UyNkLWZu$ z4=zFhT1uFD(!6i2Vk)zgC&z{4gXJAOL+R0Ktowj5z@8e# zYD7&y><9fiSToFyr_)^i8Y<`-BW+t<#9>T)9%1s2yr3TTRz4%obYqiO1w3F&!*Ud~ zzC8WydSG_)FMN*Ns%7iys-lq=RR6aFCJq*#~mwgj@&9+lgH({FKck^BDLMK)@WK~Z3DN7 z0OU`gf=7gru77x-TM|SFkz9XoFjrW*ygyuZB@#*Mr-hM$5gF0Iq)9@Qu4`;|`&Z~2 zDA0bsi01Ct{B4wH&`Vuq&`c9o)1KV-N0TG(hw}P7}MjlDu4Kai+x55 z2JY;k_H0bfVkw)T?S0d)xD|tYwlw;~Bu6M3j*n>87M8bTqSLL`#m>XY@+L z9Xv4WZb!CG#&~Fa_sb~%9Lf7G^|dpAmoq#QQO@O*HuQAq>w4g8nPa}N9TfMYq(T!! zp)ho4m$Ni1*d8LdQycqZjh&9b&w$GgjbOnL(M;4#MoLiQ0K!F65w*@n$+prGF||N8wU&MAQZU(OIaYNiD+wu5nVx@SpEeVve!qdNo!z!L!P zw>Y?GWveLs!3lhhYB|doa1bTKkHEBM(8n8iVb50ob+U+Yu-9ds^#Uwi6jfn7>MD}#J`50bEjI7F5MiET{ zE9iqx%WsGrzkhLfKZ3pd^_B7UfTK-(;m4UW^&$?|^E1UlMQ;~Pv)vZDnY_KZh}F&z z$MLqyOpgZ=GX|R&p0qegVCFVSYX7x4tFS2~4S^qaP|#$Z2~i#UYtZP+egR@iq0U6M zj#Dk%n1qLJm|u2mh}Uv451axJWVzQbX-1>-{KIvqy~4^_i^L9z8*W0qLpPx5hNT?LpJ-Pj(OA+y)b2?9LzGWY)5VjpK@RFASjkVOiB@Qh8eR&$EFQj4 zl?D@9cP7_+h2d8TE22%DieWcwD-hjY*$ZHjQXhlDdZ!Z4|6SDlmpvx*CVI==k7)@}uqE+oFV(_9y954Ffo54GGt` zuw=#B#c+!X{5fuSu-2H?MQAbJWfVlON);UAz#AtsJ!?ds86hNscuj08bBG}!{5QH+ z!cKDH+7j#;!&R?xdu|;Mt9SO5jBk&Gr4A3YGqlIlx3wxmDmZe|y&V#SEJcoA)NmnQ zeq{!7%wtVl*82Lmbw2Ms+CH9zK1Ig55%AM*>V5jWUaUY-Ywv$d(G4hw@Z(Qe1>^Use=Ti+dA zPTE&J4ts`9@!Ot*xIyv)=HMSIBH^T;<{}8avbl45ci~ZhXH%7)a|T)Iw!6@7W&1{1 z9e9_C6cwUYC+PKLB6nHzbIfx7q!(yPUy(E_=V!?1+mLZV{SY;C#0F@Fg;qLMvK!KpHB+%o;d(t)~{jyIpIxG!emjgM3 zobgb3pA$i^0(u88b1+@6_n4IzJRd6b7QA}y4{t*sU@8y?ShDQkj`SA6-?>3__S=;~ z>!lHg6oHB%5pv-4>)a53D2%ZUP!ogJ48j4^Ly87K#Ra882D2OdKpSFBpXwdON};5j zDPkPk=7-e?c(J{ggy7ywk_8D}Vq611MD)?#w8*SA&m+l|SCU7}RnL#Va*s!`X-Y33 zdi}xzCGaiQj7q^)y_P7Jk_`x^zs07`1-$fwjgxzwr_16ee@tOoQAab3_k?lyRJSO% z5G@M{z$mIr{x~=GEwc$Eia=_U(fUHSy{unsf#mAsG@$Ra5`+D=noPZg4!tb!YV+HJ z{fWoJ6i?bLt6PKbgsa~JTTGNZDRSh)57}jdj}>Zliu2&s^xVRT3lI4;D<=nSmd+Fl z?!87yigV^(O84E8zS%{R&b9yi&w z1>$sL*S&=0S@*dFQFA?jijL^1*8MySGQ)S8dkssoFDeeZhLZ%Z99w3uM`wDw!)uTB zcax_ZFOO!l%wVO*+Ww%!kzRP!wr(M2#fM!$6>w+B{+ZAlr$kzpeOSavDTws-4tdhx zS%u^y_9fA#Hqo`r`xD7Lk_i(fObaoE!s#B?7CA)`hwMaIMEMd-RLQd}&bUX~=)%&b zWo_inN;~lt^q8{x%xD(*v$U_IGbAcb_=@QUE=__B-~1h^mm3Q*TxK8UIWXF%r03JW zel(lJa$)LJ=Ns+{nKRc)hTeSQsnjr)Z!N??XxXrET3&DP?pYc1CmMeTkW%&#R_uGlc8Mt1WpTJjTfZp%XFrNwAs@LLa>-87MhY3$v9MhhTm!VR*-*R6u zic}Rza4KJtpWcDuQk$L1P#n=l|T zA221OA%PYev%)P_a2FkiUBnXMVQ~*=0;(akBzPBfcGMH!hULv1%HoWC<;XA%n($q} zRC!RBpx8!|PIJWUIKmIgJ<1J@tj1|w?ishK?xtmWM94Sf$AT($OVI?439#0IiRH1Y z)y(x|Ne(&xu8_i8lcYQ0NFOJsqtj8hTD($Dyd&dDldSsD@Z;+7;kx>r?d|kFCiqE( zpM8*4Z=B;cFoY{-@TnAQQG)!MFnjSB98VN&1BR>U38SIi%dlOFndaeAxW>Qf6!PiszaY<8x9D+dFDe!#?1OS(m77N3B%OQjqBxFxZQ zCO+1zr}G8vE#l)$$MaFj?q^_fl-8aho8eEjjIKw;Vz!{2u~dQcjWft?pl~<$EGzWq z9|A&=3-Z%~)B1%Q3a$W}RM3x8h!7h0EUj^uNSAJ~>f3+#2MM%Lw-$qKJ zCfq40qRrh#qDnF=qT%)jq6O%5J)jCRGe@E^N8Zg#p)%h|D&8q7Dxpf=q9rJzNk;ll zBux~|?j2twZ`uqZ_uwUhfABW-qtXhb>ON~E9y3Uz7ywt+$!{?LIf z)+&JN-vo4;f)+s44f?|9p7qE7OaXxES=_U16m=?5m=L|EYcUs>GVlApA+<+{f(aqs zpnFjk7iF$&EL%5_CwgiPeqI{4Cew`Yn>LhbCC-hmN+jC6ek-mpB2Y*G-=UJ7b3RZJE%sx?ZvJ19V&T0H(~KAiz~ zCQrZ6g^Uy$M+=5O?#o?3)SWS@Nj@1$?CHuhVzD*#k)Z-r&&HX@acmW7L6OsUB*>_5 z?M`4W927_5E|O@w9S60FIHCTuqhRhzo$!_ukUGRJlin>~)c~0m(?~l_L_F&u&?hb~ zwtZL7Ihg32VjsXT4?`cKbVa$_+(M1JZfUP47Co7qH|0pzkQ8rSqk7(-I5KcP`bhbp zk97kBE~Dd5&Gsq~5xbRFg6l9Qb3yy9!u49KPA=8C0$<{esF^ummb$@gmFuM_-cU@4 zyX7m&^vS`+hbvj5K!aIM>cb1ERxXzWnePM%7N0?JRc1?3UEQ7km?*!ylA%jFgc{H; zf~GHm;}KYZ%kMgIy!s)YzEeGqz7G@Ps)T2M^4M_ATJ_nT$B zu!VzVgs@_$U%!X{8V1Yyf_oQiPr= z9b=lnE`p?>Sau*ONh{07;-6`eHvp!r2uJ`6$D)?W>1Ra)9AWaR?gRUIyJvZhc*Xo) zyp@=VkmamMy9O{;_#m`IdASF)XnFgKNjVjcojo%!;Kc{ddk@H;{*N!b{b4O}2h)x} zCRh!Lwf9E>B%~l{_kjIn{=6LY`?8yZt*L}qv8|)5>8VJ1be6oW!p#s)RuteN1TOXj z*x&8XI|Dod()9m*=bt07Bz!#n(BdIWzOP_6nu8MyNa+V6_9=ws@7sTLh5fdo*?*1B z8WJ(#Go=R$4)_12D=0b2R?J#YNv20cDNszw(#_he-ZwNeu{^&%^Fx~ljW{(^Pcun< zUtTjyQ@JWNRWC_1PN_UKMtWPSHK3~df>;zWv8-u58h1>;QuoO( z*|J8u7J;uADHprHhmsmS$D{H+LPG__caY_QBupNM7NJ1In)wmHk7;IPO?zS&_KQ$b z-eX8PviQy)AT{LS`fAhH+XD2m`)=j~QE|u-&awq1H*BX|?ZZveT&ZVq;GoqKuNb3KM8c2|A(R?nEuG%^Xui78EtQV|P;D<9Od z>;Pp--iz`u*JeC^BN8(lHsHrb6PdR){G}kLNu?Eqk767}*P2)NfT#+K|Gfb6*r>7S zM|}v@VsHc69p%hL6p#2$zCR;&0jTjfE_NN4x{YCkFAMS{!zLxI(S>5nN8(dJXHixK zWM~iA$7|Y5E4mDvFxw&44-!-)_{mZ+XA?@SZ1VR3_l{}RQYuB?>A2Eou8TvznM!JG zHI*MfKB&fr4j`D&S!T&1x83Oq6-qxvBTJyOtxjk+Pxwo28(yVRH&&#lm=CK$nqy?6 zSRI8g&A*>;RRK9LMVw=Fr#`DrdjCFwl$R_#vPgBcbA}Erw!gNlT!f_V-a%`YIiJ;f z<%&-OWDX!dx_(0FofMemI)J+c^W^~Md(GxC|AOZ0T+BhC$^ zu$wy3eM?wM^m!AzD(fQx`;qPVtCtt0-#d{1;AHv^auC0J*4bgscYY!3f~wg8!tQVx z$#3=ARON%CqUm5{=`S9CU<^JH5fJnsSovtWMfxao%uXM4AN}TUD8LFgNq<49ExIc% zLN7WjE;=MLD?uN2lu0o|&YYMgB`hi}MGz4!9wh4!E%qQwZ!b?gNV_K&XDruGtT0t{ z9;KwBnvofkE1zeZVVkX%k5KsyOtcJ(e;(2S=PuUFC#)w0*(cAlZ3{w{S5Y*9QV&kp z*)Nr*4)_gtWTN4t=^iJ9Odx#yqv#V2i2{s~VSZ?*DJjN>s9%cjqsXUCW|5S}WTffG z7*yvJ&`~ns;^~e1EL|W1OweZ*W3z+P*N6f(Ah04Qg)ZkL8|~ z`F(SMUnuckS6nDr0EEXNN9}okyqZ#7vt4IL^j=a!JpFP`Jg?iei7A9kDhiA`BBg+H z5m>KdKdKSlEK)(*+@gKI#Y0-$ZGHd%(p>hd-npLG*}+P9V%tNY4OJ;n2ixb9SSc)4 zJ?s?CIRCC*o*XO7@|NF{P-9+R-vl6^3u3F888ZCg{p;jO>(R@^X2JVYpojUey>xCDd~+NCaZ$^$uM%SiC|jBRGO@!k<0Ocs(#KCaAwzopy;n zPlVhY?acUs1eKH!*dUZ5N2v_toFnsdK(M;nd9}%>$iAkq(>!>BZ110Jn8s(6lr_Q1 z9t7gW6)r|&h!C@TeyL+(#oyZUMD{&dam~)rt#j3;Yg74nIczRiH%7Fnmmq8!9mwwW zruCb=Hhr<>Y=bSgAt?R3iqr-$j=-IE2Wc8JtsOh8z`d<(Or?IC(z4 zaTJgtwIEC_Erh1~K0?*HE80ikO`p0} zODc}FLoBk=mS*o=WIF5b?XHtmV0&b-!3{J50hxXxhJaTX77>WBS2vamVk`e3S0fPL zRd1TYi#k1?FRA2dD5q5Vl#T#Hs7ot(s={rJCngRjkT)R;S zv=}D`2M3ks>t7D_CAN6gFMR@y22ZcUZiZnc$D)340Ki+!Au*+*FxEUOd{w@(qVVbN z^JhP=ReExnpmCC?8Kuvxn+|1m(Z(LVxPILwE>xA{7=LgS!g9YxrO>2bbKaenwJryuomXV5ec)YPB5x?VrVt-~nOo*mTZ z6Ii)NBx4&WMD8~RpuUjt3I+bVK$+B#1<=-mVfOyX`^Rn97!kW(X*<|PY{ z7}rL>MJC#v)AZ4cJ)_QQmGRB`UkO(Y;(O0b$%+@!69z5Y$G8f33zUC1M2 zsNJh;Npu*03D^`VrsXXdWEHdKw!yAX{4R)yNh!TQcU~I4J zlaeMxj;G2QB;2}Q^{fNM@EDhH1PP&t!@|5(0)Xe5!h)@K=L*4d$tJ`qQ*??z6MuK^(sOF6V zNbhb;Q(`j|CtqKrFp<~sD@~kkn>@PPnWqDv9{N?1HyH&=S(2?D%f!~h3-SW79%^K$ zI+kEfdlObaRZ(5}jcrQSY~gJdw)a z0HHOdAlw?`c?10f^fpD;c&Hde9N~AgO$$m-!yYz|Vy%;Ce~4*b^lE2wfn1lxhs-+< z=cZ~#ou4;s45mK*VlJq&GaoTfmHlE?RjE)vM`IrPVSiR16|^d#%LUhw!2!rB)oK^~ zt+JAW-8>_#&vb3rkF$i$4kkEOL=-}zo1wTk&g>HH)0UmpBFS|dyxrbu2`$%ipoiiX zfwf!#o;9J&KwJIctV{piJ>e~JEYHXbQW=;-#9@ADR|q1_D`fq`V=W@0F?46LH2nGp zB4qt>PK+f1+vip$;@+40WM7DlyGrdg?h(ODgpQ@yO{%@ur(IIAx1gH2H<*ECp>4I; zi?=7>HX}3RWBEvByWb!$KKSRs{NC+Rp2%Js9^whi&$ zGX~6sQY=Z-{rbcs`K77mh~aN+6j)jB+vKbxMEzttOP*;$^v}_HfwsF5z9TRWN`q_F z`K!rmrFJG_yl6Jwijm1UQXPCz!oGY`O%MHw$RK zW*nYwWV<77R8DQAdg{qg9ckD1Cexcfq$(FsrwHBl^(WGx{gLq|R=0fm(~MB#pfOko z=PYB8s6pB7RS^ z`&)}=BDH0E=_9+f#8V0J6<6BJO3{1`{%~kg;IE$Y1wLv+KMRInA{5HNb%JW)quu&H8gTlGSn3{ zlQeP1lM^(PG*T)u)svDm6qD4I%k?V}t3i*bPADmblm|!#4BOiZloVn9*yOrPU=a!- zJgZTql%k`anwSP@NQQlg@)z63NCLcsa|y;L6wE0Hua4eCl{`o!la&wZi%M#bijEG6 zS%eRgG0JEkw;)?EFI$*&lud!G6=`WEq=U3f3nG}4EbS*pB?6rqo0=Sg2QvSmy<^Jn zf?7(|!RL1xk(eWTS@~V{50Z(NhqwQx+|asxA3o4v;i7}(q9|8(Y&#LM5_CUhBv%|^EVXTNVe-+P`KpA3ngnf*JhQN}JqY^v| zs|i82G7NcVOc@%{jP2iu%{eU^(mSeVu?k%IGf2Z(85?i$B(XKVw~Bp#bT2M<>kZ`A zuFA|;Dqf}GlWl`k-U;OJQ zL^tWp4f?T1#{6fcRnJfPXaD_P zz70YN?vg=yUm_Ep>~PhuEqR+FD-NschwiCYqPqKfN@7;zJ#4e%9p*`2%4qEo0R25byy;?yUw`Y9OUuw&*pb~SO9q}WsW6o6<55hom^ zUXKlnrz4oN2)ESgD6HrT4yW$UH2PIOI0SqnTptPRdZPh82JXwe0icnuQ}cE0o*BQh zlGmSTGr?AIqA)ct{@J9UHbmz*=t-*hrQh1@7;7}dc7jXSm*6L$uRMA37hs&!1m#+@@I= z#WO)Yb9r%@98PYUa}+(O0=Mes?d336fJ>ZF?f8b6SDKQbD1hsPwVjvt+X&Zb&^?UA z5t$+LzM*Qs+3!SnYSce1BPW3XsR~8u0hy$3uR3id$Df>Za5t9l{{r#Ett7zTt!1S2~`{!Q*I^4IxAczGnj zIr)iq@9;mX?^4DG0G*AGD#^$Kx-X6}Vv08_H=!rMqZ|odT^hC`-U2DE&KCNb5Jtj8 zQ|Kh$A~)+MVU}zh3Ku@NE(L^G48UQquyLdbdh7=1$C3Z8m9U+D_)rm6Kn~`aG$I$X?#VA6Je@jCqMqggd7ikS{)V$H>@E9}^Q0E_pSqHcrYt$f%d`ms|VqLSW_u4Nb3tbjs5e3&{1gKKK5C9 zxMy`rM&naj0{fLXS*#`n*#%$QQ6oBNY9rWl~QH9J|G-Y+T}@pED13QaYxa63Dw>UtOQ*8K_4a-K)tHK?cTkzgarpPX|tp zx_$6aiwl;Mjw!ATrP5Q+Fs`?dgcC|G0h!Vt$;G}7S3@3}pO4OLWZI)=Ly?-sC@0&4 zdYI`EWw1-Qh`1>f`BHzdR@B)r9nsW)E`I`b$Z)rH{H8v|sy4BO?1&#zwROi!ETr1D zcAgzQS@WvNzp6bIi)#u-{E40ot&I^nGb?{>@vz4M#>F;N;}f>iJr3Xdo}x!$cL8f( zBe9p=XwhS1IyDVlc3T!Gt-=Z+>SVDm1}lU3&A^6f5Jhpr(P@nEsMd#bKiZ6XTj5tW zGTZv?H025#`0*rv20a$voQhaVLZtZCVCc8s%csjU90k|3# zXoO@Kmcn(~qD%XkZeF^hFJIBQG74FNDBh&1YcZQ|Q+wvBSW}3a1y8^1`+7tw>QwG) zSU?&VEvW~Rb3}L+3&p7J2Tkd8KJ9fu@O;Hx1|~=7WSBCKxK_~IZXS)*IW|gVFy^VH zQD4=|J>&Baq&MFzBB)Ym`jPD{3;$sl4fzv=LV`PW`24Cq`sxe~g&{{n+R|~*S(gXp zQTJIl&&B|n+j0bLBz}>WvPiL=CPheA2o?rw717n)E&^qN6Bg6pQVz3-2}zd9JcEzM z9r`v3OI!s#OS1Axo`8>1eay3xF3Q(qND$W`*8^QKYC7Hwjwj>tbuq zW%RsHUe8Q{JsDC+M)#G7PpWpVvO7f=>Q+WY*FG!lnYJ&VTnRu*gErJ#ur z^6VGodyz{%y%GCYUoL~g1JV7@0d%FN2DpTs3*?GyZ>gW=KsQY&F^Bn`f^{-wabHd7a`SHLM zmtJAv@?({`t=C2ou&qm5J2Cct(~S))<#92+yMA(;C#wj0#$>RA+{^J8FLsRw)`vK0 zMuI4BfYKd5KKDyXLAxsua47{Tp&|U_#mWays&86}kxt!}%55agi!@Zg(fpc^2D$Mu z9#Odw1v0lky=7HtRrxwv+^J}SDRG2zfCnXMe=4|Oblo{U{EWK=-Umwge6~Jv$Tc%# zbP%;LCp8;cVE62{@P(RYBzEKKSscWo5|~DP9oS|>dP8Cm%H8RO*f@T8yaII_o+gXYDLI)Kby`B1;Lb&%fwF-w#jdQs~Ag?fo?K4Z;ZhU8l0 zgAWaov^ipxRU5qaE&wjO`C|l=Qj)Rk(5hgE$ClflIhF+oq}+1xA)}mFy#Zp_FS+Km zHH?oOo5Pz zckyX0GU=Kw3PG?EV{hPQXC;sqo)z_8L-gq>zUDtg6P{A6P@J>hoyC1C!B{-$=n}z0 zLJ7!sk!(M&R?ZdfK0m}qJFOzZgT4#{!0Gc4%BI^o25`h|h&CJ@Oq`@qge^odO!WSu zzfE?;>t}t8;6r7NAn8itM%8qlFhN?^8TUX z&NzEgQI2{=({YvcjUd_7iKrkqxxp5x&75H#V4=j~Rlt)oqxd)n0Bt&}z$5RGj#XwT zrfBSa%J?n4hAzg+QOFbu5t_139{|5dwxRKuK0j4oL+NA#>8)@^oZDu-eNwBu3d@cj z{;_SuX$+iZeVwxF?&ah3vSU9;5$i_q(Utq@{mJ<9epmXE8al0an0xur;p@4eG~2Hh zO!BSBq$7s*f3)mg!uI`MQtX|zy z?GbHD6(7A7QtkRrbBf;Dc7_N$Hs3&tIm;?J4Mi#IJ4{oxqJqMDT!%o7^qm_gc@2_b zzFe5$BJ>XDj_N!0G6(;IY$vVfrBy_0KCT~^j}N~ zzqZ%REb8btp7*q%8sNJ%=E(R&keeloEN@y4s=8|RAY)`qF(+8X$d$`Pf$sqngb)iI zdf>e2Z4s>HnCe0+&s!(#8wb%BPP`)p+GePH;IgRo*ogR{6{$QK*HF8X z!7%>FJDD0?DA!>?+mMjE=(QwcGJI8QvGkQuZj8Tl>Kx0Ez2FA&$=O^jSGrpBe6Q#& zm(cz;BJLntOIoWdwi>LVCl`a@oi}VY+>DlHZ*=Cg+?>a~^M>m7YmR6i>fEJ<+J$PP zee}47ne|OyG}PF`q5D8H=#JrJPRsjKiv(w9E~vh{P&-DH7lJi zIaTXl%bTuDDj4VpPfkxZNC||x==wi**m$T_{UAj5oqzaMt4+?=ucFys$aNIXemD`m z$HRp+bDFD=6hFz~pHU5qT&uiOxmy6eQbbS(diN0);L~ueK^pIIhn{Xm5zn~V)v)7C4&tCQu%rnAzz2=s)uM*>wNDG_f&nPeK z;}3p3&@iB;`tpiQV^$bXmA0W%X%?wU&oIY=`Z+=kC>$(8JkeMeT-!J|R?O~xZf9mQ zQBrIceGe0jWNRR?>w8lu$Y1l|MuoKFHtXpVXBLv{wX5S$z%Kz$^>T4?f{RbezQW# zkJcXfJ6A}N%vJDny84jFKV7;R;LI^p ze*pD&&>Tbi1L%GOBLLGeEC8&306PH3Z#Z`h*YCi63=aVBG5kM3;5!75`DGt$VE_>T z(eDsDMjQZq4CHr!eg_Ny4uCjD@)#rl>N}(WqwGbv zAhRGj@|>SunGwnRFZU)E9S)KN8+cAp^v>NMh$cGqc~kCT!pc~HF3Tlbw!;&vx^jl6 zc7v!!T??5mS6Yxi`)YH(wUPl%JPMr&Ga# zRyc;MN7s?eY-nM^oZ!?GuD9nDX>~cyTX-(l#~QC0@qdar-|)(1ojz8Itj4AL?0g$t zyHD?&Xu8fFQ}%+Jw4qQE0kx|do(vm&bBkV6+dt~haJ|trszbW6x|m#g8-4ZMjWx0GvT-Iu=5hmtT)3DnZZaR3 znU-?XXGl_jRX>8|*lXRRW-JDRSG+kcY5%BWhh)rnll^ICwRPyq$wOrRe%!vJtBmpW zM!8&Go$3#~9UpJHNyDtUKgyUVzSXjSL0|S@@h%B_(!k-{@l~1G&z#r?gH1ltR9|d5 zwlnF>YqDhx*UDNEoyl*KV^%KArA|E$ck);EwsBK_T#*oAg&JY~J`G zE~nMpGQFLuPA%(h&8c?*TX1KQj0e&~U?J6P{6xpJN6|MWVaQOUu-=kz+v@c>vunI; zC^3@;JAX{Qcroarw6$p|{cHcu$Tsd&xd%zbPniy0FxkG3NsS#M{_sUXZ004EO~P#{ zvIuO{G#F2Q%Zt=xA|l??Sje|y^}gd&@W{J&t?t2ExKOoH&_h=jrc5U#3F9=Y$Iy1( zPs#%uwct!|q1;rr+5M(OG%kul)L+duejv9fYWjW|6t>VCS5=y}PcyuL>$; zWzS3q&8$ax7&==-y`^A|OG#Vgaj~}^*oh1EB&&Y{>%GJXbLN|@{1!do`|*RXUmxtf zY585SwPbkeI@6~k?T@2=fm^*IjMo$}6&drFpSKmaQmsBD4BGLC6D1qLw_af~e^s*5 zGwiw<7UoZR@AI^+S$R(KKp53)3DV4Pf}2ih^i;(mgyd8n!V;tG_J~D{YfPLYBKOPf zt|;#4SLSLOp3FnSusg{YE?O~=v&orzd0=~4FTZYJCA>=*{@M6eabgH1>Cu3vs*XEp zad!Nd7>eQRS`KT(B7&x3B-~6$vyVSorZJIHpWTZyvj*a=w=7U-Y|8USb1p>>E@-Y6 zFuziBT8nA

*-uKs#NenZ|59tKWIEXU_FeMv)a;*3OT-SC-@n4iB;OP=&fPM`X8i zZv;BX$Yxmwxv_qVQBHlnwbMu04K3M^NYAP>_tHFSY*%=Ya8|}&aaf*a(kw?{8%ogc zymhj1>Ch=aCpbUy?(Lkb4$%%Fn=)!SyveUcc_*FQjMQ>JTbX~+bffsdwX-h6W>9ZP zlrNqKMqS&nY>%V5*eak?LKDQRB#Z&tvHbK%KegDqeoLC(@7{N9?u{4FmYYu7U$~Jh zLQ1`<|&0!YZnm z=8V6esm6n-EoSTb+XVJJJ7QENeCsPEtmIMm1!E$!v5&iSrm^5y=i#I(>dikwODohq@6*=QqMw*zZFYS>GZ&L49Js~H} zpX}d#$kW%SJVO=nZs3$ZveGmrz|>LxlHW>1?LEzAJ;rROl4qPb64U2on^xQ6r_Slj zeuHlp7uPvy?mD$_54~7@6JN6G_>zUi~(H>S3a*dV)k^NsC zHRh#~FRoloG8D~cm}nQ+tfE~h`WX7P-ur$VjJhzh!tLdpF8HihQ1NnO`K!rGo`{`2 z_}$KdBa}S(G^cQQ>b;o!jAEAf28k{$cc+k*hSsRA0yK}`E*JEAKup)w$XpA%xQR+z z_q^8ktX&<^QZ`+!wmJfAVC&A^3;ETNo{l+-I(FT}WpwL|FO1Ic=t;!6Mo5)}Jv{u8 zbMILTKs)$1vfWjBx?7UPa!oa)OQg5#9xTQ_Bcu|SPW zJ|S%o4f*?7xKimaeEBe;7@$o^>~&SYUB<9%Ait6?RrXu%Rc%hBg^ zF-CVjDpFTKG|X!+coi5L%=oDwD=C$hVqYab+@)UIHePDS??jbsYpXt3F_zblzs-{J zvbOxPFSDTPOrfpEj|PB#wBG(&tr45P=^R&|RDe{~CC#$5BoB!nt$@3sYdcXe(*LM~ z$--1`>`m@xid2_Pag`6?^C_u{u%Va+*s3mkwzp>ctn}-CmS0=OBa1=5X=0=IES7Kri?6&LLt8MA0EeU(}{9#4fv{{eFaQjHJZ|>FP zDw(D;39nwJ`e>GyiT2seL)WLcM|onmnUl53bw4>;uQO09ZwS^!GfN~Ppd+AzkdzT6 zSJUx&)eVix9(g~wPj!>PftT*$6~6&56Q)Q7sst|Kgi6am?qH3J2br@si0fnE8o@UO9_j5 zO!Uwq1XCC*>J`=o4=;R!QV>%k~=50Xe0r9r{HLm68{U(OcD(#?Fzur|HN!S?5yKZIq4Ey=$x< z%?n=W=_A^*v{F?R7p^B7{x&C2r^(RV;2hmES4l7oqmX-PJyn=s^jIUEJ_~tA?x+WQ zddYTRy!X0=O&#e@^opOsGVYcNMFd8MjYR!!EQ#jp_o<2kxnBHgXmf+7;CV&5o2+hQ z6?6$aZ5r^WFB2q1Yo8vjT3b^;S}qEZ`>@MGm?NgaPtuY(j3N|G53p}-p8H&`7*_SM zDVm2$7th3;*J7E^aynq&uL4o)Qz2NAz{X+bklTEAezL5BvPWa^P8?mt0Q_LgvYgCX zQ@_~j^c&6gU^$`;cVCbov*xvP#RiAI_5k)D z@Z35bAkYbbbFTnP{{pb!qaY9~;1l`sfnyH=dp`}>eohdGNe2YNc!5C7fM23|1_GUV z4gz88f${-QOPdXR7Vw;0fS)`26a*rE16cfD;sCyr5Ac@f0q?5=_-Y1!;9S5*69J!- z$pe8{xIiF|+d#ZWK>14`kQO=cS-|V50)CeUI4%xc4{tmWYYjO52?RO`cztca&l%kV zjsd=z@dyMuB>=<_27yR5K_CLaXR3+fOQATr38F6H{cVo!1<^c5J(E}+q6Jk z@BkiM9XJNfk6DNAP@|=KYPH3vH^ZyN(8tU3;+XQwWEQ! zz%}ut0p$YWxjq8VVjBeF>;>u}9jL29;QoNRW-JHJy#mzx3h;NJzBqxpw_F6Sa|fuK zBH$VofpXP>>jR!01MrjbK5*Z_F_uQ)xd0xXhX8n9NT3|RpHnOY*A0|)z5)0w@VvQz z=fwQ_M+3r5E&ZExi)9OyW%-*+)5A|LhWNLE{y)=?$A57caVQ2QDJcO)qEQk!6bgZd z!{A^v#z7K+MPTs`FgObA0LR1rRE&Q={tE^p;Qt!`g#v#7LtzqKGCa~NU_9uC-Ycu$5o!!&jJlsjMr0tV@q zGGK`qCBp*ksy-1VN4n0M;32k|hhwj268b9uS3S0X^V9XKxSOdHl$*N5KtWF1@;Lq- z%>+|6?fHYzACywcVD-W__L{78bxc)5H~tP}M~guWYjg++hx zlW~(h?QDGSO&zz8uc;K{Gor}GK(w~w$mgh)c<&08Oa3=A#=45jeYTxO!_|6%>fK0K zElQQQrIf*J^Rtkz7PEQ{P1R?2jm6>KI=K!utKK&nK`t(F5r6md{UiN2|1o%RFhmk6 ziAO*nSO^@Af?%*1Jj?-%!DHb_BnF9qqwp9s68EQK{89eHC6DtT4uc{PP$2)|5HR>> z{{I#7C%ACCTelTVrDCx!tcs5wx=~1WPTu$$y|m>`qNo9$6h2dS>53PX^ULKE*cW{) zajPglp;;mGVlzoQ!eJ7(0y>7kYy7wUDTKCD>z-72KRyrD*ie#na@;z~N@nyD1bcqC zq8=~)bnoqRH42J}5x-IDoppZ==hI#J8{|7*mfZ~M4lNS19_k04Ur(-CCZ!=Q(O!R5 zq07ge%yM2->_hi;I@J+uYrA*+TWQ1Y$Ft6t6rOB-SQ&+!dFLSEYIMsSx9;{BJ5W6| zK_b}ZeKm`}gP1wG8c$k8;t`rA7vkNIT6B-ZmQ7ek6-pH|J zHF{w!J^!dOXwsx`s%G;vR#$Jv@a^-o3(cP#=302xGl!hk!Zxv_go3_e1QUiQJG$lq zt-l?DB9${;|L*7ZpVE)>ACD2ogV9(#S^|N`fgx}hN)m^K`R8 zvZ`M9mwd^M>U|yhX_mysmez*%Qj@#ElFz2by?RTv6UHoaN08p+YmS*6-devdV&vgs zVBvDdT>+<|8qA^OzMF;PW$f-}7uqq@)Ot-r5$sk@*UE(r;!PkrUZ{ma(=5nwxX1h` z)FgT}&Z)~@<-``gH z@&PC!@%iBEEKTC3u=!iOus(m6080-+-~Q-gw{Ej$eanAr*ie{ee!J8D5OE=w(aZ30 zvE3BWh=n-c?x8hRxE5j9^N3<}%yOL(8U3#3(vinjVf^Jr5+w-ons@xx*41+B=VeZQ z%H<D2a| z+6$WGD&VX6Y9s}c^5JOuyKm^H{zv+8{$nBHcr+R(A>n{=0D656k`OQ)ii0DNU=;Wl z+lPe0Q4qAG1N2YD_|y3hhrtoxU;2MANeSrB{QoQTzs&!fRmJ5`A&J52bocJpZKbq) ztM;>A0Kt7Yes>b+PyJWw$N7&&h+{Dlk~m2$0*b_AiUWfkkPrtn9)goVVDT8316C4-fQhB!3xl zMo9dc|L~vR|9^@62^uVx4JXtYrlw`uLkmuzARX54adh@%*Wz)KTBFU@z5<#r4JTF= z64|Q4&z&;ar`iwS=h@F#9qyIqOUm%+J$d_Ux@^s1pWk?x0P}!v&F(?w@O_a1+RJye zFB+j(94qBErujYi)%h++MTMQ_73|c$BgfXI{xwCPeLRlqa(5AZ1HER>2-iwk;!u36 zovB^7e4FNDj_X`~bNW%Qa}NqQW7?Ng^P_RDV8Z4*ZI zacWeS=2lkOW?T${`%1Fq5m?2?XE_X@ZP|C~86YZL9Jtx*4sJ>Q_?uxL#O5^{8AUB8 zxwBJbMW|#y-;(ai)aEvb6xG|*cJ-WeODB`t9`v899Iw}Nedq3Q?&>FIcJ|C~{tFo# z2jg-+AFVHLrB{nNCH0L=R8F-Y+17N+J+nESKOxrAMnKZpDyJcEkG3|aMmYOT#f}OW zceTV-nu zoEnRF?P7Wy=g0fd5yTxYY*F56Q&uky#Mj1*4y0bEhWV2L<$RrC8YAKBt6gFtc`^tE zZTE&1Um^WYRh!BB!5nGVsf=KBmejp+V~kpokpx;Auf6C+%DxJyN!$5bFAV~p&R zuHi0{btW761x-(D+B?V`8wOvrJurSD0M>ZE|H!=om)M$lL^%XWm5u(im}@Wd&FjL2 zJ3E5vgT^N<(q6a4aUo+9nfb5EBIrZgvaMLYo+TjO(SU{|U)9{xc8lT4(-R{6K<%8G zQ!?>^GtVHQG$Ovo_hPHy=^efO2GP=xZ|{2@rllw3{3l5iko`58MsWoyDX&@v4_l&J z54+7mP+ym)ZI2GV^mfWk-M@eEWvIXD+m=}fRX7^S(mh?0rID^Zoh#H`>L^*WR=3QW zX4QW=Wa{wn{+uZ z=c6wxi?v5AE3T|ulW9rftaT4(nZH0ReZvmRtrCeiFG0G zLd=W!oGy0?`M;t@Sc}co$r*i`m0jODQUEk&VEVQ z-W5eDdW-uV-l^K*7+<{km?~2={kI|T_4hX|cD<8^i%i}`&GIlG8^&fuS|eb6#$W5ZZi&X6$t6^Y zxGMuw-b&YjcMFk3nN*}GrP0n2&Py=LDRUJ071YS?UYnGt%g_=tV4vKxOg{s;NlH=) zO-oqMFIl|9m0@P`tZ(x!NB6x~j~Pci-;9Xd7elZ&Dx*vVTeL&3;4mH3WiE1*(bzp1 z2}1f4B{1b&wf6k+L?g(IZpZ$&qpH)gJw85}#Hjx4U?=wiYoT8wWbBt@MY?XS=M zT=nRbzB#ogK`vJhp+Y>5E}w=JyH>6NRlYtmq1NoBflso;Z^SqxqJ){U3D5SA=l6(Y z`7bV03z?)KJ$UyC@I;?8Lk^@{JK)s8kEx)X`nQ~`dnk29@;&>wk2XflJDOB^f4 z_zaUp=RdVie_>WecBCWy^~}6|7`~T*#F>h>B|*#6D?1=-)YJb67B~AWF@|eaWMo)A z=60fIPK1mS!BW|Fs!7@TSc;3_&reJut=xiPPb`bLx9Q>x4mi*iwbik*TzI`0v#aNm z$Fnln!#(0nPd!8VW=1IbGVJ?nzQvv}X+{lvbz?BUe}53Bt5Vvf_ztvVUsso*Yoh_X zU!PcGKwY9<7FvGgVqE$yjvnvJ;JX)!=c81Y9zzF-C!ABBg}M6$O?*Ce%k^uV-N*fNGwA{_Boeb{JE8{FjY(F)#>d?n5jLlv; z7)+x6Ktg(Iy_&a;b%5hP>K_H!BH z``NdzM4V3}oAJHgqPFmnfWs6snV&&-Y(kf%e`2YkzAv5UG13|zA?%SdaaIo zG;=Py9Iu0JG~_V-W;w0H(onq&W9QAV4AOTk$UF0ym+7=MqgmF_%NLcQ+>_=O9HQQ4 zkG&HUA|o!ajFYQ~euHZ82S@m?KK2iMHnQ|0Z`7sygZ#R-;Y71fCj1Ur)HMhb8lF!3 zSmlnFVqGA77XM_iIX(CC=_D63Uy=4q{5MYO>ZkkR^{2MD-!GiDw|#a3wv|R1)b6*8 zB~mkeu?FiGbYafVM!HkDrRIUh)X_b$iEWQg*6hgZm6STCIM4VUP8;{V1JqUuXza z`A1H85e{&H2A6Lps}ZB3HVz1`%<$IgWT<}gxt4Nvh4?M)sF18=69Ek=^wez)d_pwQ ztx(~`%;uJWsMj-=_6n|**LCYpm3GC0>?i`Qh`dC?`b1hTHANUKvr9G4A117tR}+GF zOEj{^)nr~v&Phn|CTaRVuhF`FmK5f6!TmMm_{z)#qg-1|zW(VJdcVNDa<=%dhC9vsl6jZkj|EN%1* zH{?G-pkM(oq=fQJ?@3P|4P!YJ?%LHG2%?NWd{KPVGRX^e8|!DxX!!y@(gKonhBGGx zA`_p6JFj-%QKIRAH-q#i-)|NPA$2I^gwHat*hQZG5U)V|C@B^p&-JJ90sR`MB*U?{|YX8sQZ3jNLde;8l@fBL__LjTM0Upda5L*0WHi!ukrM|t^v zbzT>B;m8vp6X$b(?v=n#{g>#+`7a?U4uwIHC@2mImV|-vUA zB#^HV$^T6LBjDf9|M_+NN8;!E-@iuw1Q~b!IsZ2~D6Ef=jK}4q<+3^N^=gSv?pGZi z`1r?OSSn5WW&W?9&({3?xpc1~%K}5Cq4E-M{*%hjeRZVsC8}#@4Rs%VjP*+AJ+1mQ z!(u1-(vsx~cs*?b$0{`+MmIncdjB?D!NPqZ8Ix+kRpoI_$5EfESq|)5j-cc!>keYM^{dg#ms$jEZS-#vuBr0LQ&=s5lEf^zKlsO%|QG z+pBo7DmH(bO&-*p|M~S+jaR=KD?{<~ zek4$SA-b#TW#>#awz@J|!@3)nr)1DiQo!F#L)*H*$Eez_h4C$n_u)!UrcZc&jqgZQJZsmE2Y2sC}Xa<%u(+?M%JihaPv2 z9Hd{PLsp)Zs+qL5eh|3^o>FAVD~oF_PU7@!5sw9hMx73=@wW*iw{EkT8pZ_4`WK(w zOzV5{gnlGtv`xkC?dih}p8yHi#ZPPBn%ERP)=F)=hP%TfPQ`Nj-l|hAnOhJQg1TC+ z`B)~%gz!htomd{^IKXyvuH4ti^id z%!Yp(_16r(QL&>0qCLuys*}0GW8DG0h?}8$H0~}gGeS2Ed|0})CbG|9C(`~~UXuN8 z{!5~ VersionerOutput { + test_base.run_versioner( + &[ + "audit", + "--no-fetch", + "--fake-crates-io-index", + test_base.test_data.join(index_name).as_str(), + ], + expect_failure, + ) +} + +/// Test that the audit passes when all the runtime crates are at the +/// special `0.0.0-smithy-rs-head` version, indicating not to use +/// independent crate versions. +#[test] +fn all_smithy_rs_head() { + let test_base = TestBase::new("all_smithy_rs_head"); + let result = run_audit(&test_base, "base_crates_io_index.toml", false); + assert!(result.stdout.contains("SUCCESS")); +} + +/// Changing an independently versioned runtime crate and version bumping +/// it to a version that's never been published before succeeds. +#[test] +fn change_crate_with_bump() { + let test_base = TestBase::new("change_crate_with_bump"); + let result = run_audit(&test_base, "base_crates_io_index.toml", false); + assert!(result.stdout.contains("SUCCESS")); +} + +/// Changing an independently versioned runtime crate and version bumping +/// it to a version that's been published before (oops!) fails the audit. +#[test] +fn change_crate_with_bump_to_already_published_version() { + let test_base = TestBase::new("change_crate_with_bump"); + let result = run_audit(&test_base, "already_published_version.toml", true); + assert!(result.stderr.contains( + "aws-smithy-async was changed and version bumped, \ + but the new version number (1.0.1) has already been \ + published to crates.io", + )); +} + +/// Changing an independent runtime crate without version bumping it fails the audit. +#[test] +fn change_crate_without_bump() { + let test_base = TestBase::new("change_crate_without_bump"); + let result = run_audit(&test_base, "base_crates_io_index.toml", true); + assert!(result + .stderr + .contains("aws-smithy-async changed since release-2023-10-02 and requires a version bump")); +} + +/// Adding a new crate that's never been published before passes audit. +#[test] +fn add_new_crate() { + let test_base = TestBase::new("add_new_crate"); + let result = run_audit(&test_base, "base_crates_io_index.toml", false); + assert!(result.stderr.contains("'aws-smithy-newcrate' is a new crate (or wasn't independently versioned before) and will publish at 1.0.0")); + assert!(result.stdout.contains("SUCCESS")); +} + +/// Removing an old crate that's been published before passes audit. +#[test] +fn remove_old_crate() { + let test_base = TestBase::new("remove_old_crate"); + let result = run_audit(&test_base, "base_crates_io_index.toml", false); + assert!(result + .stderr + .contains("runtime crate 'aws-smithy-http' was removed and will not be published")); + assert!(result.stdout.contains("SUCCESS")); +} diff --git a/tools/ci-build/runtime-versioner/tests/test_previous_release_tag.rs b/tools/ci-build/runtime-versioner/tests/test_previous_release_tag.rs new file mode 100644 index 00000000000..991bb32d139 --- /dev/null +++ b/tools/ci-build/runtime-versioner/tests/test_previous_release_tag.rs @@ -0,0 +1,25 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use test_common::TestBase; + +#[test] +fn previous_release_tag() { + let test_base = TestBase::new("all_smithy_rs_head"); + assert_eq!( + "release-2023-10-01\n", + test_base + .run_versioner(&["previous-release-tag"], false) + .stdout + ); + + test_base.change_branch("change_crate_with_bump"); + assert_eq!( + "release-2023-10-02\n", + test_base + .run_versioner(&["previous-release-tag"], false) + .stdout + ); +} diff --git a/tools/ci-build/sdk-lints/Cargo.lock b/tools/ci-build/sdk-lints/Cargo.lock index a9981777901..ae77b733636 100644 --- a/tools/ci-build/sdk-lints/Cargo.lock +++ b/tools/ci-build/sdk-lints/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -19,28 +19,28 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "async-trait" -version = "0.1.72" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] @@ -62,9 +62,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -77,9 +77,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.2" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bitflags" @@ -89,38 +89,40 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cargo_toml" -version = "0.10.3" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "363c7cfaa15f101415c4ac9e68706ca4a2277773932828b33f96e59d28c68e62" +checksum = "802b755090e39835a4b0440fb0bbee0df7495a8b337f63db21e616f7821c7e8c" dependencies = [ "serde", - "serde_derive", - "toml", + "toml 0.8.8", ] [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -138,7 +140,7 @@ dependencies = [ "bitflags 1.3.2", "clap_derive", "clap_lex", - "indexmap", + "indexmap 1.9.3", "lazy_static", "strsim", "termcolor", @@ -169,9 +171,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -179,45 +181,40 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] [[package]] -name = "errno" -version = "0.3.1" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "errno" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fnv" @@ -242,45 +239,45 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", "futures-task", @@ -290,15 +287,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7" dependencies = [ "bytes", "fnv", @@ -306,7 +303,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -319,6 +316,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "heck" version = "0.4.1" @@ -336,9 +339,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -347,9 +350,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -364,15 +367,15 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -407,9 +410,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -422,26 +425,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", ] [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -454,27 +467,27 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "mime" @@ -493,13 +506,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -522,26 +535,26 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -558,7 +571,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] @@ -569,9 +582,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" dependencies = [ "cc", "libc", @@ -581,21 +594,21 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.5.1" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -605,9 +618,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "proc-macro-error" @@ -635,36 +648,36 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", @@ -674,9 +687,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -685,15 +698,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ "base64", "bytes", @@ -716,6 +729,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tower-service", @@ -734,30 +748,30 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.4" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "schannel" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -770,7 +784,7 @@ dependencies = [ "lazy_static", "serde", "smithy-rs-tool-common", - "toml", + "toml 0.5.11", ] [[package]] @@ -798,41 +812,50 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.176" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.176" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e7b8c5dc823e3b90651ff1d3808419cd14e5ad76de04feaf37da114e7a306f" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -847,9 +870,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -866,18 +889,19 @@ dependencies = [ "semver", "serde", "serde_json", - "toml", + "thiserror", + "toml 0.5.11", "tracing", ] [[package]] name = "socket2" -version = "0.4.9" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -899,33 +923,54 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" -version = "3.7.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -936,6 +981,26 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -953,18 +1018,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", "mio", "pin-project-lite", "socket2", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -979,9 +1043,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -997,8 +1061,42 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "indexmap", + "indexmap 1.9.3", + "serde", +] + +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.1.0", "serde", + "serde_spanned", + "toml_datetime", + "winnow", ] [[package]] @@ -1009,11 +1107,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1021,41 +1118,41 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -1068,9 +1165,9 @@ dependencies = [ [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -1106,9 +1203,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1116,24 +1213,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if", "js-sys", @@ -1143,9 +1240,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1153,28 +1250,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -1198,9 +1295,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -1217,71 +1314,147 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +dependencies = [ + "memchr", +] [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] diff --git a/tools/ci-build/sdk-lints/Cargo.toml b/tools/ci-build/sdk-lints/Cargo.toml index 99a567c13a1..c1fd1e1599f 100644 --- a/tools/ci-build/sdk-lints/Cargo.toml +++ b/tools/ci-build/sdk-lints/Cargo.toml @@ -12,7 +12,7 @@ opt-level = 0 [dependencies] anyhow = "1" -cargo_toml = "0.10.1" +cargo_toml = "0.18.0" clap = { version = "~3.1.18", features = ["derive"]} lazy_static = "1.4.0" serde = { version = "1", features = ["derive"]} diff --git a/tools/ci-build/sdk-lints/src/lint.rs b/tools/ci-build/sdk-lints/src/lint.rs index c7ffb012c7a..82592e5e12d 100644 --- a/tools/ci-build/sdk-lints/src/lint.rs +++ b/tools/ci-build/sdk-lints/src/lint.rs @@ -7,6 +7,7 @@ use anyhow::Context; use std::borrow::Cow; use std::fmt::{Display, Formatter}; +use std::fs::read_to_string; use std::path::{Path, PathBuf}; #[derive(Debug)] @@ -136,6 +137,13 @@ where T: Fix, { fn check(&self, path: impl AsRef) -> anyhow::Result> { - self.fix(path).map(|(errs, _)| errs) + let old_contents = read_to_string(path.as_ref())?; + let (mut errs, new_contents) = self.fix(path)?; + if new_contents != old_contents { + errs.push(LintError::new( + "fix would have made changes. Run `sdk-lints fix`", + )); + } + Ok(errs) } } diff --git a/tools/ci-build/sdk-lints/src/lint_cargo_toml.rs b/tools/ci-build/sdk-lints/src/lint_cargo_toml.rs index 5b253e42d65..faab55f4ec7 100644 --- a/tools/ci-build/sdk-lints/src/lint_cargo_toml.rs +++ b/tools/ci-build/sdk-lints/src/lint_cargo_toml.rs @@ -89,7 +89,7 @@ impl Check for CrateLicense { fn check_crate_license(package: Package, path: impl AsRef) -> Result> { let mut errors = vec![]; match package.license { - Some(license) if license == "Apache-2.0" => {} + Some(license) if license.as_ref().unwrap() == "Apache-2.0" => {} incorrect_license => errors.push(LintError::new(format!( "invalid license: {:?}", incorrect_license @@ -145,7 +145,13 @@ fn check_crate_author(package: Package) -> Result> { } else { RUST_SDK_TEAM }; - if !package.authors.iter().any(|s| s == expected_author) { + if !package + .authors + .as_ref() + .unwrap() + .iter() + .any(|s| s == expected_author) + { errors.push(LintError::new(format!( "missing `{}` in package author list ({:?})", expected_author, package.authors @@ -211,6 +217,7 @@ fn check_docs_rs(package: &Package) -> Vec { const DEFAULT_DOCS_RS_SECTION: &str = r#" all-features = true targets = ["x86_64-unknown-linux-gnu"] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] rustdoc-args = ["--cfg", "docsrs"] "#; diff --git a/tools/ci-build/sdk-lints/src/readmes.rs b/tools/ci-build/sdk-lints/src/readmes.rs index 2d5073a7153..32d235ffa35 100644 --- a/tools/ci-build/sdk-lints/src/readmes.rs +++ b/tools/ci-build/sdk-lints/src/readmes.rs @@ -8,7 +8,12 @@ use anyhow::{Context, Result}; use std::fs; use std::path::{Path, PathBuf}; -const CRATES_TO_BE_USED_DIRECTLY: &[&str] = ["aws-config"].as_slice(); +const CRATES_TO_BE_USED_DIRECTLY: &[&str] = [ + "aws-config", + "aws-smithy-types-convert", + "aws-smithy-mocks-experimental", +] +.as_slice(); pub(crate) struct ReadmesExist; impl Lint for ReadmesExist { diff --git a/tools/ci-build/sdk-versioner/Cargo.lock b/tools/ci-build/sdk-versioner/Cargo.lock index 0ff7ddce42e..22de949b43a 100644 --- a/tools/ci-build/sdk-versioner/Cargo.lock +++ b/tools/ci-build/sdk-versioner/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -19,28 +19,28 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "async-trait" -version = "0.1.72" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] @@ -62,9 +62,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -77,9 +77,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.2" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bitflags" @@ -89,27 +89,30 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -158,9 +161,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -168,9 +171,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "diff" @@ -180,9 +183,9 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] @@ -195,30 +198,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] name = "fastrand" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fnv" @@ -243,45 +235,45 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-core", "futures-task", @@ -291,15 +283,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -307,7 +299,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -322,9 +314,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heck" @@ -343,9 +335,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -371,9 +363,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" @@ -392,7 +384,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -414,9 +406,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -434,19 +426,19 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.3", ] [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itoa" @@ -456,9 +448,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -471,27 +463,27 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "mime" @@ -510,13 +502,13 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -539,26 +531,26 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", @@ -575,7 +567,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] @@ -586,9 +578,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" dependencies = [ "cc", "libc", @@ -598,9 +590,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.5.1" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "pathdiff" @@ -610,15 +602,15 @@ checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -668,36 +660,36 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", @@ -707,9 +699,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -718,15 +710,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ "base64", "bytes", @@ -749,6 +741,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tower-service", @@ -767,15 +760,15 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.4" +version = "0.38.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "9470c4bf8246c8daf25f9598dca807fb6510347b1e1cfa55749113850c79d88a" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -790,7 +783,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -831,35 +824,35 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.176" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.176" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e7b8c5dc823e3b90651ff1d3808419cd14e5ad76de04feaf37da114e7a306f" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -880,9 +873,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -899,20 +892,31 @@ dependencies = [ "semver", "serde", "serde_json", + "thiserror", "toml", "tracing", ] [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", ] +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "strsim" version = "0.10.0" @@ -932,33 +936,54 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tempfile" -version = "3.7.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" dependencies = [ "winapi-util", ] @@ -969,6 +994,26 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -986,18 +1031,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", "mio", "pin-project-lite", - "socket2", - "windows-sys", + "socket2 0.5.5", + "windows-sys 0.48.0", ] [[package]] @@ -1012,9 +1056,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -1036,17 +1080,17 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.1.0", "toml_datetime", "winnow", ] @@ -1059,11 +1103,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1071,41 +1114,41 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -1118,9 +1161,9 @@ dependencies = [ [[package]] name = "url" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -1156,9 +1199,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1166,24 +1209,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if", "js-sys", @@ -1193,9 +1236,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1203,28 +1246,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.27", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -1248,9 +1291,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -1267,82 +1310,149 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.1" +version = "0.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b5872fa2e10bd067ae946f927e726d7d603eaeb6e02fa6a350e0722d2b8c11" +checksum = "b67b5f0a4e7a27a64c651977932b9dc5667ca7fc31ac44b03ed37a0cf42fdfff" dependencies = [ "memchr", ] [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] [[package]] diff --git a/tools/ci-build/smithy-rs-tool-common/Cargo.toml b/tools/ci-build/smithy-rs-tool-common/Cargo.toml index 6a18a15a864..def306f5a7e 100644 --- a/tools/ci-build/smithy-rs-tool-common/Cargo.toml +++ b/tools/ci-build/smithy-rs-tool-common/Cargo.toml @@ -9,7 +9,7 @@ publish = false [workspace] [features] -async-shell = ["tokio"] +async = ["tokio"] [profile.release] # prefer fast compile time over runtime performance @@ -17,13 +17,14 @@ opt-level = 0 [dependencies] anyhow = "1" -async-trait = "0.1" +async-trait = "0.1.74" lazy_static = "1" regex = "1.6.0" reqwest = "0.11.10" semver = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" +thiserror = "1.0.56" tokio = { version = "1.20.1", features = ["rt", "macros"], optional = true } toml = { version = "0.5.8", features = ["preserve_order"] } tracing = "0.1" diff --git a/tools/ci-build/smithy-rs-tool-common/src/changelog.rs b/tools/ci-build/smithy-rs-tool-common/src/changelog.rs index fa67649c11d..f68325d463a 100644 --- a/tools/ci-build/smithy-rs-tool-common/src/changelog.rs +++ b/tools/ci-build/smithy-rs-tool-common/src/changelog.rs @@ -108,7 +108,7 @@ impl FromStr for Reference { ), Some((repo, number)) => { let number = number.parse::()?; - if !matches!(repo, "smithy-rs" | "aws-sdk-rust") { + if !matches!(repo, "smithy-rs" | "aws-sdk-rust" | "aws-sdk") { bail!("unexpected repo: {}", repo); } Ok(Reference { @@ -211,9 +211,9 @@ impl Changelog { } pub fn merge(&mut self, other: Changelog) { - self.smithy_rs.extend(other.smithy_rs.into_iter()); - self.aws_sdk_rust.extend(other.aws_sdk_rust.into_iter()); - self.sdk_models.extend(other.sdk_models.into_iter()); + self.smithy_rs.extend(other.smithy_rs); + self.aws_sdk_rust.extend(other.aws_sdk_rust); + self.sdk_models.extend(other.sdk_models); } pub fn parse_str(value: &str) -> Result { diff --git a/tools/ci-build/smithy-rs-tool-common/src/command.rs b/tools/ci-build/smithy-rs-tool-common/src/command.rs new file mode 100644 index 00000000000..113014240a2 --- /dev/null +++ b/tools/ci-build/smithy-rs-tool-common/src/command.rs @@ -0,0 +1,75 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Utilities to simplify working with [`std::command::Command`]. + +/// Synchronous command extension functions. +pub mod sync { + use anyhow::{bail, Context, Result}; + use std::process::Command; + + /// Extension trait to make `Command` nicer to work with. + pub trait CommandExt { + /// Expects the command to exit with a successful status, and returns the command's stdout. + /// + /// If the command fails, the `context` is used to help describe the problem. + /// It will always be formatted with "failed to {context}". + fn expect_success_output(&mut self, context: &str) -> Result; + + /// Expects the command to exit with one of the given statuses. + /// + /// If the command fails, the `context` is used to help describe the problem. + /// It will always be formatted with "failed to {context}". + fn expect_status_one_of( + &mut self, + context: &str, + statuses: impl IntoIterator, + ) -> Result; + } + + impl CommandExt for Command { + fn expect_success_output(&mut self, context: &str) -> Result { + let output = self + .output() + .with_context(|| format!("failed to invoke {:?}", self))?; + let stdout = String::from_utf8(output.stdout) + .with_context(|| format!("command: {:?}", self)) + .context("output had invalid utf-8")?; + if !output.status.success() { + bail!( + "failed to {context}\n\ncommand: {:?}\n\nstdout:\n{}\n\nstderr:\n{}\n", + self, + stdout, + String::from_utf8_lossy(&output.stderr), + ); + } + Ok(stdout) + } + + fn expect_status_one_of( + &mut self, + context: &str, + statuses: impl IntoIterator, + ) -> Result { + let output = self + .output() + .with_context(|| format!("failed to invoke {:?}", self))?; + let expected: Vec<_> = statuses.into_iter().collect(); + let actual = output.status.code().unwrap(); + if expected.contains(&actual) { + Ok(actual) + } else { + bail!( + "failed to {context}\n\n\ + expected exit status to be one of {expected:?}, but got {actual}\n\n\ + command: {:?}\n\nstdout:\n{}\n\nstderr:\n{}\n", + self, + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr), + ) + } + } + } +} diff --git a/tools/ci-build/smithy-rs-tool-common/src/git/get_current_tag.rs b/tools/ci-build/smithy-rs-tool-common/src/git/get_current_tag.rs index 51259358ca0..4bf88a666eb 100644 --- a/tools/ci-build/smithy-rs-tool-common/src/git/get_current_tag.rs +++ b/tools/ci-build/smithy-rs-tool-common/src/git/get_current_tag.rs @@ -53,7 +53,7 @@ mod tests { assert_eq!("some-tag", tag); } - #[cfg(feature = "async-shell")] + #[cfg(feature = "async")] #[tokio::test] async fn get_current_tag_success_async() { let tag = GetCurrentTag { diff --git a/tools/ci-build/smithy-rs-tool-common/src/lib.rs b/tools/ci-build/smithy-rs-tool-common/src/lib.rs index 12876e5dac4..7d2e7083b86 100644 --- a/tools/ci-build/smithy-rs-tool-common/src/lib.rs +++ b/tools/ci-build/smithy-rs-tool-common/src/lib.rs @@ -5,10 +5,12 @@ pub mod changelog; pub mod ci; +pub mod command; pub mod git; #[macro_use] pub mod macros; pub mod package; pub mod release_tag; +pub mod retry; pub mod shell; pub mod versions_manifest; diff --git a/tools/ci-build/publisher/src/retry.rs b/tools/ci-build/smithy-rs-tool-common/src/retry.rs similarity index 55% rename from tools/ci-build/publisher/src/retry.rs rename to tools/ci-build/smithy-rs-tool-common/src/retry.rs index 1608da8448f..fd02e18ec49 100644 --- a/tools/ci-build/publisher/src/retry.rs +++ b/tools/ci-build/smithy-rs-tool-common/src/retry.rs @@ -5,7 +5,6 @@ use std::error::Error; use std::error::Error as StdError; -use std::future::Future; use std::time::Duration; use tracing::{error, info}; @@ -24,6 +23,7 @@ pub enum RetryError { FailedMaxAttempts(usize), } +#[cfg(feature = "async")] pub async fn run_with_retry( what: &str, max_attempts: usize, @@ -33,7 +33,7 @@ pub async fn run_with_retry( ) -> Result where F: Fn() -> Ft, - Ft: Future> + Send, + Ft: std::future::Future> + Send, C: Fn(&E) -> ErrorClass, E: Into, { @@ -68,6 +68,49 @@ where } } +pub fn run_with_retry_sync( + what: &str, + max_attempts: usize, + backoff: Duration, + op: F, + classify_error: C, +) -> Result +where + F: Fn() -> Result, + C: Fn(&E) -> ErrorClass, + E: Into, +{ + assert!(max_attempts > 0); + + let mut attempt = 1; + loop { + let result = (op)(); + match result { + Ok(output) => return Ok(output), + Err(err) => { + match classify_error(&err) { + ErrorClass::NoRetry => { + return Err(RetryError::FailedUnretryable(err.into())); + } + ErrorClass::Retry => { + info!( + "{} failed on attempt {} with retryable error: {:?}. Will retry after {:?}", + what, attempt, err.into(), backoff + ); + } + } + } + } + + // If we made it this far, we're retrying or failing at max retries + if attempt == max_attempts { + return Err(RetryError::FailedMaxAttempts(max_attempts)); + } + attempt += 1; + std::thread::sleep(backoff); + } +} + #[cfg(test)] mod tests { use super::*; @@ -179,4 +222,95 @@ mod tests { } assert_eq!(2, attempt.load(Ordering::Relaxed)); } + + #[test] + fn fail_max_attempts_sync() { + let attempt = Arc::new(AtomicU8::new(1)); + let result = { + let attempt = attempt.clone(); + assert_send(run_with_retry_sync( + "test", + 3, + Duration::from_millis(0), + { + let attempt = attempt.clone(); + move || { + attempt.fetch_add(1, Ordering::Relaxed); + Result::<(), _>::Err(FakeError) + } + }, + |_err| ErrorClass::Retry, + )) + }; + + assert!(matches!(result, Err(RetryError::FailedMaxAttempts(3)))); + // `attempt` holds the number of the next attempt, so 4 instead of 3 in this case + assert_eq!(4, attempt.load(Ordering::Relaxed)); + } + + #[test] + fn fail_then_succeed_sync() { + let attempt = Arc::new(AtomicU8::new(1)); + let result = { + let attempt = attempt.clone(); + run_with_retry_sync( + "test", + 3, + Duration::from_millis(0), + { + let attempt = attempt.clone(); + move || { + if attempt.fetch_add(1, Ordering::Relaxed) == 1 { + Err(FakeError) + } else { + Ok(2) + } + } + }, + |_err| ErrorClass::Retry, + ) + }; + + assert!(matches!(result, Ok(2))); + // `attempt` holds the number of the next attempt, so 3 instead of 2 in this case + assert_eq!(3, attempt.load(Ordering::Relaxed)); + } + + #[test] + fn unretryable_error_sync() { + let attempt = Arc::new(AtomicU8::new(1)); + let result = { + let attempt = attempt.clone(); + run_with_retry_sync( + "test", + 3, + Duration::from_millis(0), + { + let attempt = attempt.clone(); + move || { + if attempt.fetch_add(1, Ordering::Relaxed) == 1 { + Err(UnretryableError) + } else { + Ok(2) + } + } + }, + |err| { + if matches!(err, UnretryableError) { + ErrorClass::NoRetry + } else { + ErrorClass::Retry + } + }, + ) + }; + + match result { + Err(RetryError::FailedUnretryable(err)) => { + assert!(err.downcast_ref::().is_some()); + } + _ => panic!("should be an unretryable error"), + } + assert_eq!(2, attempt.load(Ordering::Relaxed)); + } } diff --git a/tools/ci-build/smithy-rs-tool-common/src/shell.rs b/tools/ci-build/smithy-rs-tool-common/src/shell.rs index 9136ab541d9..d67604c2084 100644 --- a/tools/ci-build/smithy-rs-tool-common/src/shell.rs +++ b/tools/ci-build/smithy-rs-tool-common/src/shell.rs @@ -3,6 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ +//! In general, the `crate::command` module should be preferred over this one going forward. +//! +//! This module was an attempt to make unit testing against command-line tools easier (especially +//! in regards to git), but over time we've been realizing it's easier to just set up fake git +//! repositories to run real commands against, or to mock out individual pieces of functionality +//! where needed rather than individual commands. This module requires a ton of boilerplate for +//! what is providing. + use anyhow::Result; use async_trait::async_trait; use std::process::Output; @@ -15,7 +23,7 @@ pub trait ShellOperation { fn run(&self) -> Result; /// Runs the command asynchronously. - #[cfg(feature = "async-shell")] + #[cfg(feature = "async")] async fn spawn(self) -> Result where Self: Sized + 'static, diff --git a/tools/ci-cdk/canary-lambda/src/canary.rs b/tools/ci-cdk/canary-lambda/src/canary.rs index 137b8f64a91..67689fd0931 100644 --- a/tools/ci-cdk/canary-lambda/src/canary.rs +++ b/tools/ci-cdk/canary-lambda/src/canary.rs @@ -21,6 +21,7 @@ macro_rules! mk_canary { sdk_config: &aws_config::SdkConfig, env: &CanaryEnv, ) -> Option<(&'static str, $crate::canary::CanaryFuture)> { + #[allow(clippy::redundant_closure_call)] Some(($name, Box::pin($run_canary(sdk_config, env)))) } }; diff --git a/tools/ci-cdk/canary-runner/Cargo.lock b/tools/ci-cdk/canary-runner/Cargo.lock index 4af4fa079b4..6da3d4076c5 100644 --- a/tools/ci-cdk/canary-runner/Cargo.lock +++ b/tools/ci-cdk/canary-runner/Cargo.lock @@ -55,7 +55,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -66,7 +66,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -1012,7 +1012,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -1582,7 +1582,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -1782,18 +1782,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -2241,7 +2241,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2367,6 +2367,7 @@ dependencies = [ "semver", "serde", "serde_json", + "thiserror", "tokio", "toml", "tracing", @@ -2439,9 +2440,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -2508,22 +2509,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2607,7 +2608,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2679,7 +2680,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -2863,7 +2864,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -2897,7 +2898,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/tools/ci-cdk/canary-runner/Cargo.toml b/tools/ci-cdk/canary-runner/Cargo.toml index d0d6cef2b7e..3235945fae8 100644 --- a/tools/ci-cdk/canary-runner/Cargo.toml +++ b/tools/ci-cdk/canary-runner/Cargo.toml @@ -11,7 +11,7 @@ publish = false [dependencies] anyhow = "1" -async-trait = "0.1.56" +async-trait = "0.1.74" aws-config = { version = "1", features = ["behavior-version-latest"] } aws-sdk-cloudwatch = "1" aws-sdk-lambda = "1" @@ -26,7 +26,7 @@ semver = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" sha1 = "0.10.1" -smithy-rs-tool-common = { version = "0.1", path = "../../ci-build/smithy-rs-tool-common", features = ["async-shell"] } +smithy-rs-tool-common = { version = "0.1", path = "../../ci-build/smithy-rs-tool-common", features = ["async"] } tokio = { version = "1.20.1", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3.15", features = ["env-filter", "fmt"] } diff --git a/tools/ci-cdk/canary-runner/src/build_bundle.rs b/tools/ci-cdk/canary-runner/src/build_bundle.rs index 237740991d1..9a212bd7c80 100644 --- a/tools/ci-cdk/canary-runner/src/build_bundle.rs +++ b/tools/ci-cdk/canary-runner/src/build_bundle.rs @@ -163,23 +163,38 @@ fn write_dependencies( None => required_crate, }; let crate_path = path.join(path_name); - writeln!( + write!( output, - r#"{required_crate} = {{ path = "{path}" }}"#, + r#"{required_crate} = {{ path = "{path}""#, path = crate_path.to_string_lossy() ) - .unwrap() + .unwrap(); + if required_crate == "aws-config" { + write!(output, r#", features = ["behavior-version-latest"]"#).unwrap(); + } + writeln!(output, " }}").unwrap(); } CrateSource::VersionsManifest { versions, release_tag, } => match versions.crates.get(required_crate) { - Some(version) => writeln!( - output, - r#"{required_crate} = "{version}""#, - version = version.version - ) - .unwrap(), + Some(version) => { + if required_crate == "aws-config" { + writeln!( + output, + r#"{required_crate} = {{ version = "{version}", features = ["behavior-version-latest"] }}"#, + version = version.version + ) + .unwrap(); + } else { + writeln!( + output, + r#"{required_crate} = "{version}""#, + version = version.version + ) + .unwrap(); + } + } None => { bail!("Couldn't find `{required_crate}` in versions.toml for `{release_tag}`") } @@ -436,7 +451,7 @@ uuid = { version = "0.8", features = ["v4"] } tokio-stream = "0" tracing-texray = "0.1.1" reqwest = { version = "0.11.14", features = ["rustls-tls"], default-features = false } -aws-config = { path = "some/sdk/path/aws-config" } +aws-config = { path = "some/sdk/path/aws-config", features = ["behavior-version-latest"] } aws-sdk-s3 = { path = "some/sdk/path/s3" } aws-sdk-ec2 = { path = "some/sdk/path/ec2" } aws-sdk-transcribestreaming = { path = "some/sdk/path/transcribestreaming" } @@ -500,7 +515,7 @@ uuid = { version = "0.8", features = ["v4"] } tokio-stream = "0" tracing-texray = "0.1.1" reqwest = { version = "0.11.14", features = ["rustls-tls"], default-features = false } -aws-config = "0.46.0" +aws-config = { version = "0.46.0", features = ["behavior-version-latest"] } aws-sdk-s3 = "0.20.0" aws-sdk-ec2 = "0.19.0" aws-sdk-transcribestreaming = "0.16.0" diff --git a/tools/ci-scripts/check-rust-runtimes b/tools/ci-scripts/check-rust-runtimes index 78b6221b5a4..377f017abad 100755 --- a/tools/ci-scripts/check-rust-runtimes +++ b/tools/ci-scripts/check-rust-runtimes @@ -13,6 +13,9 @@ set -eux cd smithy-rs +echo -e "# ${C_YELLOW}Auditing runtime crate version numbers...${C_RESET}" +runtime-versioner audit --no-fetch + for runtime_path in \ "rust-runtime" \ "aws/rust-runtime" @@ -30,8 +33,9 @@ do RUSTDOCFLAGS="--cfg docsrs -Dwarnings" cargo +"${RUST_NIGHTLY_VERSION}" doc --no-deps --document-private-items --all-features - echo -e "## ${C_YELLOW}Running 'cargo minimal-versions check' on ${runtime_path}...${C_RESET}" + # Print out the cargo tree with minimal versions for easier debugging + cargo +"${RUST_NIGHTLY_VERSION}" minimal-versions tree || echo "cargo minimal-versions tree failed" cargo +"${RUST_NIGHTLY_VERSION}" minimal-versions check --all-features for crate_path in *; do diff --git a/tools/ci-scripts/check-tools b/tools/ci-scripts/check-tools index afcbce9083f..fc7ced22279 100755 --- a/tools/ci-scripts/check-tools +++ b/tools/ci-scripts/check-tools @@ -26,6 +26,7 @@ test_tool "tools/ci-build/changelogger" "${RUST_STABLE_VERSION}" test_tool "tools/ci-build/crate-hasher" "${RUST_STABLE_VERSION}" test_tool "tools/ci-build/difftags" "${RUST_STABLE_VERSION}" test_tool "tools/ci-build/publisher" "${RUST_STABLE_VERSION}" +test_tool "tools/ci-build/runtime-versioner" "${RUST_STABLE_VERSION}" test_tool "tools/ci-build/sdk-lints" "${RUST_STABLE_VERSION}" test_tool "tools/ci-build/sdk-versioner" "${RUST_STABLE_VERSION}" test_tool "tools/ci-build/smithy-rs-tool-common" "${RUST_STABLE_VERSION}" diff --git a/tools/ci-scripts/configure-tls/configure-badssl b/tools/ci-scripts/configure-tls/configure-badssl index f0b04951cbc..05d2a9a412f 100755 --- a/tools/ci-scripts/configure-tls/configure-badssl +++ b/tools/ci-scripts/configure-tls/configure-badssl @@ -6,20 +6,23 @@ set -euxo pipefail -perl -p -i -e 's/ruby2\.4/ruby2.6/' Dockerfile +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + + +cp "$DIR/new-badssl-dockerfile" Dockerfile grep -q 'start of badssl\.test hosts' /etc/hosts || make list-hosts | sudo tee -a /etc/hosts -# badssl fails to create dh480.pem on our Ubuntu host. -# Create it manually inside the docker container. -sed -i '/CMD /i \ -RUN echo "-----BEGIN DH PARAMETERS-----" >/var/www/badssl/_site/certs/sets/current/gen/dhparam/dh480.pem \ -RUN echo "MEICPQDZ/YFp3iEs3/k9iRGoC/5/To2+5pUF/C6GkO6VjXHHyRVy68I0rI0q7IAq" >>/var/www/badssl/_site/certs/sets/current/gen/dhparam/dh480.pem \ -RUN echo "VyyGQ7/5Q/Iu0QQnHT4X9uMCAQI=" >>/var/www/badssl/_site/certs/sets/current/gen/dhparam/dh480.pem \ -RUN echo "-----END DH PARAMETERS-----" >>/var/www/badssl/_site/certs/sets/current/gen/dhparam/dh480.pem \ -' Dockerfile + +# we manually create this in the dockerfile. Tell the makefile not to bother to generate it. sed -i '/ 480/c \\ttrue' certs/Makefile # badssl does not create an expired certificate; # it creates a certificate that expires after 1 day and waits for 1 day to run the "expired certificate" test. # This command patches this behavior to run the test immediately. # See: https://github.com/chromium/badssl.com/blob/df8d5a9d062f4b99fc19d8aacdea5333b399d624/certs/Makefile#L177 sed -i 's%./tool sign $@ $(D) 1 sha256 req_v3_usr $^%faketime -f "-2d" ./tool sign $@ $(D) 1 sha256 req_v3_usr $^%' certs/Makefile -screen -dmS badssl sudo make serve +# there is a command "make serve" We don't want to actually run that because we want to error out early on `docker build` +sudo make certs-test +sudo make docker-build + +# manually invoke the "serve" part of things +# if things are broken, try removing the screen session to see any failure logs. +screen -dmS badssl sudo docker run -t -p 80:80 -p 443:443 -p 1000-1024:1000-1024 badssl diff --git a/tools/ci-scripts/configure-tls/new-badssl-dockerfile b/tools/ci-scripts/configure-tls/new-badssl-dockerfile new file mode 100644 index 00000000000..369b3e894b1 --- /dev/null +++ b/tools/ci-scripts/configure-tls/new-badssl-dockerfile @@ -0,0 +1,88 @@ +# Why does this file exist? +# badssl seems to be abandoned. The orginal Dockerfile was based on ubuntu 16.04 and all the bits were rotting. +# I've updated the Dockerfilet l to ubuntu 22.04 which will hopefully let everything limp along a little longer. +FROM ubuntu:22.04 as nginx +# Install necessary packages for building NGINX +RUN apt-get update && apt-get install -y \ + build-essential \ + libpcre3 \ + libpcre3-dev \ + zlib1g \ + zlib1g-dev \ + wget + +# Define NGINX version (this is the old version from ubuntu 16.04 to match) +ARG NGINX_VERSION=1.14.2 +ARG OPEN_SSL_VERSION=1.0.2g + +RUN wget https://www.openssl.org/source/openssl-${OPEN_SSL_VERSION}.tar.gz \ + && tar -xzvf openssl-${OPEN_SSL_VERSION}.tar.gz + +# Download NGINX source code +RUN wget http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz \ + && tar -xzvf nginx-$NGINX_VERSION.tar.gz \ + && cd nginx-$NGINX_VERSION + + +# Configure NGINX before building it +RUN cd nginx-$NGINX_VERSION \ + && ./configure \ + --prefix=/usr/local/nginx \ + --with-http_ssl_module \ + --with-openssl=../openssl-${OPEN_SSL_VERSION} \ + --with-openssl-opt=enable-weak-ssl-ciphers \ + --with-stream \ + --with-threads \ + && make -j 6 \ + && make install -j 6 + +RUN /usr/local/nginx/sbin/nginx -V + +FROM ubuntu:22.04 + +EXPOSE 80 443 +RUN apt-get update && apt-get install -y apt-transport-https +RUN apt-get install -y software-properties-common +RUN apt-get update && apt-get install -y \ + build-essential \ + git \ + libffi-dev \ + make \ + ruby3.0 \ + ruby3.0-dev +#RUN gem update --system +RUN gem install jekyll + +COPY --from=nginx /usr/local/nginx /usr/local/nginx +ENV PATH="/usr/local/nginx/sbin:${PATH}" + +# Install badssl.com +ADD . badssl.com +WORKDIR badssl.com + +RUN sed -i 's/SECLEVEL=2/SECLEVEL=0/' /etc/ssl/openssl.cnf +RUN tail -n10 /etc/ssl/openssl.cnf + +RUN nginx -V +RUN mkdir /etc/nginx +# `make-in-docker` requires this file to exist. +RUN ln -s /usr/local/nginx/conf/nginx.conf /etc/nginx/nginx.conf + +# Update the nginx config to include the badssl configs. +RUN head -n-1 /etc/nginx/nginx.conf > wip.conf +RUN echo "# Virtual Host Configs\ninclude /var/www/badssl/_site/nginx.conf;\n}" >> wip.conf +RUN mv wip.conf /usr/local/nginx/conf/nginx.conf +RUN make inside-docker + +# Allow unsecure certs +RUN sed -i 's/SECLEVEL=2/SECLEVEL=0/' /etc/ssl/openssl.cnf + +# Fix DH key that can't be generated...works in docker bug not on github. Who knows. +RUN echo "-----BEGIN DH PARAMETERS-----" > /var/www/badssl/_site/certs/sets/current/gen/dhparam/dh480.pem +RUN echo "MEICPQDZ/YFp3iEs3/k9iRGoC/5/To2+5pUF/C6GkO6VjXHHyRVy68I0rI0q7IAq" >> /var/www/badssl/_site/certs/sets/current/gen/dhparam/dh480.pem +RUN echo "VyyGQ7/5Q/Iu0QQnHT4X9uMCAQI=" >> /var/www/badssl/_site/certs/sets/current/gen/dhparam/dh480.pem +RUN echo "-----END DH PARAMETERS-----" >> /var/www/badssl/_site/certs/sets/current/gen/dhparam/dh480.pem + +RUN nginx -t +# Start things up! +CMD nginx && tail -f /usr/local/nginx/logs/access.log /usr/local/nginx/logs/error.log diff --git a/tools/echo-server/Cargo.lock b/tools/echo-server/Cargo.lock index fd152095120..1894c3dd975 100644 --- a/tools/echo-server/Cargo.lock +++ b/tools/echo-server/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -19,18 +19,18 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "async-trait" -version = "0.1.72" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", @@ -92,9 +92,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -113,15 +113,18 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -141,6 +144,12 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fnv" version = "1.0.7" @@ -149,45 +158,45 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-core", "futures-task", @@ -197,15 +206,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -222,21 +231,21 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -268,9 +277,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" @@ -289,7 +298,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -298,11 +307,11 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ - "autocfg", + "equivalent", "hashbrown", ] @@ -320,15 +329,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -336,9 +345,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "matchers" @@ -357,9 +366,9 @@ checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "mime" @@ -378,9 +387,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", @@ -409,18 +418,18 @@ dependencies = [ [[package]] name = "object" -version = "0.31.1" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "overload" @@ -440,9 +449,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", @@ -453,24 +462,24 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", @@ -479,9 +488,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -491,41 +500,41 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.9.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.3", - "regex-syntax 0.7.4", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -539,13 +548,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.8.2", ] [[package]] @@ -556,9 +565,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustc-demangle" @@ -580,15 +589,29 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.176" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76dc28c9523c5d70816e393136b86d48909cfb27cecaa902d338c19ed47164dc" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -609,9 +632,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -627,34 +650,44 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", ] +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "syn" -version = "2.0.27" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -679,11 +712,10 @@ dependencies = [ [[package]] name = "tokio" -version = "1.29.1" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", @@ -692,16 +724,16 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.5", "tokio-macros", "windows-sys", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", @@ -710,9 +742,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -771,11 +803,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -784,9 +815,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", @@ -795,9 +826,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -805,20 +836,20 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -834,15 +865,15 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "valuable" @@ -898,9 +929,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -913,42 +944,42 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" From a081c6dbe09f98454287fd91d32e31d84781257e Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 23 Jan 2024 00:37:25 +0000 Subject: [PATCH 312/312] modified: codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt modified: codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt modified: codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt --- .../client/smithy/customize/SerdeDecorator.kt | 67 ++++++++++++++----- .../core/smithy/generators/LibRsGenerator.kt | 12 ++++ .../smithy/generators/BuilderGeneratorTest.kt | 2 +- 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt index 3190f20b65a..108b4687820 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customize/SerdeDecorator.kt @@ -6,15 +6,22 @@ package software.amazon.smithy.rust.codegen.client.smithy.customize import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext +import software.amazon.smithy.rust.codegen.core.rustlang.containerDocs import software.amazon.smithy.rust.codegen.core.rustlang.Feature +import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter +import software.amazon.smithy.rust.codegen.core.rustlang.Writable +import software.amazon.smithy.rust.codegen.core.rustlang.writable import software.amazon.smithy.rust.codegen.core.smithy.RustCrate +import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization +import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection +import software.amazon.smithy.rust.codegen.core.smithy.generators.ModuleDocSection /** * Decorator that adds the `serde-serialize` and `serde-deserialize` features. */ class SerdeDecorator : ClientCodegenDecorator { override val name: String = "SerdeDecorator" - override val order: Byte = -1 + override val order: Byte = 5 override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) { fun feature(featureName: String): Feature { @@ -22,31 +29,55 @@ class SerdeDecorator : ClientCodegenDecorator { } rustCrate.mergeFeature(feature("serde-serialize")) rustCrate.mergeFeature(feature("serde-deserialize")) + + } + + override fun libRsCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List + ): List { + return baseCustomizations + SerdeDocGenerator(codegenContext) } +} - // I initially tried to implement with LibRsCustomization, but it didn't work somehow. - companion object { - const val SerdeInfoText = """ +class SerdeDocGenerator(private val codegenContext: ClientCodegenContext) : LibRsCustomization() { + override fun section(section: LibRsSection): Writable { + return when (section) { + is LibRsSection.ModuleDoc-> + if (section.subsection is ModuleDocSection.AWSSdkUnstable) { + serdeInfoText() + } else { + emptySection + } - ## How to enable `Serialize` and `Deserialize` + else -> emptySection + } + } - This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, - but those traits are behind feature gate. + private fun serdeInfoText(): Writable { + return writable { + containerDocs( + """ + ## How to enable `Serialize` and `Deserialize` - As they increase it's compile time dramatically, you should not turn them on unless it's necessary. - Furthermore, implementation of serde is still unstable, and implementation may change anytime in future. + This data type implements `Serialize` and `Deserialize` traits from the popular serde crate, but those traits are behind feature gate. - To enable traits, you must pass `aws_sdk_unstable` to RUSTFLAGS and enable `serde-serialize` or `serde-deserialize` feature. + As they increase it's compile time dramatically, you should not turn them on unless it's necessary. + Implementation of `serde` traits in AWS SDK for Rust is still unstable, and implementation may change anytime in future. - e.g. - ```bash,no_run - export RUSTFLAGS="--cfg aws_sdk_unstable" - cargo build --features serde-serialize serde-deserialize - ``` + To enable traits, you must pass `aws_sdk_unstable` to RUSTFLAGS and enable `serde-serialize` or `serde-deserialize` feature. - If you enable `serde-serialize` and/or `serde-deserialize` without `RUSTFLAGS="--cfg aws_sdk_unstable"`, - compilation will fail with warning. + e.g. + ```bash,no_run + export RUSTFLAGS="--cfg aws_sdk_unstable" + cargo build --features serde-serialize serde-deserialize + ``` - """ + If you enable `serde-serialize` and/or `serde-deserialize` without `RUSTFLAGS="--cfg aws_sdk_unstable"`, + compilation will fail with warning. + + """.trimIndent() + ) + } } } diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt index 85fc05ee985..dafb7476354 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/LibRsGenerator.kt @@ -25,6 +25,8 @@ sealed class ModuleDocSection { object CrateOrganization : ModuleDocSection() object Examples : ModuleDocSection() + + object AWSSdkUnstable : ModuleDocSection() } sealed class LibRsSection(name: String) : Section(name) { @@ -77,6 +79,16 @@ class LibRsGenerator( } } + docSection(ModuleDocSection.AWSSdkUnstable).also { docs -> + if (docs.isNotEmpty()) { + containerDocs("\n## Enabling Unstable Features") + docs.forEach { writeTo -> + writeTo(this) + } + } + } + + // Examples docSection(ModuleDocSection.Examples).also { docs -> if (docs.isNotEmpty() || settings.examplesUri != null) { diff --git a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt index 179b89512dc..c65c9077b75 100644 --- a/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt +++ b/codegen-core/src/test/kotlin/software/amazon/smithy/rust/codegen/core/smithy/generators/BuilderGeneratorTest.kt @@ -184,7 +184,7 @@ internal class BuilderGeneratorTest { Assertions.assertFalse(file.contains("serde::")) } } - + @Test fun `it supports nonzero defaults`() { val model =

Provides authorization for Amazon to bring an Autonomous System Number (ASN) to a specific Amazon Web Services account using bring your own ASN (BYOASN). \n For details on the format of the message and signature, see Tutorial: Bring your ASN to IPAM in the Amazon VPC IPAM guide.