// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
pub(all) suberror ReaderError {
EndOfStream
InvalidString
InvalidBase64
InvalidLength
InvalidPackedLength
OverlongVarint
UnknownWireType(UInt)
} derive(Eq, Debug)
///|
pub impl Show for ReaderError with fn output(self, logger) {
match self {
EndOfStream => logger.write_string("EndOfStream")
InvalidString => logger.write_string("InvalidString")
InvalidBase64 => logger.write_string("InvalidBase64")
InvalidLength => logger.write_string("InvalidLength")
InvalidPackedLength => logger.write_string("InvalidPackedLength")
OverlongVarint => logger.write_string("OverlongVarint")
UnknownWireType(wire_type) =>
logger
..write_string("UnknownWireType(")
..write_object(wire_type)
.write_string(")")
}
}
///|
struct BytesReader {
data : Bytes
len : Int
mut start : Int
}
///|
pub impl Show for BytesReader with fn output(self, logger) {
logger
..write_string("{data: ")
..write_object(self.data)
..write_string(", len: ")
..write_object(self.len)
..write_string(", start: ")
..write_object(self.start)
.write_string("}")
}
///|
pub fn BytesReader::from_bytes(data : Bytes) -> BytesReader {
{ data, len: data.length(), start: 0, }
}
///|
pub impl Reader for BytesReader with fn read(
self,
bytes : FixedArray[Byte],
offset~ : Int,
max_length~ : Int,
) -> Int? {
if offset >= bytes.length() || max_length <= 0 || self.start >= self.len {
return None
}
let read_length = @cmp.minimum(
@cmp.minimum(bytes.length() - offset, max_length),
self.len - self.start,
)
if read_length == 1 {
bytes[offset] = self.data[self.start]
} else {
bytes.blit_from_bytes(offset, self.data, self.start, read_length)
}
self.start += read_length
Some(read_length)
}
///|
pub impl AsyncReader for BytesReader with fn read(
self,
bytes : FixedArray[Byte],
offset~ : Int,
max_length~ : Int,
) -> Int? raise {
if offset >= bytes.length() || max_length <= 0 || self.start >= self.len {
return None
}
let read_length = @cmp.minimum(
@cmp.minimum(bytes.length() - offset, max_length),
self.len - self.start,
)
if read_length == 1 {
bytes[offset] = self.data[self.start]
} else {
bytes.blit_from_bytes(offset, self.data, self.start, read_length)
}
self.start += read_length
Some(read_length)
}
///|
struct LimitedReader[T] {
reader : T
mut limit : Int?
mut end_group : UInt?
mut end_group_seen : Bool
}
///|
/// Creates a reader wrapper that optionally limits how many bytes a nested
/// length-delimited message can consume.
pub fn[T] LimitedReader::LimitedReader(
reader : T,
limit? : Int,
) -> LimitedReader[T] {
{ reader, limit, end_group: None, end_group_seen: false, }
}
///|
#deprecated
pub fn[T] LimitedReader::new(reader : T, limit? : Int) -> LimitedReader[T] {
{ reader, limit, end_group: None, end_group_seen: false, }
}
///|
pub impl[T : Reader] Reader for LimitedReader[T] with fn read(
self,
bytes : FixedArray[Byte],
offset~ : Int,
max_length~ : Int,
) -> Int? {
if self.limit is Some(0) {
return None
}
let max_length = if self.limit is Some(limit) {
@cmp.minimum(limit, max_length)
} else {
max_length
}
let read_length = self.reader.read(bytes, offset~, max_length~)
if read_length is Some(length) && self.limit is Some(limit) {
self.limit = Some(limit - length)
}
read_length
}
///|
pub impl[T : AsyncReader] AsyncReader for LimitedReader[T] with fn read(
self,
bytes : FixedArray[Byte],
offset~ : Int,
max_length~ : Int,
) -> Int? raise {
if self.limit is Some(0) {
return None
}
let max_length = if self.limit is Some(limit) {
@cmp.minimum(limit, max_length)
} else {
max_length
}
let read_length = self.reader.read(bytes, offset~, max_length~)
if read_length is Some(length) && self.limit is Some(limit) {
self.limit = Some(limit - length)
}
read_length
}