pub fn parse_ip(s: &[u8]) -> Option<[u8; 4]> { let mut octets = [0u8; 4]; let mut octet_idx = 0usize; let mut current: u16 = 0; let mut has_digit = false; let result = (0..s.len()).try_fold((), |(), i| match s[i] { b'0'..=b'9' => { current = current * 10 + (s[i] - b'0') as u16; has_digit = true; match current > 255 { true => None, false => Some(()), } } b'.' => match has_digit && octet_idx < 3 { true => { octets[octet_idx] = current as u8; octet_idx += 1; current = 0; has_digit = false; Some(()) } false => None, }, _ => None, }); match result.is_some() && has_digit && octet_idx == 3 { true => { octets[3] = current as u8; Some(octets) } false => None, } } pub fn parse_decimal_u16(s: &[u8]) -> Option { match s.is_empty() { true => None, false => { let result = (0..s.len()).try_fold(0u32, |acc, i| match s[i] { b'0'..=b'9' => { let v = acc * 10 + (s[i] - b'0') as u32; match v > 65535 { true => None, false => Some(v), } } _ => None, }); result.map(|v| v as u16) } } } pub fn skip_spaces(s: &[u8]) -> &[u8] { match (0..s.len()).find(|&i| s[i] != b' ') { Some(start) => &s[start..], None => &[], } } pub fn next_token(s: &[u8]) -> (&[u8], &[u8]) { let trimmed = skip_spaces(s); match (0..trimmed.len()).find(|&i| trimmed[i] == b' ') { Some(pos) => (&trimmed[..pos], &trimmed[pos..]), None => (trimmed, &[]), } } pub fn bytes_eq(a: &[u8], b: &[u8]) -> bool { a.len() == b.len() && (0..a.len()).all(|i| a[i] == b[i]) } pub fn write_u8_decimal(buf: &mut [u8], val: u8) -> usize { match val { 0 => { buf[0] = b'0'; 1 } _ => { let mut digits = [0u8; 3]; let mut v = val; let start = (0..3usize).rev().fold(3usize, |pos, _| match v { 0 => pos, _ => { let np = pos - 1; digits[np] = b'0' + (v % 10); v /= 10; np } }); let len = 3 - start; buf[..len].copy_from_slice(&digits[start..]); len } } } pub fn write_u16_decimal(buf: &mut [u8], val: u16) -> usize { match val { 0 => { buf[0] = b'0'; 1 } _ => { let mut digits = [0u8; 5]; let mut v = val; let start = (0..5usize).rev().fold(5usize, |pos, _| match v { 0 => pos, _ => { let np = pos - 1; digits[np] = b'0' + (v % 10) as u8; v /= 10; np } }); let len = 5 - start; buf[..len].copy_from_slice(&digits[start..]); len } } } pub fn write_ip_decimal(buf: &mut [u8], octets: &[u8]) -> usize { let mut pos = 0usize; pos += write_u8_decimal(&mut buf[pos..], octets[0]); buf[pos] = b'.'; pos += 1; pos += write_u8_decimal(&mut buf[pos..], octets[1]); buf[pos] = b'.'; pos += 1; pos += write_u8_decimal(&mut buf[pos..], octets[2]); buf[pos] = b'.'; pos += 1; pos += write_u8_decimal(&mut buf[pos..], octets[3]); pos } pub fn write_ipv6(buf: &mut [u8], octets: &[u8]) -> usize { let groups: [u16; 8] = [ (octets[0] as u16) << 8 | octets[1] as u16, (octets[2] as u16) << 8 | octets[3] as u16, (octets[4] as u16) << 8 | octets[5] as u16, (octets[6] as u16) << 8 | octets[7] as u16, (octets[8] as u16) << 8 | octets[9] as u16, (octets[10] as u16) << 8 | octets[11] as u16, (octets[12] as u16) << 8 | octets[13] as u16, (octets[14] as u16) << 8 | octets[15] as u16, ]; let (best_start, best_len) = (0u8..8).fold((255u8, 0u8), |(bs, bl), i| { let run = (i..8).take_while(|&j| groups[j as usize] == 0).count() as u8; match run > bl && run >= 2 { true => (i, run), false => (bs, bl), } }); let mut pos = 0usize; let mut i = 0u8; core::iter::from_fn(|| match i < 8 { false => None, true => { match best_len > 0 && i == best_start { true => { if i == 0 { buf[pos] = b':'; pos += 1; } buf[pos] = b':'; pos += 1; i += best_len; } false => { if i > 0 { buf[pos] = b':'; pos += 1; } pos += write_hex_u16(&mut buf[pos..], groups[i as usize]); i += 1; } } Some(()) } }) .count(); pos } pub fn parse_ipv6(s: &[u8]) -> Option<[u8; 16]> { if s.is_empty() || s.len() > 39 { return None; } let mut groups = [0u16; 8]; let mut group_count = 0u8; let mut expand_pos: Option = None; let mut current: u16 = 0; let mut digits_in_group = 0u8; let mut after_colon = false; let result = (0..s.len()).try_fold((), |(), i| { let ch = s[i]; match ch { b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F' => { let nibble = match ch { b'0'..=b'9' => ch - b'0', b'a'..=b'f' => ch - b'a' + 10, _ => ch - b'A' + 10, }; match digits_in_group >= 4 { true => return None, false => { current = (current << 4) | nibble as u16; digits_in_group += 1; after_colon = false; } } Some(()) } b':' => match after_colon { true => match expand_pos.is_some() { true => None, false => { expand_pos = Some(group_count); after_colon = false; Some(()) } }, false => { match digits_in_group > 0 { true => match group_count >= 8 { true => return None, false => { groups[group_count as usize] = current; group_count += 1; current = 0; digits_in_group = 0; } }, false => match i == 0 { true => {} false => return None, }, } after_colon = true; Some(()) } }, _ => None, } }); result?; if digits_in_group > 0 { match group_count >= 8 { true => return None, false => { groups[group_count as usize] = current; group_count += 1; } } } match expand_pos { Some(pos) => { if group_count > 8 { return None; } let tail_len = group_count - pos; let mut expanded = [0u16; 8]; (0..pos as usize).for_each(|i| expanded[i] = groups[i]); (0..tail_len as usize).for_each(|i| { expanded[8 - tail_len as usize + i] = groups[pos as usize + i]; }); groups = expanded; } None => { if group_count != 8 { return None; } } } let mut octets = [0u8; 16]; (0..8).for_each(|i| { octets[i * 2] = (groups[i] >> 8) as u8; octets[i * 2 + 1] = groups[i] as u8; }); Some(octets) } pub fn write_hex_u16(buf: &mut [u8], val: u16) -> usize { let hex = |n: u8| match n < 10 { true => b'0' + n, false => b'a' + (n - 10), }; match val { 0 => { buf[0] = b'0'; 1 } _ => { let mut digits = [0u8; 4]; let mut v = val; let start = (0..4usize).rev().fold(4usize, |p, _| match v { 0 => p, _ => { let np = p - 1; digits[np] = hex((v & 0xf) as u8); v >>= 4; np } }); let len = 4 - start; buf[..len].copy_from_slice(&digits[start..]); len } } }