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
use super::net_port::is_port; ← from net.port ^1.0.0 · built alongside by fune
use std::collections::HashSet;
/// Spaces and tabs only: a newline inside a port list is a mistake, not padding.
fn trim_blank(s: &str) -> &str {
s.trim_matches(|c| c == ' ' || c == '\t')
}
/// Whole ASCII digits with no leading zero: "80", not "080", "+80" or "٨٠".
fn is_number(s: &str) -> bool {
!s.is_empty() && s.bytes().all(|b| b.is_ascii_digit()) && (s.len() == 1 || !s.starts_with('0'))
}
fn port(token: &str) -> i64 {
// More than five digits cannot be a port, and would overflow an i64 parse.
let value = if token.len() > 5 { 0 } else { token.parse::<i64>().unwrap() };
if !is_port(value) {
panic!("port \"{}\" is out of range 1-65535", token);
}
value
}
/// Parse a port list such as "22,80,8000-8010" into port numbers: each port
/// once, in the order first given. Ranges are inclusive.
///
/// # Panics
/// Panics on an empty list or item, a malformed port or range, a port outside
/// 1..=65535, or a range that runs backwards.
pub fn parse_port_list(text: &str) -> Vec<i64> {
if trim_blank(text).is_empty() {
panic!("port list is empty");
}
let mut out = Vec::new();
let mut seen = HashSet::new();
let mut add = |p: i64| {
if seen.insert(p) {
out.push(p);
}
};
for raw in text.split(',') {
let item = trim_blank(raw);
if item.is_empty() {
panic!("empty item in port list");
}
if item.contains('-') {
let ends: Vec<&str> = item.split('-').collect();
if ends.len() != 2 || !is_number(ends[0]) || !is_number(ends[1]) {
panic!("invalid port range \"{}\"", item);
}
let low = port(ends[0]);
let high = port(ends[1]);
if low > high {
panic!("port range \"{}\" runs backwards", item);
}
for p in low..=high {
add(p);
}
} else {
if !is_number(item) {
panic!("invalid port \"{}\"", item);
}
add(port(item));
}
}
out
}
pub fn fune_vector(args: &[Value]) -> Value {
let text = match &args[0] {
Value::Str(s) => s.as_str(),
_ => panic!("text must be a string"),
};
Value::Arr(parse_port_list(text).into_iter().map(Value::Int).collect())
}