// Copyright 2026 Noverberrain.
// SPDX-License-Identifier: Apache-2.0
///|
priv struct Reader {
input : Bytes
mut pos : Int32
}
///|
fn Reader::new(
input : Bytes,
max_input_bytes~ : Int32,
) -> Reader raise ParseError {
if max_input_bytes < 0 {
raise InvalidInputLimit(offset=0, limit=max_input_bytes)
}
if input.length() > max_input_bytes {
raise InputTooLarge(offset=0, size=input.length(), limit=max_input_bytes)
}
{ input, pos: 0, }
}
///|
fn Reader::remaining(self : Reader) -> Int32 {
self.input.length() - self.pos
}
///|
fn Reader::require(self : Reader, count : UInt64) -> Unit raise ParseError {
let remaining = self.remaining()
if count > remaining.to_uint64() {
raise UnexpectedEnd(offset=self.pos, needed=count, remaining~)
}
}
///|
// Check before narrowing or adding. The returned view does not copy data.
fn Reader::read_bytes(
self : Reader,
count : UInt64,
) -> BytesView raise ParseError {
self.require(count)
let start = self.pos
self.pos += count.to_int()
self.input[start:self.pos]
}
///|
fn Reader::read_u8(self : Reader) -> Byte raise ParseError {
self.read_bytes(1UL)[0]
}
///|
// All callers use fixed widths 1, 2, 4 or 8, so shifts remain within 0..63.
fn Reader::read_unsigned(
self : Reader,
width : Int32,
little_endian~ : Bool,
) -> UInt64 raise ParseError {
let bytes = self.read_bytes(width.to_uint64())
for i = 0, value = 0UL; i < width; i = i + 1 {
let index = if little_endian { width - 1 - i } else { i }
continue i + 1, (value << 8) | bytes[index].to_uint64()
} nobreak {
value
}
}
///|
fn Reader::read_u32_le(self : Reader) -> UInt32 raise ParseError {
self.read_unsigned(4, little_endian=true).to_uint()
}
///|
fn Reader::read_u64_le(self : Reader) -> UInt64 raise ParseError {
self.read_unsigned(8, little_endian=true)
}
///|
fn Reader::read_i8(self : Reader) -> Int32 raise ParseError {
let raw = self.read_u8().to_int()
if raw >= 128 {
raw - 256
} else {
raw
}
}
///|
fn Reader::read_i16_le(self : Reader) -> Int32 raise ParseError {
let raw = self.read_unsigned(2, little_endian=true).to_int()
if raw >= 32768 {
raw - 65536
} else {
raw
}
}
///|
fn Reader::read_i32_le(self : Reader) -> Int32 raise ParseError {
self.read_u32_le().reinterpret_as_int()
}
///|
fn Reader::read_i64_le(self : Reader) -> Int64 raise ParseError {
self.read_u64_le().reinterpret_as_int64()
}
///|
fn Reader::read_header(self : Reader) -> Int32 raise ParseError {
self.require(9UL)
let start = self.pos
let magic = b"REDIS"
for i in 0..<5 {
if self.input[start + i] != magic[i] {
raise InvalidMagic(offset=start + i)
}
}
let mut version = 0
for i in 5..<9 {
let digit = self.input[start + i].to_int()
if digit < 48 || digit > 57 {
raise InvalidVersionDigit(offset=start + i)
}
version = version * 10 + digit - 48
}
if version != 11 {
raise UnsupportedVersion(offset=start + 5, version~)
}
self.pos = start + 9
version
}