Programming Language

Nocter

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

/examples/async-file-report/report.nct

report.nct

see ./index.nct

use std/fs.FileType
use std/fs
use std/io.{File, Writer}
use std/io/buffer.BufWriter
use std/io/stream.ByteChunks
use std/iter/asynchronous.AsyncIterator
use std/process
use std/string.String
use std/task
use std/task.Timeout
use std/time.Duration

const CHUNK_BYTES: usize = 8192

const OUTPUT_BUFFER_BYTES: usize = 4096

const REPORT_TIMEOUT_SECONDS: u64 = 5

async func count_file(path: &str): usize! {
    let source = await File.open(path)?
    var chunks = ByteChunks.with_chunk_size(move source, CHUNK_BYTES)
    var total: usize = 0
    while true {
        let chunk = await chunks.next()? otherwise { break }
        total += chunk.len()
    }
    var completed = chunks.finish()
    await completed.close()?
    return total
}

async func write_summary<W>(
    output: &+W,
    files: usize,
    bytes: usize,
): void! where W impl Writer {
    let file_text = files.to_string()
    let byte_text = bytes.to_string()
    await output.write_text("files")?
    await output.write_text("\t")?
    await output.write_line(&file_text)?
    await output.write_text("bytes")?
    await output.write_text("\t")?
    await output.write_line(&byte_text)?
    return
}

async func build_report(root: &str, temporary_path: &str, output_path: &str): void! {
    let walker = await fs.walk_dir(root)?
    let files = walker.filter(
        (entry) {
            if entry.file_type() is FileType.regular { return true }
            return false
        },
    )
    let indexed = files.enumerate()
    var files_seen: usize = 0
    var bytes_seen: usize = 0

    for await record in move indexed {
        files_seen = record.index + 1
        let entry = move record.item
        let path: &str = entry.path()
        bytes_seen += await count_file(path)?
    }

    let destination = await File.create(temporary_path)?
    var output = BufWriter.with_capacity(move destination, OUTPUT_BUFFER_BYTES)
    await write_summary(&+output, files_seen, bytes_seen)?
    var completed = await output.finish()?
    await completed.close()?
    await fs.rename(temporary_path, output_path)?
    return
}

async func remove_temporary(path: &str): void {
    await fs.remove_file(path) catch _ {}
    return
}

async func run(): i32 {
    if process.arg_count() != 3 {
        return 2
    }
    let root = process.arg(1) catch _ { return 2 } otherwise { return 2 }
    let output_path = process.arg(2) catch _ { return 2 } otherwise { return 2 }
    let temporary_path = String.concat(output_path, ".tmp")
    let bounded = await task.with_timeout(
        build_report(root, &temporary_path, output_path),
        Duration.from_seconds(REPORT_TIMEOUT_SECONDS),
    )
    match move bounded {
        Timeout.completed(result) {
            move result catch _ {
                await remove_temporary(&temporary_path)
                return 1
            }
            return 0
        }
        Timeout.elapsed {
            await remove_temporary(&temporary_path)
            return 1
        }
    }
}