Programming Language

Nocter

A self-contained systems language built around simplicity, encapsulation, and foolproof design.

/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 }
}