/**
* Protobuf binary writer for ArkTS
*
* Provides varint/zigzag encoders, fixed-width writes and length-delimited
* string/bytes with delimiter helpers for nested messages.
*/
import { encodeUTF8 } from './util'
export class Writer {
private b: number[]
constructor() { this.b = [] }
get length(): number { return this.b.length }
private push(v: number): void { this.b.push(v & 0xFF) }
/** Write unsigned varint32 */
uint32(v: number): Writer {
while (v >= 0x80) { this.push((v & 0x7F) | 0x80); v >>>= 7 }
this.push(v)
return this
}
/** Write field tag (fieldNo<<3 | wireType) */
tag(fieldNo: number, wireType: number): Writer { return this.uint32((fieldNo << 3) | wireType) }
/** Write boolean (varint) */
bool(v: boolean): Writer { return this.uint32(v ? 1 : 0) }
/** Write int32 */
int32(v: number): Writer { return this.uint32(v >>> 0) }
/** Write sint32 (zigzag) */
sint32(v: number): Writer { return this.uint32(((v << 1) ^ (v >> 31)) >>> 0) }
/** Write signed varint64 as bigint */
int64(v: bigint): Writer {
let x = BigInt.asUintN(64, v)
while (x > 0x7Fn) { this.push(Number((x & 0x7Fn) | 0x80n)); x >>= 7n }
this.push(Number(x & 0x7Fn))
return this
}
/** Write sint64 (zigzag) as bigint */
sint64(v: bigint): Writer {
const zz = (v << 1n) ^ (v >> 63n)
return this.int64(zz)
}
/** Write signed varint64 from number (may lose precision) */
int64Number(v: number): Writer { return this.int64(BigInt(v)) }
/** Write fixed32 little-endian */
fixed32(v: number): Writer { const ab = new ArrayBuffer(4); const dv = new DataView(ab); dv.setUint32(0, v >>> 0, true); const u = new Uint8Array(ab); for (let i = 0; i < 4; i++) this.push(u[i]); return this }
/** Write sfixed32 little-endian */
sfixed32(v: number): Writer { const ab = new ArrayBuffer(4); const dv = new DataView(ab); dv.setInt32(0, v | 0, true); const u = new Uint8Array(ab); for (let i = 0; i < 4; i++) this.push(u[i]); return this }
/** Write fixed64 little-endian */
fixed64(v: bigint): Writer { const ab = new ArrayBuffer(8); const dv = new DataView(ab); const lo = Number(v & 0xFFFFFFFFn); const hi = Number((v >> 32n) & 0xFFFFFFFFn); dv.setUint32(0, lo >>> 0, true); dv.setUint32(4, hi >>> 0, true); const u = new Uint8Array(ab); for (let i = 0; i < 8; i++) this.push(u[i]); return this }
/** Write sfixed64 little-endian */
sfixed64(v: bigint): Writer { const ab = new ArrayBuffer(8); const dv = new DataView(ab); const lo = Number(v & 0xFFFFFFFFn); const hi = Number((v >> 32n) & 0xFFFFFFFFn); dv.setInt32(0, lo | 0, true); dv.setInt32(4, hi | 0, true); const u = new Uint8Array(ab); for (let i = 0; i < 8; i++) this.push(u[i]); return this }
/** Write float32 little-endian */
float(v: number): Writer { const ab = new ArrayBuffer(4); const dv = new DataView(ab); dv.setFloat32(0, v, true); const u = new Uint8Array(ab); for (let i = 0; i < 4; i++) this.push(u[i]); return this }
/** Write float64 little-endian */
double(v: number): Writer { const ab = new ArrayBuffer(8); const dv = new DataView(ab); dv.setFloat64(0, v, true); const u = new Uint8Array(ab); for (let i = 0; i < 8; i++) this.push(u[i]); return this }
/** Write length-delimited UTF-8 string */
string(s: string): Writer {
const e = encodeUTF8(s)
this.uint32(e.length)
for (let i = 0; i < e.length; i++) this.push(e[i])
return this
}
/** Write length-delimited bytes */
bytes(a: Uint8Array): Writer {
this.uint32(a.length)
for (let i = 0; i < a.length; i++) this.push(a[i])
return this
}
/** Create a child writer for length-delimited section */
fork(): Writer { return new Writer() }
/** Write length prefix and append child buffer */
ldelim(child: Writer): Writer {
const buf = child.finish()
this.uint32(buf.length)
for (let i = 0; i < buf.length; i++) this.push(buf[i])
return this
}
/** Finalize and get the composed buffer */
finish(): Uint8Array { return Uint8Array.from(this.b) }
}