fun render()

in smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/httpResponse/HttpResponseHeaders.kt [35:185]


    fun render() {
        bindings.forEach { hdrBinding ->
            val memberTarget = ctx.model.expectShape(hdrBinding.member.target)
            val memberName = ctx.symbolProvider.toMemberName(hdrBinding.member)
            val headerName = hdrBinding.locationName
            val headerDeclaration = "${memberName}HeaderValue"
            val isBoxed = ctx.symbolProvider.toSymbol(memberTarget).isBoxed()
            writer.write("if let $headerDeclaration = httpResponse.headers.value(for: \$S) {", headerName)
            writer.indent()
            when (memberTarget) {
                is NumberShape -> {
                    val memberValue = stringToNumber(memberTarget, headerDeclaration)
                    writer.write("self.\$L = $memberValue", memberName)
                }
                is BlobShape -> {
                    val memberValue = "$headerDeclaration.data(using: .utf8)"
                    writer.write("self.\$L = $memberValue", memberName)
                }
                is BooleanShape -> {
                    val memberValue = "${SwiftTypes.Bool}($headerDeclaration) ?? false"
                    writer.write("self.\$L = $memberValue", memberName)
                }
                is StringShape -> {
                    val memberValue = when {
                        memberTarget.hasTrait<EnumTrait>() -> {
                            val enumSymbol = ctx.symbolProvider.toSymbol(memberTarget)
                            "$enumSymbol(rawValue: $headerDeclaration)"
                        }
                        memberTarget.hasTrait<MediaTypeTrait>() -> {
                            "try $headerDeclaration.base64DecodedString()"
                        }
                        else -> {
                            headerDeclaration
                        }
                    }
                    writer.write("self.\$L = $memberValue", memberName)
                }
                is TimestampShape -> {
                    val bindingIndex = HttpBindingIndex.of(ctx.model)
                    val tsFormat = bindingIndex.determineTimestampFormat(
                        hdrBinding.member,
                        HttpBinding.Location.HEADER,
                        defaultTimestampFormat
                    )
                    var memberValue = stringToDate(headerDeclaration, tsFormat)
                    if (tsFormat == TimestampFormatTrait.Format.EPOCH_SECONDS) {
                        memberValue = stringToDate("${headerDeclaration}Double", tsFormat)
                        writer.write("if let ${headerDeclaration}Double = \$N(\$LHeaderValue) {", SwiftTypes.Double, memberName)
                        writer.indent()
                        writer.write("self.\$L = $memberValue", memberName)
                        writer.dedent()
                        writer.write("} else {")
                        writer.indent()
                        writer.write("throw \$N.deserializationFailed(HeaderDeserializationError.invalidTimestampHeader(value: \$LHeaderValue))", ClientRuntimeTypes.Core.ClientError, memberName)
                        writer.dedent()
                        writer.write("}")
                    } else {
                        writer.write("self.\$L = $memberValue", memberName)
                    }
                }
                is CollectionShape -> {
                    // member > boolean, number, string, or timestamp
                    // headers are List<String>, get the internal mapping function contents (if any) to convert
                    // to the target symbol type

                    // we also have to handle multiple comma separated values (e.g. 'X-Foo': "1, 2, 3"`)
                    var splitFn = "splitHeaderListValues"
                    var splitFnPrefix = ""
                    var invalidHeaderListErrorName = "invalidNumbersHeaderList"
                    val conversion = when (val collectionMemberTarget = ctx.model.expectShape(memberTarget.member.target)) {
                        is BooleanShape -> {
                            invalidHeaderListErrorName = "invalidBooleanHeaderList"
                            "${SwiftTypes.Bool}(\$0)"
                        }
                        is NumberShape -> "(${stringToNumber(collectionMemberTarget, "\$0")} ?? 0)"
                        is TimestampShape -> {
                            val bindingIndex = HttpBindingIndex.of(ctx.model)
                            val tsFormat = bindingIndex.determineTimestampFormat(
                                hdrBinding.member,
                                HttpBinding.Location.HEADER,
                                defaultTimestampFormat
                            )
                            if (tsFormat == TimestampFormatTrait.Format.HTTP_DATE) {
                                splitFn = "splitHttpDateHeaderListValues"
                                splitFnPrefix = "try "
                            }
                            invalidHeaderListErrorName = "invalidTimestampHeaderList"
                            "(${stringToDate("\$0", tsFormat)} ?? ${ClientRuntimeTypes.Core.Date}())"
                        }
                        is StringShape -> {
                            invalidHeaderListErrorName = "invalidStringHeaderList"
                            when {
                                collectionMemberTarget.hasTrait<EnumTrait>() -> {
                                    val enumSymbol = ctx.symbolProvider.toSymbol(collectionMemberTarget)
                                    "($enumSymbol(rawValue: \$0) ?? $enumSymbol(rawValue: \"Bar\")!)"
                                }
                                collectionMemberTarget.hasTrait<MediaTypeTrait>() -> {
                                    "try \$0.base64EncodedString()"
                                }
                                else -> ""
                            }
                        }
                        else -> throw CodegenException("invalid member type for header collection: binding: $hdrBinding; member: $memberName")
                    }
                    val mapFn = if (conversion.isNotEmpty()) ".map { $conversion }" else ""
                    var memberValue = "${memberName}HeaderValues$mapFn"
                    if (memberTarget.isSetShape) {
                        memberValue = "${SwiftTypes.Set}(${memberName}HeaderValues)"
                    }
                    writer.write("if let ${memberName}HeaderValues = $splitFnPrefix$splitFn(${memberName}HeaderValue) {")
                    writer.indent()
                    // render map function
                    val collectionMemberTargetShape = ctx.model.expectShape(memberTarget.member.target)
                    val collectionMemberTargetSymbol = ctx.symbolProvider.toSymbol(collectionMemberTargetShape)
                    if (!collectionMemberTargetSymbol.isBoxed()) {
                        writer.openBlock("self.\$L = try \$LHeaderValues.map {", "}", memberName, memberName) {
                            val transformedHeaderDeclaration = "${memberName}Transformed"
                            writer.openBlock("guard let \$L = \$L else {", "}", transformedHeaderDeclaration, conversion) {
                                writer.write("throw \$N.deserializationFailed(HeaderDeserializationError.\$L(value: \$LHeaderValue))", ClientRuntimeTypes.Core.ClientError, invalidHeaderListErrorName, memberName)
                            }
                            writer.write("return \$L", transformedHeaderDeclaration)
                        }
                    } else {
                        writer.write("self.\$L = \$L", memberName, memberValue)
                    }
                    writer.dedent()
                    writer.write("} else {")
                    writer.indent()
                    writer.write("self.\$L = nil", memberName)
                    writer.dedent()
                    writer.write("}")
                }
                else -> throw CodegenException("unknown deserialization: header binding: $hdrBinding; member: `$memberName`")
            }
            writer.dedent()
            writer.write("} else {")
            writer.indent()
            var assignmentValue = "nil"
            when (memberTarget) {
                is NumberShape -> {
                    assignmentValue = if (isBoxed) "nil" else "0"
                }
                is BooleanShape -> {
                    assignmentValue = if (isBoxed) "nil" else "false"
                }
            }
            writer.write("self.$memberName = $assignmentValue")
            writer.dedent()
            writer.write("}")
        }
    }