All files / src/chain variant.ts

96.42% Statements 27/28
83.33% Branches 10/12
100% Functions 9/9
96.29% Lines 26/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85                                        1x 1x         147x 76x   71x 2x   69x               76x 76x 293x 76x     76x                   5x 5x 5x 1x   4x       115x 115x         40x       1x 1x 8x 8x 8x 8x        
import {
    ABISerializable,
    ABISerializableConstructor,
    ABISerializableObject,
    ABISerializableType,
    ABITypeDescriptor,
    abiTypeString,
    toTypeDescriptor,
} from '../serializer/serializable'
import {abiDecode, Resolved} from '../serializer/decoder'
import {abiEncode} from '../serializer/encoder'
import {isInstanceOf} from '../utils'
 
export interface VariantConstructor extends ABISerializableConstructor {
    new <T extends Variant>(...args: any[]): T
}
 
export type AnyVariant = Variant | ABISerializable | [string, any]
 
export class Variant implements ABISerializableObject {
    static abiName = '__variant'
    static abiVariant: ABITypeDescriptor[] = []
 
    static from<T extends VariantConstructor>(this: T, object: AnyVariant): InstanceType<T>
    static from(object: AnyVariant): unknown
    static from(object: AnyVariant) {
        if (object[Resolved]) {
            return new this(object as [string, ABISerializable])
        }
        if (isInstanceOf(object, this)) {
            return object
        }
        return abiDecode({object, type: this})
    }
 
    value: ABISerializable
    variantIdx: number
 
    /** @internal */
    constructor(variant: [string, ABISerializable]) {
        const abiVariant = (this.constructor as VariantConstructor).abiVariant!
        this.value = variant[1]
        const variantIdx = abiVariant.map(abiTypeString).findIndex((t) => t === variant[0])
        Iif (0 > variantIdx || abiVariant.length <= variantIdx) {
            throw new Error(`Unknown variant ${variant[0]}`)
        }
        this.variantIdx = variantIdx
    }
 
    /**
     * Return true if this variant equals the other.
     *
     * Note: This compares the ABI encoded bytes of both variants, subclasses
     *       should implement their own fast equality check when possible.
     */
    equals(other: AnyVariant): boolean {
        const self = this.constructor as typeof Variant
        const otherVariant = self.from(other)
        if (this.variantIdx !== otherVariant.variantIdx) {
            return false
        }
        return abiEncode({object: this}).equals(abiEncode({object: otherVariant}))
    }
 
    get variantName(): string {
        const variant = (this.constructor as VariantConstructor).abiVariant![this.variantIdx]
        return abiTypeString(variant)
    }
 
    /** @internal */
    toJSON() {
        return [this.variantName, this.value]
    }
}
 
export namespace Variant {
    export function type(name: string, types: ABISerializableType[]) {
        return function <T extends VariantConstructor>(variant: T) {
            variant.abiName = name
            variant.abiVariant = types.map(toTypeDescriptor)
            return variant
        }
    }
}