Skip to content

Commit

Permalink
Add a code generated Unhandled error
Browse files Browse the repository at this point in the history
  • Loading branch information
jdisanti committed Oct 28, 2022
1 parent 9b2bd36 commit b3a2b6c
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ class CombinedErrorGenerator(
rust(
"""
/// An unexpected error, e.g. invalid JSON returned by the service or an unknown error code
Unhandled(Box<dyn #T + Send + Sync + 'static>),
Unhandled(#T),
""",
RuntimeType.StdError,
unhandledError(),
)
}
writer.rustBlock("impl #T for ${errorSymbol.name}", RuntimeType.Display) {
Expand Down Expand Up @@ -215,7 +215,7 @@ class CombinedErrorGenerator(
/// Creates the `${errorSymbol.name}::Unhandled` variant from any error type.
pub fn unhandled(err: impl Into<Box<dyn #{std_error} + Send + Sync + 'static>>) -> Self {
Self {
kind: ${errorSymbol.name}Kind::Unhandled(err.into()),
kind: ${errorSymbol.name}Kind::Unhandled(#{Unhandled}::new(err.into())),
meta: Default::default()
}
}
Expand All @@ -224,7 +224,7 @@ class CombinedErrorGenerator(
pub fn generic(err: #{generic_error}) -> Self {
Self {
meta: err.clone(),
kind: ${errorSymbol.name}Kind::Unhandled(err.into()),
kind: ${errorSymbol.name}Kind::Unhandled(#{Unhandled}::new(err.into())),
}
}
Expand All @@ -249,7 +249,9 @@ class CombinedErrorGenerator(
self.meta.code()
}
""",
"generic_error" to genericError, "std_error" to RuntimeType.StdError,
"generic_error" to genericError,
"std_error" to RuntimeType.StdError,
"Unhandled" to unhandledError(),
)
errors.forEach { error ->
val errorVariantSymbol = symbolProvider.toSymbol(error)
Expand All @@ -265,10 +267,7 @@ class CombinedErrorGenerator(
rustBlock("fn source(&self) -> Option<&(dyn #T + 'static)>", RuntimeType.StdError) {
delegateToVariants(errors, errorSymbol) {
writable {
when (it) {
is VariantMatch.Unhandled -> rust("Some(_inner.as_ref())")
is VariantMatch.Modeled -> rust("Some(_inner)")
}
rust("Some(_inner)")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.documentShape
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.smithy.CodegenContext
import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
Expand Down Expand Up @@ -92,17 +93,17 @@ class TopLevelErrorGenerator(private val codegenContext: CodegenContext, private
}
}

private fun RustWriter.renderImplFrom(symbol: RuntimeType, errors: List<ShapeId>) {
private fun RustWriter.renderImplFrom(errorSymbol: RuntimeType, errors: List<ShapeId>) {
if (errors.isNotEmpty() || CodegenTarget.CLIENT == codegenContext.target) {
rustBlock(
"impl<R> From<#T<#T, R>> for Error where R: Send + Sync + std::fmt::Debug + 'static",
sdkError,
symbol,
errorSymbol,
) {
rustBlockTemplate(
"fn from(err: #{SdkError}<#{OpError}, R>) -> Self",
"SdkError" to sdkError,
"OpError" to symbol,
"OpError" to errorSymbol,
) {
rustBlock("match err") {
val operationErrors = errors.map { model.expectShape(it) }
Expand All @@ -111,12 +112,16 @@ class TopLevelErrorGenerator(private val codegenContext: CodegenContext, private
val errSymbol = symbolProvider.toSymbol(errorShape)
rust(
"#TKind::${errSymbol.name}(inner) => Error::${errSymbol.name}(inner),",
symbol,
errorSymbol,
)
}
rust("#TKind::Unhandled(inner) => Error::Unhandled(inner),", symbol)
rustTemplate(
"#{errorSymbol}Kind::Unhandled(inner) => Error::Unhandled(#{unhandled}::new(inner.into())),",
"errorSymbol" to errorSymbol,
"unhandled" to unhandledError(),
)
}
rust("_ => Error::Unhandled(err.into()),")
rust("_ => Error::Unhandled(#T::new(err.into())),", unhandledError())
}
}
}
Expand All @@ -137,7 +142,7 @@ class TopLevelErrorGenerator(private val codegenContext: CodegenContext, private
rust("${sym.name}(#T),", sym)
}
rust("/// An unhandled error occurred.")
rust("Unhandled(Box<dyn #T + Send + Sync + 'static>)", RuntimeType.StdError)
rust("Unhandled(#T)", unhandledError())
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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.error

import software.amazon.smithy.rust.codegen.core.rustlang.RustModule
import software.amazon.smithy.rust.codegen.core.rustlang.docs
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.smithy.RuntimeType

internal fun unhandledError(): RuntimeType = RuntimeType.forInlineFun("Unhandled", RustModule.Error) {
docs(
"""
An unexpected error occurred (e.g., invalid JSON returned by the service or an unknown error code)
Call [`Error::source`](std::error::Error::source) for more details about the underlying cause.
""",
)
rust("##[derive(Debug)]")
rustBlock("pub struct Unhandled") {
rust("source: Box<dyn #T + Send + Sync + 'static>", RuntimeType.StdError)
}
rustBlock("impl Unhandled") {
rustBlock("pub(crate) fn new(source: Box<dyn #T + Send + Sync + 'static>) -> Self", RuntimeType.StdError) {
rust("Self { source }")
}
}
rustBlock("impl std::fmt::Display for Unhandled") {
rustBlock("fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error>") {
rust("write!(f, \"unhandled error\")")
}
}
rustBlock("impl std::error::Error for Unhandled") {
rustBlock("fn source(&self) -> Option<&(dyn std::error::Error + 'static)>") {
rust("Some(self.source.as_ref() as _)")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,9 @@ class EventStreamUnmarshallerGeneratorTest {
assert!(result.is_ok(), "expected ok, got: {:?}", result);
match expect_error(result.unwrap())$kindSuffix {
TestStreamErrorKind::Unhandled(err) => {
assert!(format!("{}", err).contains("message: \"unmodeled error\""));
let message = format!("{}", aws_smithy_types::error::display::DisplayErrorContext(&err));
let expected = "message: \"unmodeled error\"";
assert!(message.contains(expected), "Expected '{message}' to contain '{expected}'");
}
kind => panic!("expected generic error, but got {:?}", kind),
}
Expand Down

0 comments on commit b3a2b6c

Please sign in to comment.