/development/std/io_buffer.nct
io_buffer.nct
//! Buffered file I/O.
//!
//! Fallible flushes are always explicit. Dropping a writer discards an
//! unflushed buffer instead of hiding an I/O failure in destruction.
use std/io.{File, Reader, Writer}
use std/io.read as file_read
use std/io.write as file_write
use std/vec.Vec
pub struct BufReader {
source: File
buffer: Vec<u8>
next: usize
}
construct BufReader {
pub default func new(source: File): Self {
return BufReader.with_capacity(move source, 8192)
}
pub func with_capacity(source: File, requested_capacity: usize): Self {
var storage: Vec<u8> = Vec.with_capacity(requested_capacity)
return BufReader { source: move source, buffer: move storage, next: 0 }
}
}
pub func read(reader: &+BufReader, destination: &+[u8]): usize! {
var written: usize = 0
while written < destination.len() {
if reader.next == reader.buffer.len() {
reader.buffer.clear()
var initialized: usize = 0
while initialized < reader.buffer.capacity() {
reader.buffer.push(0)
initialized = initialized + 1
}
let received: usize = file_read(&+reader.source, reader.buffer.view_mut())?
reader.buffer.truncate(received)
reader.next = 0
if received == 0 { break }
}
destination[written] = reader.buffer.view()[reader.next]
written = written + 1
reader.next = reader.next + 1
}
return written
}
impl Reader for BufReader {
method &+self.read(destination: &+[u8]): usize! from static { return read(self, destination)? }
}
pub struct BufWriter {
destination: File
buffer: Vec<u8>
limit: usize
}
construct BufWriter {
pub default func new(destination: File): Self {
return BufWriter.with_capacity(move destination, 8192)
}
pub func with_capacity(destination: File, requested_capacity: usize): Self {
let storage: Vec<u8> = Vec.with_capacity(requested_capacity)
return BufWriter {
destination: move destination,
buffer: move storage,
limit: requested_capacity,
}
}
}
pub func write(writer: &+BufWriter, bytes: &[u8]): void! {
var offset: usize = 0
while offset < bytes.len() {
if writer.buffer.len() == writer.limit { flush(writer)? }
writer.buffer.push(bytes[offset])
offset = offset + 1
}
return
}
pub func flush(writer: &+BufWriter): void! {
if writer.buffer.len() == 0 { return }
file_write(&+writer.destination, writer.buffer.view())?
writer.buffer.clear()
writer.destination.flush()?
return
}
pub func close(writer: &+BufWriter): void! {
flush(writer)?
writer.destination.close()
return
}
impl BufWriter {
pub method &+self.close(): void! { close(self)? return }
}
impl Writer for BufWriter {
method &+self.write(bytes: &[u8]): void! from static { write(self, bytes)? return }
method &+self.flush(): void! { flush(self)? return }
}