import { Identifier } from './type' ; import { immerable } from 'immer' ; /**
 * The IdentifierMap is like a built-in Map<Identifier, T>.
 *
 * Because Identifier is not a value-type record so to make it behave like a value-type,
 * please use this class instead of Map<Identifier, T>.
 */ export class IdentifierMap < IdentifierType extends Identifier , T > implements Map < IdentifierType , T > { [ immerable ] = true ; param __raw_map__ param constructor constructor ( public readonly __raw_map__ , ... constructor ) { if ( constructor ) { this . constructorName = constructor . map ( ( x ) => x . name ) ; } } private readonly constructorName : string [ ] = [ ] ; get ( key ) { return this . __raw_map__ . get ( key . toText ( ) ) ; } set ( key , data ) { if ( ! key ) return this ; if ( this . constructorName . length ) { if ( ! this . constructorName . includes ( key . constructor . name ) ) { console . warn ( `IdentifierMap found a invalid write try which violates the constraint ${ this . constructorName }` , key ) ; return this ; } } this . __raw_map__ . set ( key . toText ( ) , data ) ; return this ; } clear ( ) { this . __raw_map__ . clear ( ) ; } delete ( data ) { return this . __raw_map__ . delete ( data . toText ( ) ) ; } private _identifierFromString ( key ) { const identifier = Identifier . fromString ( key ) ; if ( identifier . err ) { console . warn ( 'IdentifierMap found a key which cannot be converted into Identifier: ' , identifier . val . message ) ; } else { if ( this . constructorName . length === 0 ) return identifier . val as IdentifierType ; if ( this . constructorName . includes ( identifier . val . constructor . name ) ) return identifier . val as IdentifierType ; console . warn ( `IdentifierMap found a key which is not compatible with it constraint(${ this . constructorName }), ${ key }` ) ; } return null ; } * entries ( ) { const iter = this . __raw_map__ . entries ( ) ; for ( const [ key , data ] of iter ) { const identifier = this . _identifierFromString ( key ) ; if ( ! identifier ) continue ; yield [ identifier , data ] ; } } forEach ( callbackfn , thisArg ? ) { this . __raw_map__ . forEach ( ( value , key ) => { const i = this . _identifierFromString ( key ) ; if ( ! i ) return ; callbackfn . call ( thisArg , value , i , this ) ; } ) ; } has ( key ) { return this . __raw_map__ . has ( key . toText ( ) ) ; } * keys ( ) { const iter = this . __raw_map__ . keys ( ) ; for ( const key of iter ) { const i = this . _identifierFromString ( key ) ; if ( i ) yield i ; else continue ; } } get size ( ) { return [ ... this . keys ( ) ] . length ; } * values ( ) { for ( const [ k , v ] of this . entries ( ) ) yield v ; } public [ Symbol . toStringTag ] : string ; [ Symbol . iterator ] ( ) { return this . entries ( ) ; } } IdentifierMap . prototype [ Symbol . toStringTag ] = 'IdentifierMap' ; export type ReadonlyIdentifierMap < IdentifierType extends Identifier , T > = ReadonlyMap < IdentifierType , T > & { readonly __raw_map__ : ReadonlyMap < string , T > ; } ; export const ReadonlyIdentifierMap = IdentifierMap as any ;