Functional Weave
Code in Python

net.ipv4@1.0.0

impl/rust/parse_ipv4.rs

1,701 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one

/// The address as an unsigned 32-bit number.
///
/// Only the strict dotted quad is accepted. The C library's inet_aton also
/// reads "010.1.1.1" as octal 8.1.1.1, "0x7f.1" as hex and "127.1" as
/// 127.0.0.1; a validator that agrees with one reader and a socket library
/// that agrees with the other is how an allow-list gets bypassed, so all of
/// those are refused.
///
/// # Panics
/// Panics when the text is not a strict dotted quad.
pub fn parse_ipv4(text: &str) -> i64 {
    match ipv4_value(text) {
        Some(value) => value,
        None => panic!("\"{}\" is not a dotted-quad IPv4 address", text),
    }
}

// Exported for is_ipv4 and for capabilities that parse IPv4 text without
// wanting a panic; not part of the group's contract.

/// The address as a number, or None when the text is not a strict dotted quad.
pub fn ipv4_value(text: &str) -> Option<i64> {
    let parts: Vec<&str> = text.split('.').collect();
    if parts.len() != 4 {
        return None;
    }
    let mut value: i64 = 0;
    for part in parts {
        let bytes = part.as_bytes();
        if bytes.is_empty() || bytes.len() > 3 || !bytes.iter().all(|b| b.is_ascii_digit()) {
            return None;
        }
        // A leading zero is where octal readers and decimal readers part company.
        if bytes.len() > 1 && bytes[0] == b'0' {
            return None;
        }
        let octet = bytes.iter().fold(0i64, |acc, b| acc * 10 + (b - b'0') as i64);
        if octet > 255 {
            return None;
        }
        value = value * 256 + octet;
    }
    Some(value)
}

pub fn fune_vector(args: &[Value]) -> Value {
    Value::Int(parse_ipv4(args[0].as_str()))
}