use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use crate::bytesbits::BytesBits;
pub fn decode(input: &str) -> Option<IpAddr> {
let bits = bits_from_utf8_bytes(input.as_bytes());
let mut out_vec = Vec::new();
for bits in bits.chunks(8) {
out_vec.push(bits_to_byte(bits.iter()))
}
if out_vec.len() == 16 {
Some(
Ipv6Addr::new(
u16::from_be_bytes([out_vec[0], out_vec[1]]),
u16::from_be_bytes([out_vec[2], out_vec[3]]),
u16::from_be_bytes([out_vec[4], out_vec[5]]),
u16::from_be_bytes([out_vec[6], out_vec[7]]),
u16::from_be_bytes([out_vec[8], out_vec[9]]),
u16::from_be_bytes([out_vec[10], out_vec[11]]),
u16::from_be_bytes([out_vec[12], out_vec[13]]),
u16::from_be_bytes([out_vec[14], out_vec[15]]),
)
.into(),
)
} else if out_vec.len() == 4 {
Some(
Ipv4Addr::new(out_vec[0], out_vec[1], out_vec[2], out_vec[3])
.into(),
)
} else {
None
}
}
fn bits_from_utf8_bytes(utf8_bytes: &[u8]) -> Vec<bool> {
let mut ret = Vec::new();
for byte in utf8_bytes {
let mut started = false;
for bit in BytesBits::new(vec![*byte]) {
if started {
ret.push(bit);
} else if bit == false {
started = true;
}
}
}
ret
}
fn bits_to_byte<'a, I: Iterator<Item = &'a bool>>(bits: I) -> u8 {
let mut ret = 0;
for bit in bits {
ret <<= 1;
if *bit {
ret |= 1;
}
}
ret
}
#[cfg(test)]
mod tests {
use hex;
use super::*;
use crate::encode;
use crate::ConfusionLevel;
fn hex2string(input: &str) -> String {
String::from_utf8(hex::decode(input).unwrap()).unwrap()
}
fn assert_roundtrip(ip: &str) {
assert_eq!(
ip,
decode(
&encode(ip.parse().unwrap(), ConfusionLevel::Minimum).unwrap()
)
.unwrap()
.to_string()
);
}
#[test]
fn bits_from_utf8_bytes_extracts_the_right_bits() {
assert_eq!(
vec![false, false, false, false, false, false, false],
bits_from_utf8_bytes(&[0b0000000])
);
assert_eq!(
vec![false, true, false, false, false, true, false],
bits_from_utf8_bytes(&[0b0100010])
);
assert_eq!(
vec![
true, false, true, false, true, false, true, false, true,
false, true, true, false, false, true, true, true, true, true,
false, false, false
],
bits_from_utf8_bytes(&[
0b11101010, 0b10101010, 0b10110011, 0b10111000
])
);
}
#[test]
fn can_make_byte_from_8_bits() {
assert_eq!(
bits_to_byte(
[false, false, false, false, false, false, true, false].iter()
),
2
);
}
#[test]
fn decode_a_tiny_number() {
assert_eq!(
decode(&hex2string("00000001")).unwrap(),
Ipv4Addr::new(0, 0, 0, 1)
);
}
#[test]
fn decode_a_small_number() {
assert_eq!(
decode(&hex2string("000000c481")).unwrap(),
Ipv4Addr::new(0, 0, 1, 1)
);
assert_roundtrip("0.0.1.1");
}
#[test]
fn decode_localhost() {
assert_eq!(
decode(&hex2string("3fd0800001")).unwrap(),
Ipv4Addr::new(127, 0, 0, 1)
);
assert_eq!(
decode(&hex2string("cfb8000001")).unwrap(),
Ipv4Addr::new(127, 0, 0, 1)
);
assert_roundtrip("127.0.0.1");
}
#[test]
fn decoding_something_with_only_one_delightful_but_more_satisfactory() {
assert_eq!(
decode(&hex2string("3e0800cc8a")).unwrap(),
Ipv4Addr::new(124, 32, 3, 10)
);
assert_eq!(
decode(&hex2string("cfa100060a")).unwrap(),
Ipv4Addr::new(124, 32, 3, 10)
);
assert_roundtrip("124.32.3.10");
}
#[test]
fn decoding_198_51_100_164() {
assert_eq!(
decode(&hex2string("630c6cd2a4")).unwrap(),
Ipv4Addr::new(198, 51, 100, 164)
);
assert_eq!(
decode(&hex2string("630cdb8924")).unwrap(),
Ipv4Addr::new(198, 51, 100, 164)
);
assert_eq!(
decode(&hex2string("d8b14d4924")).unwrap(),
Ipv4Addr::new(198, 51, 100, 164)
);
assert_roundtrip("198.51.100.164");
}
#[test]
fn decoding_an_ipv6_address() {
assert_eq!(
decode(&hex2string("000000000000000000000000000000e2b08264"))
.unwrap(),
IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x16, 0x164))
);
}
#[test]
fn decoding_an_ipv6_address_with_lots_of_options() {
assert_eq!(
decode(&hex2string("1000215b400000000000000851380670e78cb4"))
.unwrap(),
IpAddr::V6(Ipv6Addr::new(
0x2001, 0xdb8, 0, 0, 0, 0x8a2e, 0x370, 0x7334
))
);
}
}