OpenViSTAI · Agents · Blockchain · Crypto
Menu
OPENVIST RECIPES

Compact bounded integers into inclusive consecutive ranges with Rust

Rust

Summarize present values as maximal runs after numeric sorting and deduplication.

Rust code excerpt: Compact bounded integers into inclusive consecutive ranges with Rust. Version 0.1.0. Read the full recipe for code, sources and recorded test scope.

Summarize present values as maximal runs after numeric sorting and deduplication. 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 -o recipe. Run ./recipe with input on stdin. No arguments are accepted, including help flags.
  • Uses only the standard library, with explicit imports from std::io. std::env::args_os is used only to reject arguments; std::process::exit is used only for exit status.
  • 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 byte, including CRLF.
  • Splits only at LF and discards exactly empty segments. Before numeric parsing, sorting or deduplication, enforces at most 100 retained lines and at most 256 UTF-8 bytes per retained line. Nothing is trimmed or normalized.
  • Each retained line must contain canonical ASCII decimal in 0..1000000. Signs, whitespace, non-ASCII digits and leading zeroes other than the single spelling 0 are rejected.
  • Sorts numerically, removes duplicates and emits maximal consecutive ranges with inclusive endpoints in ascending order. Singletons use equal endpoints. These are present ranges, not missing gaps.
  • Empty input or input containing only LF bytes produces {"ranges":[]}. Successful output is exactly one compact JSON object followed by a newline, with exit status 0 and no stderr.
  • Argument errors, invalid input and stdin-read failures produce no stdout, exit with status 2, and write exactly error: invalid input followed by a newline to stderr, subject to the allocation and output-failure limitations below. Diagnostics never contain 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 waiting for data or EOF. Input of exactly 65536 bytes requires an additional read attempt to establish EOF; detection of a 65537th byte causes rejection without reading further.
  • Memory use includes a fixed 65537-byte stack buffer, vectors holding at most 100 line references, values and ranges, and a small output string. Storage is O(B + L), where B is the bounded input capacity and L is the retained-line count; standard-library buffering and allocation overhead are additional.
  • Successful output reveals the accepted distinct values through their ranges and may be sensitive.
  • Memory-allocation failures and output-write failures, including stderr failures, are outside the input-error guarantee. A stdout write or flush failure exits 2 without adding a diagnostic and may leave partial stdout.
  • The program performs no filesystem access, networking, subprocess execution, dynamic loading or unsafe operations.

Run it

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

Example input

5
1
2
5
8
6

Expected output

{"ranges":[[1,2],[5,6],[8,8]]}
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 build_output() -> Result<String, ()> {
    if std::env::args_os().skip(1).next().is_some() {
        return Err(());
    }

    // Read at most 65537 bytes, including the byte used to detect oversize input.
    let mut buffer = [0u8; 65537];
    let mut used = 0usize;
    {
        let stdin = io::stdin();
        let mut input = stdin.lock();
        loop {
            if used == buffer.len() {
                return Err(());
            }
            match input.read(&mut buffer[used..]) {
                Ok(0) => break,
                Ok(n) => used += n,
                Err(e) if e.kind() == io::ErrorKind::Interrupted => continue,
                Err(_) => return Err(()),
            }
        }
    }
    if used > 65536 {
        return Err(());
    }

    let text = std::str::from_utf8(&buffer[..used]).map_err(|_| ())?;
    if text.starts_with('\u{feff}') || text.as_bytes().contains(&b'\r') {
        return Err(());
    }

    // Enforce every line/count limit before parsing, sorting or deduplication.
    let mut lines: Vec<&str> = Vec::new();
    for line in text.split('\n') {
        if line.is_empty() {
            continue;
        }
        if line.len() > 256 || lines.len() >= 100 {
            return Err(());
        }
        lines.push(line);
    }

    let mut values: Vec<u32> = Vec::with_capacity(lines.len());
    for line in lines {
        let bytes = line.as_bytes();
        if bytes.len() > 1 && bytes[0] == b'0' {
            return Err(());
        }
        let mut value = 0u32;
        for &byte in bytes {
            if !byte.is_ascii_digit() {
                return Err(());
            }
            // The previous value is at most 1000000, so this cannot overflow.
            value = value * 10 + u32::from(byte - b'0');
            if value > 1000000 {
                return Err(());
            }
        }
        values.push(value);
    }

    values.sort_unstable();
    values.dedup();

    let mut ranges: Vec<(u32, u32)> = Vec::new();
    for value in values {
        if let Some(last) = ranges.last_mut() {
            if value == last.1 + 1 {
                last.1 = value;
                continue;
            }
        }
        ranges.push((value, value));
    }

    let mut output = String::from("{\"ranges\":[");
    for (index, &(start, end)) in ranges.iter().enumerate() {
        if index != 0 {
            output.push(',');
        }
        output.push('[');
        output.push_str(&start.to_string());
        output.push(',');
        output.push_str(&end.to_string());
        output.push(']');
    }
    output.push_str("]}\n");
    Ok(output)
}

fn main() {
    let output = match build_output() {
        Ok(output) => output,
        Err(()) => {
            let stderr = io::stderr();
            let mut error_output = stderr.lock();
            let _ = error_output.write_all(b"error: invalid input\n");
            let _ = error_output.flush();
            std::process::exit(2);
        }
    };

    let stdout = io::stdout();
    let mut output_stream = stdout.lock();
    if output_stream.write_all(output.as_bytes()).is_err()
        || output_stream.flush().is_err()
    {
        std::process::exit(2);
    }
}
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 19 supplementary cases are executed in pinned, offline Rust 1.99.0 containers. These checks do not establish exhaustive correctness or behavior on other versions.