From 66c7e835bd8ba02f1c148a2f21355865ef18a55f Mon Sep 17 00:00:00 2001 From: Ian Botsford <83236726+ianbotsf@users.noreply.github.com> Date: Tue, 17 Dec 2024 18:16:00 +0000 Subject: [PATCH 1/6] WIP: partial implementation of bignums, pushed for multi-dev debugging --- gradle.properties | 3 +- gradle/libs.versions.toml | 3 ++ runtime/runtime-core/build.gradle.kts | 8 +++ .../kotlin/runtime/content/BigIntegerTest.kt | 1 - .../runtime/content/BigIntegerNative.kt | 49 ++++++++++--------- 5 files changed, 38 insertions(+), 26 deletions(-) diff --git a/gradle.properties b/gradle.properties index f35cfc1d5..aab7fa746 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,6 +2,7 @@ kotlin.code.style=official kotlin.incremental.js=true kotlin.incremental.multiplatform=true kotlin.mpp.stability.nowarn=true +kotlin.native.binary.sourceInfoType=libbacktrace kotlin.native.ignoreDisabledTargets=true # atomicfu @@ -16,4 +17,4 @@ org.gradle.jvmargs=-Xmx2G -XX:MaxMetaspaceSize=1G sdkVersion=1.3.30-SNAPSHOT # codegen -codegenVersion=0.33.30-SNAPSHOT \ No newline at end of file +codegenVersion=0.33.30-SNAPSHOT diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 31cf20db2..0e4a877e8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,6 +15,7 @@ slf4j-version = "2.0.16" slf4j-v1x-version = "1.7.36" crt-kotlin-version = "0.8.10" micrometer-version = "1.13.6" +kotlin-multiplatform-bignum-version = "0.3.10" # codegen smithy-version = "1.51.0" @@ -101,6 +102,8 @@ ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor-ve kaml = { module = "com.charleskorn.kaml:kaml", version.ref = "kaml-version" } jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup-version" } +kotlin-multiplatform-bignum = { module = "com.ionspin.kotlin:bignum", version.ref = "kotlin-multiplatform-bignum-version" } + [plugins] dokka = { id = "org.jetbrains.dokka", version.ref = "dokka-version"} kotlin-jvm = {id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-version" } diff --git a/runtime/runtime-core/build.gradle.kts b/runtime/runtime-core/build.gradle.kts index d902f42a7..226c4240d 100644 --- a/runtime/runtime-core/build.gradle.kts +++ b/runtime/runtime-core/build.gradle.kts @@ -1,3 +1,5 @@ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat + /* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 @@ -43,6 +45,12 @@ kotlin { } } + nativeMain { + dependencies { + implementation(libs.kotlin.multiplatform.bignum) + } + } + all { languageSettings.optIn("aws.smithy.kotlin.runtime.InternalApi") } diff --git a/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/content/BigIntegerTest.kt b/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/content/BigIntegerTest.kt index 2dc908302..be78e6c3d 100644 --- a/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/content/BigIntegerTest.kt +++ b/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/content/BigIntegerTest.kt @@ -77,7 +77,6 @@ class BigIntegerTest { "0x123456789abcdef0" to "1311768467463790320", "0x00ffffffffffffffffffffffffffffffec" to "340282366920938463463374607431768211436", "0x81445edf51ddc07216da5621c727bfd379d400f3da08018d45749a" to "-52134902384590238490284023839028330923830129830129301234239834982", - ) tests.forEach { (hex, expected) -> diff --git a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/content/BigIntegerNative.kt b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/content/BigIntegerNative.kt index 5ddee8af7..a1b3f7963 100644 --- a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/content/BigIntegerNative.kt +++ b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/content/BigIntegerNative.kt @@ -4,37 +4,38 @@ */ package aws.smithy.kotlin.runtime.content -public actual class BigInteger actual constructor(value: String) : +import com.ionspin.kotlin.bignum.integer.util.fromTwosComplementByteArray +import com.ionspin.kotlin.bignum.integer.util.toTwosComplementByteArray +import com.ionspin.kotlin.bignum.integer.BigInteger as IonSpinBigInteger + +public actual class BigInteger private constructor(private val delegate: IonSpinBigInteger) : Number(), Comparable { - public actual constructor(bytes: ByteArray) : this("Not yet implemented") - actual override fun toByte(): Byte { - TODO("Not yet implemented") + private companion object { + fun coalesceOrCreate(value: IonSpinBigInteger, left: BigInteger, right: BigInteger): BigInteger = when (value) { + left.delegate -> left + right.delegate -> right + else -> BigInteger(value) + } } - actual override fun toDouble(): Double { - TODO("Not yet implemented") - } + public actual constructor(value: String) : this(IonSpinBigInteger.parseString(value, 10)) + public actual constructor(bytes: ByteArray) : this(IonSpinBigInteger.fromTwosComplementByteArray(bytes)) - actual override fun toFloat(): Float { - TODO("Not yet implemented") - } + actual override fun toByte(): Byte = delegate.byteValue(exactRequired = false) + actual override fun toDouble(): Double = delegate.doubleValue(exactRequired = false) + actual override fun toFloat(): Float = delegate.floatValue(exactRequired = false) + actual override fun toInt(): Int = delegate.intValue(exactRequired = false) + actual override fun toLong(): Long = delegate.longValue(exactRequired = false) + actual override fun toShort(): Short = delegate.shortValue(exactRequired = false) - actual override fun toInt(): Int { - TODO("Not yet implemented") - } + public actual operator fun plus(other: BigInteger): BigInteger = + coalesceOrCreate(delegate + other.delegate, this, other) - actual override fun toLong(): Long { - TODO("Not yet implemented") - } - - actual override fun toShort(): Short { - TODO("Not yet implemented") - } + public actual operator fun minus(other: BigInteger): BigInteger = + coalesceOrCreate(delegate - other.delegate, this, other) - public actual operator fun plus(other: BigInteger): BigInteger = TODO("Not yet implemented") - public actual operator fun minus(other: BigInteger): BigInteger = TODO("Not yet implemented") - public actual fun toByteArray(): ByteArray = TODO("Not yet implemented") - actual override fun compareTo(other: BigInteger): Int = TODO("Not yet implemented") + public actual fun toByteArray(): ByteArray = delegate.toTwosComplementByteArray() + actual override fun compareTo(other: BigInteger): Int = delegate.compare(other.delegate) } From ca1c1f1c5d3f6ae95170d72338dcbbe747275e12 Mon Sep 17 00:00:00 2001 From: Ian Botsford <83236726+ianbotsf@users.noreply.github.com> Date: Thu, 19 Dec 2024 23:44:23 +0000 Subject: [PATCH 2/6] working implementation of BigInteger/BigDecimal for Kotlin/Native --- runtime/build.gradle.kts | 21 ++++++ .../kotlin/runtime/content/BigDecimal.kt | 74 +++++++++++++++++-- .../kotlin/runtime/content/BigInteger.kt | 63 ++++++++++++++++ .../kotlin/runtime/content/BigDecimalJVM.kt | 51 +++++++++---- .../kotlin/runtime/content/BigIntegerJVM.kt | 36 +++++++-- .../runtime/content/BigDecimalNative.kt | 65 ++++++++-------- .../runtime/content/BigIntegerNative.kt | 26 +++++-- 7 files changed, 270 insertions(+), 66 deletions(-) diff --git a/runtime/build.gradle.kts b/runtime/build.gradle.kts index 393b61436..bea1350f5 100644 --- a/runtime/build.gradle.kts +++ b/runtime/build.gradle.kts @@ -88,6 +88,27 @@ subprojects { tasks.withType { compilerOptions { freeCompilerArgs.add("-Xexpect-actual-classes") + + // FIXME When building LinuxX64 on AL2 the linker inclues a bunch of dynamic links to unavailable versions + // of zlib. The below workaround forces the linker to statically link zlib but it's a hack because the + // linker will still dynamically link zlib (although the executable will no longer fail at runtime due to + // link resolution failures). The correct solution for this is probably containerized builds similar to + // what we do in aws-crt-kotlin. The following compiler args were helpful in debugging this issue: + // * Enable verbose compiler output : -verbose + // * Increase verbosity during the compiler's linker phase : -Xverbose-phases=Linker + // * Enable verbose linker output from gold : -linker-option --verbose + if (target.contains("linux", ignoreCase = true)) { + freeCompilerArgs.addAll( + listOf( + "-linker-option", // The subsequent argument is for the linker + "-Bstatic", // Enable static linking for the libraries that follow + "-linker-option", // The subsequent argument is for the linker + "-lz", // Link zlib statically (because of -Bstatic above) + "-linker-option", // The subsequent argument is for the linker + "-Bdynamic", // Restore dynamic linking, which is the default + ), + ) + } } } } diff --git a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/content/BigDecimal.kt b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/content/BigDecimal.kt index d9af8f85d..408f4080f 100644 --- a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/content/BigDecimal.kt +++ b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/content/BigDecimal.kt @@ -11,32 +11,94 @@ package aws.smithy.kotlin.runtime.content public expect class BigDecimal(value: String) : Number, Comparable { + /** * Create an instance of [BigDecimal] from a mantissa and exponent. - * @param mantissa a [BigInteger] representing the mantissa of this big decimal - * @param exponent an [Int] representing the exponent of this big decimal + * @param mantissa a [BigInteger] representing the [significant digits](https://en.wikipedia.org/wiki/Significand) + * of this decimal value + * @param exponent an [Int] representing the exponent of this decimal value */ public constructor(mantissa: BigInteger, exponent: Int) /** - * The mantissa of this decimal number + * The [significant digits](https://en.wikipedia.org/wiki/Significand) of this decimal value */ public val mantissa: BigInteger /** - * The exponent of this decimal number. - * If zero or positive, this represents the number of digits to the right of the decimal point. - * If negative, the mantissa is multiplied by ten to the power of the negation of the scale. + * The exponent of this decimal number. If zero or positive, this represents the number of digits to the right of + * the decimal point. If negative, the [mantissa] is multiplied by ten to the power of the negation of the scale. */ public val exponent: Int + /** + * Converts this value to a [Byte], which may involve rounding or truncation + */ override fun toByte(): Byte + + /** + * Converts this value to a [Double], which may involve rounding or truncation + */ override fun toDouble(): Double + + /** + * Converts this value to a [Float], which may involve rounding or truncation + */ override fun toFloat(): Float + + /** + * Converts this value to a [Short], which may involve rounding or truncation + */ override fun toShort(): Short + + /** + * Converts this value to an [Int], which may involve rounding or truncation + */ override fun toInt(): Int + + /** + * Converts this value to a [Long], which may involve rounding or truncation + */ override fun toLong(): Long + + /** + * Returns the decimal (i.e., radix-10) string representation of this value in long-form (i.e., _not_ scientific) + * notation + */ public fun toPlainString(): String + + /** + * Returns the decimal (i.e., radix-10) string representation of this value using scientific notation if an exponent + * is needed + */ + override fun toString(): String + + /** + * Returns a hash code for this value + */ + override fun hashCode(): Int + + /** + * Checks if this value is equal to the given object + * @param other The other value to compare against + */ override fun equals(other: Any?): Boolean + + /** + * Returns the sum of this value and the given value + * @param other The other value to add (i.e., the addend) + */ + public operator fun plus(other: BigDecimal): BigDecimal + + /** + * Returns the difference of this value and the given value + * @param other The value to subtract (i.e., the subtrahend) + */ + public operator fun minus(other: BigDecimal): BigDecimal + + /** + * Compare this value to the given value for in/equality + * @param other The value to compare against + */ public override operator fun compareTo(other: BigDecimal): Int } diff --git a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/content/BigInteger.kt b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/content/BigInteger.kt index f223bc36c..798c65300 100644 --- a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/content/BigInteger.kt +++ b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/content/BigInteger.kt @@ -11,23 +11,86 @@ package aws.smithy.kotlin.runtime.content public expect class BigInteger(value: String) : Number, Comparable { + /** * Create an instance of [BigInteger] from a [ByteArray] * @param bytes ByteArray representing the large integer */ public constructor(bytes: ByteArray) + /** + * Converts this value to a [Byte], which may involve rounding or truncation + */ override fun toByte(): Byte + + /** + * Converts this value to a [Long], which may involve rounding or truncation + */ override fun toLong(): Long + + /** + * Converts this value to a [Short], which may involve rounding or truncation + */ override fun toShort(): Short + + /** + * Converts this value to an [Int], which may involve rounding or truncation + */ override fun toInt(): Int + + /** + * Converts this value to a [Float], which may involve rounding or truncation + */ override fun toFloat(): Float + + /** + * Converts this value to a [Double], which may involve rounding or truncation + */ override fun toDouble(): Double + + /** + * Returns the decimal (i.e., radix-10) string representation of this value + */ override fun toString(): String + + /** + * Returns a string representation of this value in the given radix + * @param radix The [numerical base](https://en.wikipedia.org/wiki/Radix) in which to represent the value + */ + public fun toString(radix: Int = 10): String + + /** + * Returns a hash code for this value + */ override fun hashCode(): Int + + /** + * Checks if this value is equal to the given object + * @param other The other value to compare against + */ override fun equals(other: Any?): Boolean + + /** + * Returns the sum of this value and the given value + * @param other The other value to add (i.e., the addend) + */ public operator fun plus(other: BigInteger): BigInteger + + /** + * Returns the difference of this value and the given value + * @param other The value to subtract (i.e., the subtrahend) + */ public operator fun minus(other: BigInteger): BigInteger + + /** + * Returns the [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement) binary representation of this + * value + */ public fun toByteArray(): ByteArray + + /** + * Compare this value to the given value for in/equality + * @param other The value to compare against + */ public override operator fun compareTo(other: BigInteger): Int } diff --git a/runtime/runtime-core/jvm/src/aws/smithy/kotlin/runtime/content/BigDecimalJVM.kt b/runtime/runtime-core/jvm/src/aws/smithy/kotlin/runtime/content/BigDecimalJVM.kt index 9fb5d4efc..a7de1ab95 100644 --- a/runtime/runtime-core/jvm/src/aws/smithy/kotlin/runtime/content/BigDecimalJVM.kt +++ b/runtime/runtime-core/jvm/src/aws/smithy/kotlin/runtime/content/BigDecimalJVM.kt @@ -4,33 +4,52 @@ */ package aws.smithy.kotlin.runtime.content -public actual class BigDecimal actual constructor(public val value: String) : +import java.math.BigDecimal as JvmBigDecimal + +public actual class BigDecimal private constructor(private val delegate: JvmBigDecimal) : Number(), Comparable { - private val delegate = java.math.BigDecimal(value) - public actual constructor(mantissa: BigInteger, exponent: Int) : this( - java.math.BigDecimal( - java.math.BigInteger(mantissa.toString()), - exponent, - ).toPlainString(), - ) + private companion object { + /** + * Returns a new or existing [BigDecimal] wrapper for the given delegate [value] + * @param value The delegate value to wrap + * @param left A candidate wrapper which may already contain [value] + * @param right A candidate wrapper which may already contain [value] + */ + fun coalesceOrCreate(value: JvmBigDecimal, left: BigDecimal, right: BigDecimal): BigDecimal = when (value) { + left.delegate -> left + right.delegate -> right + else -> BigDecimal(value) + } + } + + public actual constructor(value: String) : this(JvmBigDecimal(value)) + public actual constructor(mantissa: BigInteger, exponent: Int) : this(JvmBigDecimal(mantissa.delegate, exponent)) public actual fun toPlainString(): String = delegate.toPlainString() - actual override fun toByte(): Byte = delegate.toByte() - actual override fun toDouble(): Double = delegate.toDouble() - actual override fun toFloat(): Float = delegate.toFloat() - actual override fun toInt(): Int = delegate.toInt() - actual override fun toLong(): Long = delegate.toLong() - actual override fun toShort(): Short = delegate.toShort() + public actual override fun toString(): String = delegate.toString() + public actual override fun toByte(): Byte = delegate.toByte() + public actual override fun toDouble(): Double = delegate.toDouble() + public actual override fun toFloat(): Float = delegate.toFloat() + public actual override fun toInt(): Int = delegate.toInt() + public actual override fun toLong(): Long = delegate.toLong() + public actual override fun toShort(): Short = delegate.toShort() - actual override fun equals(other: Any?): Boolean = other is BigDecimal && delegate == other.delegate + public actual override fun equals(other: Any?): Boolean = other is BigDecimal && delegate == other.delegate + public actual override fun hashCode(): Int = 31 + delegate.hashCode() public actual val mantissa: BigInteger - get() = BigInteger(delegate.unscaledValue().toString()) + get() = BigInteger(delegate.unscaledValue()) public actual val exponent: Int get() = delegate.scale() + public actual operator fun plus(other: BigDecimal): BigDecimal = + coalesceOrCreate(delegate + other.delegate, this, other) + + public actual operator fun minus(other: BigDecimal): BigDecimal = + coalesceOrCreate(delegate - other.delegate, this, other) + actual override fun compareTo(other: BigDecimal): Int = delegate.compareTo(other.delegate) } diff --git a/runtime/runtime-core/jvm/src/aws/smithy/kotlin/runtime/content/BigIntegerJVM.kt b/runtime/runtime-core/jvm/src/aws/smithy/kotlin/runtime/content/BigIntegerJVM.kt index e89d12c9c..2f864710b 100644 --- a/runtime/runtime-core/jvm/src/aws/smithy/kotlin/runtime/content/BigIntegerJVM.kt +++ b/runtime/runtime-core/jvm/src/aws/smithy/kotlin/runtime/content/BigIntegerJVM.kt @@ -4,12 +4,28 @@ */ package aws.smithy.kotlin.runtime.content -public actual class BigInteger actual constructor(public val value: String) : +import java.math.BigInteger as JvmBigInteger + +public actual class BigInteger internal constructor(internal val delegate: JvmBigInteger) : Number(), Comparable { - private val delegate = java.math.BigInteger(value) - public actual constructor(bytes: ByteArray) : this(java.math.BigInteger(bytes).toString()) + private companion object { + /** + * Returns a new or existing [BigInteger] wrapper for the given delegate [value] + * @param value The delegate value to wrap + * @param left A candidate wrapper which may already contain [value] + * @param right A candidate wrapper which may already contain [value] + */ + fun coalesceOrCreate(value: JvmBigInteger, left: BigInteger, right: BigInteger): BigInteger = when (value) { + left.delegate -> left + right.delegate -> right + else -> BigInteger(value) + } + } + + public actual constructor(value: String) : this(JvmBigInteger(value)) + public actual constructor(bytes: ByteArray) : this(JvmBigInteger(bytes)) public actual override fun toByte(): Byte = delegate.toByte() public actual override fun toLong(): Long = delegate.toLong() @@ -17,12 +33,18 @@ public actual class BigInteger actual constructor(public val value: String) : public actual override fun toInt(): Int = delegate.toInt() public actual override fun toFloat(): Float = delegate.toFloat() public actual override fun toDouble(): Double = delegate.toDouble() - public actual override fun toString(): String = delegate.toString() - public actual override fun hashCode(): Int = delegate.hashCode() + public actual override fun toString(): String = toString(10) + public actual fun toString(radix: Int): String = delegate.toString(radix) + + public actual override fun hashCode(): Int = 17 + delegate.hashCode() public actual override fun equals(other: Any?): Boolean = other is BigInteger && delegate == other.delegate - public actual operator fun plus(other: BigInteger): BigInteger = BigInteger((delegate + other.delegate).toString()) - public actual operator fun minus(other: BigInteger): BigInteger = BigInteger((delegate - other.delegate).toString()) + public actual operator fun plus(other: BigInteger): BigInteger = + coalesceOrCreate(delegate + other.delegate, this, other) + + public actual operator fun minus(other: BigInteger): BigInteger = + coalesceOrCreate(delegate - other.delegate, this, other) + public actual override operator fun compareTo(other: BigInteger): Int = delegate.compareTo(other.delegate) public actual fun toByteArray(): ByteArray = delegate.toByteArray() } diff --git a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/content/BigDecimalNative.kt b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/content/BigDecimalNative.kt index 202cebe00..b22085d02 100644 --- a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/content/BigDecimalNative.kt +++ b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/content/BigDecimalNative.kt @@ -4,46 +4,53 @@ */ package aws.smithy.kotlin.runtime.content -public actual class BigDecimal actual constructor(value: String) : +import com.ionspin.kotlin.bignum.decimal.BigDecimal as IonSpinBigDecimal + +public actual class BigDecimal private constructor(private val delegate: IonSpinBigDecimal) : Number(), Comparable { - public actual fun toPlainString(): String { - TODO("Not yet implemented") - } - actual override fun toByte(): Byte { - TODO("Not yet implemented") + private companion object { + /** + * Returns a new or existing [BigDecimal] wrapper for the given delegate [value] + * @param value The delegate value to wrap + * @param left A candidate wrapper which may already contain [value] + * @param right A candidate wrapper which may already contain [value] + */ + fun coalesceOrCreate(value: IonSpinBigDecimal, left: BigDecimal, right: BigDecimal): BigDecimal = when (value) { + left.delegate -> left + right.delegate -> right + else -> BigDecimal(value) + } } - actual override fun toDouble(): Double { - TODO("Not yet implemented") - } + public actual constructor(value: String) : this(IonSpinBigDecimal.parseString(value, 10)) - actual override fun toFloat(): Float { - TODO("Not yet implemented") - } + public actual constructor(mantissa: BigInteger, exponent: Int) : + this(IonSpinBigDecimal.fromBigIntegerWithExponent(mantissa.delegate, exponent.toLong())) - actual override fun toInt(): Int { - TODO("Not yet implemented") - } - - actual override fun toLong(): Long { - TODO("Not yet implemented") - } - - actual override fun toShort(): Short { - TODO("Not yet implemented") - } + actual override fun toByte(): Byte = delegate.byteValue(exactRequired = false) + actual override fun toDouble(): Double = delegate.doubleValue(exactRequired = false) + actual override fun toFloat(): Float = delegate.floatValue(exactRequired = false) + actual override fun toInt(): Int = delegate.intValue(exactRequired = false) + actual override fun toLong(): Long = delegate.longValue(exactRequired = false) + actual override fun toShort(): Short = delegate.shortValue(exactRequired = false) public actual val mantissa: BigInteger - get() = TODO("Not yet implemented") + get() = BigInteger(delegate.significand) public actual val exponent: Int - get() = TODO("Not yet implemented") + get() = delegate.exponent.toInt() - public actual constructor(mantissa: BigInteger, exponent: Int) : this("TODO(Not yet implemented)") { - TODO("Not yet implemented") - } + actual override fun compareTo(other: BigDecimal): Int = delegate.compare(other.delegate) + actual override fun equals(other: Any?): Boolean = other is BigDecimal && other.delegate == delegate + actual override fun hashCode(): Int = 31 + delegate.hashCode() + public actual fun toPlainString(): String = delegate.toPlainString() + actual override fun toString(): String = delegate.toString() + + public actual operator fun plus(other: BigDecimal): BigDecimal = + coalesceOrCreate(delegate + other.delegate, this, other) - actual override fun compareTo(other: BigDecimal): Int = TODO("Not yet implemented") + public actual operator fun minus(other: BigDecimal): BigDecimal = + coalesceOrCreate(delegate - other.delegate, this, other) } diff --git a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/content/BigIntegerNative.kt b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/content/BigIntegerNative.kt index a1b3f7963..09674a0d2 100644 --- a/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/content/BigIntegerNative.kt +++ b/runtime/runtime-core/native/src/aws/smithy/kotlin/runtime/content/BigIntegerNative.kt @@ -8,11 +8,17 @@ import com.ionspin.kotlin.bignum.integer.util.fromTwosComplementByteArray import com.ionspin.kotlin.bignum.integer.util.toTwosComplementByteArray import com.ionspin.kotlin.bignum.integer.BigInteger as IonSpinBigInteger -public actual class BigInteger private constructor(private val delegate: IonSpinBigInteger) : +public actual class BigInteger internal constructor(internal val delegate: IonSpinBigInteger) : Number(), Comparable { private companion object { + /** + * Returns a new or existing [BigInteger] wrapper for the given delegate [value] + * @param value The delegate value to wrap + * @param left A candidate wrapper which may already contain [value] + * @param right A candidate wrapper which may already contain [value] + */ fun coalesceOrCreate(value: IonSpinBigInteger, left: BigInteger, right: BigInteger): BigInteger = when (value) { left.delegate -> left right.delegate -> right @@ -23,12 +29,12 @@ public actual class BigInteger private constructor(private val delegate: IonSpin public actual constructor(value: String) : this(IonSpinBigInteger.parseString(value, 10)) public actual constructor(bytes: ByteArray) : this(IonSpinBigInteger.fromTwosComplementByteArray(bytes)) - actual override fun toByte(): Byte = delegate.byteValue(exactRequired = false) - actual override fun toDouble(): Double = delegate.doubleValue(exactRequired = false) - actual override fun toFloat(): Float = delegate.floatValue(exactRequired = false) - actual override fun toInt(): Int = delegate.intValue(exactRequired = false) - actual override fun toLong(): Long = delegate.longValue(exactRequired = false) - actual override fun toShort(): Short = delegate.shortValue(exactRequired = false) + public actual override fun toByte(): Byte = delegate.byteValue(exactRequired = false) + public actual override fun toDouble(): Double = delegate.doubleValue(exactRequired = false) + public actual override fun toFloat(): Float = delegate.floatValue(exactRequired = false) + public actual override fun toInt(): Int = delegate.intValue(exactRequired = false) + public actual override fun toLong(): Long = delegate.longValue(exactRequired = false) + public actual override fun toShort(): Short = delegate.shortValue(exactRequired = false) public actual operator fun plus(other: BigInteger): BigInteger = coalesceOrCreate(delegate + other.delegate, this, other) @@ -37,5 +43,9 @@ public actual class BigInteger private constructor(private val delegate: IonSpin coalesceOrCreate(delegate - other.delegate, this, other) public actual fun toByteArray(): ByteArray = delegate.toTwosComplementByteArray() - actual override fun compareTo(other: BigInteger): Int = delegate.compare(other.delegate) + public actual override fun compareTo(other: BigInteger): Int = delegate.compare(other.delegate) + public actual override fun equals(other: Any?): Boolean = other is BigInteger && other.delegate == delegate + public actual override fun hashCode(): Int = 17 + delegate.hashCode() + public actual override fun toString(): String = toString(10) + public actual fun toString(radix: Int): String = delegate.toString(radix) } From 1679172ef2ef2fa8a1d86b1727e94bb7047fc19a Mon Sep 17 00:00:00 2001 From: Ian Botsford <83236726+ianbotsf@users.noreply.github.com> Date: Thu, 19 Dec 2024 23:45:36 +0000 Subject: [PATCH 3/6] remove unused import --- runtime/runtime-core/build.gradle.kts | 2 -- 1 file changed, 2 deletions(-) diff --git a/runtime/runtime-core/build.gradle.kts b/runtime/runtime-core/build.gradle.kts index 226c4240d..54979250c 100644 --- a/runtime/runtime-core/build.gradle.kts +++ b/runtime/runtime-core/build.gradle.kts @@ -1,5 +1,3 @@ -import org.gradle.api.tasks.testing.logging.TestExceptionFormat - /* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0 From 5698dc3cbb1ec700f22fa59893fc6e6c563a1cc7 Mon Sep 17 00:00:00 2001 From: Ian Botsford <83236726+ianbotsf@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:46:25 +0000 Subject: [PATCH 4/6] remove unnecessary libbacktrace usage --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index aab7fa746..7dcb1c424 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ kotlin.code.style=official kotlin.incremental.js=true kotlin.incremental.multiplatform=true kotlin.mpp.stability.nowarn=true -kotlin.native.binary.sourceInfoType=libbacktrace +# kotlin.native.binary.sourceInfoType=libbacktrace kotlin.native.ignoreDisabledTargets=true # atomicfu From 5d492c3f36c47017923fe78ede362132c5b96746 Mon Sep 17 00:00:00 2001 From: Ian Botsford <83236726+ianbotsf@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:48:09 +0000 Subject: [PATCH 5/6] update API manifest --- runtime/runtime-core/api/runtime-core.api | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/runtime/runtime-core/api/runtime-core.api b/runtime/runtime-core/api/runtime-core.api index 942f99e34..a1628eeeb 100644 --- a/runtime/runtime-core/api/runtime-core.api +++ b/runtime/runtime-core/api/runtime-core.api @@ -343,6 +343,7 @@ public final class aws/smithy/kotlin/runtime/config/EnvironmentSettingKt { public final class aws/smithy/kotlin/runtime/content/BigDecimal : java/lang/Number, java/lang/Comparable { public fun (Laws/smithy/kotlin/runtime/content/BigInteger;I)V public fun (Ljava/lang/String;)V + public synthetic fun (Ljava/math/BigDecimal;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun byteValue ()B public fun compareTo (Laws/smithy/kotlin/runtime/content/BigDecimal;)I public synthetic fun compareTo (Ljava/lang/Object;)I @@ -351,9 +352,11 @@ public final class aws/smithy/kotlin/runtime/content/BigDecimal : java/lang/Numb public final fun floatValue ()F public final fun getExponent ()I public final fun getMantissa ()Laws/smithy/kotlin/runtime/content/BigInteger; - public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I public final fun intValue ()I public final fun longValue ()J + public final fun minus (Laws/smithy/kotlin/runtime/content/BigDecimal;)Laws/smithy/kotlin/runtime/content/BigDecimal; + public final fun plus (Laws/smithy/kotlin/runtime/content/BigDecimal;)Laws/smithy/kotlin/runtime/content/BigDecimal; public final fun shortValue ()S public fun toByte ()B public fun toDouble ()D @@ -362,6 +365,7 @@ public final class aws/smithy/kotlin/runtime/content/BigDecimal : java/lang/Numb public fun toLong ()J public final fun toPlainString ()Ljava/lang/String; public fun toShort ()S + public fun toString ()Ljava/lang/String; } public final class aws/smithy/kotlin/runtime/content/BigInteger : java/lang/Number, java/lang/Comparable { @@ -373,7 +377,6 @@ public final class aws/smithy/kotlin/runtime/content/BigInteger : java/lang/Numb public final fun doubleValue ()D public fun equals (Ljava/lang/Object;)Z public final fun floatValue ()F - public final fun getValue ()Ljava/lang/String; public fun hashCode ()I public final fun intValue ()I public final fun longValue ()J @@ -388,6 +391,8 @@ public final class aws/smithy/kotlin/runtime/content/BigInteger : java/lang/Numb public fun toLong ()J public fun toShort ()S public fun toString ()Ljava/lang/String; + public final fun toString (I)Ljava/lang/String; + public static synthetic fun toString$default (Laws/smithy/kotlin/runtime/content/BigInteger;IILjava/lang/Object;)Ljava/lang/String; } public abstract class aws/smithy/kotlin/runtime/content/ByteStream { From 16c85d1090fbe7c2dbb0377d95ec2a12de9d7328 Mon Sep 17 00:00:00 2001 From: Ian Botsford <83236726+ianbotsf@users.noreply.github.com> Date: Fri, 20 Dec 2024 22:51:09 +0000 Subject: [PATCH 6/6] tickle CI