import { Buffer } from 'buffer'; import { AsyncLock } from './async-lock.mjs'; /** * Represents an asynchronous byte queue for managing byte data. */ export class AsyncByteQueue { /** * Creates an instance of AsyncByteQueue. */ constructor() { /** * The buffer to store byte data. * @type {Buffer} * @private */ this.data = Buffer.alloc(0); /** * The index indicating the head of the byte queue. * @type {number} * @private */ this.head = 0; /** * The lock used to manage access to the byte queue. * @type {AsyncLock} * @private */ this.lock = new AsyncLock(); } /** * Checks if the byte queue is empty. * @returns {boolean} True if the byte queue is empty; otherwise, false. */ empty() { return this.head === this.data.byteLength; } /** * Retrieves the byte at the front of the queue asynchronously. * @returns {Promise} A promise that resolves with the byte at the front of the queue. */ async front() { while (this.empty()) { await this.lock.acquire(); } this.lock.forceRelease(); return this.data[this.head]; } /** * Removes and retrieves the byte at the front of the queue asynchronously. * @returns {Promise} A promise that resolves with the byte removed from the front of the queue. */ async popFront() { while (this.empty()) { await this.lock.acquire(); } let res = this.data[this.head]; this.head += 1; this._refactor(); if (!this.empty()) { this.lock.forceRelease(); } return res; } /** * Appends byte data to the end of the queue. * @param {Buffer} data The byte data to append to the queue. */ pushBack(data) { this.data = Buffer.concat([this.data, data]); this.lock.forceRelease(); } /** * Refactors the internal data buffer by discarding processed bytes if necessary. * @private */ _refactor() { if (this.head >= (this.data.byteLength >> 1) && this.head >= 16) { this.data = this.data.subarray(this.head); } } }