use std::fmt;
use std::mem;
use std::ops::{AddAssign, SubAssign};
fn add_assign(bytes: &mut [u8], mut rhs: i64) {
if rhs < 0 {
sub_assign(bytes, -rhs)
} else {
for it in bytes.iter_mut().rev() {
let (val, car) = it.overflowing_add(rhs as u8);
*it = val;
rhs >>= 8;
if car {
rhs += 1;
}
}
if rhs > 0 {
panic!("overflow");
}
}
}
fn sub_assign(bytes: &mut [u8], mut rhs: i64) {
if rhs < 0 {
add_assign(bytes, -rhs)
} else {
for it in bytes.iter_mut().rev() {
let (val, car) = it.overflowing_sub(rhs as u8);
*it = val;
rhs >>= 8;
if car {
rhs += 1;
}
}
if rhs > 0 {
panic!("overflow");
}
}
}
#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct LlAddr {
bytes: [u8; 6],
}
impl LlAddr {
pub fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> LlAddr {
LlAddr { bytes: [a,b,c,d,e,f] }
}
pub fn from_bytes(bytes: [u8; 6]) -> LlAddr {
LlAddr { bytes: bytes }
}
pub fn as_bytes(&self) -> &[u8; 6] {
&self.bytes
}
}
impl AddAssign<i64> for LlAddr {
fn add_assign(&mut self, rhs: i64) {
add_assign(&mut self.bytes, rhs)
}
}
impl SubAssign<i64> for LlAddr {
fn sub_assign(&mut self, rhs: i64) {
sub_assign(&mut self.bytes, rhs)
}
}
impl fmt::Display for LlAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
self.bytes[0], self.bytes[1], self.bytes[2],
self.bytes[3], self.bytes[4], self.bytes[5])
}
}
impl fmt::Debug for LlAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct IpAddrV4 {
bytes: [u8; 4],
}
impl IpAddrV4 {
pub fn new(a: u8, b: u8, c: u8, d: u8) -> IpAddrV4 {
IpAddrV4 { bytes: [a,b,c,d] }
}
pub fn from_bytes(bytes: [u8; 4]) -> IpAddrV4 {
IpAddrV4 { bytes: bytes }
}
pub fn from_u32(mut addr: u32) -> IpAddrV4 {
let d = (addr & 0xFF) as u8;
addr >>= 8;
let c = (addr & 0xFF) as u8;
addr >>= 8;
let b = (addr & 0xFF) as u8;
addr >>= 8;
IpAddrV4::new(addr as u8, b, c, d)
}
pub fn any() -> IpAddrV4 {
IpAddrV4 { bytes: [0; 4] }
}
pub fn loopback() -> IpAddrV4 {
IpAddrV4::new(127,0,0,1)
}
pub fn is_unspecified(&self) -> bool {
self.bytes.iter().all(|&x| x == 0)
}
pub fn is_loopback(&self) -> bool {
(self.bytes[0] & 0xFF) == 0x7F
}
pub fn is_class_a(&self) -> bool {
(self.bytes[0] & 0x80) == 0
}
pub fn is_class_b(&self) -> bool {
(self.bytes[0] & 0xC0) == 0x80
}
pub fn is_class_c(&self) -> bool {
(self.bytes[0] & 0xE0) == 0xC0
}
pub fn is_private(&self) -> bool {
self.is_class_a() || self.is_class_b() || self.is_class_c()
}
pub fn is_multicast(&self) -> bool {
(self.bytes[0] & 0xF0) == 0xE0
}
pub fn is_link_local(&self) -> bool {
self.bytes[0] == 0xA9 && self.bytes[1] == 0xFE
}
pub fn as_bytes(&self) -> &[u8; 4] {
&self.bytes
}
pub fn to_u32(&self) -> u32 {
((((((self.bytes[0] as u32) << 8)
+ self.bytes[1] as u32) << 8)
+ self.bytes[2] as u32) << 8)
+ self.bytes[3] as u32
}
}
impl AddAssign<i64> for IpAddrV4 {
fn add_assign(&mut self, rhs: i64) {
*self = Self::from_u32(self.to_u32() + rhs as u32);
}
}
impl SubAssign<i64> for IpAddrV4 {
fn sub_assign(&mut self, rhs: i64) {
*self = Self::from_u32(self.to_u32() - rhs as u32);
}
}
impl fmt::Display for IpAddrV4 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}.{}.{}.{}",
self.bytes[0], self.bytes[1], self.bytes[2], self.bytes[3])
}
}
impl fmt::Debug for IpAddrV4 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct IpAddrV6 {
scope_id: u32,
bytes: [u8; 16],
}
impl IpAddrV6 {
pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddrV6 {
let ar = [ a.to_be(), b.to_be(), c.to_be(), d.to_be(), e.to_be(), f.to_be(), g.to_be(), h.to_be() ];
IpAddrV6::from_bytes(unsafe { mem::transmute(ar) }, 0)
}
pub fn with_scope_id(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16, scope_id: u32) -> IpAddrV6 {
let ar = [ a.to_be(), b.to_be(), c.to_be(), d.to_be(), e.to_be(), f.to_be(), g.to_be(), h.to_be() ];
IpAddrV6::from_bytes(unsafe { mem::transmute(ar) }, scope_id)
}
pub fn any() -> IpAddrV6 {
IpAddrV6 { scope_id: 0, bytes: [0; 16] }
}
pub fn loopback() -> IpAddrV6 {
IpAddrV6 { scope_id: 0, bytes: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1] }
}
pub fn from_bytes(bytes: [u8; 16], scope_id: u32) -> IpAddrV6 {
IpAddrV6 { scope_id: scope_id, bytes: bytes }
}
pub fn get_scope_id(&self) -> u32 {
self.scope_id
}
pub fn set_scope_id(&mut self, scope_id: u32) {
self.scope_id = scope_id
}
pub fn is_unspecified(&self) -> bool {
self.bytes.iter().all(|&x| x == 0)
}
pub fn is_loopback(&self) -> bool {
(self.bytes[0] == 0 && self.bytes[1] == 0 && self.bytes[2] == 0 && self.bytes[3] == 0 &&
self.bytes[4] == 0 && self.bytes[5] == 0 && self.bytes[6] == 0 && self.bytes[7] == 0 &&
self.bytes[8] == 0 && self.bytes[9] == 0 && self.bytes[10] == 0 && self.bytes[11] == 0 &&
self.bytes[12] == 0 && self.bytes[13] == 0 && self.bytes[14] == 0 && self.bytes[15] == 1)
}
pub fn is_link_local(&self) -> bool {
self.bytes[0] == 0xFE && (self.bytes[1] & 0xC0) == 0x80
}
pub fn is_site_local(&self) -> bool {
self.bytes[0] == 0xFE && (self.bytes[1] & 0xC0) == 0xC0
}
pub fn is_multicast(&self) -> bool {
self.bytes[0] == 0xFF
}
pub fn is_multicast_global(&self) -> bool {
self.bytes[0] == 0xFF && (self.bytes[1] & 0x0F) == 0x0E
}
pub fn is_multicast_link_local(&self) -> bool {
self.bytes[0] == 0xFF && (self.bytes[1] & 0x0F) == 0x02
}
pub fn is_multicast_node_local(&self) -> bool {
self.bytes[0] == 0xFF && (self.bytes[1] & 0x0F) == 0x01
}
pub fn is_multicast_org_local(&self) -> bool {
self.bytes[0] == 0xFF && (self.bytes[1] & 0x0F) == 0x08
}
pub fn is_multicast_site_local(&self) -> bool {
self.bytes[0] == 0xFF && (self.bytes[1] & 0x0F) == 0x05
}
pub fn is_v4_mapped(&self) -> bool {
(self.bytes[0] == 0 && self.bytes[1] == 0 && self.bytes[2] == 0 && self.bytes[3] == 0 &&
self.bytes[4] == 0 && self.bytes[5] == 0 && self.bytes[6] == 0 && self.bytes[7] == 0 &&
self.bytes[8] == 0 && self.bytes[9] == 0 && self.bytes[10] == 0xFF && self.bytes[11] == 0xFF)
}
pub fn is_v4_compatible(&self) -> bool {
((self.bytes[0] == 0 && self.bytes[1] == 0 && self.bytes[2] == 0 && self.bytes[3] == 0 &&
self.bytes[4] == 0 && self.bytes[5] == 0 && self.bytes[6] == 0 && self.bytes[7] == 0 &&
self.bytes[8] == 0 && self.bytes[9] == 0 && self.bytes[10] == 0 && self.bytes[11] == 0)
&& !(self.bytes[12] == 0 && self.bytes[13] == 0 && self.bytes[14] == 0
&& (self.bytes[15] == 0 || self.bytes[15] == 1)))
}
pub fn as_bytes(&self) -> &[u8; 16] {
&self.bytes
}
pub fn to_v4(&self) -> Option<IpAddrV4> {
if self.is_v4_mapped() || self.is_v4_compatible() {
Some(IpAddrV4 { bytes: [ self.bytes[12], self.bytes[13], self.bytes[14], self.bytes[15] ] })
} else {
None
}
}
pub fn v4_mapped(addr: &IpAddrV4) -> Self {
IpAddrV6 {
scope_id: 0,
bytes: [0,0,0,0,0,0,0,0,0,0,0xFF,0xFF,
addr.bytes[0], addr.bytes[1], addr.bytes[2], addr.bytes[3]]
}
}
pub fn v4_compatible(addr: &IpAddrV4) -> Option<Self> {
if addr.bytes[0] == 0 && addr.bytes[1] == 0 && addr.bytes[2] == 0
&& (addr.bytes[3] == 0 || addr.bytes[3] == 1)
{
None
} else {
Some(IpAddrV6 {
scope_id: 0,
bytes: [0,0,0,0,0,0,0,0,0,0,0,0,
addr.bytes[0], addr.bytes[1], addr.bytes[2], addr.bytes[3]]
})
}
}
}
impl AddAssign<i64> for IpAddrV6 {
fn add_assign(&mut self, rhs: i64) {
add_assign(&mut self.bytes, rhs)
}
}
impl SubAssign<i64> for IpAddrV6 {
fn sub_assign(&mut self, rhs: i64) {
sub_assign(&mut self.bytes, rhs)
}
}
impl fmt::Display for IpAddrV6 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ar: &[u16; 8] = unsafe { mem::transmute(&self.bytes) };
let mut cnt = 0;
let mut max_idx = 0;
let mut max_cnt = 0;
for (i, e) in ar.iter().enumerate() {
if *e != 0 {
if max_cnt < cnt {
max_idx = i - cnt;
max_cnt = cnt;
}
cnt = 0;
} else {
cnt += 1;
}
}
if max_cnt < cnt {
max_idx = ar.len() - cnt;
max_cnt = cnt;
}
if max_idx == 0 && max_cnt == 0 {
return write!(f, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
u16::from_be(ar[0]), u16::from_be(ar[1]), u16::from_be(ar[2]), u16::from_be(ar[3]),
u16::from_be(ar[4]), u16::from_be(ar[5]), u16::from_be(ar[6]), u16::from_be(ar[7]));
}
if max_idx == 0 {
try!(write!(f, ":"));
} else {
for i in 0..max_idx {
try!(write!(f, "{:x}:", u16::from_be(ar[i])));
}
}
if max_idx + max_cnt == 8 {
try!(write!(f, ":"));
} else {
for i in max_idx + max_cnt..ar.len() {
try!(write!(f, ":{:x}", u16::from_be(ar[i])));
}
}
Ok(())
}
}
impl fmt::Debug for IpAddrV6 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum IpAddr {
V4(IpAddrV4),
V6(IpAddrV6),
}
impl IpAddr {
pub fn is_unspecified(&self) -> bool {
match self {
&IpAddr::V4(ref addr) => addr.is_unspecified(),
&IpAddr::V6(ref addr) => addr.is_unspecified(),
}
}
pub fn is_loopback(&self) -> bool {
match self {
&IpAddr::V4(ref addr) => addr.is_loopback(),
&IpAddr::V6(ref addr) => addr.is_loopback(),
}
}
pub fn is_multicast(&self) -> bool {
match self {
&IpAddr::V4(ref addr) => addr.is_multicast(),
&IpAddr::V6(ref addr) => addr.is_multicast(),
}
}
}
impl AddAssign<i64> for IpAddr {
fn add_assign(&mut self, rhs: i64) {
match self {
&mut IpAddr::V4(ref mut addr) => addr.add_assign(rhs),
&mut IpAddr::V6(ref mut addr) => addr.add_assign(rhs),
}
}
}
impl SubAssign<i64> for IpAddr {
fn sub_assign(&mut self, rhs: i64) {
match self {
&mut IpAddr::V4(ref mut addr) => addr.sub_assign(rhs),
&mut IpAddr::V6(ref mut addr) => addr.sub_assign(rhs),
}
}
}
impl fmt::Display for IpAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&IpAddr::V4(ref addr) => write!(f, "{}", addr),
&IpAddr::V6(ref addr) => write!(f, "{}", addr),
}
}
}
impl fmt::Debug for IpAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
#[test]
fn test_lladdr() {
assert_eq!(LlAddr::default().bytes, [0,0,0,0,0,0]);
assert_eq!(LlAddr::new(1,2,3,4,5,6).bytes, [1,2,3,4,5,6]);
assert!(LlAddr::new(1,2,3,4,5,6) == LlAddr::from_bytes([1,2,3,4,5,6]));
assert!(LlAddr::new(1,2,3,4,5,6) < LlAddr::new(1,2,3,4,5,7));
assert!(LlAddr::new(1,2,3,4,5,6) < LlAddr::new(1,2,3,4,6,0));
assert!(LlAddr::new(1,2,3,4,5,6) < LlAddr::new(1,2,3,5,0,0));
assert!(LlAddr::new(1,2,3,4,5,6) < LlAddr::new(1,2,4,0,0,0));
assert!(LlAddr::new(1,2,3,4,5,6) < LlAddr::new(1,3,0,0,0,0));
assert!(LlAddr::new(1,2,3,4,5,6) < LlAddr::new(2,0,0,0,0,0));
}
#[test]
fn test_lladdr_format() {
assert_eq!(format!("{}", LlAddr::new(1,2,3,4,5,6)), "01:02:03:04:05:06");
assert_eq!(format!("{}", LlAddr::new(0xAA,0xBB,0xCC,0xDD,0xEE,0xFF)), "AA:BB:CC:DD:EE:FF");
}
#[test]
fn test_ipaddr_v4() {
assert_eq!(IpAddrV4::default().bytes, [0,0,0,0]);
assert_eq!(IpAddrV4::new(1,2,3,4).bytes, [1,2,3,4]);
assert_eq!(IpAddrV4::new(1,2,3,4), IpAddrV4::from_bytes([1,2,3,4]));
assert!(IpAddrV4::new(1,2,3,4) < IpAddrV4::new(1,2,3,5));
assert!(IpAddrV4::new(1,2,3,4) < IpAddrV4::new(1,2,4,0));
assert!(IpAddrV4::new(1,2,3,4) < IpAddrV4::new(1,3,0,0));
assert!(IpAddrV4::new(1,2,3,4) < IpAddrV4::new(2,0,0,0));
}
#[test]
fn test_ipaddr_v4_format() {
assert_eq!(format!("{}", IpAddrV4::any()), "0.0.0.0");
assert_eq!(format!("{}", IpAddrV4::loopback()), "127.0.0.1");
}
#[test]
fn test_ipaddr_v4_add() {
let mut a = IpAddrV4::new(192,168,0,1);
a += 1;
assert_eq!(a, IpAddrV4::new(192,168,0,2));
a += 100;
assert_eq!(a, IpAddrV4::new(192,168,0,102));
a += 256*10;
assert_eq!(a, IpAddrV4::new(192,168,10,102));
}
#[test]
fn test_ipaddr_v4_sub() {
let mut a = IpAddrV4::new(192,168,0,1);
a -= 1;
assert_eq!(a, IpAddrV4::new(192,168,0,0));
a -= 100;
assert_eq!(a, IpAddrV4::new(192,167,255,156));
a -= 256*10;
assert_eq!(a, IpAddrV4::new(192,167,245,156));
}
#[test]
fn test_ipaddr_v6() {
assert_eq!(IpAddrV6::default().bytes, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);
assert_eq!(IpAddrV6::new(0x0102,0x0304,0x0506,0x0708,0x090a,0x0b0c,0x0d0e,0x0f10).bytes,
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]);
assert_eq!(IpAddrV6::new(0x0102,0x0304,0x0506,0x0708,0x090a,0x0b0c,0x0d0e,0x0f10),
IpAddrV6::from_bytes([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], 0));
assert_eq!(IpAddrV6::with_scope_id(0,0,0,0,0,0,0,0,100).get_scope_id(), 100);
assert!(IpAddrV6::from_bytes([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], 0) <
IpAddrV6::from_bytes([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17], 0));
assert!(IpAddrV6::from_bytes([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], 0) <
IpAddrV6::from_bytes([1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,00], 0));
assert!(IpAddrV6::from_bytes([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], 0) <
IpAddrV6::from_bytes([1,2,3,4,5,6,7,8,9,10,11,12,13,15,00,00], 0));
}
#[test]
fn test_ipaddr_v6_format() {
assert_eq!(format!("{}", IpAddrV6::any()), "::");
assert_eq!(format!("{}", IpAddrV6::loopback()), "::1");
assert_eq!(format!("{}", IpAddrV6::new(1,2,3,4,5,6,7,8)), "1:2:3:4:5:6:7:8");
assert_eq!(format!("{}", IpAddrV6::new(0,2,3,4,5,6,7,8)), "::2:3:4:5:6:7:8");
assert_eq!(format!("{}", IpAddrV6::new(1,2,3,4,5,6,7,0)), "1:2:3:4:5:6:7::");
assert_eq!(format!("{}", IpAddrV6::new(1,2,3,4,0,6,7,8)), "1:2:3:4::6:7:8");
assert_eq!(format!("{}", IpAddrV6::new(1,0,0,0,0,0,0,8)), "1::8");
}
#[test]
fn test_add_assign() {
let mut a = [0,0];
add_assign(&mut a, 0xFF);
assert_eq!(&a, &[0, 0xFF]);
add_assign(&mut a, 0x01);
assert_eq!(&a, &[1, 0]);
add_assign(&mut a, 0x101);
assert_eq!(&a, &[2, 1]);
}
#[should_panic]
#[test]
fn test_add_assign_overflow() {
let mut a = [0xFF, 0xFF];
add_assign(&mut a, 1);
}
#[test]
fn test_sub_assign() {
let mut a = [0xFF, 0xFF];
sub_assign(&mut a, 0xFF);
assert_eq!(&a, &[0xFF, 0]);
sub_assign(&mut a, 0x01);
assert_eq!(&a, &[0xFE, 0xFF]);
sub_assign(&mut a, 0x101);
assert_eq!(&a, &[0xFD, 0xFE]);
}
#[should_panic]
#[test]
fn test_sub_assign_underflow() {
let mut a = [0, 0];
sub_assign(&mut a, 1);
}