import { ASON_EFFECTIVE_INITIAL_ARRAY_DATA_SEGMENT_TABLE_LENGTH , ASON_EFFECTIVE_INITIAL_ARRAY_LINK_TABLE_LENGTH , ASON_EFFECTIVE_INITIAL_ARRAY_TABLE_LENGTH , ASON_EFFECTIVE_INITIAL_CUSTOM_TABLE_LENGTH , ASON_EFFECTIVE_INITIAL_DATA_SEGMENT_TABLE_LENGTH , ASON_EFFECTIVE_INITIAL_LINK_TABLE_LENGTH , ASON_EFFECTIVE_INITIAL_MAP_KEY_VALUE_PAIR_ENTRY_TABLE_LENGTH , ASON_EFFECTIVE_INITIAL_REFERENCE_TABLE_LENGTH , ASON_EFFECTIVE_INITIAL_SET_ENTRY_TABLE_LENGTH , ASON_EFFECTIVE_INITIAL_SET_REFERENCE_TABLE_LENGTH , ASON_EFFECTIVE_MAP_REFERENCE_TABLE_LENGTH , ASON_EFFECTIVE_INITIAL_STATIC_REFERENCE_TABLE_LENGTH , } from "./configuration" ; import { TOTAL_OVERHEAD , OBJECT } from "rt/common" ; import { ArrayDataSegmentEntry , ArrayEntry , ArrayLinkEntry , ASONHeader , CustomEntry , DataSegmentEntry , LinkEntry , MapKeyValuePairEntry , MapKeyValueType , MapReferenceEntry , ReferenceEntry , SetKeyEntry , SetReferenceEntry , StaticReferenceEntry , Table , } from "./util" ; class Dummy { } /** Structure of a set entry. Credit: https://github.com/AssemblyScript/assemblyscript/blob/master/std/assembly/set.ts */ @ unmanaged class SetEntry < K > { key : K ; taggedNext : usize ; } /** Structure of a map entry. Credit: https://github.com/AssemblyScript/assemblyscript/blob/master/std/assembly/map.ts */ @ unmanaged class MapEntry < K , V > { key : K ; value : V ; taggedNext : usize ; } @ inline function getObjectSize < T > ( value ) { return changetype < OBJECT > ( changetype < usize > ( value ) - TOTAL_OVERHEAD ) . rtSize ; } @ inline function getObjectType ( value ) { return changetype < OBJECT > ( value - TOTAL_OVERHEAD ) . rtId ; } function __unusedVoidCallDeserialize < T > ( value ) { let buffer ; value . __asonDeserialize ( buffer ) ; return true ; } export namespace ASON { export class Serializer < T > { private entryId : u32 ; private entries : Map < usize , u32 > = new Map < usize , u32 > ( ) ; private segments : Map < u32 , usize > = new Map < u32 , usize > ( ) ; private arrayDataSegmentTable : Table < ArrayDataSegmentEntry > = new Table < ArrayDataSegmentEntry > ( ASON_EFFECTIVE_INITIAL_ARRAY_DATA_SEGMENT_TABLE_LENGTH ) ; private arrayLinkTable : Table < ArrayLinkEntry > = new Table < ArrayLinkEntry > ( ASON_EFFECTIVE_INITIAL_ARRAY_LINK_TABLE_LENGTH ) ; private arrayTable : Table < ArrayEntry > = new Table < ArrayEntry > ( ASON_EFFECTIVE_INITIAL_ARRAY_TABLE_LENGTH ) ; private customTable : Table < CustomEntry > = new Table < CustomEntry > ( ASON_EFFECTIVE_INITIAL_CUSTOM_TABLE_LENGTH ) ; private dataSegmentTable : Table < DataSegmentEntry > = new Table < DataSegmentEntry > ( ASON_EFFECTIVE_INITIAL_DATA_SEGMENT_TABLE_LENGTH ) ; private linkTable : Table < LinkEntry > = new Table < LinkEntry > ( ASON_EFFECTIVE_INITIAL_LINK_TABLE_LENGTH ) ; private mapKeyValuePairsTable : Table < MapKeyValuePairEntry > = new Table < MapKeyValuePairEntry > ( ASON_EFFECTIVE_INITIAL_MAP_KEY_VALUE_PAIR_ENTRY_TABLE_LENGTH ) ; private mapReferenceTable : Table < MapReferenceEntry > = new Table < MapReferenceEntry > ( ASON_EFFECTIVE_MAP_REFERENCE_TABLE_LENGTH ) ; private referenceTable : Table < ReferenceEntry > = new Table < ReferenceEntry > ( ASON_EFFECTIVE_INITIAL_REFERENCE_TABLE_LENGTH ) ; private setEntryTable : Table < SetKeyEntry > = new Table < SetKeyEntry > ( ASON_EFFECTIVE_INITIAL_SET_ENTRY_TABLE_LENGTH ) ; private setReferenceTable : Table < SetReferenceEntry > = new Table < SetReferenceEntry > ( ASON_EFFECTIVE_INITIAL_SET_REFERENCE_TABLE_LENGTH ) ; private staticReferenceTable : Table < StaticReferenceEntry > = new Table < StaticReferenceEntry > ( ASON_EFFECTIVE_INITIAL_STATIC_REFERENCE_TABLE_LENGTH ) ; constructor ( ) { } param { T } value returns { StaticArray < u8 > } public serialize ( value ) { if ( isReference ( value ) ) { if ( changetype < usize > ( value ) == 0 ) return new StaticArray < u8 > ( 0 ) ; } this . entryId = 0 ; this . entries . clear ( ) ; this . entries . set ( 0 , u32 . MAX_VALUE ) ; this . segments . clear ( ) ; this . arrayDataSegmentTable . reset ( ) ; this . arrayLinkTable . reset ( ) ; this . arrayTable . reset ( ) ; this . customTable . reset ( ) ; this . dataSegmentTable . reset ( ) ; this . linkTable . reset ( ) ; this . mapKeyValuePairsTable . reset ( ) ; this . mapReferenceTable . reset ( ) ; this . referenceTable . reset ( ) ; this . setEntryTable . reset ( ) ; this . setReferenceTable . reset ( ) ; this . staticReferenceTable . reset ( ) ; let entryId ; if ( isReference ( value ) ) { entryId = this . put ( value ) ; } else { entryId = this . put ( new Box < T > ( value ) ) ; } assert ( entryId == < u32 > 0 ) ; return this . commit ( ) ; } /** This is a private method that must be publicly exposed to work. Please do not use it. */ @ unsafe public put < U > ( value ) { if ( isReference ( value ) ) { if ( this . entries . has ( changetype < usize > ( value ) ) ) return this . entries . get ( changetype < usize > ( value ) ) ; } if ( isDefined ( value . __asonSerialize ) ) { if ( isDefined ( value . __asonDeserialize ) ) { let temp ; if ( ! isDefined ( temp = value . __asonSerialize ( ) ) ) { ERROR ( "__asonSerialize method must return a StaticArray<u8>" ) ; } if ( ! isDefined ( __unusedVoidCallDeserialize ( value ) ) ) { ERROR ( "__asonDeserialize method must accept a StaticArray<u8>" ) ; } if ( ! isReference ( value ) ) { ERROR ( "Custom ASON serializtion can only be performed on a reference." ) ; } return this . putCustom ( value ) ; } } if ( isFunction ( value ) ) { return this . putDataSegment ( value ) ; } else if ( value instanceof ArrayBufferView ) { return this . putArrayDataSegment ( value ) ; } else if ( value instanceof Map ) { return this . putMap ( value ) ; } else if ( value instanceof Set ) { return this . putSet ( value ) ; } else if ( value instanceof ArrayBuffer ) { return this . putDataSegment ( value ) ; } else if ( value instanceof String ) { if ( changetype < usize > ( value ) < __heap_base ) return this . putStaticReference ( value ) ; return this . putDataSegment ( value ) ; } else if ( value instanceof StaticArray ) { if ( isReference ( unchecked ( value [ 0 ] ) ) ) { let parent = this . putReference ( value ) ; if ( changetype < usize > ( value ) != 0 ) { let length = value . length ; for ( let i = 0 ; i < length ; i ++ ) { let child = unchecked ( value [ i ] ) ; if ( changetype < usize > ( child ) != 0 ) { this . putLink ( this . put ( child ) , parent , < usize > i << alignof < usize > ( ) ) ; } } } return parent ; } return this . putDataSegment ( value ) ; } else if ( value instanceof Array ) { if ( isReference ( unchecked ( value [ 0 ] ) ) ) { let parent = this . putArray ( value ) ; let length = value . length ; for ( let i = 0 ; i < length ; i ++ ) { let child = unchecked ( value [ i ] ) ; if ( changetype < usize > ( child ) != 0 ) { this . putArrayLink ( this . put ( child ) , parent , i ) ; } } return parent ; } return this . putArrayDataSegment ( value ) ; } else { return this . putReferenceAndFields ( value ) ; } } private putCustom < U > ( value ) { let buffer = value . __asonSerialize ( ) ; let length = buffer . length ; let customTable = this . customTable ; let entry = customTable . allocate ( ) ; let entryId = this . entryId ++ ; entry . entryId = entryId ; entry . rtId = idof < U > ( ) ; entry . offset = offsetof < U > ( ) ; entry . byteLength = length ; entry . deserializeFuncIndex = value . __asonDeserialize . index ; let copyToPtr = customTable . allocateSegment ( length ) ; memory . copy ( copyToPtr , changetype < usize > ( buffer ) , length ) ; this . entries . set ( changetype < usize > ( value ) , entryId ) ; return entryId ; } private putStaticReference < U > ( value ) { let entryId = this . entryId ++ ; let entry = this . staticReferenceTable . allocate ( ) ; entry . entryId = entryId ; entry . ptr = changetype < usize > ( value ) ; this . entries . set ( changetype < usize > ( value ) , entryId ) ; return entryId ; } private putMap < U > ( value ) { if ( ! isReference < indexof < U > > ( ) && ! isReference < valueof < U > > ( ) ) { return this . putReferenceAndFields ( value ) ; } let mapEntryId = this . entryId ++ ; let mapEntry = this . mapReferenceTable . allocate ( ) ; mapEntry . entryId = mapEntryId ; mapEntry . rtId = idof < U > ( ) ; let maxkv = max < i32 > ( sizeof < indexof < U > > ( ) , sizeof < valueof < U > > ( ) ) ; let align = max < usize > ( maxkv , sizeof < usize > ( ) ) - 1 ; let entryOffset = offsetof < MapEntry < indexof < U > , valueof < U > > > ( ) ; let entrySize = ( entryOffset + align ) & ~ align ; mapEntry . entrySize = entrySize ; mapEntry . capacity = 1 << ( 32 - clz < i32 > ( value . size ) ) ; let keys = value . keys ( ) ; let values = value . values ( ) ; let size = value . size ; let mapKeyValuePairsTable = this . mapKeyValuePairsTable ; for ( let i = 0 ; i < size ; i ++ ) { let entry = mapKeyValuePairsTable . allocate ( ) ; let key = unchecked ( keys [ i ] ) ; let value = unchecked ( values [ i ] ) ; entry . parentEntryId = mapEntryId ; if ( isReference ( key ) ) { entry . keyType = isString ( key ) ? MapKeyValueType . String : MapKeyValueType . Dummy ; let keyEntryId = this . put ( key ) ; store < u32 > ( changetype < usize > ( entry ) , keyEntryId , offsetof < MapKeyValuePairEntry > ( "key" ) ) ; } else { entry . keyType = MapKeyValueType . Number ; store < indexof < U > > ( changetype < usize > ( entry ) , key , offsetof < MapKeyValuePairEntry > ( "key" ) ) ; entry . keySize = sizeof < indexof < U > > ( ) ; entry . keyIsSigned = isSigned < indexof < U > > ( ) || isFloat < indexof < U > > ( ) ; } if ( isReference ( value ) ) { entry . valueType = MapKeyValueType . Dummy ; let valueEntryId = this . put ( value ) ; store < u32 > ( changetype < usize > ( entry ) , valueEntryId , offsetof < MapKeyValuePairEntry > ( "value" ) ) ; } else { entry . valueType = MapKeyValueType . Number ; store < valueof < U > > ( changetype < usize > ( entry ) , value , offsetof < MapKeyValuePairEntry > ( "value" ) ) ; entry . valueSize = sizeof < valueof < U > > ( ) ; } } return mapEntryId ; } private putSet < U > ( value ) { if ( ! isReference < indexof < U > > ( ) ) { return this . putReferenceAndFields ( value ) ; } let capacity = 1 << ( 32 - clz < i32 > ( value . size ) ) ; const align = sizeof < usize > ( ) - 1 ; const entrySize = ( offsetof < SetEntry < T > > ( ) + align ) & ~ align ; let entryId = this . entryId ++ ; let entry = this . setReferenceTable . allocate ( ) ; entry . entryId = entryId ; entry . rtId = idof < U > ( ) ; entry . entrySize = entrySize ; entry . capacity = capacity ; let childEntries = value . values ( ) ; let length = childEntries . length ; let setEntryTable = this . setEntryTable ; for ( let i = 0 ; i < length ; i ++ ) { let child = unchecked ( childEntries [ i ] ) ; let childEntryId = this . put ( child ) ; let childEntry = setEntryTable . allocate ( ) ; childEntry . childEntryId = childEntryId ; childEntry . parentEntryId = entryId ; childEntry . isString = isString ( child ) ; } return entryId ; } private putReferenceAndFields < U > ( value ) { let entryId = this . putReference ( value ) ; if ( isNullable ( value ) ) { value ! . __asonPut ( this , entryId ) ; } else { value . __asonPut ( this , entryId ) ; } return entryId ; } private putDataSegment < U > ( value ) { let entryId = this . entryId ++ ; this . entries . set ( changetype < usize > ( value ) , entryId ) ; let size = getObjectSize ( value ) ; let entry = this . dataSegmentTable . allocate ( ) ; entry . byteLength = size ; entry . entryId = entryId ; entry . rtId = idof < U > ( ) ; let segment = this . dataSegmentTable . allocateSegment ( < i32 > size ) ; memory . copy ( segment , changetype < usize > ( value ) , size ) ; return entryId ; } private putArrayDataSegment < U > ( value ) { let entryId = this . entryId ++ ; this . entries . set ( changetype < usize > ( value ) , entryId ) ; let arrayLength ; if ( isNullable < U > ( ) ) { arrayLength = value ! . length ; } else { arrayLength = value . length ; } let entry = this . arrayDataSegmentTable . allocate ( ) ; entry . length = arrayLength ; entry . align = alignof < valueof < U > > ( ) ; entry . entryId = entryId ; entry . rtId = idof < U > ( ) ; let size = < usize > arrayLength << ( alignof < valueof < U > > ( ) ) ; let dataStart = load < usize > ( changetype < usize > ( value ) , offsetof < U > ( "dataStart" ) ) ; let segment = this . arrayDataSegmentTable . allocateSegment ( < i32 > size ) ; memory . copy ( segment , dataStart , size ) ; return entryId ; } private putLink ( childEntryId , parentEntryId , offset ) { let entry = this . linkTable . allocate ( ) ; entry . childEntryId = childEntryId ; entry . parentEntryId = parentEntryId ; entry . offset = offset ; assert ( this . segments . has ( parentEntryId ) ) ; let parentSegment = this . segments . get ( parentEntryId ) ; store < usize > ( parentSegment + offset , 0 ) ; } private putReference < U > ( value ) { let entryId = this . entryId ++ ; this . entries . set ( changetype < usize > ( value ) , entryId ) ; let entry = this . referenceTable . allocate ( ) ; entry . entryId = entryId ; let offset = getObjectSize ( value ) ; entry . offset = offset ; entry . rtId = idof < U > ( ) ; let segment = this . referenceTable . allocateSegment ( < i32 > offset ) ; this . segments . set ( entryId , segment ) ; return entryId ; } private putArray < U extends Array < valueof < U > > > ( value ) { let entryId = this . entryId ++ ; this . entries . set ( changetype < usize > ( value ) , entryId ) ; let entry = this . arrayTable . allocate ( ) ; entry . entryId = entryId ; if ( isNullable ( value ) ) { entry . length = value ! . length ; } else { entry . length = value . length ; } entry . rtId = idof < U > ( ) ; return entryId ; } private putArrayLink ( childEntryId , parentEntryId , index ) { let entry = this . arrayLinkTable . allocate ( ) ; entry . childEntryId = childEntryId ; entry . parentEntryId = parentEntryId ; entry . index = index ; } public putField < U > ( entryId , value , offset ) { if ( isReference ( value ) ) { if ( changetype < usize > ( value ) != 0 ) { if ( isNullable ( value ) ) { this . putLink ( this . put ( value ! ) , entryId , offset ) ; } else { this . putLink ( this . put ( value ) , entryId , offset ) ; } } return ; } assert ( this . segments . has ( entryId ) ) ; let parentSegment = this . segments . get ( entryId ) ; store < U > ( parentSegment + offset , value ) ; } private commit ( ) { let referenceTable = this . referenceTable ; let dataSegmentTable = this . dataSegmentTable ; let arrayTable = this . arrayTable ; let arrayDataSegmentTable = this . arrayDataSegmentTable ; let linkTable = this . linkTable ; let arrayLinkTable = this . arrayLinkTable ; let staticReferenceTable = this . staticReferenceTable ; let customTable = this . customTable ; let setReferenceTable = this . setReferenceTable ; let setEntryTable = this . setEntryTable ; let mapReferenceTable = this . mapReferenceTable ; let mapKeyValueEntryTable = this . mapKeyValuePairsTable ; let referenceTableIndex = < usize > referenceTable . index ; let dataSegmentTableIndex = < usize > dataSegmentTable . index ; let arrayTableIndex = < usize > arrayTable . index ; let arrayDataSegmentTableIndex = < usize > arrayDataSegmentTable . index ; let linkTableIndex = < usize > linkTable . index ; let arrayLinkTableIndex = < usize > arrayLinkTable . index ; let staticReferenceTableIndex = < usize > staticReferenceTable . index ; let customTableIndex = < usize > customTable . index ; let setReferenceTableIndex = < usize > setReferenceTable . index ; let setEntryTableIndex = < usize > setEntryTable . index ; let mapReferenceTableIndex = < usize > mapReferenceTable . index ; let mapKeyValueEntryTableIndex = < usize > mapKeyValueEntryTable . index ; let length = referenceTableIndex + dataSegmentTableIndex + arrayTableIndex + arrayDataSegmentTableIndex + linkTableIndex + arrayLinkTableIndex + staticReferenceTableIndex + customTableIndex + setReferenceTableIndex + setEntryTableIndex + mapReferenceTableIndex + mapKeyValueEntryTableIndex + offsetof < ASONHeader > ( ) ; let result = new StaticArray < u8 > ( < i32 > length ) ; let header = changetype < ASONHeader > ( result ) ; header . referenceTableByteLength = referenceTableIndex ; header . dataSegmentTableByteLength = dataSegmentTableIndex ; header . arrayTableByteLength = arrayTableIndex ; header . arrayDataSegmentTableByteLength = arrayDataSegmentTableIndex ; header . linkTableByteLength = linkTableIndex ; header . arrayLinkTableByteLength = arrayLinkTableIndex ; header . staticReferenceTableByteLength = staticReferenceTableIndex ; header . customTableByteLength = customTableIndex ; header . setReferenceTableByteLength = setReferenceTableIndex ; header . setEntryTableByteLength = setEntryTableIndex ; header . mapReferenceTableByteLength = mapReferenceTableIndex ; header . mapKeyValueEntryTableByteLength = mapKeyValueEntryTableIndex ; let offset = offsetof < ASONHeader > ( ) ; referenceTable . copyTo ( result , offset ) ; offset += referenceTableIndex ; dataSegmentTable . copyTo ( result , offset ) ; offset += dataSegmentTableIndex ; arrayTable . copyTo ( result , offset ) ; offset += arrayTableIndex ; arrayDataSegmentTable . copyTo ( result , offset ) ; offset += arrayDataSegmentTableIndex ; linkTable . copyTo ( result , offset ) ; offset += linkTableIndex ; arrayLinkTable . copyTo ( result , offset ) ; offset += arrayLinkTableIndex ; staticReferenceTable . copyTo ( result , offset ) ; offset += staticReferenceTableIndex ; customTable . copyTo ( result , offset ) ; offset += customTableIndex ; setReferenceTable . copyTo ( result , offset ) ; offset += setReferenceTableIndex ; setEntryTable . copyTo ( result , offset ) ; offset += setEntryTableIndex ; mapReferenceTable . copyTo ( result , offset ) ; offset += mapReferenceTableIndex ; mapKeyValueEntryTable . copyTo ( result , offset ) ; return result ; } } /**
     * A class that deserializes a buffer and assembles a final reference.
     */ export class Deserializer < T > { param data returns public deserialize ( data ) { if ( isReference < T > ( ) ) { if ( data . length == 0 ) { if ( isNullable < T > ( ) ) { return null ; } else { throw new Error ( "Cannot return null with null buffer when type T is not nullable." ) ; } } } let startPointer = changetype < usize > ( data ) ; let length = < usize > data . length ; assert ( length > offsetof < ASONHeader > ( ) , "Inputted array is too small." ) ; let header = changetype < ASONHeader > ( data ) ; let arrayDataSegmentTableByteLength = header . arrayDataSegmentTableByteLength ; let arrayLinkTableByteLength = header . arrayLinkTableByteLength ; let arrayTableByteLength = header . arrayTableByteLength ; let customTableByteLength = header . customTableByteLength ; let dataSegmentTableByteLength = header . dataSegmentTableByteLength ; let linkTableByteLength = header . linkTableByteLength ; let mapKeyValueEntryTableByteLength = header . mapKeyValueEntryTableByteLength ; let mapReferenceTableByteLength = header . mapReferenceTableByteLength ; let referenceTableByteLength = header . referenceTableByteLength ; let setEntryTableByteLength = header . setEntryTableByteLength ; let setReferenceTableByteLength = header . setReferenceTableByteLength ; let staticReferenceTableByteLength = header . staticReferenceTableByteLength ; assert ( length == offsetof < ASONHeader > ( ) + referenceTableByteLength + dataSegmentTableByteLength + arrayTableByteLength + arrayDataSegmentTableByteLength + linkTableByteLength + arrayLinkTableByteLength + staticReferenceTableByteLength + customTableByteLength + setReferenceTableByteLength + setEntryTableByteLength + mapReferenceTableByteLength + mapKeyValueEntryTableByteLength , "Inputted array is malformed." ) ; let referenceTablePointer = startPointer + offsetof < ASONHeader > ( ) ; let dataSegmentTablePointer = referenceTablePointer + referenceTableByteLength ; let arrayTablePointer = dataSegmentTablePointer + dataSegmentTableByteLength ; let arrayDataSegmentTablePointer = arrayTablePointer + arrayTableByteLength ; let linkTablePointer = arrayDataSegmentTablePointer + arrayDataSegmentTableByteLength ; let arrayLinkTablePointer = linkTablePointer + linkTableByteLength ; let staticReferenceTablePointer = arrayLinkTablePointer + arrayLinkTableByteLength ; let customTablePointer = staticReferenceTablePointer + staticReferenceTableByteLength ; ; let setReferenceTablePointer = customTablePointer + customTableByteLength ; let setEntryTablePointer = setReferenceTablePointer + setReferenceTableByteLength ; let mapReferenceTablePointer = setEntryTablePointer + setEntryTableByteLength ; let mapKeyValueEntryTablePointer = mapReferenceTablePointer + mapReferenceTableByteLength ; let referenceTable = Table . from < ReferenceEntry > ( referenceTablePointer , referenceTableByteLength ) ; let dataSegmentTable = Table . from < DataSegmentEntry > ( dataSegmentTablePointer , dataSegmentTableByteLength ) ; let arrayTable = Table . from < ArrayEntry > ( arrayTablePointer , arrayTableByteLength ) ; let arrayDataSegmentTable = Table . from < ArrayDataSegmentEntry > ( arrayDataSegmentTablePointer , arrayDataSegmentTableByteLength ) ; let linkTable = Table . from < LinkEntry > ( linkTablePointer , linkTableByteLength ) ; let arrayLinkTable = Table . from < ArrayLinkEntry > ( arrayLinkTablePointer , arrayLinkTableByteLength ) ; let staticReferenceTable = Table . from < StaticReferenceEntry > ( staticReferenceTablePointer , staticReferenceTableByteLength ) ; let customTable = Table . from < CustomEntry > ( customTablePointer , customTableByteLength ) ; let setReferenceTable = Table . from < SetReferenceEntry > ( setReferenceTablePointer , setReferenceTableByteLength ) ; let setEntryTable = Table . from < SetKeyEntry > ( setEntryTablePointer , setEntryTableByteLength ) ; let mapReferenceTable = Table . from < MapReferenceEntry > ( mapReferenceTablePointer , mapReferenceTableByteLength ) ; let mapKeyValueEntryTable = Table . from < MapKeyValuePairEntry > ( mapKeyValueEntryTablePointer , mapKeyValueEntryTableByteLength ) ; let entryMap = new Map < u32 , Dummy > ( ) ; entryMap . set ( u32 . MAX_VALUE , changetype < Dummy > ( 0 ) ) ; let i = 0 ; while ( i < referenceTableByteLength ) { let entry = referenceTable . allocate ( ) ; let offset = entry . offset ; let referencePointer = __new ( offset , entry . rtId ) ; entryMap . set ( entry . entryId , changetype < Dummy > ( referencePointer ) ) ; let segment = referenceTable . allocateSegment ( < i32 > offset ) ; memory . copy ( referencePointer , segment , offset ) ; i = referenceTable . index ; } i = 0 ; while ( i < dataSegmentTableByteLength ) { let entry = dataSegmentTable . allocate ( ) ; let segmentLength = entry . byteLength ; let segment = dataSegmentTable . allocateSegment ( < i32 > segmentLength ) ; let referencePointer = __new ( entry . byteLength , entry . rtId ) ; memory . copy ( referencePointer , segment , segmentLength ) ; entryMap . set ( entry . entryId , changetype < Dummy > ( referencePointer ) ) ; i = dataSegmentTable . index ; } i = 0 ; while ( i < arrayTableByteLength ) { let entry = arrayTable . allocate ( ) ; let length = entry . length ; let temp = new ArrayBuffer ( length << < i32 > alignof < usize > ( ) ) ; let referencePointer = __newArray ( length , alignof < usize > ( ) , entry . rtId , changetype < usize > ( temp ) ) ; entryMap . set ( entry . entryId , changetype < Dummy > ( referencePointer ) ) ; i += offsetof < ArrayEntry > ( ) ; } i = 0 ; while ( i < arrayDataSegmentTableByteLength ) { let entry = arrayDataSegmentTable . allocate ( ) ; let length = entry . length ; let segment = arrayDataSegmentTable . allocateSegment ( < i32 > ( length << ( < i32 > entry . align ) ) ) ; let referencePointer = __newArray ( length , entry . align , entry . rtId , segment ) ; entryMap . set ( entry . entryId , changetype < Dummy > ( referencePointer ) ) ; i = arrayDataSegmentTable . index ; } i = 0 ; while ( i < setReferenceTableByteLength ) { let entry = setReferenceTable . allocate ( ) ; let entryId = entry . entryId ; let rtId = entry . rtId ; let entrySize = entry . entrySize ; let capacity = entry . capacity ; let set = changetype < Dummy > ( __new ( offsetof < Set < Dummy > > ( ) , rtId ) ) ; entryMap . set ( entryId , set ) ; let buckets = new ArrayBuffer ( capacity * < i32 > sizeof < usize > ( ) ) ; store < usize > ( changetype < usize > ( set ) , changetype < usize > ( buckets ) , offsetof < Set < Dummy > > ( "buckets" ) ) ; __link ( changetype < usize > ( set ) , changetype < usize > ( buckets ) , false ) ; store < u32 > ( changetype < usize > ( set ) , capacity - 1 , offsetof < Set < Dummy > > ( "bucketsMask" ) ) ; let entries = new ArrayBuffer ( capacity * < i32 > entrySize ) ; store < usize > ( changetype < usize > ( set ) , changetype < usize > ( entries ) , offsetof < Set < Dummy > > ( "entries" ) ) ; __link ( changetype < usize > ( set ) , changetype < usize > ( buckets ) , false ) ; store < i32 > ( changetype < usize > ( set ) , capacity , offsetof < Set < Dummy > > ( "entriesCapacity" ) ) ; changetype < OBJECT > ( changetype < usize > ( set ) - TOTAL_OVERHEAD ) . rtId = rtId ; i += offsetof < SetReferenceEntry > ( ) ; } i = 0 ; while ( i < mapReferenceTableByteLength ) { let entry = mapReferenceTable . allocate ( ) ; let entryId = entry . entryId ; let rtId = entry . rtId ; let entrySize = entry . entrySize ; let capacity = entry . capacity ; let mapPtr = changetype < Dummy > ( __new ( rtId , offsetof < Map < u32 , Dummy > > ( ) ) ) ; let buckets = new ArrayBuffer ( capacity * < i32 > sizeof < usize > ( ) ) ; store < usize > ( changetype < usize > ( mapPtr ) , changetype < usize > ( buckets ) , offsetof < Map < u32 , Dummy > > ( "buckets" ) ) ; __link ( changetype < usize > ( mapPtr ) , changetype < usize > ( buckets ) , false ) ; store < u32 > ( changetype < usize > ( mapPtr ) , capacity - 1 , offsetof < Map < u32 , Dummy > > ( "bucketsMask" ) ) ; let entries = new ArrayBuffer ( capacity * < i32 > entrySize ) ; store < usize > ( changetype < usize > ( mapPtr ) , changetype < usize > ( entries ) , offsetof < Map < u32 , Dummy > > ( "entries" ) ) ; __link ( changetype < usize > ( mapPtr ) , changetype < usize > ( entries ) , false ) ; store < i32 > ( changetype < usize > ( mapPtr ) , capacity , offsetof < Map < u32 , Dummy > > ( "entriesCapacity" ) ) ; changetype < OBJECT > ( changetype < usize > ( mapPtr ) - TOTAL_OVERHEAD ) . rtId = rtId ; entryMap . set ( entryId , mapPtr ) ; i += offsetof < MapReferenceEntry > ( ) ; } i = 0 ; while ( i < staticReferenceTableByteLength ) { let entry = staticReferenceTable . allocate ( ) ; entryMap . set ( entry . entryId , changetype < Dummy > ( entry . ptr ) ) ; i += offsetof < StaticReferenceEntry > ( ) ; } i = 0 ; while ( i < customTableByteLength ) { let entry = customTable . allocate ( ) ; let byteLength = entry . byteLength ; let entryId = entry . entryId ; let deserializeFuncIndex = entry . deserializeFuncIndex ; let offset = entry . offset ; let rtId = entry . rtId ; let ptr = __new ( offset , rtId ) ; entryMap . set ( entryId , changetype < Dummy > ( ptr ) ) ; let buffer = new StaticArray < u8 > ( byteLength ) ; let sourcePtr = customTable . allocateSegment ( byteLength ) ; memory . copy ( changetype < usize > ( buffer ) , sourcePtr , byteLength ) ; call_indirect ( deserializeFuncIndex , ptr , buffer ) ; i = customTable . index ; } let entry0 = changetype < usize > ( entryMap . get ( 0 ) ) ; if ( isReference < T > ( ) ) { assert ( getObjectType ( entry0 ) == idof < T > ( ) || __instanceof ( entry0 , idof < T > ( ) ) ) ; } else { assert ( getObjectType ( entry0 ) == idof < Box < T > > ( ) ) ; } i = 0 ; while ( i < linkTableByteLength ) { let entry = linkTable . allocate ( ) ; let parentEntryId = entry . parentEntryId ; assert ( entryMap . has ( parentEntryId ) ) ; let parentPointer = changetype < usize > ( entryMap . get ( parentEntryId ) ) ; let childEntryId = entry . childEntryId ; assert ( entryMap . has ( childEntryId ) ) ; let childPointer = changetype < usize > ( entryMap . get ( childEntryId ) ) ; __link ( parentPointer , childPointer , false ) ; store < usize > ( parentPointer + entry . offset , childPointer ) ; i += offsetof < LinkEntry > ( ) ; } i = 0 ; while ( i < arrayLinkTableByteLength ) { let entry = arrayLinkTable . allocate ( ) ; let parentEntryId = entry . parentEntryId ; assert ( entryMap . has ( parentEntryId ) ) ; let parentPointer = changetype < usize > ( entryMap . get ( parentEntryId ) ) ; let childEntryId = entry . childEntryId ; assert ( entryMap . has ( childEntryId ) ) ; let childPointer = changetype < usize > ( entryMap . get ( childEntryId ) ) ; __link ( parentPointer , childPointer , false ) ; let parentDataPointer = load < usize > ( parentPointer , offsetof < Array < usize > > ( "dataStart" ) ) ; store < usize > ( parentDataPointer + ( < usize > entry . index << alignof < usize > ( ) ) , childPointer ) ; i += offsetof < ArrayLinkEntry > ( ) ; } i = 0 ; while ( i < setEntryTableByteLength ) { let entry = setEntryTable . allocate ( ) ; let parentEntryId = entry . parentEntryId ; assert ( entryMap . has ( parentEntryId ) ) ; let parent = entryMap . get ( parentEntryId ) ; let childEntryId = entry . childEntryId ; assert ( entryMap . has ( childEntryId ) ) ; let child = entryMap . get ( childEntryId ) ; if ( entry . isString ) { let parentStringSet = changetype < Set < string > > ( parent ) ; let childString = changetype < string > ( child ) ; parentStringSet . add ( childString ) ; } else { changetype < Set < Dummy > > ( parent ) . add ( child ) ; } i += offsetof < SetKeyEntry > ( ) ; } i = 0 ; while ( i < mapKeyValueEntryTableByteLength ) { let entry = mapKeyValueEntryTable . allocate ( ) ; let parentEntryId = entry . parentEntryId ; assert ( entryMap . has ( parentEntryId ) ) ; let parent = entryMap . get ( parentEntryId ) ; switch ( entry . keyType ) { case MapKeyValueType . Dummy : { let keyEntryId = load < u32 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "key" ) ) ; assert ( entryMap . has ( keyEntryId ) ) ; let key = entryMap . get ( keyEntryId ) ; if ( entry . valueType == MapKeyValueType . Dummy ) { let valueEntryId = load < u32 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "value" ) ) ; assert ( entryMap . has ( valueEntryId ) ) ; changetype < Map < Dummy , Dummy > > ( parent ) . set ( key , entryMap . get ( valueEntryId ) ) ; } else { switch ( entry . valueSize ) { case 1 : { let value = load < u8 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "value" ) ) ; changetype < Map < Dummy , u8 > > ( parent ) . set ( key , value ) ; break ; } case 2 : { let value = load < u16 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "value" ) ) ; changetype < Map < Dummy , u16 > > ( parent ) . set ( key , value ) ; break ; } case 4 : { let value = load < u32 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "value" ) ) ; changetype < Map < Dummy , u32 > > ( parent ) . set ( key , value ) ; break ; } case 8 : { let value = load < u64 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "value" ) ) ; changetype < Map < Dummy , u64 > > ( parent ) . set ( key , value ) ; break ; } default : assert ( false ) ; } } break ; } case MapKeyValueType . String : { let keyEntryId = load < u32 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "key" ) ) ; assert ( entryMap . has ( keyEntryId ) ) ; let key = changetype < string > ( entryMap . get ( keyEntryId ) ) ; if ( entry . valueType == MapKeyValueType . Dummy ) { let valueEntryId = load < u32 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "value" ) ) ; assert ( entryMap . has ( valueEntryId ) ) ; changetype < Map < string , Dummy > > ( parent ) . set ( key , entryMap . get ( valueEntryId ) ) ; } else { switch ( entry . valueSize ) { case 1 : { let value = load < u8 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "value" ) ) ; changetype < Map < string , u8 > > ( parent ) . set ( key , value ) ; break ; } case 2 : { let value = load < u16 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "value" ) ) ; changetype < Map < string , u16 > > ( parent ) . set ( key , value ) ; break ; } case 4 : { let value = load < u32 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "value" ) ) ; changetype < Map < string , u32 > > ( parent ) . set ( key , value ) ; break ; } case 8 : { let value = load < u64 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "value" ) ) ; changetype < Map < string , u64 > > ( parent ) . set ( key , value ) ; break ; } default : assert ( false ) ; } } break ; } case MapKeyValueType . Number : { let mapValueEntryId = load < u32 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "value" ) ) ; assert ( entryMap . has ( mapValueEntryId ) ) ; let mapValue = entryMap . get ( mapValueEntryId ) ; switch ( entry . keySize ) { case 1 : { if ( entry . keyIsSigned ) { changetype < Map < i8 , Dummy > > ( parent ) . set ( load < i8 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "key" ) ) , mapValue ) ; } else { changetype < Map < u8 , Dummy > > ( parent ) . set ( load < u8 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "key" ) ) , mapValue ) ; } break ; } case 2 : { if ( entry . keyIsSigned ) { changetype < Map < i16 , Dummy > > ( parent ) . set ( load < i16 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "key" ) ) , mapValue ) ; } else { changetype < Map < u16 , Dummy > > ( parent ) . set ( load < u16 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "key" ) ) , mapValue ) ; } break ; } case 4 : { if ( entry . keyIsSigned ) { changetype < Map < i32 , Dummy > > ( parent ) . set ( load < i32 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "key" ) ) , mapValue ) ; } else { changetype < Map < u32 , Dummy > > ( parent ) . set ( load < u32 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "key" ) ) , mapValue ) ; } break ; } case 8 : { if ( entry . keyIsSigned ) { changetype < Map < i64 , Dummy > > ( parent ) . set ( load < i64 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "key" ) ) , mapValue ) ; } else { changetype < Map < u64 , Dummy > > ( parent ) . set ( load < u64 > ( changetype < usize > ( entry ) , offsetof < MapKeyValuePairEntry > ( "key" ) ) , mapValue ) ; } break ; } default : assert ( false ) ; } break ; } default : assert ( false ) ; } i += offsetof < MapKeyValuePairEntry > ( ) ; } if ( isReference < T > ( ) ) { return changetype < T > ( entryMap . get ( 0 ) ) ; } else { return changetype < Box < T > > ( entryMap . get ( 0 ) ) . value ; } } } class Box < T > { constructor ( public value ) { } } param value returns { StaticArray < u8 > } export function serialize < T > ( value ) { let a = new Serializer < T > ( ) ; return a . serialize ( value ) ; } param buffer returns { T } export function deserialize < T > ( buffer ) { let a = new Deserializer < T > ( ) ; return a . deserialize ( buffer ) ; } }