Nothing to see here, move along
at main 324 lines 9.3 kB view raw
1pub fn parse_ip(s: &[u8]) -> Option<[u8; 4]> { 2 let mut octets = [0u8; 4]; 3 let mut octet_idx = 0usize; 4 let mut current: u16 = 0; 5 let mut has_digit = false; 6 7 let result = (0..s.len()).try_fold((), |(), i| match s[i] { 8 b'0'..=b'9' => { 9 current = current * 10 + (s[i] - b'0') as u16; 10 has_digit = true; 11 match current > 255 { 12 true => None, 13 false => Some(()), 14 } 15 } 16 b'.' => match has_digit && octet_idx < 3 { 17 true => { 18 octets[octet_idx] = current as u8; 19 octet_idx += 1; 20 current = 0; 21 has_digit = false; 22 Some(()) 23 } 24 false => None, 25 }, 26 _ => None, 27 }); 28 29 match result.is_some() && has_digit && octet_idx == 3 { 30 true => { 31 octets[3] = current as u8; 32 Some(octets) 33 } 34 false => None, 35 } 36} 37 38pub fn parse_decimal_u16(s: &[u8]) -> Option<u16> { 39 match s.is_empty() { 40 true => None, 41 false => { 42 let result = (0..s.len()).try_fold(0u32, |acc, i| match s[i] { 43 b'0'..=b'9' => { 44 let v = acc * 10 + (s[i] - b'0') as u32; 45 match v > 65535 { 46 true => None, 47 false => Some(v), 48 } 49 } 50 _ => None, 51 }); 52 result.map(|v| v as u16) 53 } 54 } 55} 56 57pub fn skip_spaces(s: &[u8]) -> &[u8] { 58 match (0..s.len()).find(|&i| s[i] != b' ') { 59 Some(start) => &s[start..], 60 None => &[], 61 } 62} 63 64pub fn next_token(s: &[u8]) -> (&[u8], &[u8]) { 65 let trimmed = skip_spaces(s); 66 match (0..trimmed.len()).find(|&i| trimmed[i] == b' ') { 67 Some(pos) => (&trimmed[..pos], &trimmed[pos..]), 68 None => (trimmed, &[]), 69 } 70} 71 72pub fn bytes_eq(a: &[u8], b: &[u8]) -> bool { 73 a.len() == b.len() && (0..a.len()).all(|i| a[i] == b[i]) 74} 75 76pub fn write_u8_decimal(buf: &mut [u8], val: u8) -> usize { 77 match val { 78 0 => { 79 buf[0] = b'0'; 80 1 81 } 82 _ => { 83 let mut digits = [0u8; 3]; 84 let mut v = val; 85 let start = (0..3usize).rev().fold(3usize, |pos, _| match v { 86 0 => pos, 87 _ => { 88 let np = pos - 1; 89 digits[np] = b'0' + (v % 10); 90 v /= 10; 91 np 92 } 93 }); 94 let len = 3 - start; 95 buf[..len].copy_from_slice(&digits[start..]); 96 len 97 } 98 } 99} 100 101pub fn write_u16_decimal(buf: &mut [u8], val: u16) -> usize { 102 match val { 103 0 => { 104 buf[0] = b'0'; 105 1 106 } 107 _ => { 108 let mut digits = [0u8; 5]; 109 let mut v = val; 110 let start = (0..5usize).rev().fold(5usize, |pos, _| match v { 111 0 => pos, 112 _ => { 113 let np = pos - 1; 114 digits[np] = b'0' + (v % 10) as u8; 115 v /= 10; 116 np 117 } 118 }); 119 let len = 5 - start; 120 buf[..len].copy_from_slice(&digits[start..]); 121 len 122 } 123 } 124} 125 126pub fn write_ip_decimal(buf: &mut [u8], octets: &[u8]) -> usize { 127 let mut pos = 0usize; 128 pos += write_u8_decimal(&mut buf[pos..], octets[0]); 129 buf[pos] = b'.'; 130 pos += 1; 131 pos += write_u8_decimal(&mut buf[pos..], octets[1]); 132 buf[pos] = b'.'; 133 pos += 1; 134 pos += write_u8_decimal(&mut buf[pos..], octets[2]); 135 buf[pos] = b'.'; 136 pos += 1; 137 pos += write_u8_decimal(&mut buf[pos..], octets[3]); 138 pos 139} 140 141pub fn write_ipv6(buf: &mut [u8], octets: &[u8]) -> usize { 142 let groups: [u16; 8] = [ 143 (octets[0] as u16) << 8 | octets[1] as u16, 144 (octets[2] as u16) << 8 | octets[3] as u16, 145 (octets[4] as u16) << 8 | octets[5] as u16, 146 (octets[6] as u16) << 8 | octets[7] as u16, 147 (octets[8] as u16) << 8 | octets[9] as u16, 148 (octets[10] as u16) << 8 | octets[11] as u16, 149 (octets[12] as u16) << 8 | octets[13] as u16, 150 (octets[14] as u16) << 8 | octets[15] as u16, 151 ]; 152 153 let (best_start, best_len) = (0u8..8).fold((255u8, 0u8), |(bs, bl), i| { 154 let run = (i..8).take_while(|&j| groups[j as usize] == 0).count() as u8; 155 match run > bl && run >= 2 { 156 true => (i, run), 157 false => (bs, bl), 158 } 159 }); 160 161 let mut pos = 0usize; 162 let mut i = 0u8; 163 core::iter::from_fn(|| match i < 8 { 164 false => None, 165 true => { 166 match best_len > 0 && i == best_start { 167 true => { 168 if i == 0 { 169 buf[pos] = b':'; 170 pos += 1; 171 } 172 buf[pos] = b':'; 173 pos += 1; 174 i += best_len; 175 } 176 false => { 177 if i > 0 { 178 buf[pos] = b':'; 179 pos += 1; 180 } 181 pos += write_hex_u16(&mut buf[pos..], groups[i as usize]); 182 i += 1; 183 } 184 } 185 Some(()) 186 } 187 }) 188 .count(); 189 190 pos 191} 192 193pub fn parse_ipv6(s: &[u8]) -> Option<[u8; 16]> { 194 if s.is_empty() || s.len() > 39 { 195 return None; 196 } 197 198 let mut groups = [0u16; 8]; 199 let mut group_count = 0u8; 200 let mut expand_pos: Option<u8> = None; 201 let mut current: u16 = 0; 202 let mut digits_in_group = 0u8; 203 let mut after_colon = false; 204 205 let result = (0..s.len()).try_fold((), |(), i| { 206 let ch = s[i]; 207 match ch { 208 b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F' => { 209 let nibble = match ch { 210 b'0'..=b'9' => ch - b'0', 211 b'a'..=b'f' => ch - b'a' + 10, 212 _ => ch - b'A' + 10, 213 }; 214 match digits_in_group >= 4 { 215 true => return None, 216 false => { 217 current = (current << 4) | nibble as u16; 218 digits_in_group += 1; 219 after_colon = false; 220 } 221 } 222 Some(()) 223 } 224 b':' => match after_colon { 225 true => match expand_pos.is_some() { 226 true => None, 227 false => { 228 expand_pos = Some(group_count); 229 after_colon = false; 230 Some(()) 231 } 232 }, 233 false => { 234 match digits_in_group > 0 { 235 true => match group_count >= 8 { 236 true => return None, 237 false => { 238 groups[group_count as usize] = current; 239 group_count += 1; 240 current = 0; 241 digits_in_group = 0; 242 } 243 }, 244 false => match i == 0 { 245 true => {} 246 false => return None, 247 }, 248 } 249 after_colon = true; 250 Some(()) 251 } 252 }, 253 _ => None, 254 } 255 }); 256 257 result?; 258 259 if digits_in_group > 0 { 260 match group_count >= 8 { 261 true => return None, 262 false => { 263 groups[group_count as usize] = current; 264 group_count += 1; 265 } 266 } 267 } 268 269 match expand_pos { 270 Some(pos) => { 271 if group_count > 8 { 272 return None; 273 } 274 let tail_len = group_count - pos; 275 let mut expanded = [0u16; 8]; 276 (0..pos as usize).for_each(|i| expanded[i] = groups[i]); 277 (0..tail_len as usize).for_each(|i| { 278 expanded[8 - tail_len as usize + i] = groups[pos as usize + i]; 279 }); 280 groups = expanded; 281 } 282 None => { 283 if group_count != 8 { 284 return None; 285 } 286 } 287 } 288 289 let mut octets = [0u8; 16]; 290 (0..8).for_each(|i| { 291 octets[i * 2] = (groups[i] >> 8) as u8; 292 octets[i * 2 + 1] = groups[i] as u8; 293 }); 294 Some(octets) 295} 296 297pub fn write_hex_u16(buf: &mut [u8], val: u16) -> usize { 298 let hex = |n: u8| match n < 10 { 299 true => b'0' + n, 300 false => b'a' + (n - 10), 301 }; 302 match val { 303 0 => { 304 buf[0] = b'0'; 305 1 306 } 307 _ => { 308 let mut digits = [0u8; 4]; 309 let mut v = val; 310 let start = (0..4usize).rev().fold(4usize, |p, _| match v { 311 0 => p, 312 _ => { 313 let np = p - 1; 314 digits[np] = hex((v & 0xf) as u8); 315 v >>= 4; 316 np 317 } 318 }); 319 let len = 4 - start; 320 buf[..len].copy_from_slice(&digits[start..]); 321 len 322 } 323 } 324}