///|
pub struct Prefix {
afi : Int
length : Int
address : Bytes
} derive(Eq, ToJson)
///|
pub extend Prefix with Eq::{equal, not_equal}
///|
pub extend Prefix with ToJson::{to_json}
///|
fn address_size(afi : Int) -> Int raise ParseError {
match afi {
1 => 4
2 => 16
_ => raise Invalid(0, "不支持的地址族")
}
}
///|
fn read_prefix(c : Cursor, afi : Int) -> Prefix raise ParseError {
let size = address_size(afi)
let length = c.u8()
if length > size * 8 {
raise Invalid(c.pos - 1, "前缀长度超出地址族范围")
}
let raw = c.bytes((length + 7) / 8)
let address = Array::make(size, b'\x00')
for i = 0; i < raw.length(); i = i + 1 {
address[i] = raw[i]
}
if length % 8 != 0 {
let last = raw.length() - 1
address[last] = (address[last].to_int() & (255 << (8 - length % 8))).to_byte()
}
{ afi, length, address: Bytes::from_array(address), }
}
///|
pub fn parse_prefix(data : Bytes, afi : Int) -> Prefix raise ParseError {
let c = Cursor::new(data)
let prefix = read_prefix(c, afi)
c.finish()
prefix
}
///|
fn ip_text(address : Bytes) -> String {
if address.length() == 4 {
return "\{address[0].to_int()}.\{address[1].to_int()}.\{address[2].to_int()}.\{address[3].to_int()}"
}
let groups = Array::makei(8, fn(i) {
(address[i * 2].to_int() << 8) | address[i * 2 + 1].to_int()
})
let mut best_start = -1
let mut best_len = 1
let mut i = 0
while i < 8 {
if groups[i] == 0 {
let start = i
while i < 8 && groups[i] == 0 {
i += 1
}
if i - start > best_len {
best_start = start
best_len = i - start
}
} else {
i += 1
}
}
let out = StringBuilder()
i = 0
while i < 8 {
if i == best_start {
out.write_string("::")
i += best_len
} else {
if i > 0 && i != best_start + best_len {
out.write_string(":")
}
out.write_string(groups[i].to_string(radix=16))
i += 1
}
}
out.to_string()
}
///|
pub fn Prefix::text(self : Prefix) -> String {
"\{ip_text(self.address)}/\{self.length}"
}