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 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | 17373x 12408x 12408x 4965x 1x 1x 6715x 3767x 2948x 14x 2934x 3933x 3933x 4514x 581x 4514x 18064x 3933x 3933x 3769x 3769x 17371x 17371x 17371x 17209x 17205x 5x 5x 5x 164x 164x 164x 693x 685x 683x 164x 1x 1x 93x 93x 93x 388x 388x 388x 88x 88x 300x 4x 4x 4x 388x | import {
ABIField,
ABISerializableConstructor,
ABISerializableObject,
ABITypeModifiers,
} from '../serializer/serializable'
import {abiDecode, Resolved} from '../serializer/decoder'
import {abiEncode} from '../serializer/encoder'
import {isInstanceOf} from '../utils'
import {ABI} from './abi'
export interface StructConstructor extends ABISerializableConstructor {
new <T extends Struct>(...args: any[]): T
structFields: ABIField[]
}
function fieldModifiers(field: ABIField) {
if (typeof field.type === 'string') {
const resolved = new ABI.ResolvedType(field.type)
return {isOptional: resolved.isOptional, isExtension: resolved.isExtension}
}
return {isOptional: !!field.optional, isExtension: !!field.extension}
}
export class Struct implements ABISerializableObject {
static abiName = '__struct'
static abiFields: ABIField[]
static abiBase: ABISerializableConstructor
static from<T extends StructConstructor>(this: T, value: any): InstanceType<T>
static from(value: any): unknown
static from(value: any) {
if (value[Resolved] === true) {
// objects already resolved
return new this(value)
}
if (isInstanceOf(value, this)) {
return value
}
return abiDecode({object: value, type: this})
}
static get structFields() {
const rv: ABIField[] = []
const walk = (t: ABISerializableConstructor) => {
if (t.abiBase) {
walk(t.abiBase)
}
for (const field of t.abiFields || []) {
rv.push(field)
}
}
walk(this)
return rv
}
/** @internal */
constructor(object: any) {
const self = this.constructor as typeof Struct
for (const field of self.structFields) {
const {isOptional, isExtension} = fieldModifiers(field)
const value = object[field.name]
if (isOptional && !value) continue
if (isExtension && value === undefined) continue
this[field.name] = value
}
}
/**
* Return true if this struct equals the other.
*
* Note: This compares the ABI encoded bytes of both structs, subclasses
* should implement their own fast equality check when possible.
*/
equals(other: any): boolean {
const self = this.constructor as typeof Struct
Iif (
other.constructor &&
typeof other.constructor.abiName === 'string' &&
other.constructor.abiName !== self.abiName
) {
return false
}
return abiEncode({object: this}).equals(abiEncode({object: self.from(other) as any}))
}
/** @internal */
toJSON() {
const self = this.constructor as typeof Struct
const rv: any = {}
for (const field of self.structFields) {
if (field.optional && !this[field.name]) continue
if (this[field.name] === undefined && fieldModifiers(field).isExtension) continue
rv[field.name] = this[field.name]
}
return rv
}
}
export namespace Struct {
const FieldsOwner = Symbol('FieldsOwner')
export function type(name: string) {
return function <T extends StructConstructor>(struct: T) {
struct.abiName = name
return struct
}
}
export function field(
type: ABISerializableConstructor | string,
options: ABITypeModifiers = {}
) {
return <T extends Struct>(target: T, name: string) => {
const ctor = target.constructor as StructConstructor
if (!ctor.abiFields) {
ctor.abiFields = []
ctor.abiFields[FieldsOwner] = ctor
} else if (ctor.abiFields[FieldsOwner] !== ctor) {
// if the target class isn't the owner we set the base and start new fields
ctor.abiBase = ctor.abiFields[FieldsOwner]
ctor.abiFields = []
ctor.abiFields[FieldsOwner] = ctor
}
ctor.abiFields.push({...options, name, type})
}
}
}
|