"use strict";
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _BufWriter_writer, _BufWriterSync_writer;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BufWriterSync = exports.BufWriter = void 0;
const copy_js_1 = require("../../bytes/0.218.2/copy.js");
const DEFAULT_BUF_SIZE = 4096;
class AbstractBufBase {
    constructor(buf) {
        Object.defineProperty(this, "buf", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "usedBufferBytes", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 0
        });
        Object.defineProperty(this, "err", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: null
        });
        this.buf = buf;
    }
    /** Size returns the size of the underlying buffer in bytes. */
    size() {
        return this.buf.byteLength;
    }
    /** Returns how many bytes are unused in the buffer. */
    available() {
        return this.buf.byteLength - this.usedBufferBytes;
    }
    /** buffered returns the number of bytes that have been written into the
     * current buffer.
     */
    buffered() {
        return this.usedBufferBytes;
    }
}
/** BufWriter implements buffering for an deno.Writer object.
 * If an error occurs writing to a Writer, no more data will be
 * accepted and all subsequent writes, and flush(), will return the error.
 * After all data has been written, the client should call the
 * flush() method to guarantee all data has been forwarded to
 * the underlying deno.Writer.
 *
 * @deprecated (will be removed after 1.0.0) Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
 */
class BufWriter extends AbstractBufBase {
    /** return new BufWriter unless writer is BufWriter */
    static create(writer, size = DEFAULT_BUF_SIZE) {
        return writer instanceof BufWriter ? writer : new BufWriter(writer, size);
    }
    constructor(writer, size = DEFAULT_BUF_SIZE) {
        super(new Uint8Array(size <= 0 ? DEFAULT_BUF_SIZE : size));
        _BufWriter_writer.set(this, void 0);
        __classPrivateFieldSet(this, _BufWriter_writer, writer, "f");
    }
    /** Discards any unflushed buffered data, clears any error, and
     * resets buffer to write its output to w.
     */
    reset(w) {
        this.err = null;
        this.usedBufferBytes = 0;
        __classPrivateFieldSet(this, _BufWriter_writer, w, "f");
    }
    /** Flush writes any buffered data to the underlying io.Writer. */
    async flush() {
        if (this.err !== null)
            throw this.err;
        if (this.usedBufferBytes === 0)
            return;
        try {
            const p = this.buf.subarray(0, this.usedBufferBytes);
            let nwritten = 0;
            while (nwritten < p.length) {
                nwritten += await __classPrivateFieldGet(this, _BufWriter_writer, "f").write(p.subarray(nwritten));
            }
        }
        catch (e) {
            if (e instanceof Error) {
                this.err = e;
            }
            throw e;
        }
        this.buf = new Uint8Array(this.buf.length);
        this.usedBufferBytes = 0;
    }
    /** Writes the contents of `data` into the buffer. If the contents won't fully
     * fit into the buffer, those bytes that are copied into the buffer will be flushed
     * to the writer and the remaining bytes are then copied into the now empty buffer.
     *
     * @return the number of bytes written to the buffer.
     */
    async write(data) {
        if (this.err !== null)
            throw this.err;
        if (data.length === 0)
            return 0;
        let totalBytesWritten = 0;
        let numBytesWritten = 0;
        while (data.byteLength > this.available()) {
            if (this.buffered() === 0) {
                // Large write, empty buffer.
                // Write directly from data to avoid copy.
                try {
                    numBytesWritten = await __classPrivateFieldGet(this, _BufWriter_writer, "f").write(data);
                }
                catch (e) {
                    if (e instanceof Error) {
                        this.err = e;
                    }
                    throw e;
                }
            }
            else {
                numBytesWritten = (0, copy_js_1.copy)(data, this.buf, this.usedBufferBytes);
                this.usedBufferBytes += numBytesWritten;
                await this.flush();
            }
            totalBytesWritten += numBytesWritten;
            data = data.subarray(numBytesWritten);
        }
        numBytesWritten = (0, copy_js_1.copy)(data, this.buf, this.usedBufferBytes);
        this.usedBufferBytes += numBytesWritten;
        totalBytesWritten += numBytesWritten;
        return totalBytesWritten;
    }
}
exports.BufWriter = BufWriter;
_BufWriter_writer = new WeakMap();
/** BufWriterSync implements buffering for a deno.WriterSync object.
 * If an error occurs writing to a WriterSync, no more data will be
 * accepted and all subsequent writes, and flush(), will return the error.
 * After all data has been written, the client should call the
 * flush() method to guarantee all data has been forwarded to
 * the underlying deno.WriterSync.
 *
 * @deprecated (will be removed after 1.0.0) Use the {@link https://developer.mozilla.org/en-US/docs/Web/API/Streams_API | Web Streams API} instead.
 */
