///|
fn emit_reader(
output : StringBuilder,
root_type : String,
has_numeric_fields~ : Bool,
has_uint64~ : Bool,
has_repeated_fields~ : Bool,
has_contents~ : Bool,
has_validation~ : Bool,
) -> Unit {
let validation_error = if has_validation {
" __ROOT__InvalidValue(field~ : String, offset~ : Int, value~ : Int64, minimum~ : Int64, maximum~ : Int64)\n"
} else {
""
}
let contents_error = if has_contents {
" __ROOT__ContentsMismatch(field~ : String, offset~ : Int, expected~ : Byte, actual~ : Byte)\n"
} else {
""
}
let repeat_error = if has_repeated_fields {
" __ROOT__RepeatLimit(field~ : String, offset~ : Int, count~ : Int64)\n"
} else {
""
}
let repeat_state = if has_repeated_fields {
" mut repeats_left : Int\n"
} else {
""
}
let header =
#|///|
#|pub suberror __ROOT__ParseError {
#| __ROOT__Truncated(field~ : String, offset~ : Int, needed~ : Int64, remaining~ : Int)
#| __ROOT__InvalidLength(field~ : String, offset~ : Int, length~ : Int64)
#|__REPEAT_ERROR____CONTENTS_ERROR____VALIDATION_ERROR__}
#|
#|///|
#|priv struct __ROOT__Reader {
#| input : Bytes
#| mut offset : Int
#|__REPEAT_STATE__}
#|
#|///|
#|fn __ROOT__Reader::take(
#| self : __ROOT__Reader,
#| length : Int64,
#| field : String,
#|) -> BytesView raise __ROOT__ParseError {
#| guard length >= 0L else {
#| raise __ROOT__InvalidLength(field~, offset=self.offset, length~)
#| }
#| let remaining = self.input.length() - self.offset
#| guard length <= remaining.to_int64() else {
#| raise __ROOT__Truncated(field~, offset=self.offset, needed=length, remaining~)
#| }
#| let start = self.offset
#| self.offset = start + length.to_int()
#| self.input[start:self.offset]
#|}
#|
let header = header
.replace_all(old="__REPEAT_ERROR__", new=repeat_error[:])
.replace_all(old="__CONTENTS_ERROR__", new=contents_error[:])
.replace_all(old="__VALIDATION_ERROR__", new=validation_error[:])
.replace_all(old="__REPEAT_STATE__", new=repeat_state[:])
write_reader_block(output, header, root_type)
if has_numeric_fields {
write_reader_block(
output,
numeric_reader("read_bits", "UInt", "0U", "to_uint"),
root_type,
)
}
if has_uint64 {
write_reader_block(
output,
numeric_reader("read_uint64_bits", "UInt64", "0UL", "to_uint64"),
root_type,
)
}
if has_repeated_fields {
let repeat =
#|///|
#|fn __ROOT__Reader::reserve_repeats(
#| self : __ROOT__Reader,
#| count : Int64,
#| field : String,
#|) -> Int raise __ROOT__ParseError {
#| guard count >= 0L else {
#| raise __ROOT__InvalidLength(field~, offset=self.offset, length=count)
#| }
#| guard count <= self.repeats_left.to_int64() else {
#| raise __ROOT__RepeatLimit(field~, offset=self.offset, count~)
#| }
#| let count = count.to_int()
#| self.repeats_left -= count
#| count
#|}
#|
write_reader_block(output, repeat, root_type)
}
if has_contents {
let contents =
#|///|
#|fn __ROOT__Reader::read_contents(
#| self : __ROOT__Reader,
#| expected : Bytes,
#| field : String,
#|) -> BytesView raise __ROOT__ParseError {
#| let start = self.offset
#| let actual = self.take(expected.length().to_int64(), field)
#| for i in 0.. Unit raise __ROOT__ParseError {
#| guard value >= minimum && value <= maximum else {
#| raise __ROOT__InvalidValue(field~, offset=self.offset - width, value~, minimum~, maximum~)
#| }
#|}
#|
write_reader_block(output, validation, root_type)
}
}
///|
fn numeric_reader(
name : String,
type_name : String,
zero : String,
convert : String,
) -> String {
let block =
#|///|
#|fn __ROOT__Reader::__NAME__(
#| self : __ROOT__Reader,
#| width : Int,
#| little_endian : Bool,
#| field : String,
#|) -> __TYPE__ raise __ROOT__ParseError {
#| let bytes = self.take(width.to_int64(), field)
#| let mut value = __ZERO__
#| for i in 0.. Unit {
output.write_string(block.replace_all(old="__ROOT__", new=root_type[:]))
output.write_char('\n')
}