-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add support for smithy.protocols#rpcv2Cbor
protocol
#1103
Conversation
Added new deserializeBlob and deserializeTimestamp functions to deserializer interface.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Note: acknowledge-api-break was added because of a bug in Kotlin around our use of typealias in BigDecimalJVM / BigIntegerJVM. This was going to break during our upgrade to K2, but I had to move it forward into this PR to add new functions like |
This comment has been minimized.
This comment has been minimized.
runtime/serde/serde-cbor/common/src/aws/smithy/kotlin/runtime/serde/cbor/encoding/Simple.kt
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved pending positive outcomes of remaining nits/questions.
...hy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt
Outdated
Show resolved
Hide resolved
...hy/kotlin/runtime/awsprotocol/rpcv2/cbor/RpcV2CborSmithyProtocolResponseHeaderInterceptor.kt
Outdated
Show resolved
Hide resolved
public fun toHttpBody(): HttpBody = buffer.readByteArray().toHttpBody() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: I'm still concerned about reading this all into memory at once although I note that RPC v2 does not (yet) support blob streams, merely event streams. What's the behavior for event streams wrt CborSerializer.toHttpBody()
? Is that invoked for the initial request and separately for each subsequent event (as opposed to once for the entire stream)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes that's correct, each message will be encoded separately in the CborSerializer
instead of all-at-once. I wasn't able to functionally test this because there's no services that have an input event stream and support CBOR at the moment. I was able to test output event streams using CloudWatch Logs and they work as expected.
runtime/serde/serde-cbor/common/src/aws/smithy/kotlin/runtime/serde/cbor/encoding/Number.kt
Outdated
Show resolved
Hide resolved
runtime/serde/serde-cbor/common/src/aws/smithy/kotlin/runtime/serde/cbor/encoding/Simple.kt
Outdated
Show resolved
Hide resolved
runtime/serde/serde-cbor/common/src/aws/smithy/kotlin/runtime/serde/cbor/encoding/Simple.kt
Outdated
Show resolved
Hide resolved
runtime/serde/serde-cbor/common/src/aws/smithy/kotlin/runtime/serde/cbor/encoding/Simple.kt
Outdated
Show resolved
Hide resolved
val sb = StringBuilder() | ||
|
||
// Append mantissa | ||
sb.append( | ||
when (mantissa) { | ||
is UInt -> mantissa.value.toString() | ||
is NegInt -> "-${mantissa.value}" | ||
is Tag -> when (mantissa.value) { | ||
is NegBigNum -> mantissa.value.value.toString() | ||
is BigNum -> mantissa.value.value.toString() | ||
else -> throw DeserializationException("Expected BigNum or NegBigNum for CBOR tagged decimal fraction mantissa, got ${mantissa.id}") | ||
} | ||
else -> throw DeserializationException("Expected UInt, NegInt, or Tag for CBOR decimal fraction mantissa, got $mantissa") | ||
}, | ||
) | ||
|
||
when (exponent) { | ||
is UInt -> { // Positive exponent, suffix with zeroes | ||
sb.append("0".repeat(exponent.value.toInt())) | ||
sb.append(".") | ||
} | ||
is NegInt -> { // Negative exponent, prefix with zeroes if necessary | ||
val exponentValue = exponent.value.toInt().absoluteValue | ||
val insertIndex = if (sb[0] == '-') 1 else 0 | ||
if (exponentValue > sb.length - insertIndex) { | ||
sb.insert(insertIndex, "0".repeat(exponentValue - sb.length + insertIndex)) | ||
sb.insert(insertIndex, '.') | ||
} else { | ||
sb.insert(sb.length - exponentValue, '.') | ||
} | ||
} | ||
else -> throw DeserializationException("Expected integer for CBOR decimal fraction exponent value, got $exponent.") | ||
} | ||
|
||
return DecimalFraction(BigDecimal(sb.toString())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Apologies but I missed this the first time around when commenting on string manipulation for BigInteger
but same suggestion applies: I suggest we delegate these down to JVM's BigDecimal
, which has a constructor for accepting a BigInteger
mantissa (which JVM calls the unscaledVal
) and an Int
exponent (which JVM calls the scale
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I think you did mention doing this for BigDecimal
and I missed it, either way, I think it's the right change so I'll do it
val list = mutableListOf<UByte>() | ||
while (hasNextElement()) { | ||
list.add(deserializeByte().toUByte()) | ||
list.add(deserializeLong().toUByte()) | ||
} | ||
return@deserializeList list |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Why did so many tests from deserializing narrow types (e.g., Byte
) to deserializing Long
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests of this form started failing after adding the out-of-bounds check for number deserialization because the numeric value is 255 which doesn't fit in a Byte. Trying to call deserializeByte
here would result in the out-of-bounds check throwing an exception, so it's updated instead to deserializeLong
...me/serde/serde-cbor/common/test/aws/smithy/kotlin/runtime/serde/cbor/CborDeserializerTest.kt
Outdated
Show resolved
Hide resolved
…Collections.kt and rename it to TextString
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Latest changes look great to me!
Affected ArtifactsSignificantly increased in size
Changed in size
|
This PR adds support for a new protocol,
smithy.protocols#rpcv2Cbor
.This is a subset of the Concise Binary Object Representation (CBOR) RFC.
Check out the Smithy docs to see where this protocol differs from the RFC.
(potentially) Controversial changes:
deserializeByteArray()
anddeserializeInstant()
toPrimitiveDeserializer
interfaceserializeByteArray()
toPrimitiveSerializer
interfaceserializeInstant()
already existsBugs fixed:
equals()
functions for structs with:==
) which is prone to failure because ByteArrays need to be compared withcontentEquals
..equals()
. This is becauseFloat.NaN == Float.NaN
always returnsfalse
, but if two structures have the exact same members and a NaN floating point, I believe they should be treated as equal? (at least according to Smithy protocol tests, which were failing without this change)smithy.api#Unit
shape, we would set the archetype to the operation shape. I updated this to set the unit shape as the archetype so we don't lose that information.Issue #
Closes #843 and part of awslabs/aws-sdk-kotlin#1302
Description of changes
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.