Programming Language

Nocter

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

/development/std/io/buffer/buffering.nct

buffering.nct

//! Buffered reader and writer state machines.

include ./index.nct

use std/io.{File, Reader, Writer}
use std/io.read as file_read
use std/io.write as file_write
use std/vec.Vec

struct BufReader {
    source: File
    buffer: Vec<u8>
    next: usize
}

construct BufReader {
    default func new(source: File): Self {
        return BufReader.with_capacity(move source, 8192)
    }

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

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 as &+[u8])?
            reader.buffer.truncate(received)
            reader.next = 0
            if received == 0 { break }
        }
        let available: &[u8] = &reader.buffer as &[u8]
        destination[written] = available[reader.next]
        written = written + 1
        reader.next = reader.next + 1
    }
    return written
}

conform Reader for BufReader {
    method &+self.read(destination: &+[u8]): usize! { return read(self, destination)? }
}

struct BufWriter {
    destination: File
    buffer: Vec<u8>
    limit: usize
}

construct BufWriter {
    default func new(destination: File): Self {
        return BufWriter.with_capacity(move destination, 8192)
    }

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

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
}

func flush(writer: &+BufWriter): void! {
    if writer.buffer.len() == 0 { return }
    file_write(&+writer.destination, &writer.buffer as &[u8])?
    writer.buffer.clear()
    writer.destination.flush()?
    return
}

func close(writer: &+BufWriter): void! {
    flush(writer)?
    writer.destination.close()
    return
}

instance BufWriter {
    method &+self.close(): void! {
        close(self)?
        return
    }
}

conform Writer for BufWriter {
    method &+self.write(bytes: &[u8]): void! {
        write(self, bytes)?
        return
    }

    method &+self.flush(): void! {
        flush(self)?
        return
    }
}