OpenViSTAI · Agents · Blockchain · Crypto
Menu
OPENVIST RECIPES

Locate trailing spaces and tabs in text lines with Rust

Rust

Find retained lines ending in ASCII space or tab without trimming other Unicode whitespace.

Rust code excerpt: Locate trailing spaces and tabs in text lines with Rust. Version 0.1.0. Read the full recipe for code, sources and recorded test scope.

Find retained lines ending in ASCII space or tab without trimming other Unicode whitespace. Work only with supplied input; this does not contact external services or modify input.

Before you start

  • Save as recipe.rs and compile with Rust 1.99.0 using: rustc --edition=2021 recipe.rs
  • Run the compiled executable with no arguments and supply text through stdin. All arguments, including help flags, are rejected.
  • Reads at most 65537 bytes and rejects input exceeding 65536 bytes. Requires strict UTF-8, rejects a leading UTF-8 BOM, and rejects every CR, including CRLF.
  • Splits only on LF and discards exactly empty segments. Retains at most 100 nonempty lines, each at most 256 UTF-8 bytes. These limits are checked before classification.
  • Outputs one-based retained-line indices for lines whose final character is ASCII space U+0020 or tab U+0009. Other Unicode whitespace does not qualify. No trimming, normalization, grouping, or deduplication occurs.
  • Successful execution exits 0, writes exactly one JSON object followed by a newline, and writes nothing to stderr. Empty input or no matching lines produces {"positions":[]}.
  • Invalid arguments, invalid input, and stdin-read failures exit 2 with no stdout and exactly error: invalid input followed by a newline on stderr, subject to the output-write limitation below. Diagnostics never disclose input values.

Build and check

  1. Save the example as recipe.rs.
  2. Compile with Rust 1.99.0 using rustc --edition=2021 recipe.rs -o recipe.
  3. Prepare UTF-8 input.txt following the documented operation-specific conventions.
  4. Run ./recipe < input.txt.
  5. Inspect the JSON result. Exit 2 with exactly error: invalid input followed by a newline on stderr and no stdout identifies rejected input or stdin-read failure. Output-write failures may also exit nonzero, without that diagnostic and potentially after partial stdout; these are outside the input-error guarantee.

Limits to understand

  • Stdin can block while awaiting more bytes or EOF; no timeout is implemented. Input below the read bound must reach EOF before processing completes.
  • Memory use is proportional to the bounded input buffer, plus up to 100 borrowed line references, a small result string, and standard-library I/O buffering. Lines are not copied.
  • Successful output can reveal sensitive information through matching positions and their relationship to retained input lines.
  • Memory-allocation failures and output-write failures are outside the input-error guarantee. A detected stdout write or flush failure exits 1 and may leave partial stdout; failure to write an error diagnostic can prevent its delivery.
  • Uses only the standard library and accesses only stdin, stdout, stderr, argument presence, and exit status. No filesystem, network, subprocess, or dynamic-loading operations are performed.

Run it

rustc --edition=2021 recipe.rs -o recipe
./recipe < input.txt

Example input

a 
b
c	

Expected output

{"positions":[1,3]}
INSPECT THE SCRIPT

Inspect, copy and run the documented checks.

This browser preview builds code locally. It does not contact an API or run the code.

Default example ready.

Rust example
use std::io::{self, Read, Write};

fn invalid() -> ! {
    let _ = io::stderr().lock().write_all(b"error: invalid input\n");
    std::process::exit(2);
}

fn main() {
    if std::env::args_os().skip(1).next().is_some() {
        invalid();
    }

    let stdin = io::stdin();
    let mut reader = stdin.lock().take(65_537);
    let mut bytes = Vec::with_capacity(65_537);
    if reader.read_to_end(&mut bytes).is_err() {
        invalid();
    }
    if bytes.len() > 65_536 || bytes.starts_with(&[0xEF, 0xBB, 0xBF]) {
        invalid();
    }
    if bytes.contains(&b'\r') {
        invalid();
    }
    let text = match std::str::from_utf8(&bytes) {
        Ok(text) => text,
        Err(_) => invalid(),
    };

    // Validate every retained line before classifying any line.
    let mut lines = Vec::with_capacity(100);
    for line in text.split('\n') {
        if line.is_empty() {
            continue;
        }
        if line.len() > 256 || lines.len() == 100 {
            invalid();
        }
        lines.push(line);
    }

    let mut output = String::from("{\"positions\":[");
    let mut first = true;
    for (index, line) in lines.iter().enumerate() {
        if matches!(line.as_bytes().last(), Some(&b' ') | Some(&b'\t')) {
            if !first {
                output.push(',');
            }
            first = false;
            output.push_str(&(index + 1).to_string());
        }
    }
    output.push_str("]}\n");

    let stdout = io::stdout();
    let mut writer = stdout.lock();
    if writer.write_all(output.as_bytes()).is_err() || writer.flush().is_err() {
        std::process::exit(1);
    }
}
What to verify after running
  • The example must produce the documented JSON result.
  • Empty stdin must produce the documented empty result.
  • Reject extra arguments, malformed UTF-8, a leading BOM, oversized input and unreadable stdin with the fixed input-error diagnostic and no stdout.

Request or format preview

Illustrative preview. No provider response, price or balance is fetched.

Change a setting to inspect the preview.

Official sources and related profiles

    Code license: MIT. Keep the license notice with your copy.

    Example version 0.1.0 · Documentation reviewed 2026-10-14.

    Six independent CLI fixtures and 16 supplementary cases are executed in pinned, offline Rust 1.99.0 containers. These checks do not establish exhaustive correctness or behavior on other versions.