OpenViSTAI · Agents · Blockchain · Crypto
Menu
OPENVIST RECIPES

Count shared leading octets in IPv4 pairs with Rust

Rust

Compare canonical address pairs by complete leading octets without inferring subnet masks.

Rust code excerpt: Count shared leading octets in IPv4 pairs with Rust. Version 0.1.0. Read the full recipe for code, sources and recorded test scope.

Compare canonical address pairs by complete leading octets without inferring subnet masks. Work only with supplied input; this does not contact external services or modify input.

Before you start

  • Save as recipe.rs and compile using Rust 1.99.0: rustc --edition=2021 recipe.rs -o recipe. Uses only the standard library, without Cargo or external crates.
  • Run recipe with no arguments, including no help flags. Supply input through stdin.
  • 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 on LF and discards exactly empty segments. Before parsing any pair, enforces at most 100 nonempty lines and at most 256 UTF-8 bytes per retained line. No trimming, normalization, grouping, or deduplication occurs.
  • Each retained line must contain exactly two IPv4 addresses separated by exactly one |. Each address requires four ASCII decimal octets in 0..255, with no signs, whitespace, or leading zeroes except the octet 0.
  • Returns one count per retained line in input order. Counts equal complete leading octets until the first difference, from 0 through 4; this is not a CIDR prefix-bit calculation. Empty input or only LF characters produces {"shared":[]}. A final LF is optional.
  • Success exits 0 and writes exactly one JSON object followed by LF, with no stderr. Invalid arguments, invalid input, and stdin-read failures exit 2 with no stdout and exactly error: invalid input followed by LF on stderr, subject to the failure limitations below.
  • Uses no std::net, filesystem access, networking, subprocesses, unsafe code, external code, or dynamic loading. Argument access is used only to reject arguments, and process exit is used only for exit status.

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

  • Memory use is O(B + L), where B is the bounded input size and L is the retained line count. Storage includes an input buffer initially allocated for 65537 bytes, up to 100 borrowed line references, up to 100 counts, and at most 213 bytes of successful JSON output, plus standard-library buffering and allocation overhead.
  • Stdin can block while waiting for EOF or the 65537-byte read bound. No timeout is provided.
  • All input validation finishes before successful stdout begins. Successful output preserves pair order and reveals address-similarity information, which may be sensitive even though address spellings are not echoed.
  • Memory-allocation failures and output-write failures are outside the input-error guarantee. A stdout-write failure may leave partial output and triggers exit status 2. Diagnostic writes are best effort if stderr itself fails.

Run it

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

Example input

1.2.3.4|1.2.3.5
1.2.3.4|9.2.3.4

Expected output

{"shared":[3,0]}
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");
    std::process::exit(2);
}

fn parse_ipv4(text: &str) -> Option<[u8; 4]> {
    let mut parts = text.split('.');
    let mut address = [0u8; 4];
    for octet in &mut address {
        let part = parts.next()?;
        let bytes = part.as_bytes();
        if bytes.is_empty() || bytes.len() > 3 {
            return None;
        }
        if bytes.len() > 1 && bytes[0] == b'0' {
            return None;
        }
        let mut value = 0u16;
        for &byte in bytes {
            if !byte.is_ascii_digit() {
                return None;
            }
            value = value * 10 + u16::from(byte - b'0');
        }
        if value > 255 {
            return None;
        }
        *octet = value as u8;
    }
    if parts.next().is_some() {
        return None;
    }
    Some(address)
}

fn run() -> Result<String, ()> {
    let stdin = io::stdin();
    let mut reader = stdin.lock().take(65_537);
    let mut input = Vec::with_capacity(65_537);
    reader.read_to_end(&mut input).map_err(|_| ())?;
    if input.len() > 65_536 {
        return Err(());
    }

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

    // Enforce all line limits before parsing or comparing any pairs.
    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 {
            return Err(());
        }
        lines.push(line);
    }

    let mut shared = Vec::with_capacity(lines.len());
    for line in lines {
        let mut pair = line.split('|');
        let left = pair.next().ok_or(())?;
        let right = pair.next().ok_or(())?;
        if pair.next().is_some() {
            return Err(());
        }
        let a = parse_ipv4(left).ok_or(())?;
        let b = parse_ipv4(right).ok_or(())?;
        let mut count = 0u8;
        for i in 0..4 {
            if a[i] != b[i] {
                break;
            }
            count += 1;
        }
        shared.push(count);
    }

    // Construct successful output only after the entire input is valid.
    let mut output = String::with_capacity(213);
    output.push_str("{\"shared\":[");
    for (index, count) in shared.into_iter().enumerate() {
        if index != 0 {
            output.push(',');
        }
        output.push(char::from(b'0' + count));
    }
    output.push_str("]}\n");
    Ok(output)
}

fn main() {
    if std::env::args_os().skip(1).next().is_some() {
        invalid_input();
    }
    let output = match run() {
        Ok(output) => output,
        Err(()) => invalid_input(),
    };
    let stdout = io::stdout();
    let mut out = stdout.lock();
    if out.write_all(output.as_bytes()).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 18 supplementary cases are executed in pinned, offline Rust 1.99.0 containers. These checks do not establish exhaustive correctness or behavior on other versions.