Dorian 0d073fa89e Add comprehensive installation and setup documentation
- Add GETTING_STARTED.md with quick start guide and development modes
- Add INSTALL.sh automated installation script
- Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md
- Add QUICK_REFERENCE.md for common commands
- Add SETUP_GUIDE.md with detailed setup instructions
- Update README.md with improved project overview
- Add did-wallet app dependencies and node_modules
2026-01-27 17:18:21 +00:00

125 lines
4.2 KiB
JavaScript

/**
* Bl is a list of byte chunks, similar to https://github.com/rvagg/bl but for
* writing rather than reading.
* A Bl object accepts set() operations for individual bytes and copyTo() for
* inserting byte arrays. These write operations don't automatically increment
* the internal cursor so its "length" won't be changed. Instead, increment()
* must be called to extend its length to cover the inserted data.
* The toBytes() call will convert all internal memory to a single Uint8Array of
* the correct length, truncating any data that is stored but hasn't been
* included by an increment().
* get() can retrieve a single byte.
* All operations (except toBytes()) take an "offset" argument that will perform
* the write at the offset _from the current cursor_. For most operations this
* will be `0` to write at the current cursor position but it can be ahead of
* the current cursor. Negative offsets probably work but are untested.
*/
// TODO: ipjs doesn't support this, only for test files: https://github.com/mikeal/ipjs/blob/master/src/package/testFile.js#L39
import { alloc, concat, slice } from './byte-utils.js'
// the ts-ignores in this file are almost all for the `Uint8Array|number[]` duality that exists
// for perf reasons. Consider better approaches to this or removing it entirely, it is quite
// risky because of some assumptions about small chunks === number[] and everything else === Uint8Array.
const defaultChunkSize = 256
export class Bl {
/**
* @param {number} [chunkSize]
*/
constructor (chunkSize = defaultChunkSize) {
this.chunkSize = chunkSize
/** @type {number} */
this.cursor = 0
/** @type {number} */
this.maxCursor = -1
/** @type {(Uint8Array|number[])[]} */
this.chunks = []
// keep the first chunk around if we can to save allocations for future encodes
/** @type {Uint8Array|number[]|null} */
this._initReuseChunk = null
}
reset () {
this.cursor = 0
this.maxCursor = -1
if (this.chunks.length) {
this.chunks = []
}
if (this._initReuseChunk !== null) {
this.chunks.push(this._initReuseChunk)
this.maxCursor = this._initReuseChunk.length - 1
}
}
/**
* @param {Uint8Array|number[]} bytes
*/
push (bytes) {
let topChunk = this.chunks[this.chunks.length - 1]
const newMax = this.cursor + bytes.length
if (newMax <= this.maxCursor + 1) {
// we have at least one chunk and we can fit these bytes into that chunk
const chunkPos = topChunk.length - (this.maxCursor - this.cursor) - 1
// @ts-ignore
topChunk.set(bytes, chunkPos)
} else {
// can't fit it in
if (topChunk) {
// trip the last chunk to `cursor` if we need to
const chunkPos = topChunk.length - (this.maxCursor - this.cursor) - 1
if (chunkPos < topChunk.length) {
// @ts-ignore
this.chunks[this.chunks.length - 1] = topChunk.subarray(0, chunkPos)
this.maxCursor = this.cursor - 1
}
}
if (bytes.length < 64 && bytes.length < this.chunkSize) {
// make a new chunk and copy the new one into it
topChunk = alloc(this.chunkSize)
this.chunks.push(topChunk)
this.maxCursor += topChunk.length
if (this._initReuseChunk === null) {
this._initReuseChunk = topChunk
}
// @ts-ignore
topChunk.set(bytes, 0)
} else {
// push the new bytes in as its own chunk
this.chunks.push(bytes)
this.maxCursor += bytes.length
}
}
this.cursor += bytes.length
}
/**
* @param {boolean} [reset]
* @returns {Uint8Array}
*/
toBytes (reset = false) {
let byts
if (this.chunks.length === 1) {
const chunk = this.chunks[0]
if (reset && this.cursor > chunk.length / 2) {
/* c8 ignore next 2 */
// @ts-ignore
byts = this.cursor === chunk.length ? chunk : chunk.subarray(0, this.cursor)
this._initReuseChunk = null
this.chunks = []
} else {
// @ts-ignore
byts = slice(chunk, 0, this.cursor)
}
} else {
// @ts-ignore
byts = concat(this.chunks, this.cursor)
}
if (reset) {
this.reset()
}
return byts
}
}