import type { LevelDBI , LevelDBIteratorI } from "./index" ; function getIdx ( kv , k , start ? , end ? ) { if ( ! kv ) { throw new Error ( 'FakeLevelDB was closed!' ) ; } k = toArraybuf ( k ) ; start = start || 0 ; end = end || kv . length ; const pivot = Math . floor ( start + ( end - start ) / 2 ) ; if ( end - start <= 1 ) { if ( pivot < kv . length && arraybufGt ( k , kv [ pivot ] [ 0 ] ) ) { return end ; } else { return pivot ; } } if ( ! arraybufGt ( kv [ pivot ] [ 0 ] , k ) && ! arraybufGt ( k , kv [ pivot ] [ 0 ] ) ) { return pivot ; } if ( arraybufGt ( kv [ pivot ] [ 0 ] , k ) ) { return getIdx ( kv , k , start , pivot ) ; } else { return getIdx ( kv , k , pivot , end ) ; } } export class FakeLevelDBIterator implements LevelDBIteratorI { private kv : [ ArrayBuffer , ArrayBuffer ] [ ] ; private pos : undefined | number ; constructor ( db ) { if ( ! db . kv ) { throw new Error ( `Could't make FakeLevelDBIterator: DB was closed!` ) ; } this . kv = [ ... db . kv ] ; this . pos = undefined ; } seekToFirst ( ) { this . pos = 0 ; return this ; } seekLast ( ) { this . pos = this . kv . length - 1 ; return this ; } seek ( target ) { this . pos = getIdx ( this . kv , target ) ; return this ; } valid ( ) { return this . pos !== undefined && this . pos >= 0 && this . pos < this . kv . length ; } next ( ) { this . pos ! ++ ; } prev ( ) { this . pos ! -- ; } close ( ) { this . pos = undefined ; } keyStr ( ) { return toString ( this . kv [ this . pos ! ] [ 0 ] ) ; } keyBuf ( ) { return toArraybuf ( this . kv [ this . pos ! ] [ 0 ] ) ; } valueStr ( ) { return toString ( this . kv [ this . pos ! ] [ 1 ] ) ; } valueBuf ( ) { return toArraybuf ( this . kv [ this . pos ! ] [ 1 ] ) ; } } var decoder = new ( global as any ) . TextDecoder ( ) ; var encoder = new ( global as any ) . TextEncoder ( ) ; export function toString ( buf ) { if ( typeof buf == 'string' ) { return buf ; } return decoder . decode ( new Uint8Array ( buf ) ) ; } export function toArraybuf ( str ) { if ( str instanceof ArrayBuffer ) { return str ; } var uint8Arr = encoder . encode ( str ) ; return uint8Arr . buffer ; } export function arraybufGt ( a , b ) { var keyA = new Uint8Array ( a ) ; var keyB = new Uint8Array ( b ) ; for ( var i = 0 ; i < keyA . byteLength && i < keyB . byteLength ; ++ i ) { if ( keyA [ i ] > keyB [ i ] ) { return true ; } if ( keyA [ i ] < keyB [ i ] ) { return false ; } } return keyA . byteLength > keyB . byteLength ; } export class FakeLevelDB implements LevelDBI { public kv : null | [ ArrayBuffer , ArrayBuffer ] [ ] ; constructor ( ) { this . kv = [ ] ; } close ( ) { this . kv = null ; } closed ( ) { return this . kv == null ; } put ( k , v ) { const curIdx = getIdx ( this . kv , k ) ; if ( curIdx == this . kv ! . length ) { this . kv ! . push ( [ toArraybuf ( k ) , toArraybuf ( v ) ] ) ; } else if ( arraybufGt ( this . kv ! [ curIdx ] [ 0 ] , toArraybuf ( k ) ) ) { this . kv ! . splice ( curIdx , 0 , [ toArraybuf ( k ) , toArraybuf ( v ) ] ) ; } else { this . kv ! [ curIdx ] [ 1 ] = toArraybuf ( v ) ; } } delete ( k ) { k = toArraybuf ( k ) ; const curIdx = getIdx ( this . kv , k ) ; if ( curIdx < this . kv ! . length && ! arraybufGt ( this . kv ! [ curIdx ] [ 0 ] , k ) && ! arraybufGt ( k , this . kv ! [ curIdx ] [ 0 ] ) ) { this . kv ! . splice ( curIdx , 1 ) ; } } getStr ( k ) { const buf = this . getBuf ( k ) ; return buf && toString ( buf ) ; } getBuf ( k ) { k = toArraybuf ( k ) ; const curIdx = getIdx ( this . kv , k ) ; const kv = curIdx < this . kv ! . length ? this . kv ! [ curIdx ] : null ; return ! kv || arraybufGt ( kv [ 0 ] , k ) || arraybufGt ( k , kv [ 0 ] ) ? null : kv [ 1 ] ; } newIterator ( ) { return new FakeLevelDBIterator ( this ) ; } }