Loading codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt +3 −4 Original line number Diff line number Diff line Loading @@ -327,10 +327,9 @@ class ServerProtocolTestGenerator( rustWriter.rust( """ let extensions = http_request.extensions().expect("unable to extract http request extensions"); let namespace = extensions.get::<aws_smithy_http_server::ExtensionNamespace>().expect("extension ExtensionNamespace not found"); assert_eq!(**namespace, ${operationShape.id.getNamespace().dq()}); let operation_name = extensions.get::<aws_smithy_http_server::ExtensionOperationName>().expect("extension ExtensionOperationName not found"); assert_eq!(**operation_name, ${operationSymbol.name.dq()}); let request_extensions = extensions.get::<aws_smithy_http_server::RequestExtensions>().expect("extension RequestExtensions not found"); assert_eq!(request_extensions.namespace, ${operationShape.id.getNamespace().dq()}); assert_eq!(request_extensions.operation_name, ${operationSymbol.name.dq()}); """.trimIndent() ) } Loading codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpProtocolGenerator.kt +39 −22 Original line number Diff line number Diff line Loading @@ -316,8 +316,7 @@ private class ServerHttpProtocolImplGenerator( val operationName = symbolProvider.toSymbol(operationShape).name return """ let extensions = req.extensions_mut().ok_or(#{SmithyHttpServer}::rejection::ExtensionsAlreadyExtracted)?; extensions.insert(#{SmithyHttpServer}::ExtensionNamespace::new(${namespace.dq()})); extensions.insert(#{SmithyHttpServer}::ExtensionOperationName::new(${operationName.dq()})); extensions.insert(#{SmithyHttpServer}::RequestExtensions::new(${namespace.dq()}, ${operationName.dq()})); """.trimIndent() } Loading Loading @@ -640,11 +639,13 @@ private class ServerHttpProtocolImplGenerator( } else if (targetMapValue.isSetShape) { QueryParamsTargetMapValueType.SET } else { throw ExpectationNotMetException(""" throw ExpectationNotMetException( """ @httpQueryParams trait applied to non-supported target $targetMapValue of type ${targetMapValue.type} """.trimIndent(), targetMapValue.sourceLocation) targetMapValue.sourceLocation ) } private fun serverRenderQueryStringParser(writer: RustWriter, operationShape: OperationShape) { Loading @@ -669,7 +670,8 @@ private class ServerHttpProtocolImplGenerator( } with(writer) { rustTemplate(""" rustTemplate( """ let query_string = request.uri().query().ok_or(#{SmithyHttpServer}::rejection::MissingQueryString)?; let pairs = #{SerdeUrlEncoded}::from_str::<Vec<(&str, &str)>>(query_string)?; """.trimIndent(), Loading @@ -677,7 +679,8 @@ private class ServerHttpProtocolImplGenerator( ) if (queryParamsBinding != null) { rustTemplate("let mut query_params: #{HashMap}<String, " + rustTemplate( "let mut query_params: #{HashMap}<String, " + "${queryParamsBinding.queryParamsBindingTargetMapValueType().asRustType().render()}> = #{HashMap}::new();", "HashMap" to RustType.HashMap.RuntimeType, ) Loading @@ -694,7 +697,8 @@ private class ServerHttpProtocolImplGenerator( rustBlock("for (k, v) in pairs") { queryBindingsTargettingSimple.forEach { val deserializer = generateParsePercentEncodedStrFn(it) rustTemplate(""" rustTemplate( """ if !seen_${it.memberName.toSnakeCase()} && k == "${it.locationName}" { input = input.${it.member.setterName()}( #{deserializer}(v)? Loading @@ -702,7 +706,8 @@ private class ServerHttpProtocolImplGenerator( seen_${it.memberName.toSnakeCase()} = true; } """.trimIndent(), "deserializer" to deserializer) "deserializer" to deserializer ) } queryBindingsTargettingCollection.forEach { rustBlock("if k == ${it.locationName.dq()}") { Loading @@ -714,9 +719,12 @@ private class ServerHttpProtocolImplGenerator( // `<_>::from()` is necessary to convert the `&str` into: // * the Rust enum in case the `string` shape has the `enum` trait; or // * `String` in case it doesn't. rustTemplate(""" rustTemplate( """ let v = <_>::from(#{PercentEncoding}::percent_decode_str(v).decode_utf8()?.as_ref()); """.trimIndent(), *codegenScope) """.trimIndent(), *codegenScope ) } memberShape.isTimestampShape -> { val index = HttpBindingIndex.of(model) Loading @@ -727,7 +735,8 @@ private class ServerHttpProtocolImplGenerator( protocol.defaultTimestampFormat, ) val timestampFormatType = RuntimeType.TimestampFormat(runtimeConfig, timestampFormat) rustTemplate(""" rustTemplate( """ let v = #{PercentEncoding}::percent_decode_str(v).decode_utf8()?; let v = #{DateTime}::from_str(&v, #{format})?; """.trimIndent(), Loading @@ -736,9 +745,12 @@ private class ServerHttpProtocolImplGenerator( ) } else -> { // Number or boolean. rust(""" rust( """ let v = <_ as #T>::parse_smithy_primitive(v)?; """.trimIndent(), CargoDependency.SmithyTypes(runtimeConfig).asType().member("primitive::Parse")) """.trimIndent(), CargoDependency.SmithyTypes(runtimeConfig).asType().member("primitive::Parse") ) } } rust("${it.memberName.toSnakeCase()}.push(v);") Loading @@ -750,10 +762,12 @@ private class ServerHttpProtocolImplGenerator( QueryParamsTargetMapValueType.STRING -> { rust("query_params.entry(String::from(k)).or_insert_with(|| String::from(v));") } else -> { rustTemplate(""" rustTemplate( """ let entry = query_params.entry(String::from(k)).or_default(); entry.push(String::from(v)); """.trimIndent()) """.trimIndent() ) } } } Loading @@ -762,9 +776,11 @@ private class ServerHttpProtocolImplGenerator( rust("input = input.${queryParamsBinding.member.setterName()}(Some(query_params));") } queryBindingsTargettingCollection.forEach { rustTemplate(""" rustTemplate( """ input = input.${it.member.setterName()}(Some(${it.memberName.toSnakeCase()})); """.trimIndent()) """.trimIndent() ) } } } Loading Loading @@ -810,7 +826,8 @@ private class ServerHttpProtocolImplGenerator( // `<_>::from()` is necessary to convert the `&str` into: // * the Rust enum in case the `string` shape has the `enum` trait; or // * `String` in case it doesn't. rustTemplate(""" rustTemplate( """ let value = <_>::from(#{PercentEncoding}::percent_decode_str(value).decode_utf8()?.as_ref()); Ok(Some(value)) """.trimIndent(), Loading rust-runtime/aws-smithy-http-server/rustfmt.toml +0 −6 Original line number Diff line number Diff line edition = "2018" max_width = 120 # The "Default" setting has a heuristic which splits lines too aggresively. # We are willing to revisit this setting in future versions of rustfmt. # Bugs: # * https://github.com/rust-lang/rustfmt/issues/3119 # * https://github.com/rust-lang/rustfmt/issues/3120 use_small_heuristics = "Max" # Prevent carriage returns newline_style = "Unix" rust-runtime/aws-smithy-http-server/src/extension.rs +22 −8 Original line number Diff line number Diff line Loading @@ -39,15 +39,29 @@ use async_trait::async_trait; use axum_core::extract::{FromRequest, RequestParts}; use std::ops::Deref; /// Extension type used to store the Smithy model namespace. #[derive(Debug, Clone)] pub struct ExtensionNamespace(&'static str); impl_extension_new_and_deref!(ExtensionNamespace); /// Extension type used to store Smithy request information. #[derive(Debug, Clone, Default, Copy)] pub struct RequestExtensions { /// Smithy model namespace. pub namespace: &'static str, /// Smithy operation name. pub operation_name: &'static str, } /// Extension type used to store the Smithy operation name. #[derive(Debug, Clone)] pub struct ExtensionOperationName(&'static str); impl_extension_new_and_deref!(ExtensionOperationName); impl RequestExtensions { /// Generates a new `RequestExtensions`. pub fn new(namespace: &'static str, operation_name: &'static str) -> Self { Self { namespace, operation_name, } } /// Returns the current operation formatted as <namespace>#<operation_name>. pub fn operation(&self) -> String { format!("{}#{}", self.namespace, self.operation_name) } } /// Extension type used to store the type of user defined error returned by an operation. /// These are modeled errors, defined in the Smithy model. Loading rust-runtime/aws-smithy-http-server/src/lib.rs +1 −3 Original line number Diff line number Diff line Loading @@ -24,9 +24,7 @@ pub use self::body::{boxed, to_boxed, Body, BoxBody, HttpBody}; #[doc(inline)] pub use self::error::Error; #[doc(inline)] pub use self::extension::{ Extension, ExtensionModeledError, ExtensionNamespace, ExtensionOperationName, ExtensionRejection, }; pub use self::extension::{Extension, ExtensionModeledError, ExtensionRejection, RequestExtensions}; #[doc(inline)] pub use self::routing::Router; #[doc(inline)] Loading Loading
codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt +3 −4 Original line number Diff line number Diff line Loading @@ -327,10 +327,9 @@ class ServerProtocolTestGenerator( rustWriter.rust( """ let extensions = http_request.extensions().expect("unable to extract http request extensions"); let namespace = extensions.get::<aws_smithy_http_server::ExtensionNamespace>().expect("extension ExtensionNamespace not found"); assert_eq!(**namespace, ${operationShape.id.getNamespace().dq()}); let operation_name = extensions.get::<aws_smithy_http_server::ExtensionOperationName>().expect("extension ExtensionOperationName not found"); assert_eq!(**operation_name, ${operationSymbol.name.dq()}); let request_extensions = extensions.get::<aws_smithy_http_server::RequestExtensions>().expect("extension RequestExtensions not found"); assert_eq!(request_extensions.namespace, ${operationShape.id.getNamespace().dq()}); assert_eq!(request_extensions.operation_name, ${operationSymbol.name.dq()}); """.trimIndent() ) } Loading
codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpProtocolGenerator.kt +39 −22 Original line number Diff line number Diff line Loading @@ -316,8 +316,7 @@ private class ServerHttpProtocolImplGenerator( val operationName = symbolProvider.toSymbol(operationShape).name return """ let extensions = req.extensions_mut().ok_or(#{SmithyHttpServer}::rejection::ExtensionsAlreadyExtracted)?; extensions.insert(#{SmithyHttpServer}::ExtensionNamespace::new(${namespace.dq()})); extensions.insert(#{SmithyHttpServer}::ExtensionOperationName::new(${operationName.dq()})); extensions.insert(#{SmithyHttpServer}::RequestExtensions::new(${namespace.dq()}, ${operationName.dq()})); """.trimIndent() } Loading Loading @@ -640,11 +639,13 @@ private class ServerHttpProtocolImplGenerator( } else if (targetMapValue.isSetShape) { QueryParamsTargetMapValueType.SET } else { throw ExpectationNotMetException(""" throw ExpectationNotMetException( """ @httpQueryParams trait applied to non-supported target $targetMapValue of type ${targetMapValue.type} """.trimIndent(), targetMapValue.sourceLocation) targetMapValue.sourceLocation ) } private fun serverRenderQueryStringParser(writer: RustWriter, operationShape: OperationShape) { Loading @@ -669,7 +670,8 @@ private class ServerHttpProtocolImplGenerator( } with(writer) { rustTemplate(""" rustTemplate( """ let query_string = request.uri().query().ok_or(#{SmithyHttpServer}::rejection::MissingQueryString)?; let pairs = #{SerdeUrlEncoded}::from_str::<Vec<(&str, &str)>>(query_string)?; """.trimIndent(), Loading @@ -677,7 +679,8 @@ private class ServerHttpProtocolImplGenerator( ) if (queryParamsBinding != null) { rustTemplate("let mut query_params: #{HashMap}<String, " + rustTemplate( "let mut query_params: #{HashMap}<String, " + "${queryParamsBinding.queryParamsBindingTargetMapValueType().asRustType().render()}> = #{HashMap}::new();", "HashMap" to RustType.HashMap.RuntimeType, ) Loading @@ -694,7 +697,8 @@ private class ServerHttpProtocolImplGenerator( rustBlock("for (k, v) in pairs") { queryBindingsTargettingSimple.forEach { val deserializer = generateParsePercentEncodedStrFn(it) rustTemplate(""" rustTemplate( """ if !seen_${it.memberName.toSnakeCase()} && k == "${it.locationName}" { input = input.${it.member.setterName()}( #{deserializer}(v)? Loading @@ -702,7 +706,8 @@ private class ServerHttpProtocolImplGenerator( seen_${it.memberName.toSnakeCase()} = true; } """.trimIndent(), "deserializer" to deserializer) "deserializer" to deserializer ) } queryBindingsTargettingCollection.forEach { rustBlock("if k == ${it.locationName.dq()}") { Loading @@ -714,9 +719,12 @@ private class ServerHttpProtocolImplGenerator( // `<_>::from()` is necessary to convert the `&str` into: // * the Rust enum in case the `string` shape has the `enum` trait; or // * `String` in case it doesn't. rustTemplate(""" rustTemplate( """ let v = <_>::from(#{PercentEncoding}::percent_decode_str(v).decode_utf8()?.as_ref()); """.trimIndent(), *codegenScope) """.trimIndent(), *codegenScope ) } memberShape.isTimestampShape -> { val index = HttpBindingIndex.of(model) Loading @@ -727,7 +735,8 @@ private class ServerHttpProtocolImplGenerator( protocol.defaultTimestampFormat, ) val timestampFormatType = RuntimeType.TimestampFormat(runtimeConfig, timestampFormat) rustTemplate(""" rustTemplate( """ let v = #{PercentEncoding}::percent_decode_str(v).decode_utf8()?; let v = #{DateTime}::from_str(&v, #{format})?; """.trimIndent(), Loading @@ -736,9 +745,12 @@ private class ServerHttpProtocolImplGenerator( ) } else -> { // Number or boolean. rust(""" rust( """ let v = <_ as #T>::parse_smithy_primitive(v)?; """.trimIndent(), CargoDependency.SmithyTypes(runtimeConfig).asType().member("primitive::Parse")) """.trimIndent(), CargoDependency.SmithyTypes(runtimeConfig).asType().member("primitive::Parse") ) } } rust("${it.memberName.toSnakeCase()}.push(v);") Loading @@ -750,10 +762,12 @@ private class ServerHttpProtocolImplGenerator( QueryParamsTargetMapValueType.STRING -> { rust("query_params.entry(String::from(k)).or_insert_with(|| String::from(v));") } else -> { rustTemplate(""" rustTemplate( """ let entry = query_params.entry(String::from(k)).or_default(); entry.push(String::from(v)); """.trimIndent()) """.trimIndent() ) } } } Loading @@ -762,9 +776,11 @@ private class ServerHttpProtocolImplGenerator( rust("input = input.${queryParamsBinding.member.setterName()}(Some(query_params));") } queryBindingsTargettingCollection.forEach { rustTemplate(""" rustTemplate( """ input = input.${it.member.setterName()}(Some(${it.memberName.toSnakeCase()})); """.trimIndent()) """.trimIndent() ) } } } Loading Loading @@ -810,7 +826,8 @@ private class ServerHttpProtocolImplGenerator( // `<_>::from()` is necessary to convert the `&str` into: // * the Rust enum in case the `string` shape has the `enum` trait; or // * `String` in case it doesn't. rustTemplate(""" rustTemplate( """ let value = <_>::from(#{PercentEncoding}::percent_decode_str(value).decode_utf8()?.as_ref()); Ok(Some(value)) """.trimIndent(), Loading
rust-runtime/aws-smithy-http-server/rustfmt.toml +0 −6 Original line number Diff line number Diff line edition = "2018" max_width = 120 # The "Default" setting has a heuristic which splits lines too aggresively. # We are willing to revisit this setting in future versions of rustfmt. # Bugs: # * https://github.com/rust-lang/rustfmt/issues/3119 # * https://github.com/rust-lang/rustfmt/issues/3120 use_small_heuristics = "Max" # Prevent carriage returns newline_style = "Unix"
rust-runtime/aws-smithy-http-server/src/extension.rs +22 −8 Original line number Diff line number Diff line Loading @@ -39,15 +39,29 @@ use async_trait::async_trait; use axum_core::extract::{FromRequest, RequestParts}; use std::ops::Deref; /// Extension type used to store the Smithy model namespace. #[derive(Debug, Clone)] pub struct ExtensionNamespace(&'static str); impl_extension_new_and_deref!(ExtensionNamespace); /// Extension type used to store Smithy request information. #[derive(Debug, Clone, Default, Copy)] pub struct RequestExtensions { /// Smithy model namespace. pub namespace: &'static str, /// Smithy operation name. pub operation_name: &'static str, } /// Extension type used to store the Smithy operation name. #[derive(Debug, Clone)] pub struct ExtensionOperationName(&'static str); impl_extension_new_and_deref!(ExtensionOperationName); impl RequestExtensions { /// Generates a new `RequestExtensions`. pub fn new(namespace: &'static str, operation_name: &'static str) -> Self { Self { namespace, operation_name, } } /// Returns the current operation formatted as <namespace>#<operation_name>. pub fn operation(&self) -> String { format!("{}#{}", self.namespace, self.operation_name) } } /// Extension type used to store the type of user defined error returned by an operation. /// These are modeled errors, defined in the Smithy model. Loading
rust-runtime/aws-smithy-http-server/src/lib.rs +1 −3 Original line number Diff line number Diff line Loading @@ -24,9 +24,7 @@ pub use self::body::{boxed, to_boxed, Body, BoxBody, HttpBody}; #[doc(inline)] pub use self::error::Error; #[doc(inline)] pub use self::extension::{ Extension, ExtensionModeledError, ExtensionNamespace, ExtensionOperationName, ExtensionRejection, }; pub use self::extension::{Extension, ExtensionModeledError, ExtensionRejection, RequestExtensions}; #[doc(inline)] pub use self::routing::Router; #[doc(inline)] Loading