From c857db57b00a69e63d821a89b1a523d5c7c3c000 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Mon, 23 Dec 2024 18:22:16 -0600 Subject: [PATCH 1/7] WIP --- .../aws/swift/codegen/customization/s3/S3ErrorIntegration.kt | 5 ++++- sdk.properties | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/customization/s3/S3ErrorIntegration.kt b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/customization/s3/S3ErrorIntegration.kt index ba7b3ac033f..84792280c48 100644 --- a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/customization/s3/S3ErrorIntegration.kt +++ b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/customization/s3/S3ErrorIntegration.kt @@ -36,12 +36,15 @@ class S3ErrorIntegration : SwiftIntegration { private val s3MembersParams = SectionWriter { writer, _ -> writer.write( - "static func responseErrorBinding(httpResponse: \$N, reader: \$N, message: \$D, requestID: \$D, requestID2: \$D) async throws -> \$N {", + "static func responseErrorBinding(httpResponse: \$N, reader: \$N, message: \$T = \$D, requestID: \$T = \$D, requestID2: \$T = \$D) async throws -> \$N {", SmithyHTTPAPITypes.HTTPResponse, SmithyXMLTypes.Reader, SwiftTypes.String, SwiftTypes.String, SwiftTypes.String, + SwiftTypes.String, + SwiftTypes.String, + SwiftTypes.String, SwiftTypes.Error, ) } diff --git a/sdk.properties b/sdk.properties index 0ecd6cd91c8..0a14cfb8a3f 100644 --- a/sdk.properties +++ b/sdk.properties @@ -4,3 +4,4 @@ # Use this line to exclude one or more AWS services: # excludeModels=s3,sts,dynamodb +onlyIncludeModels=bedrock-agent-runtime From de40183cc2b631acfd58feb8ee2bad33f681a36c Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Thu, 26 Dec 2024 11:22:24 -0600 Subject: [PATCH 2/7] Revert sdk.properties --- sdk.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk.properties b/sdk.properties index 0a14cfb8a3f..0ecd6cd91c8 100644 --- a/sdk.properties +++ b/sdk.properties @@ -4,4 +4,3 @@ # Use this line to exclude one or more AWS services: # excludeModels=s3,sts,dynamodb -onlyIncludeModels=bedrock-agent-runtime From 8b60c9e46673bc214b74b470ef08a3c5dbf5ff41 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Mon, 6 Jan 2025 13:11:43 -0600 Subject: [PATCH 3/7] Fix codegen tests --- .../smithy/aws/swift/codegen/EndpointParamsGeneratorTests.kt | 4 ++-- .../AWSRestJson1HttpResponseBindingErrorGeneratableTests.kt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/EndpointParamsGeneratorTests.kt b/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/EndpointParamsGeneratorTests.kt index a5510fe6ece..a472f5d9d1a 100644 --- a/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/EndpointParamsGeneratorTests.kt +++ b/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/EndpointParamsGeneratorTests.kt @@ -43,11 +43,11 @@ public struct EndpointParams { public init( boolBar: Swift.Bool? = nil, boolBaz: Swift.String? = nil, - boolFoo: Swift.Bool, + boolFoo: Swift.Bool = false, endpoint: Swift.String? = nil, flattenedArray: Swift.Array? = nil, keysFunctionArray: Swift.Array? = nil, - region: Swift.String, + region: Swift.String = "", stringArrayBar: Swift.Array? = nil, stringBar: Swift.String? = nil, stringBaz: Swift.String? = nil, diff --git a/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/awsrestjson/AWSRestJson1HttpResponseBindingErrorGeneratableTests.kt b/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/awsrestjson/AWSRestJson1HttpResponseBindingErrorGeneratableTests.kt index 3e7ccde2613..8bde1f6428e 100644 --- a/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/awsrestjson/AWSRestJson1HttpResponseBindingErrorGeneratableTests.kt +++ b/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/awsrestjson/AWSRestJson1HttpResponseBindingErrorGeneratableTests.kt @@ -23,6 +23,7 @@ enum GreetingWithErrorsOutputError { static func httpError(from httpResponse: SmithyHTTPAPI.HTTPResponse) async throws -> Swift.Error { let data = try await httpResponse.data() let responseReader = try SmithyJSON.Reader.from(data: data) + responseReader.respectsJSONName = true let baseError = try AWSClientRuntime.RestJSONError(httpResponse: httpResponse, responseReader: responseReader, noErrorWrapping: false) if let error = baseError.customError() { return error } if let error = try httpServiceError(baseError: baseError) { return error } From c38895f0eb1056cc537b061533058d167e0c5c32 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Wed, 8 Jan 2025 09:23:58 -0600 Subject: [PATCH 4/7] Revert changes to endpoints tests --- .../smithy/aws/swift/codegen/EndpointParamsGeneratorTests.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/EndpointParamsGeneratorTests.kt b/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/EndpointParamsGeneratorTests.kt index a472f5d9d1a..a5510fe6ece 100644 --- a/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/EndpointParamsGeneratorTests.kt +++ b/codegen/smithy-aws-swift-codegen/src/test/kotlin/software/amazon/smithy/aws/swift/codegen/EndpointParamsGeneratorTests.kt @@ -43,11 +43,11 @@ public struct EndpointParams { public init( boolBar: Swift.Bool? = nil, boolBaz: Swift.String? = nil, - boolFoo: Swift.Bool = false, + boolFoo: Swift.Bool, endpoint: Swift.String? = nil, flattenedArray: Swift.Array? = nil, keysFunctionArray: Swift.Array? = nil, - region: Swift.String = "", + region: Swift.String, stringArrayBar: Swift.Array? = nil, stringBar: Swift.String? = nil, stringBaz: Swift.String? = nil, From 4b12b92974949fc6cb07695eca14407c1c1bde50 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Wed, 8 Jan 2025 09:26:45 -0600 Subject: [PATCH 5/7] Revert S3ErrorIntegration --- .../aws/swift/codegen/customization/s3/S3ErrorIntegration.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/customization/s3/S3ErrorIntegration.kt b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/customization/s3/S3ErrorIntegration.kt index 84792280c48..ba7b3ac033f 100644 --- a/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/customization/s3/S3ErrorIntegration.kt +++ b/codegen/smithy-aws-swift-codegen/src/main/kotlin/software/amazon/smithy/aws/swift/codegen/customization/s3/S3ErrorIntegration.kt @@ -36,15 +36,12 @@ class S3ErrorIntegration : SwiftIntegration { private val s3MembersParams = SectionWriter { writer, _ -> writer.write( - "static func responseErrorBinding(httpResponse: \$N, reader: \$N, message: \$T = \$D, requestID: \$T = \$D, requestID2: \$T = \$D) async throws -> \$N {", + "static func responseErrorBinding(httpResponse: \$N, reader: \$N, message: \$D, requestID: \$D, requestID2: \$D) async throws -> \$N {", SmithyHTTPAPITypes.HTTPResponse, SmithyXMLTypes.Reader, SwiftTypes.String, SwiftTypes.String, SwiftTypes.String, - SwiftTypes.String, - SwiftTypes.String, - SwiftTypes.String, SwiftTypes.Error, ) } From de62afe834a300e6fc7ec0d117bd76ed85abf7e2 Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Wed, 8 Jan 2025 14:24:29 -0600 Subject: [PATCH 6/7] Add deserialization performance tests --- codegen/Package.swift | 8 +- .../PerformanceTests/PerformanceTests.swift | 101 ++++++++++++++++++ .../build.gradle.kts | 6 +- .../model/performance-tests.smithy | 49 +++++++++ scripts/protogen.sh | 1 + 5 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 codegen/protocol-test-codegen-local/Tests/swift-codegen/Tests/PerformanceTests/PerformanceTests.swift create mode 100644 codegen/protocol-test-codegen-local/model/performance-tests.smithy diff --git a/codegen/Package.swift b/codegen/Package.swift index 8ecff3b4dfc..95dc1b5f5f2 100644 --- a/codegen/Package.swift +++ b/codegen/Package.swift @@ -37,6 +37,8 @@ extension Target.Dependency { static var smithyWaitersAPI: Self { .product(name: "SmithyWaitersAPI", package: "smithy-swift") } static var smithyTestUtils: Self { .product(name: "SmithyTestUtil", package: "smithy-swift") } static var smithyStreams: Self { .product(name: "SmithyStreams", package: "smithy-swift") } + static var smithyReadWrite: Self { .product(name: "SmithyReadWrite", package: "smithy-swift") } + static var smithyJSON: Self { .product(name: "SmithyJSON", package: "smithy-swift") } } // MARK: - Base Package @@ -93,7 +95,8 @@ private var protocolTestTargets: [Target] { .init(name: "EventStream", sourcePath: "\(baseDirLocal)/EventStream", buildOnly: true), .init(name: "RPCEventStream", sourcePath: "\(baseDirLocal)/RPCEventStream", buildOnly: true), .init(name: "Waiters", sourcePath: "\(baseDirLocal)/Waiters", testPath: "../codegen/protocol-test-codegen-local/Tests"), - .init(name: "StringArrayEndpointParam", sourcePath: "\(baseDirLocal)/StringArrayEndpointParam") + .init(name: "StringArrayEndpointParam", sourcePath: "\(baseDirLocal)/StringArrayEndpointParam"), + .init(name: "Performance", sourcePath: "\(baseDirLocal)/Performance", testPath: "../codegen/protocol-test-codegen-local/Tests"), ] return protocolTests.flatMap { protocolTest in let target = Target.target( @@ -114,11 +117,14 @@ private var protocolTestTargets: [Target] { .smithyChecksumsAPI, .smithyChecksums, .smithyWaitersAPI, + .smithyReadWrite, + .smithyJSON, .awsSDKCommon, .awsSDKIdentity, .awsSDKHTTPAuth, .awsSDKEventStreamsAuth, .awsSDKChecksums, + ], path: "\(protocolTest.sourcePath)/swift-codegen/Sources/\(protocolTest.name)" ) diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/Tests/PerformanceTests/PerformanceTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/Tests/PerformanceTests/PerformanceTests.swift new file mode 100644 index 00000000000..b99cfb4c9c9 --- /dev/null +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/Tests/PerformanceTests/PerformanceTests.swift @@ -0,0 +1,101 @@ +// +// Copyright Amazon.com Inc. or its affiliates. +// All Rights Reserved. +// +// SPDX-License-Identifier: Apache-2.0 +// + +import XCTest +@testable import Performance +@_spi(SmithyReadWrite) import SmithyReadWrite +@_spi(SmithyReadWrite) import SmithyJSON + +typealias TestStructure = PerformanceClientTypes.TestStructure + +final class PerformanceTests: XCTestCase { + + var array: [TestStructure] = [] + var data: Data = Data() + + override func setUp() async throws { + try await super.setUp() + self.array = (0..<10000).map { i in + let arrayOfInts = (0..<10).map { _ in Int.random(in: 0...1000) } + let mapOfDoubles = Dictionary( + uniqueKeysWithValues: ( + (0..<10).map { _ in + ( + UUID().uuidString, + Double.random(in: 0.0...1000.0) + ) + } + ) + ) + return TestStructure( + bool: Bool.random(), + int: i, + listOfInts: arrayOfInts, + mapOfDoubles: mapOfDoubles, + string: UUID().uuidString + ) + } + let writer = Writer(nodeInfo: "") + try writer.write(array, with: listWritingClosure(memberWritingClosure: TestStructure.write(value:to:), memberNodeInfo: "member", isFlattened: false)) + self.data = try writer.data() + } + + override func tearDown() async throws { + self.array = [] + self.data = Data() + try await super.tearDown() + } + + func xtest_schema() throws { + var dup = [TestStructure]() + measure { + do { + let reader = try Reader.from(data: self.data) + dup = try reader.readListNonNull(schema: schema__namespace_aws_smithy_swift_performance__name_TestStructureList) + } catch { + XCTFail("Threw error: \(error)") + } + } + XCTAssert(array == dup) + } + + func xtest_readWrite() throws { + var dup = [TestStructure]() + measure { + do { + let reader = try Reader.from(data: self.data) + dup = try reader.readList(memberReadingClosure: TestStructure.read(from:), memberNodeInfo: "member", isFlattened: false) + } catch { + XCTFail("Threw error: \(error)") + } + } + XCTAssert(array == dup) + } +} + +extension TestStructure: Equatable { + + public static func ==(lhs: PerformanceClientTypes.TestStructure, rhs: PerformanceClientTypes.TestStructure) -> Bool { + if lhs.int != rhs.int { return false } + if lhs.string != rhs.string { return false } + if lhs.bool != rhs.bool { return false } + if lhs.listOfInts != rhs.listOfInts { return false } + if lhs.mapOfDoubles != rhs.mapOfDoubles { return false } + return true + } + + static func read(from reader: Reader) throws -> TestStructure { + guard reader.hasContent else { throw ReaderError.requiredValueNotPresent } + var value = TestStructure() + value.int = try reader["int"].readIfPresent() + value.string = try reader["string"].readIfPresent() + value.bool = try reader["bool"].readIfPresent() + value.listOfInts = try reader["ListOfInts"].readListIfPresent(memberReadingClosure: ReadingClosures.readInt(from:), memberNodeInfo: "member", isFlattened: false) + value.mapOfDoubles = try reader["MapOfDoubles"].readMapIfPresent(valueReadingClosure: ReadingClosures.readDouble(from:), keyNodeInfo: "key", valueNodeInfo: "value", isFlattened: false) + return value + } +} diff --git a/codegen/protocol-test-codegen-local/build.gradle.kts b/codegen/protocol-test-codegen-local/build.gradle.kts index 4669fc32daa..9d088732568 100644 --- a/codegen/protocol-test-codegen-local/build.gradle.kts +++ b/codegen/protocol-test-codegen-local/build.gradle.kts @@ -51,7 +51,11 @@ val codegenTests = listOf( CodegenTest( "aws.endpointtests.stringarray#EndpointStringArray", "StringArrayEndpointParam" - ) + ), + CodegenTest( + "aws.smithy.swift.performance#Performance", + "Performance" + ), ) fun generateSmithyBuild(tests: List): String { diff --git a/codegen/protocol-test-codegen-local/model/performance-tests.smithy b/codegen/protocol-test-codegen-local/model/performance-tests.smithy new file mode 100644 index 00000000000..db67ed61169 --- /dev/null +++ b/codegen/protocol-test-codegen-local/model/performance-tests.smithy @@ -0,0 +1,49 @@ +$version: "2.0" + +namespace aws.smithy.swift.performance + +use aws.protocols#restJson1 +use aws.api#service + +// A service which has a GET operation with waiters defined upon it. +// The acceptor in each waiter serves as subject for unit testing, +// to ensure that the logic in code-generated acceptors works as +// expected. +@service(sdkId: "Performance") +@restJson1 +service Performance { + version: "2022-11-30", + operations: [GetWidget] +} + +@http(uri: "/widget", method: "POST") +operation GetWidget { + input: IO, + output: IO + errors: [] +} + +structure IO { + list: TestStructureList +} + +list TestStructureList { + member: TestStructure +} + +structure TestStructure { + int: Integer + string: String + bool: Boolean + ListOfInts: ListOfIntegers + MapOfDoubles: MapOfDoubles +} + +list ListOfIntegers { + member: Integer +} + +map MapOfDoubles { + key: String + value: Double +} diff --git a/scripts/protogen.sh b/scripts/protogen.sh index 57c5e5b6c5b..572944cfafc 100755 --- a/scripts/protogen.sh +++ b/scripts/protogen.sh @@ -43,6 +43,7 @@ rm -f codegen/protocol-test-codegen-local/build/smithyprojections/protocol-test- rm -f codegen/protocol-test-codegen-local/build/smithyprojections/protocol-test-codegen-local/EventStream/swift-codegen/Package.swift rm -f codegen/protocol-test-codegen-local/build/smithyprojections/protocol-test-codegen-local/RPCEventStream/swift-codegen/Package.swift rm -f codegen/protocol-test-codegen-local/build/smithyprojections/protocol-test-codegen-local/Waiters/swift-codegen/Package.swift +rm -f codegen/protocol-test-codegen-local/build/smithyprojections/protocol-test-codegen-local/Performance/swift-codegen/Package.swift # If on Mac, reopen Xcode to the refreshed tests if [ -x "$(command -v osascript)" ]; then From 9558107f71f4a320038e6534da3d4bbf05e74e5a Mon Sep 17 00:00:00 2001 From: Josh Elkins Date: Thu, 9 Jan 2025 09:36:00 -0600 Subject: [PATCH 7/7] More performance testing --- .../PerformanceTests/PerformanceTests.swift | 196 +++++++++++++----- 1 file changed, 147 insertions(+), 49 deletions(-) diff --git a/codegen/protocol-test-codegen-local/Tests/swift-codegen/Tests/PerformanceTests/PerformanceTests.swift b/codegen/protocol-test-codegen-local/Tests/swift-codegen/Tests/PerformanceTests/PerformanceTests.swift index b99cfb4c9c9..fe30e30aced 100644 --- a/codegen/protocol-test-codegen-local/Tests/swift-codegen/Tests/PerformanceTests/PerformanceTests.swift +++ b/codegen/protocol-test-codegen-local/Tests/swift-codegen/Tests/PerformanceTests/PerformanceTests.swift @@ -14,80 +14,136 @@ typealias TestStructure = PerformanceClientTypes.TestStructure final class PerformanceTests: XCTestCase { - var array: [TestStructure] = [] - var data: Data = Data() - - override func setUp() async throws { - try await super.setUp() - self.array = (0..<10000).map { i in - let arrayOfInts = (0..<10).map { _ in Int.random(in: 0...1000) } - let mapOfDoubles = Dictionary( - uniqueKeysWithValues: ( - (0..<10).map { _ in - ( - UUID().uuidString, - Double.random(in: 0.0...1000.0) - ) - } - ) - ) - return TestStructure( - bool: Bool.random(), - int: i, - listOfInts: arrayOfInts, - mapOfDoubles: mapOfDoubles, - string: UUID().uuidString - ) - } - let writer = Writer(nodeInfo: "") - try writer.write(array, with: listWritingClosure(memberWritingClosure: TestStructure.write(value:to:), memberNodeInfo: "member", isFlattened: false)) - self.data = try writer.data() + static var array10: [TestStructure] = [] + static var data10: Data = Data() + static var array100: [TestStructure] = [] + static var data100: Data = Data() + static var array1000: [TestStructure] = [] + static var data1000: Data = Data() + + override static func setUp() { + (Self.array10, Self.data10) = try! generateData(n: 10) + (Self.array100, Self.data100) = try! generateData(n: 100) + (Self.array1000, Self.data1000) = try! generateData(n: 1000) + } + + // MARK: - Schema performance tests + + func test_schema_10() throws { + try run_test_schema(original: Self.array10, data: Self.data10) + } + + func test_schema_100() throws { + try run_test_schema(original: Self.array100, data: Self.data100) } - override func tearDown() async throws { - self.array = [] - self.data = Data() - try await super.tearDown() + func test_schema_1000() throws { + try run_test_schema(original: Self.array1000, data: Self.data1000) } - func xtest_schema() throws { + func run_test_schema(original: [TestStructure], data: Data, file: StaticString = #file, line: UInt = #line) throws { var dup = [TestStructure]() measure { do { - let reader = try Reader.from(data: self.data) + let reader = try Reader.from(data: data) dup = try reader.readListNonNull(schema: schema__namespace_aws_smithy_swift_performance__name_TestStructureList) } catch { - XCTFail("Threw error: \(error)") + XCTFail("Threw error: \(error)", file: file, line: line) } } - XCTAssert(array == dup) + XCTAssert(original == dup) + } + + // MARK: - ReadWrite performance tests + + func test_readWrite_10() throws { + try run_test_readWrite(original: Self.array10, data: Self.data10) + } + + func test_readWrite_100() throws { + try run_test_readWrite(original: Self.array100, data: Self.data100) + } + + func test_readWrite_1000() throws { + try run_test_readWrite(original: Self.array1000, data: Self.data1000) } - func xtest_readWrite() throws { + func run_test_readWrite(original: [TestStructure], data: Data, file: StaticString = #file, line: UInt = #line) throws { var dup = [TestStructure]() measure { do { - let reader = try Reader.from(data: self.data) + let reader = try Reader.from(data: data) dup = try reader.readList(memberReadingClosure: TestStructure.read(from:), memberNodeInfo: "member", isFlattened: false) } catch { - XCTFail("Threw error: \(error)") + XCTFail("Threw error: \(error)", file: file, line: line) } } - XCTAssert(array == dup) + XCTAssert(original == dup) } -} -extension TestStructure: Equatable { + // MARK: - Swift Decodable performance tests - public static func ==(lhs: PerformanceClientTypes.TestStructure, rhs: PerformanceClientTypes.TestStructure) -> Bool { - if lhs.int != rhs.int { return false } - if lhs.string != rhs.string { return false } - if lhs.bool != rhs.bool { return false } - if lhs.listOfInts != rhs.listOfInts { return false } - if lhs.mapOfDoubles != rhs.mapOfDoubles { return false } - return true + func test_decodable_10() throws { + try run_test_decodable(original: Self.array10, data: Self.data10) + } + + func test_decodable_100() throws { + try run_test_decodable(original: Self.array100, data: Self.data100) + } + + func test_decodable_1000() throws { + try run_test_decodable(original: Self.array1000, data: Self.data1000) } + func run_test_decodable(original: [TestStructure], data: Data, file: StaticString = #file, line: UInt = #line) throws { + var dup = [TestStructure]() + measure { + do { + dup = try JSONDecoder().decode([TestStructure].self, from: data) + } catch { + XCTFail("Threw error: \(error)", file: file, line: line) + } + } + XCTAssertEqual(original, dup) + } + + // MARK: - Test data generation + + private static func generateData(n: Int) throws -> ([TestStructure], Data) { + let array = (0.. TestStructure { guard reader.hasContent else { throw ReaderError.requiredValueNotPresent } var value = TestStructure() @@ -99,3 +155,45 @@ extension TestStructure: Equatable { return value } } + +extension TestStructure: Codable { + + public init(from decoder: any Decoder) throws { + self.init() + let container = try decoder.container(keyedBy: CodingKeys.self) + self.int = try container.decodeIfPresent(Int.self, forKey: .int) + self.string = try container.decodeIfPresent(String.self, forKey: .string) + self.bool = try container.decodeIfPresent(Bool.self, forKey: .bool) + self.listOfInts = try container.decodeIfPresent([Int].self, forKey: .listOfInts) + self.mapOfDoubles = try container.decodeIfPresent([String: Double].self, forKey: .mapOfDoubles) + } + + public func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(int, forKey: .int) + try container.encodeIfPresent(string, forKey: .string) + try container.encodeIfPresent(bool, forKey: .bool) + try container.encodeIfPresent(listOfInts, forKey: .listOfInts) + try container.encodeIfPresent(mapOfDoubles, forKey: .mapOfDoubles) + } + + enum CodingKeys: String, CodingKey { + case int + case string + case bool + case listOfInts = "ListOfInts" + case mapOfDoubles = "MapOfDoubles" + } +} + +extension TestStructure: Equatable { + + public static func ==(lhs: PerformanceClientTypes.TestStructure, rhs: PerformanceClientTypes.TestStructure) -> Bool { + if lhs.int != rhs.int { return false } + if lhs.string != rhs.string { return false } + if lhs.bool != rhs.bool { return false } + if lhs.listOfInts != rhs.listOfInts { return false } + if lhs.mapOfDoubles != rhs.mapOfDoubles { return false } + return true + } +}