Skip to content

Commit 551bd22

Browse files
authored
fix: make union associated values non-optional (#281)
1 parent 6aa353e commit 551bd22

File tree

10 files changed

+124
-155
lines changed

10 files changed

+124
-155
lines changed

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/UnionGenerator.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ class UnionGenerator(
5858
writer.writeMemberDocs(model, it)
5959
val enumCaseName = symbolProvider.toMemberName(it)
6060
val enumCaseAssociatedType = symbolProvider.toSymbol(it)
61-
writer.write("case \$L(\$T)", enumCaseName, enumCaseAssociatedType)
61+
writer.write("case \$L(\$L)", enumCaseName, enumCaseAssociatedType)
6262
}
6363
// add the sdkUnknown case which will always be last
64-
writer.write("case sdkUnknown(String?)")
64+
writer.write("case sdkUnknown(String)")
6565
}
6666
writer.removeContext("union.name")
6767
}

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/serde/json/MemberShapeEncodeGenerator.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,4 +259,16 @@ abstract class MemberShapeEncodeGenerator(
259259
writer.write("try $containerName.encode($memberWithExtension, forKey: .\$L)", memberName)
260260
}
261261
}
262+
263+
fun renderEncodeAssociatedType(
264+
target: Shape,
265+
member: MemberShape,
266+
containerName: String
267+
) {
268+
val symbol = ctx.symbolProvider.toSymbol(target)
269+
val memberName = ctx.symbolProvider.toMemberName(member)
270+
val isBoxed = symbol.isBoxed()
271+
val memberWithExtension = getShapeExtension(member, memberName, isBoxed, true)
272+
writer.write("try $containerName.encode($memberWithExtension, forKey: .\$L)", memberName)
273+
}
262274
}

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/serde/json/UnionEncodeGenerator.kt

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,13 @@ class UnionEncodeGenerator(
3030
writer.indent()
3131
when (target) {
3232
is CollectionShape -> {
33-
writer.openBlock("if let \$L = \$L {", "}", memberName, memberName) {
34-
renderEncodeListMember(target, memberName, containerName)
35-
}
33+
renderEncodeListMember(target, memberName, containerName)
3634
}
3735
is MapShape -> {
38-
writer.openBlock("if let \$L = \$L {", "}", memberName, memberName) {
39-
renderEncodeMapMember(target, memberName, containerName)
40-
}
36+
renderEncodeMapMember(target, memberName, containerName)
4137
}
4238
else -> {
43-
renderSimpleEncodeMember(target, member, containerName)
39+
renderEncodeAssociatedType(target, member, containerName)
4440
}
4541
}
4642
writer.dedent()

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/serde/xml/MemberShapeEncodeXMLGenerator.kt

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,19 @@ abstract class MemberShapeEncodeXMLGenerator(
3939
val memberName = ctx.symbolProvider.toMemberName(member)
4040
val resolvedMemberName = XMLNameTraitGenerator.construct(member, originalMemberName)
4141
val nestedContainer = "${memberName}Container"
42-
writer.openBlock("if let $memberName = $memberName {", "}") {
43-
if (member.hasTrait(XmlFlattenedTrait::class.java)) {
44-
writer.openBlock("if $memberName.isEmpty {", "} else {") {
45-
writer.write("var $nestedContainer = $containerName.nestedUnkeyedContainer(forKey: Key(\"$resolvedMemberName\"))")
46-
writer.write("try $nestedContainer.encodeNil()")
47-
}
48-
writer.indent()
49-
renderFlattenedListMemberItems(memberName, member, memberTarget, containerName)
50-
writer.dedent()
51-
writer.write("}")
52-
} else {
53-
writer.write("var $nestedContainer = $containerName.nestedContainer(keyedBy: Key.self, forKey: Key(\"$resolvedMemberName\"))")
54-
XMLNamespaceTraitGenerator.construct(member)?.render(writer, nestedContainer)?.appendKey(xmlNamespaces)
55-
renderListMemberItems(memberName, memberTarget, nestedContainer)
42+
if (member.hasTrait(XmlFlattenedTrait::class.java)) {
43+
writer.openBlock("if $memberName.isEmpty {", "} else {") {
44+
writer.write("var $nestedContainer = $containerName.nestedUnkeyedContainer(forKey: Key(\"$resolvedMemberName\"))")
45+
writer.write("try $nestedContainer.encodeNil()")
5646
}
47+
writer.indent()
48+
renderFlattenedListMemberItems(memberName, member, memberTarget, containerName)
49+
writer.dedent()
50+
writer.write("}")
51+
} else {
52+
writer.write("var $nestedContainer = $containerName.nestedContainer(keyedBy: Key.self, forKey: Key(\"$resolvedMemberName\"))")
53+
XMLNamespaceTraitGenerator.construct(member)?.render(writer, nestedContainer)?.appendKey(xmlNamespaces)
54+
renderListMemberItems(memberName, memberTarget, nestedContainer)
5755
}
5856
}
5957

@@ -162,20 +160,18 @@ abstract class MemberShapeEncodeXMLGenerator(
162160
val memberName = ctx.symbolProvider.toMemberName(member)
163161
val resolvedMemberName = XMLNameTraitGenerator.construct(member, originalMemberName)
164162

165-
writer.openBlock("if let $memberName = $memberName {", "}") {
166-
if (member.hasTrait(XmlFlattenedTrait::class.java)) {
167-
writer.openBlock("if $memberName.isEmpty {", "} else {") {
168-
writer.write("let _ = $containerName.nestedContainer(keyedBy: Key.self, forKey: Key(\"$resolvedMemberName\"))")
169-
}
170-
writer.indent()
171-
renderFlattenedMapMemberItem(memberName, member, memberTarget, containerName)
172-
writer.dedent().write("}")
173-
} else {
174-
val nestedContainer = "${resolvedMemberName}Container"
175-
writer.write("var $nestedContainer = $containerName.nestedContainer(keyedBy: Key.self, forKey: Key(\"$resolvedMemberName\"))")
176-
XMLNamespaceTraitGenerator.construct(member)?.render(writer, nestedContainer)?.appendKey(xmlNamespaces)
177-
renderWrappedMapMemberItem(memberName, memberTarget, nestedContainer)
163+
if (member.hasTrait(XmlFlattenedTrait::class.java)) {
164+
writer.openBlock("if $memberName.isEmpty {", "} else {") {
165+
writer.write("let _ = $containerName.nestedContainer(keyedBy: Key.self, forKey: Key(\"$resolvedMemberName\"))")
178166
}
167+
writer.indent()
168+
renderFlattenedMapMemberItem(memberName, member, memberTarget, containerName)
169+
writer.dedent().write("}")
170+
} else {
171+
val nestedContainer = "${resolvedMemberName}Container"
172+
writer.write("var $nestedContainer = $containerName.nestedContainer(keyedBy: Key.self, forKey: Key(\"$resolvedMemberName\"))")
173+
XMLNamespaceTraitGenerator.construct(member)?.render(writer, nestedContainer)?.appendKey(xmlNamespaces)
174+
renderWrappedMapMemberItem(memberName, memberTarget, nestedContainer)
179175
}
180176
}
181177

@@ -311,20 +307,12 @@ abstract class MemberShapeEncodeXMLGenerator(
311307
}
312308

313309
fun renderTimestampMember(member: MemberShape, memberTarget: TimestampShape, containerName: String) {
314-
val symbol = ctx.symbolProvider.toSymbol(memberTarget)
315-
val originalMemberName = member.memberName
316310
val memberName = ctx.symbolProvider.toMemberName(member)
311+
val originalMemberName = member.memberName
317312
val resolvedMemberName = XMLNameTraitGenerator.construct(member, originalMemberName)
318313
val format = determineTimestampFormat(member, memberTarget, defaultTimestampFormat)
319-
val isBoxed = symbol.isBoxed()
320314
val encodeLine = "try $containerName.encode(TimestampWrapper($memberName, format: .$format), forKey: Key(\"$resolvedMemberName\"))"
321-
if (isBoxed) {
322-
writer.openBlock("if let $memberName = $memberName {", "}") {
323-
writer.write(encodeLine)
324-
}
325-
} else {
326-
writer.write(encodeLine)
327-
}
315+
writer.write(encodeLine)
328316
}
329317

330318
fun renderScalarMember(member: MemberShape, memberTarget: Shape, containerName: String) {
@@ -350,6 +338,14 @@ abstract class MemberShapeEncodeXMLGenerator(
350338
}
351339
}
352340
}
341+
fun renderEncodeAssociatedType(member: MemberShape, memberTarget: Shape, containerName: String) {
342+
val memberName = ctx.symbolProvider.toMemberName(member)
343+
val originalMemberName = member.memberName
344+
val namespaceTraitGenerator = XMLNamespaceTraitGenerator.construct(member)
345+
val resolvedMemberName = XMLNameTraitGenerator.construct(member, originalMemberName).toString()
346+
val nestedContainerName = "${memberName}Container"
347+
renderItem(writer, namespaceTraitGenerator, nestedContainerName, containerName, memberName, memberTarget, resolvedMemberName)
348+
}
353349

354350
private fun renderItem(writer: SwiftWriter, XMLNamespaceTraitGenerator: XMLNamespaceTraitGenerator?, nestedContainerName: String, containerName: String, memberName: String, memberTarget: Shape, resolvedMemberName: String) {
355351
var renderableMemberName = memberName

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/serde/xml/StructEncodeXMLGenerator.kt

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import software.amazon.smithy.model.traits.TimestampFormatTrait
1414
import software.amazon.smithy.swift.codegen.SwiftWriter
1515
import software.amazon.smithy.swift.codegen.integration.ProtocolGenerator
1616
import software.amazon.smithy.swift.codegen.integration.serde.xml.trait.XMLNamespaceTraitGenerator
17+
import software.amazon.smithy.swift.codegen.isBoxed
1718

1819
class StructEncodeXMLGenerator(
1920
private val ctx: ProtocolGenerator.GenerationContext,
@@ -60,15 +61,29 @@ class StructEncodeXMLGenerator(
6061

6162
private fun renderSingleMember(member: MemberShape, containerName: String) {
6263
val memberTarget = ctx.model.expectShape(member.target)
64+
val memberName = ctx.symbolProvider.toMemberName(member)
65+
6366
when (memberTarget) {
6467
is CollectionShape -> {
65-
renderListMember(member, memberTarget, containerName)
68+
writer.openBlock("if let $memberName = $memberName {", "}") {
69+
renderListMember(member, memberTarget, containerName)
70+
}
6671
}
6772
is MapShape -> {
68-
renderMapMember(member, memberTarget, containerName)
73+
writer.openBlock("if let $memberName = $memberName {", "}") {
74+
renderMapMember(member, memberTarget, containerName)
75+
}
6976
}
7077
is TimestampShape -> {
71-
renderTimestampMember(member, memberTarget, containerName)
78+
val symbol = ctx.symbolProvider.toSymbol(memberTarget)
79+
val isBoxed = symbol.isBoxed()
80+
if (isBoxed) {
81+
writer.openBlock("if let $memberName = $memberName {", "}") {
82+
renderTimestampMember(member, memberTarget, containerName)
83+
}
84+
} else {
85+
renderTimestampMember(member, memberTarget, containerName)
86+
}
7287
}
7388
else -> {
7489
renderScalarMember(member, memberTarget, containerName)

smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/serde/xml/UnionEncodeXMLGenerator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class UnionEncodeXMLGenerator(
3737
renderTimestampMember(member, memberTarget, containerName)
3838
}
3939
else -> {
40-
renderScalarMember(member, memberTarget, containerName)
40+
renderEncodeAssociatedType(member, memberTarget, containerName)
4141
}
4242
}
4343
writer.dedent()

smithy-swift-codegen/src/test/kotlin/UnionDecodeGeneratorTests.kt

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -82,47 +82,29 @@ class UnionDecodeGeneratorTests {
8282
var container = encoder.container(keyedBy: CodingKeys.self)
8383
switch self {
8484
case let .blobvalue(blobvalue):
85-
if let blobvalue = blobvalue {
86-
try container.encode(blobvalue.base64EncodedString(), forKey: .blobvalue)
87-
}
85+
try container.encode(blobvalue.base64EncodedString(), forKey: .blobvalue)
8886
case let .booleanvalue(booleanvalue):
89-
if let booleanvalue = booleanvalue {
90-
try container.encode(booleanvalue, forKey: .booleanvalue)
91-
}
87+
try container.encode(booleanvalue, forKey: .booleanvalue)
9288
case let .enumvalue(enumvalue):
93-
if let enumvalue = enumvalue {
94-
try container.encode(enumvalue.rawValue, forKey: .enumvalue)
95-
}
89+
try container.encode(enumvalue.rawValue, forKey: .enumvalue)
9690
case let .listvalue(listvalue):
97-
if let listvalue = listvalue {
98-
var listvalueContainer = container.nestedUnkeyedContainer(forKey: .listvalue)
99-
for stringlist0 in listvalue {
100-
try listvalueContainer.encode(stringlist0)
101-
}
91+
var listvalueContainer = container.nestedUnkeyedContainer(forKey: .listvalue)
92+
for stringlist0 in listvalue {
93+
try listvalueContainer.encode(stringlist0)
10294
}
10395
case let .mapvalue(mapvalue):
104-
if let mapvalue = mapvalue {
105-
var mapvalueContainer = container.nestedContainer(keyedBy: Key.self, forKey: .mapvalue)
106-
for (dictKey0, stringmap0) in mapvalue {
107-
try mapvalueContainer.encode(stringmap0, forKey: Key(stringValue: dictKey0))
108-
}
96+
var mapvalueContainer = container.nestedContainer(keyedBy: Key.self, forKey: .mapvalue)
97+
for (dictKey0, stringmap0) in mapvalue {
98+
try mapvalueContainer.encode(stringmap0, forKey: Key(stringValue: dictKey0))
10999
}
110100
case let .numbervalue(numbervalue):
111-
if let numbervalue = numbervalue {
112-
try container.encode(numbervalue, forKey: .numbervalue)
113-
}
101+
try container.encode(numbervalue, forKey: .numbervalue)
114102
case let .stringvalue(stringvalue):
115-
if let stringvalue = stringvalue {
116-
try container.encode(stringvalue, forKey: .stringvalue)
117-
}
103+
try container.encode(stringvalue, forKey: .stringvalue)
118104
case let .structurevalue(structurevalue):
119-
if let structurevalue = structurevalue {
120-
try container.encode(structurevalue, forKey: .structurevalue)
121-
}
105+
try container.encode(structurevalue, forKey: .structurevalue)
122106
case let .timestampvalue(timestampvalue):
123-
if let timestampvalue = timestampvalue {
124-
try container.encode(timestampvalue.iso8601WithoutFractionalSeconds(), forKey: .timestampvalue)
125-
}
107+
try container.encode(timestampvalue.iso8601WithoutFractionalSeconds(), forKey: .timestampvalue)
126108
case let .sdkUnknown(sdkUnknown):
127109
try container.encode(sdkUnknown, forKey: .sdkUnknown)
128110
}

smithy-swift-codegen/src/test/kotlin/UnionEncodeGeneratorTests.kt

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -78,47 +78,29 @@ class UnionEncodeGeneratorTests {
7878
var container = encoder.container(keyedBy: CodingKeys.self)
7979
switch self {
8080
case let .blobvalue(blobvalue):
81-
if let blobvalue = blobvalue {
82-
try container.encode(blobvalue.base64EncodedString(), forKey: .blobvalue)
83-
}
81+
try container.encode(blobvalue.base64EncodedString(), forKey: .blobvalue)
8482
case let .booleanvalue(booleanvalue):
85-
if let booleanvalue = booleanvalue {
86-
try container.encode(booleanvalue, forKey: .booleanvalue)
87-
}
83+
try container.encode(booleanvalue, forKey: .booleanvalue)
8884
case let .enumvalue(enumvalue):
89-
if let enumvalue = enumvalue {
90-
try container.encode(enumvalue.rawValue, forKey: .enumvalue)
91-
}
85+
try container.encode(enumvalue.rawValue, forKey: .enumvalue)
9286
case let .listvalue(listvalue):
93-
if let listvalue = listvalue {
94-
var listvalueContainer = container.nestedUnkeyedContainer(forKey: .listvalue)
95-
for stringlist0 in listvalue {
96-
try listvalueContainer.encode(stringlist0)
97-
}
87+
var listvalueContainer = container.nestedUnkeyedContainer(forKey: .listvalue)
88+
for stringlist0 in listvalue {
89+
try listvalueContainer.encode(stringlist0)
9890
}
9991
case let .mapvalue(mapvalue):
100-
if let mapvalue = mapvalue {
101-
var mapvalueContainer = container.nestedContainer(keyedBy: Key.self, forKey: .mapvalue)
102-
for (dictKey0, stringmap0) in mapvalue {
103-
try mapvalueContainer.encode(stringmap0, forKey: Key(stringValue: dictKey0))
104-
}
92+
var mapvalueContainer = container.nestedContainer(keyedBy: Key.self, forKey: .mapvalue)
93+
for (dictKey0, stringmap0) in mapvalue {
94+
try mapvalueContainer.encode(stringmap0, forKey: Key(stringValue: dictKey0))
10595
}
10696
case let .numbervalue(numbervalue):
107-
if let numbervalue = numbervalue {
108-
try container.encode(numbervalue, forKey: .numbervalue)
109-
}
97+
try container.encode(numbervalue, forKey: .numbervalue)
11098
case let .stringvalue(stringvalue):
111-
if let stringvalue = stringvalue {
112-
try container.encode(stringvalue, forKey: .stringvalue)
113-
}
99+
try container.encode(stringvalue, forKey: .stringvalue)
114100
case let .structurevalue(structurevalue):
115-
if let structurevalue = structurevalue {
116-
try container.encode(structurevalue, forKey: .structurevalue)
117-
}
101+
try container.encode(structurevalue, forKey: .structurevalue)
118102
case let .timestampvalue(timestampvalue):
119-
if let timestampvalue = timestampvalue {
120-
try container.encode(timestampvalue.iso8601WithoutFractionalSeconds(), forKey: .timestampvalue)
121-
}
103+
try container.encode(timestampvalue.iso8601WithoutFractionalSeconds(), forKey: .timestampvalue)
122104
case let .sdkUnknown(sdkUnknown):
123105
try container.encode(sdkUnknown, forKey: .sdkUnknown)
124106
}

0 commit comments

Comments
 (0)