/development/std/io/core.nct
core.nct
//! Portable byte-stream contracts and protocol-derived operations.
//!
//! Concrete files, descriptors, buffering policy, and target primitives live
//! outside this module. Every Reader and Writer receives the same common
//! operations through interface default methods.
use std/error.Error
use std/string.{String, bytes}
use std/vec.Vec
/// A source that initializes at most `buffer.len()` bytes per read.
///
/// A zero count means end of stream. Returning a larger count violates the
/// protocol and is rejected by the common collection operations.
pub interface Reader {
pub method &+self.read(buffer: &+[u8]): usize!
/// Reads until end of stream into independently owned byte storage.
pub method &+self.read_to_end(): Vec<u8>! {
return collect_bytes(self)?
}
/// Reads until end of stream and validates the complete input as UTF-8.
pub method &+self.read_to_string(): String! {
let collected = collect_bytes(self)?
return String.from_utf8(&collected as &[u8])?
}
}
/// A destination that accepts the complete byte view or returns an error.
pub interface Writer {
pub method &+self.write(value: &[u8]): void!
pub method &+self.flush(): void! { return }
/// Writes the UTF-8 encoding bytes through the shared byte contract.
pub method &+self.write_text(text: &str): void! {
write_text_to(self, text)?
return
}
}
func collect_bytes<R: Reader>(reader: &+R): Vec<u8>! {
var result: Vec<u8> = Vec.empty()
var scratch: Vec<u8> = initialized_scratch(8192)
while true {
let received: usize = reader.read(&+scratch as &+[u8])?
if received > scratch.len() {
return invalid_read_count()
}
if received == 0 {
break
}
result.reserve(received)
let initialized: &[u8] = &scratch as &[u8]
var offset: usize = 0
while offset < received {
result.push(initialized[offset])
offset = offset + 1
}
}
return move result
}
func initialized_scratch(size: usize): Vec<u8> {
var scratch: Vec<u8> = Vec.with_capacity(size)
while scratch.len() < size {
scratch.push(0)
}
return move scratch
}
func write_text_to<W: Writer>(writer: &+W, text: &str): void! {
let encoded: &[u8] = bytes(text)
writer.write(encoded)?
return
}
pub func invalid_read_count(): error {
return Error.new(
"std.io.invalid_read_count",
"reader returned more bytes than the supplied buffer can hold",
)
}