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 d78424ec75..185fae1e4a 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 @@ -77,13 +77,21 @@ class ConstraintViolationSymbolProvider( false -> Visibility.PUBCRATE } - private fun Shape.shapeModule() = RustModule.new( - // need to use the context name so we get the correct name for maps - name = RustReservedWords.escapeIfNeeded(this.contextName(serviceShape)).toSnakeCase(), - visibility = visibility, - parent = ModelsModule, - inline = true, - ) + private fun Shape.shapeModule(): RustModule.LeafModule { + val documentation = if (publicConstrainedTypes && this.isDirectlyConstrained(base)) { + "See [`${this.contextName(serviceShape)}`]." + } else { + null + } + return RustModule.new( + // Need to use the context name so we get the correct name for maps. + name = RustReservedWords.escapeIfNeeded(this.contextName(serviceShape)).toSnakeCase(), + visibility = visibility, + parent = ModelsModule, + inline = true, + documentation = documentation, + ) + } private fun constraintViolationSymbolForCollectionOrMapOrUnionShape(shape: Shape): Symbol { check(shape is CollectionShape || shape is MapShape || shape is UnionShape) 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 87b79bab8b..2e472607d0 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 @@ -85,7 +85,8 @@ class ConstrainedCollectionGenerator( "ConstraintViolation" to constraintViolation, ) - writer.documentShape(shape, model, note = rustDocsNote(name)) + writer.documentShape(shape, model) + writer.docs(rustDocsConstrainedTypeEpilogue(name)) constrainedTypeMetadata.render(writer) writer.rustTemplate( """ 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 0ef5cbf924..48cd342058 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 @@ -14,6 +14,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.RustMetadata import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter import software.amazon.smithy.rust.codegen.core.rustlang.Visibility +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.rustTemplate import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType @@ -74,7 +75,8 @@ class ConstrainedMapGenerator( "ConstraintViolation" to constraintViolation, ) - writer.documentShape(shape, model, note = rustDocsNote(name)) + writer.documentShape(shape, model) + writer.docs(rustDocsConstrainedTypeEpilogue(name)) constrainedTypeMetadata.render(writer) writer.rustTemplate("struct $name(pub(crate) $inner);", *codegenScope) if (constrainedTypeVisibility == Visibility.PUBCRATE) { 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 45d368a6a8..ce3ee6aaa9 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 @@ -71,7 +71,7 @@ class ConstrainedNumberGenerator( val rangeTrait = shape.expectTrait() val symbol = constrainedShapeSymbolProvider.toSymbol(shape) - val constrainedTypeName = symbol.name + val name = symbol.name val unconstrainedTypeName = unconstrainedType.render() val constraintViolation = constraintViolationSymbolProvider.toSymbol(shape) val constraintsInfo = listOf(Range(rangeTrait).toTraitInfo(unconstrainedTypeName)) @@ -94,16 +94,17 @@ class ConstrainedNumberGenerator( visibility = constrainedTypeVisibility, ) - writer.documentShape(shape, model, note = rustDocsNote(constrainedTypeName)) + writer.documentShape(shape, model) + writer.docs(rustDocsConstrainedTypeEpilogue(name)) constrainedTypeMetadata.render(writer) - writer.rust("struct $constrainedTypeName(pub(crate) $unconstrainedTypeName);") + writer.rust("struct $name(pub(crate) $unconstrainedTypeName);") if (constrainedTypeVisibility == Visibility.PUBCRATE) { Attribute.AllowUnused.render(writer) } writer.rustTemplate( """ - impl $constrainedTypeName { + impl $name { /// ${rustDocsInnerMethod(unconstrainedTypeName)} pub fn inner(&self) -> &$unconstrainedTypeName { &self.0 @@ -115,7 +116,7 @@ class ConstrainedNumberGenerator( } } - impl #{ConstrainedTrait} for $constrainedTypeName { + impl #{ConstrainedTrait} for $name { type Unconstrained = $unconstrainedTypeName; } @@ -125,14 +126,14 @@ class ConstrainedNumberGenerator( } } - impl #{Display} for $constrainedTypeName { + impl #{Display} for $name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ${shape.redactIfNecessary(model, "self.0")}.fmt(f) } } - impl #{From}<$constrainedTypeName> for $unconstrainedTypeName { - fn from(value: $constrainedTypeName) -> Self { + impl #{From}<$name> for $unconstrainedTypeName { + fn from(value: $name) -> Self { value.into_inner() } } @@ -146,7 +147,7 @@ class ConstrainedNumberGenerator( "AsRef" to RuntimeType.AsRef, ) - writer.renderTryFrom(unconstrainedTypeName, constrainedTypeName, constraintViolation, constraintsInfo) + writer.renderTryFrom(unconstrainedTypeName, name, constraintViolation, constraintsInfo) writer.withInlineModule(constraintViolation.module()) { rust( 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 d0d447cdad..2b6c49abed 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,10 +9,12 @@ package software.amazon.smithy.rust.codegen.server.smithy.generators * Functions shared amongst the constrained shape generators, to keep them DRY and consistent. */ -fun rustDocsNote(typeName: String) = - "this is a constrained type because its corresponding modeled Smithy shape has one or more " + - "[constraint traits]. Use [`parse`] or [`$typeName::TryFrom`] to construct values of this type." + - "[constraint traits]: https://awslabs.github.io/smithy/1.0/spec/core/constraint-traits.html" +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) = "Constructs a `$typeName` from an [`$inner`], failing when the provided value does not satisfy the modeled constraints." 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 18a041eccc..88bebc5050 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 @@ -81,7 +81,8 @@ class ConstrainedStringGenerator( // 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 - writer.documentShape(shape, model, note = rustDocsNote(name)) + writer.documentShape(shape, model) + writer.docs(rustDocsConstrainedTypeEpilogue(name)) constrainedTypeMetadata.render(writer) writer.rust("struct $name(pub(crate) $inner);") if (constrainedTypeVisibility == Visibility.PUBCRATE) {