# Byte operations and resource policy live here; Rust owns buffers and native waits.
visible `__bytes
visible `__io
visible `__io_close
visible "__io_Bytes"
visible "__io_Reader"
visible "__io_Writer"
visible "__io_ByteSource"
visible "__io_ByteSink"
pub visible "__io_ReadError"
pub visible "__io_WriteError"
pub visible "__io_OpenError"
pub visible "__io_ClosedError"
pub visible "__io_TimeoutError"
pub visible "__io_CancelledError"
pub visible "__io_LimitError"
pub visible "__io_DecodeError"
pub visible "__io_LeaseError"
pub type Bytes = __io_Bytes
pub type Reader = __io_Reader
pub type Writer = __io_Writer
pub type ByteSource = __io_ByteSource
pub type ByteSink = __io_ByteSink
pub type Error = ReadError | WriteError | OpenError | ClosedError | TimeoutError | CancelledError | LimitError | DecodeError | LeaseError | ShortReadError
pub fn Bytes::from_string($value: String): Bytes | Error { __bytes "from_string" $value }
pub fn Bytes::from_array_integer($value: [Integer]): Bytes | Error { __bytes "from_array" $value }
pub fn Bytes::from_array_any($value: [any]): Bytes | Error { __bytes "from_array" $value }
pub fn Bytes::get_count(): Integer { __bytes "count" $self }
pub fn Bytes::decode_utf8(): String | Error { __bytes "utf8" $self }
pub fn Bytes::encode_base64(): String | Error { __bytes "base64" $self }
pub fn Bytes::to_array(): [Integer] | Error { __bytes "array" $self }
pub fn Bytes::concat($other: Bytes): Bytes | Error { __bytes "concat" $self $other }
pub fn Bytes::slice($start: Integer, $end: Integer): Bytes | Error { __bytes "slice" $self $start $end }
pub fn String::from_bytes($value: Bytes): String | Error { $value.decode_utf8 }
pub fn decode_base64($value: String): Bytes | Error { __bytes "from_base64" $value }
pub fn memory_reader($value: Bytes): Reader | Error { __io "memory_reader" $value }
pub fn open_reader($path: String): Reader | Error { __io "open_reader" $path }
pub fn open_writer($path: String): Writer | Error { __io "open_writer" $path }
pub fn Reader::read($max_bytes: Integer | ()): Bytes | () | Error
{
__io "read" $self $max_bytes
}
pub fn Reader::next_item(): Bytes | () | Error { $self.read 65536 }
pub fn Reader::close(): () | Error { __io_close $self }
pub fn Writer::write($bytes: Bytes): Integer | Error { __io "write" $self $bytes }
pub fn Writer::flush(): () | Error { __io "flush" $self }
pub fn Writer::close(): () | Error { __io_close $self }
pub fn Reader::lease(): Reader | Error { __io "lease_reader" $self }
pub fn byte_source($reader: Reader): ByteSource | Error { __io "byte_source" $reader false }
pub fn read_file($path: String): ByteSource | Error
{
let $reader = open_reader $path
__io "byte_source" $reader true
}
pub fn ByteSource::next_item(): Bytes | () | Error
{
let $reader: Reader = __io "source_reader" $self
let $chunk = $reader.read 65536
if $chunk == () { $self.close }
$chunk
}
pub fn ByteSource::close(): () | Error { __io_close $self }
pub fn byte_sink($writer: Writer): ByteSink | Error { __io "byte_sink" $writer false }
pub fn write_file($path: String): ByteSink | Error
{
let $writer = open_writer $path
__io "byte_sink" $writer true
}
pub fn ByteSink::close(): () | Error { __io_close $self }
pub fn Reader::read_all($max_bytes: Integer | ()): Bytes | Error
{
let $maximum = if $max_bytes == () { 16777216 } else { $max_bytes }
if ($maximum < 1) || ($maximum > 67108864)
{ return LimitError(message: "read_all limit must be 1..67108864", operation: "read_all") }
let $reader = $self.lease
try { return read_all_leased $reader $maximum }
finally { $reader.close }
}
fn read_all_leased($reader: Reader, $maximum: Integer): Bytes | Error
{
let $result = Bytes("")
loop
{
let $chunk = $reader.read 65536
if $chunk == () { return $result }
if $result.count + $chunk.count > $maximum
{
return LimitError(message: "Reader exceeds byte limit", operation: "read_all")
}
$result = $result.concat $chunk
}
}
pub fn Reader::read_exact($count: Integer): Bytes | Error
{
if ($count < 0) || ($count > 67108864)
{ return LimitError(message: "read_exact count must be 0..67108864", operation: "read_exact") }
let $reader = $self.lease
try { return read_exact_leased $reader $count }
finally { $reader.close }
}
fn read_exact_leased($reader: Reader, $count: Integer): Bytes | Error
{
let $result = Bytes("")
while $result.count < $count
{
let $chunk = $reader.read (min ($count - $result.count) 65536)
if $chunk == ()
{ return ShortReadError(message: "Unexpected EOF", expected: $count, received: $result) }
$result = $result.concat $chunk
}
$result
}
pub fn read_bytes($path: String, $max_bytes: Integer | ()): Bytes | Error
{
let $reader = open_reader $path
try { return $reader.read_all $max_bytes }
finally { $reader.close }
}
pub fn read_text($path: String, $max_bytes: Integer | ()): String | Error
{
String(read_bytes $path $max_bytes)
}
pub fn write_bytes($path: String, $bytes: Bytes): Integer | Error
{
let $writer = open_writer $path
try
{
let $count = $writer.write $bytes
$writer.flush
return $count
}
finally { $writer.close }
}
pub fn write_text($path: String, $text: String): Integer | Error
{
write_bytes $path Bytes($text)
}
pub fn copy($reader: Reader, $writer: Writer): Integer | Error
{
let $count = 0
for $chunk in $reader
{
$count = $count + ($writer.write $chunk)
}
$writer.flush
$count
}
visible "__io_Lines"
pub type Lines = __io_Lines
pub fn lines($reader: Reader, $max_bytes: Integer | (), $universal: Boolean | ()): Lines | Error
{
__io "lines" $reader $max_bytes $universal
}
pub fn Lines::next_item(): String | () | Error
{
let $bytes: Bytes | () = __io "read_line" $self
if $bytes == () { return () }
String($bytes)
}
pub fn Lines::close(): () | Error { __io_close $self }
pub fn utf8($value: String): Bytes | Error { Bytes($value) }
pub fn Writer::lease(): Writer | Error { __io "lease_writer" $self }
pub fn Writer::shutdown_write(): () | Error { __io "shutdown_write" $self }
pub error struct ShortReadError
{
pub message: String,
pub expected: Integer,
pub received: Bytes,
}
# Binary records keep UTF-8 conversion separate from framing.
pub fn records($reader: Reader, $separator: Integer, $max_bytes: Integer | ()): Lines | Error
{ __io "records" $reader $max_bytes $separator }
pub fn Lines::next_bytes(): Bytes | () | Error { __io "read_line" $self }