viem
Version:
183 lines (174 loc) • 5.23 kB
text/typescript
import {
NegativeOffsetError,
PositionOutOfBoundsError,
} from '../errors/cursor.js'
import type { ErrorType } from '../errors/utils.js'
import type { ByteArray } from '../types/misc.js'
export type Cursor = {
bytes: ByteArray
dataView: DataView
position: number
assertPosition(position: number): void
decrementPosition(offset: number): void
incrementPosition(offset: number): void
inspectByte(position?: number): ByteArray[number]
inspectBytes(length: number, position?: number): ByteArray
inspectUint8(position?: number): number
inspectUint16(position?: number): number
inspectUint24(position?: number): number
inspectUint32(position?: number): number
pushByte(byte: ByteArray[number]): void
pushBytes(bytes: ByteArray): void
pushUint8(value: number): void
pushUint16(value: number): void
pushUint24(value: number): void
pushUint32(value: number): void
readByte(): ByteArray[number]
readBytes(length: number): ByteArray
readUint8(): number
readUint16(): number
readUint24(): number
readUint32(): number
setPosition(position: number): void
}
export type CreateCursorErrorType = ErrorType
export type CursorErrorType =
| CursorAssertPositionErrorType
| CursorDecrementPositionErrorType
| CursorIncrementPositionErrorType
| ErrorType
export type CursorAssertPositionErrorType = PositionOutOfBoundsError | ErrorType
export type CursorDecrementPositionErrorType = NegativeOffsetError | ErrorType
export type CursorIncrementPositionErrorType = NegativeOffsetError | ErrorType
const staticCursor: Cursor = {
bytes: new Uint8Array(),
dataView: new DataView(new ArrayBuffer(0)),
position: 0,
assertPosition(position) {
if (position < 0 || position > this.bytes.length - 1)
throw new PositionOutOfBoundsError({
length: this.bytes.length,
position,
})
},
decrementPosition(offset) {
if (offset < 0) throw new NegativeOffsetError({ offset })
const position = this.position - offset
this.assertPosition(position)
this.position = position
},
incrementPosition(offset) {
if (offset < 0) throw new NegativeOffsetError({ offset })
const position = this.position + offset
this.assertPosition(position)
this.position = position
},
inspectByte(position_) {
const position = position_ ?? this.position
this.assertPosition(position)
return this.bytes[position]
},
inspectBytes(length, position_) {
const position = position_ ?? this.position
this.assertPosition(position + length - 1)
return this.bytes.subarray(position, position + length)
},
inspectUint8(position_) {
const position = position_ ?? this.position
this.assertPosition(position)
return this.bytes[position]
},
inspectUint16(position_) {
const position = position_ ?? this.position
this.assertPosition(position + 1)
return this.dataView.getUint16(position)
},
inspectUint24(position_) {
const position = position_ ?? this.position
this.assertPosition(position + 2)
return (
(this.dataView.getUint16(position) << 8) +
this.dataView.getUint8(position + 2)
)
},
inspectUint32(position_) {
const position = position_ ?? this.position
this.assertPosition(position + 3)
return this.dataView.getUint32(position)
},
pushByte(byte: ByteArray[number]) {
this.assertPosition(this.position)
this.bytes[this.position] = byte
this.position++
},
pushBytes(bytes: ByteArray) {
this.assertPosition(this.position + bytes.length - 1)
this.bytes.set(bytes, this.position)
this.position += bytes.length
},
pushUint8(value: number) {
this.assertPosition(this.position)
this.bytes[this.position] = value
this.position++
},
pushUint16(value: number) {
this.assertPosition(this.position + 1)
this.dataView.setUint16(this.position, value)
this.position += 2
},
pushUint24(value: number) {
this.assertPosition(this.position + 2)
this.dataView.setUint16(this.position, value >> 8)
this.dataView.setUint8(this.position + 2, value & ~4294967040)
this.position += 3
},
pushUint32(value: number) {
this.assertPosition(this.position + 3)
this.dataView.setUint32(this.position, value)
this.position += 4
},
readByte() {
const value = this.inspectByte()
this.position++
return value
},
readBytes(length) {
const value = this.inspectBytes(length)
this.position += length
return value
},
readUint8() {
const value = this.inspectUint8()
this.position += 1
return value
},
readUint16() {
const value = this.inspectUint16()
this.position += 2
return value
},
readUint24() {
const value = this.inspectUint24()
this.position += 3
return value
},
readUint32() {
const value = this.inspectUint32()
this.position += 4
return value
},
setPosition(position) {
this.assertPosition(position)
this.position = position
},
}
export function createCursor(bytes: ByteArray): Cursor {
const cursor = Object.create(staticCursor)
cursor.bytes = bytes
cursor.dataView = new DataView(
bytes.buffer,
bytes.byteOffset,
bytes.byteLength,
)
return cursor
}