// Copyright 2026 Noverberrain.
// SPDX-License-Identifier: Apache-2.0
///|
fn decode_intset(
input : Bytes,
base : Int32,
max_string_bytes : Int32,
budget : DecodeBudget,
sets : SetBudget,
) -> (Array[Bytes], Int32) raise ParseError {
if input.length() < 8 {
raise InvalidIntset(offset=base, inner_offset=0, reason="short header")
}
let reader = Reader::new(input, max_input_bytes=input.length())
let width = reader.read_unsigned(4, little_endian=true)
if width != 2UL && width != 4UL && width != 8UL {
raise InvalidIntset(
offset=base,
inner_offset=0,
reason="invalid integer width",
)
}
let count = reader.read_unsigned(4, little_endian=true)
// count is a UInt32 value. Widen before multiplication; never Int32 math.
if 8UL + count * width != input.length().to_uint64() {
raise InvalidIntset(offset=base, inner_offset=4, reason="length mismatch")
}
if count == 0UL {
raise InvalidSet(offset=base, reason="empty set")
}
sets.charge(count, base)
let members = []
let mut previous : Int64? = None
for _ in 0.. reader.read_i16_le().to_int64()
4UL => reader.read_i32_le().to_int64()
_ => reader.read_i64_le()
}
if previous is Some(old) && value <= old {
raise InvalidIntset(
offset=base,
inner_offset~,
reason="members not strictly increasing",
)
}
previous = Some(value)
let bytes = b"\{value}"
check_resource_limit(
"string-bytes",
base,
bytes.length().to_uint64(),
max_string_bytes,
)
budget.charge(bytes.length().to_uint64(), base)
members.push(bytes)
}
(members, width.to_int())
}