Skip to content

Commit

Permalink
Improve RustDocs for constrained types
Browse files Browse the repository at this point in the history
* We decided not to generate `parse` method in #1342.
* Fix link to `try_from` constructor.
* Always mention the type is the result of a constrained shape, even if
  the shape has no documentation.
  • Loading branch information
david-perez committed Dec 13, 2022
1 parent 30c6828 commit e2bf09f
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 23 deletions.
Expand Up @@ -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)
Expand Down
Expand Up @@ -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(
"""
Expand Down
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
Expand Up @@ -71,7 +71,7 @@ class ConstrainedNumberGenerator(
val rangeTrait = shape.expectTrait<RangeTrait>()

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))
Expand All @@ -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
Expand All @@ -115,7 +116,7 @@ class ConstrainedNumberGenerator(
}
}
impl #{ConstrainedTrait} for $constrainedTypeName {
impl #{ConstrainedTrait} for $name {
type Unconstrained = $unconstrainedTypeName;
}
Expand All @@ -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()
}
}
Expand All @@ -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(
Expand Down
Expand Up @@ -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."
Expand Down
Expand Up @@ -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) {
Expand Down

0 comments on commit e2bf09f

Please sign in to comment.