// Counts the lines piped into it, in constant memory. // // cat something.txt | nikaia run // 120 lines, 14 blank // longest: 87 characters // …the longest line itself… // // With a file name, it also appends one summary row to that file as a log: // `cat something.txt | nikaia run -- runs.log`. // // Shows: reading standard input line by line, a loop that can fail, and // named options after the `;` in a signature and at a call. // // A package: `nikaia run` in this directory runs it, and `nikaia test` checks // what it prints and the file it writes against `tests/` (ADR-247). use std::io use std::fs use std::cli // `separator` is an option: it stands after the `;`, has a default, and is // named where a call sets it. A caller that does not need it never sees it. fn summary(lines: int, blank: int; separator: String = " ") -> String { return f"{lines}{separator}{blank}" } fn main() throws { let mut lines = 0 let mut blank = 0 let mut longest = String() // Each turn of this loop reads one line, so only one line is in memory at a // time, plus the longest seen so far. // // A read can fail. Nothing marks that here, just as nothing marks a call // that can fail: the failure leaves `main`, which is why `main` says // `throws`. Without it the program does not compile: // // error[NK2701]: this function can fail because a turn of this loop can fail // help: declare the error: add `throws` to this function // // So a read that fails is reported as an error, never mistaken for the end // of the input. for line in io::lines() { lines += 1 if line.len() == 0 { blank += 1 } if line.len() > longest.len() { longest = line } } println(f"{lines} lines, {blank} blank") println(f"longest: {longest.len()} characters") println(f"{longest}") // A run log, if a file was named. `append: true` is an option set at the // call; without it `fs::write` replaces the file. let log = cli::args().nth(1) ?? "" if log.len() > 0 { let row = summary(lines, blank; separator: "\t") fs::write(ref log, fs::Root::Anywhere, f"{row}\n"; append: true) catch { eprintln(f"cannot append to {log}: {error}") return } } }