OpenViSTAI · Agents · Blockchain · Crypto
Menu
OPENVIST RECIPES

Sort and deduplicate line-separated port numbers with Rust

Rust

Convert a small LF-separated list of canonical decimal port numbers into a sorted, deduplicated JSON array.

Rust code excerpt: Sort and deduplicate line-separated port numbers with Rust. Version 0.1.0. Read the full recipe for code, sources and recorded test scope.

Read a small list of port numbers from stdin, reject noncanonical or out-of-range entries, then return distinct ports in numeric order. This does not open connections or verify service availability.

Before you start

  • Save the code as recipe.rs and compile with Rust 1.99.0 using: rustc --edition=2021 recipe.rs -o recipe
  • Run ./recipe < ports.txt without command-line arguments, supplying LF-separated port numbers on stdin.
  • Uses only the standard library, reads only stdin, and writes only stdout or stderr.
  • Validates all input before writing exactly one sorted, deduplicated JSON object followed by a newline.
  • Success exits 0 without stderr. Invalid arguments, invalid input, or stdin read failure exit 2 with exactly error: invalid input followed by a newline on stderr and no stdout.
  • Do not interpret exit 2 alone as input rejection. Input or argument rejection and stdin read failure are identified by the exact stderr diagnostic "error: invalid input\n". Detected stdout write or flush failures also exit 2, but without that diagnostic and potentially after partial stdout output.

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 an LF-separated UTF-8 ports.txt using canonical decimal numbers.
  4. Run ./recipe < ports.txt.
  5. Inspect the sorted ports array. Exit 2 with exactly error: invalid input followed by a newline on stderr and no stdout identifies an input or stdin-read failure. Detected output-write or flush failures also exit 2, but without that diagnostic and potentially after partial stdout; these are outside the input-error guarantee.

Limits to understand

  • Reads at most 65537 bytes and rejects input exceeding 65536 bytes.
  • Requires strict UTF-8 without a leading UTF-8 BOM.
  • Accepts at most 100 nonempty lines before deduplication; exactly empty lines, including the final empty segment after LF, are ignored.
  • Each nonempty line must be canonical ASCII decimal in 0..65535. CRLF, whitespace-only lines, leading or trailing whitespace, signs, decimal points, non-ASCII digits, and leading zeroes other than the single digit 0 are rejected.
  • Empty input produces {"ports":[]} followed by a newline.
  • Output-write failures and memory allocation failures are outside the diagnostic guarantee. Detected output-write failures exit 2 without an input-error diagnostic and may leave partial output.
  • This operates on supplied port numbers only; it makes no network request, connection test, availability claim or security assessment.

Run it

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

Example input

80
443
80
22

Expected output

{"ports":[22,80,443]}
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_input() -> ! {
    let stderr = io::stderr();
    let mut err = stderr.lock();
    let _ = err.write_all(b"error: invalid input\n");
    let _ = err.flush();
    std::process::exit(2);
}

fn read_and_validate() -> Result<Vec<u16>, ()> {
    let stdin = io::stdin();
    let mut reader = stdin.lock().take(65537);
    let mut bytes = Vec::new();
    reader.read_to_end(&mut bytes).map_err(|_| ())?;

    if bytes.len() > 65536 || bytes.starts_with(&[0xEF, 0xBB, 0xBF]) {
        return Err(());
    }
    let text = std::str::from_utf8(&bytes).map_err(|_| ())?;
    let mut ports = Vec::new();

    for line in text.split('\n') {
        if line.is_empty() {
            continue;
        }
        if ports.len() == 100 {
            return Err(());
        }
        let digits = line.as_bytes();
        if digits.len() > 5
            || !digits.iter().all(|b| b.is_ascii_digit())
            || (digits.len() > 1 && digits[0] == b'0')
        {
            return Err(());
        }
        let port = line.parse::<u16>().map_err(|_| ())?;
        ports.push(port);
    }

    ports.sort_unstable();
    ports.dedup();
    Ok(ports)
}

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

    let ports = match read_and_validate() {
        Ok(ports) => ports,
        Err(()) => invalid_input(),
    };

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

    let stdout = io::stdout();
    let mut out = stdout.lock();
    if out.write_all(output.as_bytes()).is_err() || out.flush().is_err() {
        std::process::exit(2);
    }
}
What to verify after running
  • The example must output ports 22, 80 and 443 exactly once in numeric order.
  • An empty input returns an empty ports array.
  • Reject 01, 65536, signs, whitespace, CRLF, malformed UTF-8, excessive bytes and more than 100 nonempty lines with exit 2 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 22 supplementary cases are executed in pinned, offline Rust 1.99.0 containers. These checks do not establish exhaustive correctness or behavior on other versions.