import { TextDecoder } from "./encoding" ; import { DenoError , EOF , ErrorKind , Reader , SyncReader , SyncWriter , Writer } from "./deno" ; const MIN_READ = 512 ; const MAX_SIZE = 2 ** 32 - 2 ; function copyBytes ( dst , src , off = 0 ) { const r = dst . byteLength - off ; if ( src . byteLength > r ) { src = src . subarray ( 0 , r ) ; } dst . set ( src , off ) ; return src . byteLength ; } /** A Buffer is a variable-sized buffer of bytes with read() and write()
 * methods. Based on https://golang.org/pkg/bytes/#Buffer
 */ export class Buffer implements Reader , SyncReader , Writer , SyncWriter { private buf : Uint8Array ; private off = 0 ; constructor ( ab ? ) { if ( ab == null ) { this . buf = new Uint8Array ( 0 ) ; return ; } this . buf = new Uint8Array ( ab ) ; } /** bytes() returns a slice holding the unread portion of the buffer.
     * The slice is valid for use only until the next buffer modification (that
     * is, only until the next call to a method like read(), write(), reset(), or
     * truncate()). The slice aliases the buffer content at least until the next
     * buffer modification, so immediate changes to the slice will affect the
     * result of future reads.
     */ bytes ( ) { return this . buf . subarray ( this . off ) ; } /** toString() returns the contents of the unread portion of the buffer
     * as a string. Warning - if multibyte characters are present when data is
     * flowing through the buffer, this method may result in incorrect strings
     * due to a character being split.
     */ toString ( ) { const decoder = new TextDecoder ( ) ; return decoder . decode ( this . buf . subarray ( this . off ) ) ; } /** empty() returns whether the unread portion of the buffer is empty. */ empty ( ) { return this . buf . byteLength <= this . off ; } /** length is a getter that returns the number of bytes of the unread
     * portion of the buffer
     */ get length ( ) : number { return this . buf . byteLength - this . off ; } /** Returns the capacity of the buffer's underlying byte slice, that is,
     * the total space allocated for the buffer's data.
     */ get capacity ( ) : number { return this . buf . buffer . byteLength ; } /** truncate() discards all but the first n unread bytes from the buffer but
     * continues to use the same allocated storage.  It throws if n is negative or
     * greater than the length of the buffer.
     */ truncate ( n ) { if ( n === 0 ) { this . reset ( ) ; return ; } if ( n < 0 || n > this . length ) { throw Error ( "bytes.Buffer: truncation out of range" ) ; } this . _reslice ( this . off + n ) ; } /** reset() resets the buffer to be empty, but it retains the underlying
     * storage for use by future writes. reset() is the same as truncate(0)
     */ reset ( ) { this . _reslice ( 0 ) ; this . off = 0 ; } /** _tryGrowByReslice() is a version of grow for the fast-case
     * where the internal buffer only needs to be resliced. It returns the index
     * where bytes should be written and whether it succeeded.
     * It returns -1 if a reslice was not needed.
     */ private _tryGrowByReslice ( n ) { const l = this . buf . byteLength ; if ( n <= this . capacity - l ) { this . _reslice ( l + n ) ; return l ; } return - 1 ; } private _reslice ( len ) { if ( len > this . buf . buffer . byteLength ) { throw new Error ( "short len" ) ; } this . buf = new Uint8Array ( this . buf . buffer , 0 , len ) ; } /** readSync() reads the next len(p) bytes from the buffer or until the buffer
     * is drained. The return value n is the number of bytes read. If the
     * buffer has no data to return, eof in the response will be true.
     */ readSync ( p ) { if ( this . empty ( ) ) { this . reset ( ) ; if ( p . byteLength === 0 ) { return 0 ; } return EOF ; } const nread = copyBytes ( p , this . buf . subarray ( this . off ) ) ; this . off += nread ; return nread ; } async read ( p ) { const rr = this . readSync ( p ) ; return Promise . resolve ( rr ) ; } writeSync ( p ) { const m = this . _grow ( p . byteLength ) ; return copyBytes ( this . buf , p , m ) ; } async write ( p ) { const n = this . writeSync ( p ) ; return Promise . resolve ( n ) ; } /** _grow() grows the buffer to guarantee space for n more bytes.
     * It returns the index where bytes should be written.
     * If the buffer can't grow it will throw with ErrTooLarge.
     */ private _grow ( n ) { const m = this . length ; if ( m === 0 && this . off !== 0 ) { this . reset ( ) ; } const i = this . _tryGrowByReslice ( n ) ; if ( i >= 0 ) { return i ; } const c = this . capacity ; if ( n <= Math . floor ( c / 2 ) - m ) { copyBytes ( this . buf , this . buf . subarray ( this . off ) ) ; } else if ( c > MAX_SIZE - c - n ) { throw new DenoError ( ErrorKind . TooLarge , "The buffer cannot be grown beyond the maximum size." ) ; } else { const buf = new Uint8Array ( 2 * c + n ) ; copyBytes ( buf , this . buf . subarray ( this . off ) ) ; this . buf = buf ; } this . off = 0 ; this . _reslice ( m + n ) ; return m ; } /** grow() grows the buffer's capacity, if necessary, to guarantee space for
     * another n bytes. After grow(n), at least n bytes can be written to the
     * buffer without another allocation. If n is negative, grow() will panic. If
     * the buffer can't grow it will throw ErrTooLarge.
     * Based on https://golang.org/pkg/bytes/#Buffer.Grow
     */ grow ( n ) { if ( n < 0 ) { throw Error ( "Buffer.grow: negative count" ) ; } const m = this . _grow ( n ) ; this . _reslice ( m ) ; } /** readFrom() reads data from r until EOF and appends it to the buffer,
     * growing the buffer as needed. It returns the number of bytes read. If the
     * buffer becomes too large, readFrom will panic with ErrTooLarge.
     * Based on https://golang.org/pkg/bytes/#Buffer.ReadFrom
     */ async readFrom ( r ) { let n = 0 ; while ( true ) { try { const i = this . _grow ( MIN_READ ) ; this . _reslice ( i ) ; const fub = new Uint8Array ( this . buf . buffer , i ) ; const nread = await r . read ( fub ) ; if ( nread === EOF ) { return n ; } this . _reslice ( i + nread ) ; n += nread ; } catch ( e ) { return n ; } } } /** Sync version of `readFrom`
     */ readFromSync ( r ) { let n = 0 ; while ( true ) { try { const i = this . _grow ( MIN_READ ) ; this . _reslice ( i ) ; const fub = new Uint8Array ( this . buf . buffer , i ) ; const nread = r . readSync ( fub ) ; if ( nread === EOF ) { return n ; } this . _reslice ( i + nread ) ; n += nread ; } catch ( e ) { return n ; } } } } /** Read `r` until EOF and return the content as `Uint8Array`.
 */ export async function readAll ( r ) { const buf = new Buffer ( ) ; await buf . readFrom ( r ) ; return buf . bytes ( ) ; } /** Read synchronously `r` until EOF and return the content as `Uint8Array`.
 */ export function readAllSync ( r ) { const buf = new Buffer ( ) ; buf . readFromSync ( r ) ; return buf . bytes ( ) ; } /** Write all the content of `arr` to `w`.
 */ export async function writeAll ( w , arr ) { let nwritten = 0 ; while ( nwritten < arr . length ) { nwritten += await w . write ( arr . subarray ( nwritten ) ) ; } } /** Write synchronously all the content of `arr` to `w`.
 */ export function writeAllSync ( w , arr ) { let nwritten = 0 ; while ( nwritten < arr . length ) { nwritten += w . writeSync ( arr . subarray ( nwritten ) ) ; } }