Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
main.org.onflow.flow.sdk.cadence.json-cadence-marshalling.kt Maven / Gradle / Ivy
package org.onflow.flow.sdk.cadence
import org.onflow.flow.sdk.Flow
import org.onflow.flow.sdk.FlowAddress
import org.onflow.flow.sdk.cadence.CadenceNamespace.Companion.ns
import java.lang.annotation.Inherited
import java.math.BigDecimal
import java.math.BigInteger
import kotlin.reflect.KClass
import kotlin.reflect.full.createInstance
@Inherited
@MustBeDocumented
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class JsonCadenceConversion(
val converter: KClass>
)
data class CadenceNamespace(
val parts: List = emptyList()
) {
companion object {
@JvmStatic
fun ns(vararg values: String): CadenceNamespace = CadenceNamespace(*values)
@JvmStatic
fun ns(address: FlowAddress): CadenceNamespace = CadenceNamespace("A", address.base16Value)
@JvmStatic
fun ns(address: FlowAddress, vararg values: String): CadenceNamespace = CadenceNamespace("A", address.base16Value, *values)
}
constructor(vararg value: String) : this(value.toList())
val value: String = parts.joinToString(separator = ".")
fun withNamespace(id: String): String = (parts + id).joinToString(separator = ".")
fun withoutNamespace(id: String): String = id.replace("$value.", "")
fun push(namespace: String): CadenceNamespace = this.copy(
parts = this.parts + namespace
)
fun push(address: FlowAddress): CadenceNamespace = push(address.base16Value)
fun pop(count: Int = 1): CadenceNamespace = this.copy(
parts = this.parts.dropLast(count)
)
operator fun plus(element: String): CadenceNamespace = this.push(element)
operator fun plus(element: FlowAddress): CadenceNamespace = this.push(element)
}
interface JsonCadenceConverter {
fun unmarshall(value: Field<*>, namespace: CadenceNamespace): T {
throw UnsupportedOperationException("${this::class.simpleName} cannot deserialize $value")
}
fun marshall(value: T, namespace: CadenceNamespace): Field<*> {
throw UnsupportedOperationException("${this::class.simpleName} cannot serializer $value")
}
}
object JsonCadenceMarshalling {
private val MARSHALLER_CACHE_JSON: MutableMap, JsonCadenceConverter<*>> = mutableMapOf()
@JvmStatic
@JvmOverloads
@Synchronized
@Suppress("UNCHECKED_CAST")
fun getSerializer(type: KClass, cache: Boolean = true): JsonCadenceConverter {
var ret = if (cache) {
MARSHALLER_CACHE_JSON[type]
} else {
null
}
if (ret == null) {
ret = type.annotations
.find { it is JsonCadenceConversion }
?.let { it as JsonCadenceConversion }
?.converter
?.createInstance()
}
if (ret != null && cache) {
MARSHALLER_CACHE_JSON[type] = ret
} else if (ret == null) {
throw IllegalArgumentException("No JsonCadenceSerializer found for ${type.simpleName}")
}
return ret as JsonCadenceConverter
}
@JvmStatic
fun unmarshall(type: KClass, value: Field<*>, namespace: FlowAddress): T = getSerializer(type).unmarshall(value, ns(namespace))
@JvmStatic
@JvmOverloads
fun unmarshall(type: KClass, value: Field<*>, namespace: CadenceNamespace = CadenceNamespace()): T = getSerializer(type).unmarshall(value, namespace)
@JvmStatic
fun marshall(value: T, clazz: KClass, namespace: FlowAddress): Field<*> = getSerializer(clazz).marshall(value, ns(namespace))
@JvmStatic
@JvmOverloads
fun marshall(value: T, clazz: KClass, namespace: CadenceNamespace = CadenceNamespace()): Field<*> = getSerializer(clazz).marshall(value, namespace)
@JvmStatic
fun marshall(value: T, namespace: FlowAddress): Field<*> = getSerializer(value::class).marshall(value, ns(namespace))
@JvmStatic
@JvmOverloads
fun marshall(value: T, namespace: CadenceNamespace = CadenceNamespace()): Field<*> = getSerializer(value::class).marshall(value, namespace)
}
fun > marshall(block: JsonCadenceBuilder.() -> T): T = block(JsonCadenceBuilder())
class JsonCadenceBuilder {
fun marshall(value: T, clazz: KClass = value::class, namespace: FlowAddress): Field<*> = Flow.marshall(value, clazz, namespace)
fun marshall(value: T, clazz: KClass = value::class, namespace: CadenceNamespace = CadenceNamespace()): Field<*> = Flow.marshall(value, clazz, namespace)
fun void(): VoidField = VoidField()
fun optional(block: JsonCadenceBuilder.() -> Field<*>?): OptionalField = OptionalField(block())
fun optional(value: Field<*>?): OptionalField = OptionalField(value)
fun optional(value: T?, block: JsonCadenceBuilder.(T) -> Field<*>?): OptionalField = OptionalField(value?.let { block(it) })
fun boolean(value: Boolean): BooleanField = BooleanField(value)
fun string(value: String): StringField = StringField(value)
fun array(value: Iterable>): ArrayField = ArrayField(value)
fun array(value: Iterable, mapper: JsonCadenceBuilder.(T) -> Field<*>): ArrayField = ArrayField(value.map { mapper(it) })
fun array(block: JsonCadenceBuilder.() -> Iterable>): ArrayField = ArrayField(block().toList().toTypedArray())
fun byteArray(value: Array): ArrayField = ArrayField(value.map { uint8(it) })
fun byteArray(value: ByteArray): ArrayField = byteArray(value.map { it.toUByte() }.toTypedArray())
fun dictionary(value: Iterable): DictionaryField = DictionaryField(value)
fun dictionary(block: JsonCadenceBuilder.() -> Array): DictionaryField = DictionaryField(block().toList().toTypedArray())
fun dictionaryOfMap(block: JsonCadenceBuilder.() -> Map, Field<*>>): DictionaryField = DictionaryField(block().map { DictionaryFieldEntry(it.key, it.value) })
fun dictionaryOfNamedMap(block: JsonCadenceBuilder.() -> Map>): DictionaryField = DictionaryField(block().map { DictionaryFieldEntry(StringField(it.key), it.value) })
fun dictionaryOfPairs(block: JsonCadenceBuilder.() -> Iterable, Field<*>>>): DictionaryField = DictionaryField(block().map { DictionaryFieldEntry(it.first, it.second) })
fun dictionaryOfNamedPairs(block: JsonCadenceBuilder.() -> Iterable>>): DictionaryField = DictionaryField(block().map { DictionaryFieldEntry(StringField(it.first), it.second) })
fun dictionary(value: Map, mapper: JsonCadenceBuilder.(Map.Entry) -> Pair, Field<*>>): DictionaryField = DictionaryField(value.map { DictionaryFieldEntry(mapper(it)) })
fun dictionaryOfNamed(value: Map, mapper: JsonCadenceBuilder.(Map.Entry) -> Pair>): DictionaryField = DictionaryField(value.map { DictionaryFieldEntry(mapper(it).let { p -> string(p.first) to p.second }) })
fun address(value: FlowAddress): AddressField = AddressField(value.formatted)
fun address(value: String): AddressField = AddressField(value)
fun address(value: ByteArray): AddressField = AddressField(value)
fun path(value: PathValue): PathField = PathField(value)
fun path(domain: String, identifier: String): PathField = PathField(PathValue(domain, identifier))
fun capability(value: CapabilityValue): CapabilityField = CapabilityField(value)
fun capability(path: String, address: String, borrowType: String): CapabilityField = CapabilityField(CapabilityValue(path, address, borrowType))
fun composite(id: String, fields: Array): CompositeValue = CompositeValue(id, fields.toList().toTypedArray())
fun composite(id: String, fields: Iterable>>): CompositeValue = CompositeValue(id, fields.map { CompositeAttribute(it.first, it.second) }.toTypedArray())
fun composite(id: String, fields: Map>): CompositeValue = CompositeValue(id, fields.map { CompositeAttribute(it.key, it.value) }.toTypedArray())
fun composite(id: String, block: JsonCadenceBuilder.() -> Array): CompositeValue = CompositeValue(id, block().toList().toTypedArray())
fun compositeOfPairs(id: String, block: JsonCadenceBuilder.() -> Iterable>>): CompositeValue = CompositeValue(id, block().map { CompositeAttribute(it.first, it.second) }.toTypedArray())
fun compositeOfNamedMap(id: String, block: JsonCadenceBuilder.() -> Map>): CompositeValue = CompositeValue(id, block().map { CompositeAttribute(it.key, it.value) }.toTypedArray())
fun struct(value: CompositeValue): StructField = StructField(value)
fun struct(block: JsonCadenceBuilder.() -> CompositeValue): StructField = StructField(block())
fun resource(value: CompositeValue): ResourceField = ResourceField(value)
fun resource(block: JsonCadenceBuilder.() -> CompositeValue): ResourceField = ResourceField(block())
fun event(value: CompositeValue): EventField = EventField(value)
fun event(block: JsonCadenceBuilder.() -> CompositeValue): EventField = EventField(block())
fun contract(value: CompositeValue): ContractField = ContractField(value)
fun contract(block: JsonCadenceBuilder.() -> CompositeValue): ContractField = ContractField(block())
fun > enum(value: T, namespace: CadenceNamespace = CadenceNamespace()): EnumField = enum(namespace.withNamespace(value.declaringJavaClass.simpleName), uint8(value.ordinal))
fun enum(value: CompositeValue): EnumField = EnumField(value)
fun enum(block: JsonCadenceBuilder.() -> CompositeValue): EnumField = EnumField(block())
fun enum(id: String, value: Field<*>): EnumField = EnumField(compositeOfPairs(id) { listOf("rawValue" to value) })
fun number(type: String, value: String): NumberField = NumberField(type, value)
fun number(type: String, value: Number): NumberField = NumberField(type, value.toString())
fun int(value: Number): IntNumberField = IntNumberField(value.toString())
fun uint(value: Number): UIntNumberField = UIntNumberField(value.toString())
fun int8(value: Number): Int8NumberField = Int8NumberField(value.toString())
fun uint8(value: Number): UInt8NumberField = UInt8NumberField(value.toString())
fun uint8(value: UByte): UInt8NumberField = UInt8NumberField(value.toString())
fun int16(value: Number): Int16NumberField = Int16NumberField(value.toString())
fun uint16(value: Number): UInt16NumberField = UInt16NumberField(value.toString())
fun uint16(value: UShort): UInt16NumberField = UInt16NumberField(value.toString())
fun int32(value: Number): Int32NumberField = Int32NumberField(value.toString())
fun uint32(value: Number): UInt32NumberField = UInt32NumberField(value.toString())
fun uint32(value: UInt): UInt64NumberField = UInt64NumberField(value.toString())
fun int64(value: Number): Int64NumberField = Int64NumberField(value.toString())
fun uint64(value: Number): UInt64NumberField = UInt64NumberField(value.toString())
fun uint64(value: ULong): UInt64NumberField = UInt64NumberField(value.toString())
fun int128(value: Number): Int128NumberField = Int128NumberField(value.toString())
fun uint128(value: Number): UInt128NumberField = UInt128NumberField(value.toString())
fun int256(value: Number): Int256NumberField = Int256NumberField(value.toString())
fun uint256(value: Number): UInt256NumberField = UInt256NumberField(value.toString())
fun word8(value: Number): Word8NumberField = Word8NumberField(value.toString())
fun word16(value: Number): Word16NumberField = Word16NumberField(value.toString())
fun word32(value: Number): Word32NumberField = Word32NumberField(value.toString())
fun word64(value: Number): Word64NumberField = Word64NumberField(value.toString())
fun fix64(value: Number): Fix64NumberField = Fix64NumberField("%.8f".format(BigDecimal(value.toString())))
fun ufix64(value: Number): UFix64NumberField = UFix64NumberField("%.8f".format(BigDecimal(value.toString())))
fun fix64(value: String): Fix64NumberField = fix64(BigDecimal(value))
fun ufix64(value: String): UFix64NumberField = ufix64(BigDecimal(value))
fun int(value: String): IntNumberField = IntNumberField(value)
fun uint(value: String): UIntNumberField = UIntNumberField(value)
fun int8(value: String): Int8NumberField = Int8NumberField(value)
fun uint8(value: String): UInt8NumberField = UInt8NumberField(value)
fun int16(value: String): Int16NumberField = Int16NumberField(value)
fun uint16(value: String): UInt16NumberField = UInt16NumberField(value)
fun int32(value: String): Int32NumberField = Int32NumberField(value)
fun uint32(value: String): UInt32NumberField = UInt32NumberField(value)
fun int64(value: String): Int64NumberField = Int64NumberField(value)
fun uint64(value: String): UInt64NumberField = UInt64NumberField(value)
fun int128(value: String): Int128NumberField = Int128NumberField(value)
fun uint128(value: String): UInt128NumberField = UInt128NumberField(value)
fun int256(value: String): Int256NumberField = Int256NumberField(value)
fun uint256(value: String): UInt256NumberField = UInt256NumberField(value)
fun word8(value: String): Word8NumberField = Word8NumberField(value)
fun word16(value: String): Word16NumberField = Word16NumberField(value)
fun word32(value: String): Word32NumberField = Word32NumberField(value)
fun word64(value: String): Word64NumberField = Word64NumberField(value)
}
fun unmarshall(root: Field<*>, block: JsonCadenceParser.() -> T): T {
val parser = JsonCadenceParser()
if (root is CompositeField) {
parser.push(root)
}
return block(parser)
}
class JsonCadenceParser {
var compositeStack: MutableList = mutableListOf()
val composite: CompositeField get() = compositeStack.last()
val compositeValue: CompositeValue get() = composite.value!!
fun push(composite: CompositeField) = compositeStack.add(composite)
fun pop(): CompositeField = compositeStack.removeLast()
fun > field(name: String): T = compositeValue.getRequiredField(name)
fun withField(composite: CompositeField, block: JsonCadenceParser.() -> T): T {
push(composite)
try {
return block(this)
} finally {
pop()
}
}
inline fun unmarshall(name: String): T = Flow.unmarshall(T::class, field(name))
inline fun unmarshall(name: String, namespace: CadenceNamespace = CadenceNamespace()): T = Flow.unmarshall(T::class, field(name), namespace)
inline fun unmarshall(name: String, namespace: FlowAddress): T = Flow.unmarshall(T::class, field(name), namespace)
inline fun unmarshall(name: String, type: KClass): T = Flow.unmarshall(type, field(name))
inline fun unmarshall(name: String, type: KClass, namespace: CadenceNamespace = CadenceNamespace()): T = Flow.unmarshall(type, field(name), namespace)
inline fun unmarshall(name: String, type: KClass, namespace: FlowAddress): T = Flow.unmarshall(type, field(name), namespace)
inline fun unmarshall(field: Field<*>, namespace: CadenceNamespace = CadenceNamespace()): T = Flow.unmarshall(T::class, field, namespace)
inline fun unmarshall(field: Field<*>, namespace: FlowAddress): T = Flow.unmarshall(T::class, field, namespace)
inline fun unmarshall(field: Field<*>, type: KClass, namespace: CadenceNamespace = CadenceNamespace()): T = Flow.unmarshall(type, field, namespace)
inline fun unmarshall(field: Field<*>, type: KClass, namespace: FlowAddress): T = Flow.unmarshall(type, field, namespace)
fun > field(name: String, block: JsonCadenceParser.(field: F) -> T): T = block(field(name))
fun boolean(field: Field<*>): Boolean = (field as BooleanField).value!!
fun string(field: Field<*>): String = (field as StringField).value!!
fun address(field: Field<*>): String = (field as AddressField).value!!
fun short(field: Field<*>): Short = (field as NumberField).toShort()!!
fun ushort(field: Field<*>): UShort = (field as NumberField).toUShort()!!
fun int(field: Field<*>): Int = (field as NumberField).toInt()!!
fun uint(field: Field<*>): UInt = (field as NumberField).toUInt()!!
fun long(field: Field<*>): Long = (field as NumberField).toLong()!!
fun ulong(field: Field<*>): ULong = (field as NumberField).toULong()!!
fun bigInteger(field: Field<*>): BigInteger = (field as NumberField).toBigInteger()!!
fun float(field: Field<*>): Float = (field as NumberField).toFloat()!!
fun double(field: Field<*>): Double = (field as NumberField).toDouble()!!
fun bigDecimal(field: Field<*>): BigDecimal = (field as NumberField).toBigDecimal()!!
fun array(field: Field<*>, block: JsonCadenceParser.(field: ArrayField) -> T): T = block(field as ArrayField)
fun arrayValues(field: Field<*>, mapper: JsonCadenceParser.(field: Field<*>) -> T): List = (field as ArrayField).value!!.map { mapper(it) }
fun byteArray(field: Field<*>): ByteArray = arrayValues(field) { (it as UInt8NumberField).toByte()!! }.toByteArray()
fun dictionary(field: Field<*>, block: JsonCadenceParser.(field: DictionaryField) -> T): T = block(field as DictionaryField)
fun dictionaryPairs(field: Field<*>, mapper: JsonCadenceParser.(key: Field<*>, value: Field<*>) -> Pair): List> = (field as DictionaryField).value!!.map { mapper(it.key, it.value) }
fun dictionaryMap(field: Field<*>, mapper: JsonCadenceParser.(key: Field<*>, value: Field<*>) -> Pair): Map = dictionaryPairs(field, mapper).toMap()
inline fun , V : Field<*>> enum(field: Field<*>, crossinline mapper: (V) -> T): T {
return withField(field as CompositeField) {
val f = compositeValue.getRequiredField("rawValue")
mapper(f)
}
}
inline fun > enum(field: Field<*>): T = enum(field) { f -> f.toInt()!!.let { enumValues()[it] } }
fun optional(field: Field<*>, block: JsonCadenceParser.(field: Field<*>) -> T): T? {
if (field !is OptionalField) {
throw IllegalArgumentException("field is not an OptionalField")
}
return field.value?.let { block(it) }
}
fun boolean(name: String): Boolean = boolean(field(name))
fun string(name: String): String = string(field(name))
fun address(name: String): String = address(field(name))
fun short(name: String): Short = short(field(name))
fun ushort(name: String): UShort = ushort(field(name))
fun int(name: String): Int = int(field(name))
fun uint(name: String): UInt = uint(field(name))
fun long(name: String): Long = long(field(name))
fun ulong(name: String): ULong = ulong(field(name))
fun bigInteger(name: String): BigInteger = bigInteger(field(name))
fun float(name: String): Float = float(field(name))
fun double(name: String): Double = double(field(name))
fun bigDecimal(name: String): BigDecimal = bigDecimal(field(name))
fun array(name: String, block: JsonCadenceParser.(field: ArrayField) -> T): T = array(field(name), block)
fun arrayValues(name: String, mapper: JsonCadenceParser.(field: Field<*>) -> T): List = arrayValues(field(name), mapper)
fun byteArray(name: String): ByteArray = byteArray(field(name))
fun dictionary(name: String, block: JsonCadenceParser.(field: DictionaryField) -> T): T = dictionary(field(name), block)
fun dictionaryPairs(name: String, mapper: JsonCadenceParser.(key: Field<*>, value: Field<*>) -> Pair): List> = dictionaryPairs(field(name), mapper)
fun dictionaryMap(name: String, mapper: JsonCadenceParser.(key: Field<*>, value: Field<*>) -> Pair): Map = dictionaryPairs(name, mapper).toMap()
inline fun , V : Field<*>> enum(name: String, crossinline mapper: (V) -> T): T = enum(field(name), mapper)
inline fun > enum(name: String): T = enum(field(name))
fun optional(name: String, block: JsonCadenceParser.(field: Field<*>) -> T): T? = optional(field(name), block)
}