/**
 * Modified from bcoin's bdb (https://github.com/bcoin-org/bdb) (MIT LICENSE).
 * Credit to the original author, Christopher Jeffrey (https://github.com/chjj).
 */ import { types } from './types' ; import { makeID , assert } from './utils' ; import { Key , KeyType } from '../../types' ; type KeyTypeName = keyof typeof types ; /**
 * Simple key implementation.
 */ export class BaseKey implements Key { private id : number ; private ops : KeyType [ ] = [ ] ; private size = 0 ; private index = - 1 ; constructor ( id , ops = [ ] ) { this . id = makeID ( id ) ; for ( let i = 0 ; i < ops . length ; i ++ ) { const name = ops [ i ] ; if ( ! ( name in types ) ) { throw new Error ( `Invalid type name: ${ name }.` ) ; } const op = types [ name ] ; if ( op . dynamic ) { if ( this . index === - 1 ) { this . index = i ; } } else { this . size += ( op as any ) . size ( ) ; } this . ops . push ( op ) ; } } param args returns public getSize ( args ) { assert ( args . length === this . ops . length ) ; let size = 1 + this . size ; if ( this . index === - 1 ) { return size ; } for ( let i = this . index ; i < args . length ; i ++ ) { const op = this . ops [ i ] ; const arg = args [ i ] ; if ( op . dynamic ) { size += op . size ( arg ) ; } } return size ; } param args returns public encode ( args = [ ] ) { assert ( args . length === this . ops . length ) ; const size = this . getSize ( args ) ; const key = Buffer . allocUnsafe ( size ) ; key [ 0 ] = this . id ; let offset = 1 ; for ( let i = 0 ; i < this . ops . length ; i ++ ) { const op = this . ops [ i ] ; const arg = args [ i ] ; offset += op . write ( key , arg , offset ) ; } return key ; } param key returns public decode ( key ) { if ( this . ops . length === 0 ) { return key ; } if ( key . length === 0 || key [ 0 ] !== this . id ) { throw new Error ( 'Key prefix mismatch.' ) ; } const args = [ ] ; let offset = 1 ; for ( const op of this . ops ) { const arg = op . read ( key , offset ) ; offset += op . size ( arg ) ; args . push ( arg ) ; } return args ; } param args returns public min ( args = [ ] ) { for ( let i = args . length ; i < this . ops . length ; i ++ ) { const op = this . ops [ i ] ; args . push ( op . min ) ; } return this . encode ( args ) ; } param args returns public max ( args = [ ] ) { for ( let i = args . length ; i < this . ops . length ; i ++ ) { const op = this . ops [ i ] ; args . push ( op . max ) ; } return this . encode ( args ) ; } }