A fast, efficient list of Buffer objects optimized for reading and writing across multiple binary chunks without unnecessary copying.
DynamicBuffer lets you append/prepend chunks, read values across chunk boundaries, and encode/decode varints without manually concatenating buffers every time.
npm i @platformatic/dynamic-buffer- Zero-copy operations: read and write across buffer boundaries without eagerly concatenating
- Buffer-compatible API: familiar methods mirroring Node.js
Buffer - Variable-length integers: built-in unsigned varint and zig-zag varint support
- Memory efficient: internal chunks are only concatenated when explicitly requested
- TypeScript ready: exports type definitions
import { DynamicBuffer } from '@platformatic/dynamic-buffer'
const db = new DynamicBuffer([Buffer.from([1, 2]), Buffer.from([3, 4, 5])])
// Read across boundaries
console.log(db.readUInt16BE(1)) // bytes [2, 3]
// Append data
db.append(Buffer.from([6, 7, 8]))
// Contiguous buffer view (concatenates on access)
console.log(db.buffer) // <Buffer 01 02 03 04 05 06 07 08>DynamicBufferOutOfBoundsError
Creates a new DynamicBuffer instance.
buffers(Buffer | Buffer[]): optional initial buffer(s)
const db1 = new DynamicBuffer()
const db2 = new DynamicBuffer(Buffer.from([1, 2, 3]))
const db3 = new DynamicBuffer([Buffer.from([1]), Buffer.from([2, 3])])Total length (in bytes) across all internal buffers.
Returns a contiguous Buffer of all internal chunks.
- Returns the original chunk when there is only one buffer
- Concatenates only when there are multiple chunks
Direct access to internal chunks (Buffer[]). Use with caution.
Checks whether a value is a DynamicBuffer instance.
DynamicBuffer.isDynamicBuffer(new DynamicBuffer()) // true
DynamicBuffer.isDynamicBuffer(Buffer.from([1, 2])) // falseAppends a chunk. Returns this.
Prepends a chunk. Returns this.
Appends chunks from another DynamicBuffer. Returns this.
Prepends chunks from another DynamicBuffer. Returns this.
Returns the byte at offset.
Returns a Buffer for the selected range.
Returns a new DynamicBuffer for the selected range.
Converts a selected range to string.
Creates a copy of the DynamicBuffer.
deep = false: copies the chunk list only (shared chunk references)deep = true: clones each chunk viaBuffer.slice()
Consumes bytes from the front up to offset. Returns this.
All read methods support an optional offset (default 0, except varints where offset is required).
readUInt8,readUInt16BE,readUInt16LE,readUInt32BE,readUInt32LEreadInt8,readInt16BE,readInt16LE,readInt32BE,readInt32LEreadBigUInt64BE,readBigUInt64LEreadBigInt64BE,readBigInt64LE
readFloatBE,readFloatLEreadDoubleBE,readDoubleLE
Returns a tuple: [value, bytesRead]
readUnsignedVarInt(offset): [number, number]readUnsignedVarInt64(offset): [bigint, number]readVarInt(offset): [number, number](zig-zag decoded)readVarInt64(offset): [bigint, number](zig-zag decoded)
Most write methods accept append = true (when false, data is prepended) and return this.
writeUInt8,writeUInt16BE,writeUInt16LE,writeUInt32BE,writeUInt32LEwriteInt8,writeInt16BE,writeInt16LE,writeInt32BE,writeInt32LEwriteBigUInt64BE,writeBigUInt64LEwriteBigInt64BE,writeBigInt64LE
writeFloatBE,writeFloatLEwriteDoubleBE,writeDoubleLE
writeUnsignedVarInt(value, append)writeUnsignedVarInt64(value, append)writeVarInt(value, append)(zig-zag encoded)writeVarInt64(value, append)(zig-zag encoded)
Note: varint write methods append/prepend encoded bytes but do not return
this.
import { DynamicBuffer } from '@platformatic/dynamic-buffer'
const payload = Buffer.from('hello')
const message = new DynamicBuffer()
message.writeUInt32BE(0x12345678) // magic
message.writeUInt16BE(1) // version
message.writeVarInt(payload.length) // payload size
message.append(payload)
socket.write(message.buffer)import { DynamicBuffer } from '@platformatic/dynamic-buffer'
const parser = new DynamicBuffer()
socket.on('data', chunk => {
parser.append(chunk)
while (parser.length >= 4) {
const messageLength = parser.readUInt32BE(0)
if (parser.length >= 4 + messageLength) {
const message = parser.slice(4, 4 + messageLength)
processMessage(message)
parser.consume(4 + messageLength)
} else {
break
}
}
})import { DynamicBuffer } from '@platformatic/dynamic-buffer'
const db = new DynamicBuffer()
db.writeVarInt(42)
db.writeVarInt(-42)
db.writeVarInt64(123456789012345n)
let offset = 0
const [v1, b1] = db.readVarInt(offset)
offset += b1
const [v2, b2] = db.readVarInt(offset)
offset += b2
const [v3] = db.readVarInt64(offset)Out-of-range access throws OutOfBoundsError with code: 'OUT_OF_BOUNDS'.
Apache-2.0. See LICENSE.