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_ipv4_parse_ipv4::ipv4_value;
/// The eight 16-bit groups of an IPv6 address written as RFC 4291 allows.
///
/// Hex groups of one to four digits in either case, at most one "::" standing
/// for one or more zero groups, and optionally a dotted IPv4 address as the
/// last 32 bits. A zone id ("%eth0") or a prefix ("/64") is not part of an
/// address and is refused, as is anything around it (spaces, newlines).
///
/// # Panics
/// Panics when the text is not an IPv6 address.
pub fn parse_ipv6(text: &str) -> Vec<i64> {
match ipv6_groups(text) {
Some(groups) => groups,
None => panic!("\"{}\" is not an IPv6 address", text),
}
}
// Exported for is_ipv6 and for capabilities that parse IPv6 text without
// wanting a panic; not part of the group's contract.
/// The eight groups, or None when the text is not an IPv6 address.
pub fn ipv6_groups(text: &str) -> Option<Vec<i64>> {
if text.is_empty() || !text.bytes().all(|b| b.is_ascii_hexdigit() || b == b':' || b == b'.') {
return None;
}
let at = match text.find("::") {
None => {
let groups = pieces(&text.split(':').collect::<Vec<_>>(), true)?;
return if groups.len() == 8 { Some(groups) } else { None };
}
Some(at) => at,
};
let before = &text[..at];
let after = &text[at + 2..];
if after.contains("::") {
return None;
}
let split = |s: &str| -> Vec<String> {
if s.is_empty() {
Vec::new()
} else {
s.split(':').map(str::to_string).collect()
}
};
let head = pieces(&split(before), false)?;
let tail = pieces(&split(after), true)?;
// "::" stands for at least one group, so at most seven are written.
if head.len() + tail.len() > 7 {
return None;
}
let mut groups = head.clone();
groups.extend(std::iter::repeat(0).take(8 - head.len() - tail.len()));
groups.extend(tail);
Some(groups)
}
fn pieces<S: AsRef<str>>(parts: &[S], may_end_with_ipv4: bool) -> Option<Vec<i64>> {
let mut groups = Vec::new();
for (i, part) in parts.iter().enumerate() {
let part = part.as_ref();
if part.contains('.') {
if !may_end_with_ipv4 || i != parts.len() - 1 {
return None;
}
let v4 = ipv4_value(part)?;
groups.push(v4 / 65536);
groups.push(v4 % 65536);
continue;
}
if part.is_empty() || part.len() > 4 {
return None;
}
groups.push(i64::from_str_radix(part, 16).ok()?);
}
Some(groups)
}
pub fn fune_vector(args: &[Value]) -> Value {
Value::Arr(parse_ipv6(args[0].as_str()).into_iter().map(Value::Int).collect())
}