class BufWriterSync extends AbstractBufBase {
    /** return new BufWriterSync unless writer is BufWriterSync */
    static create(writer, size = DEFAULT_BUF_SIZE) {
        return writer instanceof BufWriterSync
            ? writer
            : new BufWriterSync(writer, size);
    }
    constructor(writer, size = DEFAULT_BUF_SIZE) {
        super(new Uint8Array(size <= 0 ? DEFAULT_BUF_SIZE : size));
        _BufWriterSync_writer.set(this, void 0);
        __classPrivateFieldSet(this, _BufWriterSync_writer, writer, "f");
    }
    /** Discards any unflushed buffered data, clears any error, and
     * resets buffer to write its output to w.
     */
    reset(w) {
        this.err = null;
        this.usedBufferBytes = 0;
        __classPrivateFieldSet(this, _BufWriterSync_writer, w, "f");
    }
    /** Flush writes any buffered data to the underlying io.WriterSync. */
    flush() {
        if (this.err !== null)
            throw this.err;
        if (this.usedBufferBytes === 0)
            return;
        try {
            const p = this.buf.subarray(0, this.usedBufferBytes);
            let nwritten = 0;
            while (nwritten < p.length) {
                nwritten += __classPrivateFieldGet(this, _BufWriterSync_writer, "f").writeSync(p.subarray(nwritten));
            }
        }
        catch (e) {
            if (e instanceof Error) {
                this.err = e;
            }
            throw e;
        }
        this.buf = new Uint8Array(this.buf.length);
        this.usedBufferBytes = 0;
    }
    /** Writes the contents of `data` into the buffer.  If the contents won't fully
     * fit into the buffer, those bytes that can are copied into the buffer, the
     * buffer is the flushed to the writer and the remaining bytes are copied into
     * the now empty buffer.
     *
     * @return the number of bytes written to the buffer.
     */
    writeSync(data) {
        if (this.err !== null)
            throw this.err;
        if (data.length === 0)
            return 0;
        let totalBytesWritten = 0;
        let numBytesWritten = 0;
        while (data.byteLength > this.available()) {
            if (this.buffered() === 0) {
                // Large write, empty buffer.
                // Write directly from data to avoid copy.
                try {
                    numBytesWritten = __classPrivateFieldGet(this, _BufWriterSync_writer, "f").writeSync(data);
                }
                catch (e) {
                    if (e instanceof Error) {
                        this.err = e;
                    }
                    throw e;
                }
            }
            else {
                numBytesWritten = (0, copy_js_1.copy)(data, this.buf, this.usedBufferBytes);
                this.usedBufferBytes += numBytesWritten;
                this.flush();
            }
            totalBytesWritten += numBytesWritten;
            data = data.subarray(numBytesWritten);
        }
        numBytesWritten = (0, copy_js_1.copy)(data, this.buf, this.usedBufferBytes);
        this.usedBufferBytes += numBytesWritten;
        totalBytesWritten += numBytesWritten;
        return totalBytesWritten;
    }
}
exports.BufWriterSync = BufWriterSync;
_BufWriterSync_writer = new WeakMap();
