Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create an Unhandled error new-type #1849

Merged
merged 3 commits into from
Nov 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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