use super::funejson::Value; 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 { 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> { 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::>(), 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 { 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>(parts: &[S], may_end_with_ipv4: bool) -> Option> { 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()) }