to Native
Converts this SCValXdr to a native Kotlin value without a contract spec.
The conversion is total: it never throws, whatever the receiver contains. Every arm has a defined result, and where a value has no native representation the result is the SCValXdr itself (the same instance, never a copy), so a caller detects that case with is SCValXdr. The receiver and its children are never mutated. The ByteArray returned for a bytes value is the stored payload array, so writing to it writes through to the receiver.
Value conversion
SCV_BOOL→BooleanSCV_VOID→nullSCV_U32→UInt;SCV_I32→IntSCV_U64,SCV_TIMEPOINT,SCV_DURATION→ULong;SCV_I64→LongSCV_U128,SCV_I128,SCV_U256,SCV_I256→BigInteger(com.ionspin.kotlin.bignum.integer.BigInteger, as returned by Scv.fromUint128, Scv.fromInt128, Scv.fromUint256 and Scv.fromInt256)SCV_BYTES→ByteArraySCV_STRING,SCV_SYMBOL→StringSCV_ADDRESS→ strkeyString(G...,C...,M...,B...orL...)SCV_VEC→List<Any?>with each element converted recursively, in order; an absent payload yields an empty listSCV_MAP→Map<Any?, Any?>under the key rules below; an absent payload yields an empty mapSCV_ERROR,SCV_CONTRACT_INSTANCE,SCV_LEDGER_KEY_CONTRACT_INSTANCE,SCV_LEDGER_KEY_NONCE,SCV_EXECUTABLE_TAG→ the SCValXdr itself. The same holds for an address whose bytes have no strkey encoding and for a SCValXdr.Void whose discriminant is anything other thanSCV_VOID. TheScv.from*accessors, for example Scv.fromError or Scv.fromExecutableTagBytes, read those payloads on request.
Map keys
Map keys need value-based equality, which ByteArray and the generated XDR types do not provide, so keys use a narrower conversion than values:
SCV_SYMBOL,SCV_STRING→StringSCV_U32→UInt;SCV_I32→IntSCV_U64,SCV_TIMEPOINT,SCV_DURATION→ULong;SCV_I64→LongSCV_U128,SCV_I128,SCV_U256,SCV_I256→BigIntegerSCV_BOOL→BooleanSCV_VOID→nullSCV_BYTES→ lowercase hexString; this is the one asymmetry between the two tables, since a bytes value stays aByteArraySCV_ADDRESS→ strkeyString, the same representation as for a value
Every other key arm is unrepresentable. A map with an unrepresentable key, or with two entries whose converted keys are equal, converts to the SCValXdr itself as a whole. A nested map that falls back is contained: the enclosing vec or map still converts, with that map left as an SCValXdr element.
Key equality is plain Kotlin equals/hashCode on the converted keys, and a key is looked up with the exact type the table above gives, so a 128-bit or 256-bit key is looked up with a BigInteger. The primitive integer types are never normalized against each other, and a wide-integer key and a primitive integer key are compared by numeric value:
Primitive integer keys of equal value from different arms are distinct: a
U32key5(UInt) and aU64key5(ULong) coexist as two entries.A wide-integer key and a primitive integer key of equal value are the same key: an
I128key5and aU64key5collide, so such a map falls back. Keys whose values differ never collide, so anI128key-1and aU64key18446744073709551615coexist.Wide-integer keys of equal value collide even across arms: a
U128key5and anI256key5are the same key, so such a map falls back.A bytes key collides with a symbol or string key spelling its hex: the bytes
[0x30, 0x31]and the symbol"3031"are the same key, so such a map falls back.
The resulting map preserves the entry order of the XDR map.
Relation to ContractSpec
com.soneso.stellar.sdk.contract.ContractSpec.funcResToNative and com.soneso.stellar.sdk.contract.ContractSpec.scValToNative convert with a contract spec, which lets them reconstruct structs, unions and enums. This function is the spec-less companion for values whose spec is unavailable or unneeded, and its output shapes differ: a map becomes a Map here and a list of pairs on the spec path, and error, contract-instance and executable-tag values are returned as the SCValXdr itself here where the spec path unwraps their payloads.
Usage
val scVal = Scv.toMap(linkedMapOf(
Scv.toSymbol("balance") to Scv.toInt128(BigInteger.fromLong(1_000L)),
Scv.toSymbol("tags") to Scv.toVec(listOf(Scv.toString("a"), Scv.toString("b")))
))
val native = scVal.toNative() as Map<*, *>
native["balance"] // BigInteger 1000
native["tags"] // ["a", "b"]
// A value with no native form comes back unchanged
val tag = Scv.toExecutableTag("v1").toNative()
check(tag is SCValXdr)Receiver
the value to convert
Return
the native Kotlin value, null for SCV_VOID, or this SCValXdr itself when the value has no native representation