use std::net::Ipv6Addr;
use std::str::FromStr;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Ipv6Category {
Loopback,
LinkLocal,
UniqueLocal,
Documentation,
GlobalUnicast,
Unspecified,
Special,
}
#[derive(Debug, Clone)]
pub struct CompressedIpv6 {
pub category: Ipv6Category,
pub compressed_data: Vec<u8>,
pub original_bits: usize,
pub compressed_bits: usize,
pub port: Option<u16>,
}
pub struct Ipv6Compressor;
impl Ipv6Compressor {
pub fn new() -> Self {
Self
}
pub fn compress(&self, ip: Ipv6Addr, port: Option<u16>) -> Result<CompressedIpv6, String> {
let category = Self::categorize_address(&ip);
println!("Category: {:?}", category);
match category {
Ipv6Category::Documentation => Self::compress_documentation(ip, port),
_ => Err("Not documentation".to_string()),
}
}
fn categorize_address(ip: &Ipv6Addr) -> Ipv6Category {
let segments = ip.segments();
println!("Categorizing: segments = {:x?}", segments);
if segments[0] == 0x2001 && segments[1] == 0x0DB8 {
println!("Matched documentation pattern");
return Ipv6Category::Documentation;
}
println!("Did not match documentation pattern");
Ipv6Category::Special
}
fn compress_documentation(
ip: Ipv6Addr,
port: Option<u16>,
) -> Result<CompressedIpv6, String> {
let segments = ip.segments();
println!("Compressing documentation address: {:x?}", segments);
let mut compressed = Vec::new();
compressed.extend_from_slice(&segments[2].to_be_bytes());
compressed.extend_from_slice(&segments[3].to_be_bytes());
println!("After storing segments 2-3: {:?}", compressed);
let non_zero_interface: Vec<(usize, u16)> = segments[4..8]
.iter()
.enumerate()
.filter(|&(_, &seg)| seg != 0)
.map(|(i, &seg)| (i + 4, seg))
.collect();
println!("Non-zero interface segments: {:?}", non_zero_interface);
println!("Is empty: {}", non_zero_interface.is_empty());
if non_zero_interface.is_empty() {
println!("Using marker 0 (empty interface)");
compressed.insert(0, 0);
} else if non_zero_interface.len() == 1 && non_zero_interface[0].1 <= 255 {
println!("Using marker 1 (single small value)");
compressed.insert(0, 1);
let (pos, val) = non_zero_interface[0];
compressed.push((pos - 4) as u8);
compressed.push(val as u8);
} else {
println!("Using marker 2 (complex interface)");
compressed.insert(0, 2);
for &(pos, val) in &non_zero_interface {
compressed.push((pos - 4) as u8);
compressed.extend_from_slice(&val.to_be_bytes());
}
compressed.push(255); }
let compressed_bits = 3 + (compressed.len() * 8); println!("Final compressed data: {:?}", compressed);
Ok(CompressedIpv6 {
category: Ipv6Category::Documentation,
compressed_data: compressed,
original_bits: 128,
compressed_bits,
port,
})
}
}
fn main() {
let ip = Ipv6Addr::from_str("2001:db8:85a3::8a2e:370:7334").unwrap();
let port = Some(8080);
println!("Testing compression of: {}", ip);
let compressor = Ipv6Compressor::new();
match compressor.compress(ip, port) {
Ok(compressed) => {
println!("Compression successful!");
println!("Category: {:?}", compressed.category);
println!("Compressed data: {:?}", compressed.compressed_data);
println!("Original bits: {}", compressed.original_bits);
println!("Compressed bits: {}", compressed.compressed_bits);
}
Err(e) => {
println!("Compression failed: {}", e);
}
}
}