use std::ops;
use std::collections::HashMap;
use std::net::{Ipv4Addr, Ipv6Addr};
use bytes::{BufMut, Bytes, BytesMut};
use super::name::{Dname, Label, ToDname};
use super::parse::ShortBuf;
pub trait Compose {
fn compose_len(&self) -> usize;
fn compose<B: BufMut>(&self, buf: &mut B);
}
impl<'a, C: Compose> Compose for &'a C {
fn compose_len(&self) -> usize {
(*self).compose_len()
}
fn compose<B: BufMut>(&self, buf: &mut B) {
(*self).compose(buf)
}
}
impl Compose for i8 {
fn compose_len(&self) -> usize {
1
}
fn compose<B: BufMut>(&self, buf: &mut B) {
buf.put_i8(*self)
}
}
impl Compose for u8 {
fn compose_len(&self) -> usize {
1
}
fn compose<B: BufMut>(&self, buf: &mut B) {
buf.put_u8(*self)
}
}
impl Compose for i16 {
fn compose_len(&self) -> usize {
2
}
fn compose<B: BufMut>(&self, buf: &mut B) {
buf.put_i16_be(*self)
}
}
impl Compose for u16 {
fn compose_len(&self) -> usize {
2
}
fn compose<B: BufMut>(&self, buf: &mut B) {
buf.put_u16_be(*self)
}
}
impl Compose for i32 {
fn compose_len(&self) -> usize {
4
}
fn compose<B: BufMut>(&self, buf: &mut B) {
buf.put_i32_be(*self)
}
}
impl Compose for u32 {
fn compose_len(&self) -> usize {
4
}
fn compose<B: BufMut>(&self, buf: &mut B) {
buf.put_u32_be(*self)
}
}
impl Compose for [u8] {
fn compose_len(&self) -> usize {
self.len()
}
fn compose<B: BufMut>(&self, buf: &mut B) {
buf.put_slice(self)
}
}
impl Compose for Bytes {
fn compose_len(&self) -> usize {
self.len()
}
fn compose<B: BufMut>(&self, buf: &mut B) {
buf.put_slice(self.as_ref())
}
}
impl Compose for Ipv4Addr {
fn compose_len(&self) -> usize {
4
}
fn compose<B: BufMut>(&self, buf: &mut B) {
buf.put_slice(&self.octets())
}
}
impl Compose for Ipv6Addr {
fn compose_len(&self) -> usize {
16
}
fn compose<B: BufMut>(&self, buf: &mut B) {
buf.put_slice(&self.octets())
}
}
pub trait Compress {
fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf>;
}
impl<'a, C: Compress + 'a> Compress for &'a C {
fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf> {
(*self).compress(buf)
}
}
#[derive(Clone, Debug, )]
pub struct Compressor {
buf: BytesMut,
start: usize,
limit: usize,
page_size: usize,
map: Option<HashMap<Dname, u16>>,
}
impl Compressor {
pub fn from_buf(buf: BytesMut) -> Self {
Compressor {
start: buf.len(),
limit: buf.capacity(),
page_size: 0,
buf,
map: None }
}
pub fn new() -> Self {
Self::from_buf(BytesMut::new())
}
pub fn with_capacity(capacity: usize) -> Self {
Self::from_buf(BytesMut::with_capacity(capacity))
}
pub fn enable_compression(&mut self) {
if self.map.is_none() {
self.map = Some(HashMap::new())
}
}
pub fn set_limit(&mut self, limit: usize) {
let limit = limit + self.start;
self.limit = ::std::cmp::max(limit, self.buf.len())
}
pub fn set_page_size(&mut self, page_size: usize) {
self.page_size = page_size
}
pub fn unwrap(self) -> BytesMut {
self.buf
}
pub fn freeze(self) -> Bytes {
self.buf.freeze()
}
pub fn so_far(&self) -> &[u8] {
&self.buf.as_ref()[self.start..]
}
pub fn so_far_mut(&mut self) -> &mut [u8] {
&mut self.buf.as_mut()[self.start..]
}
pub fn compress_name<N: ToDname>(&mut self, name: &N)
-> Result<(), ShortBuf> {
let mut name = name.to_name();
while !name.is_root() {
if let Some(pos) = self.get_pos(&name) {
return self.compose_compress_target(pos)
}
let pos = {
let first = name.first();
let pos = self.buf.len() - self.start;
self.compose(first)?;
pos
};
self.add_name(&name, pos);
name.parent();
}
self.compose(Label::root())
}
fn compose_compress_target(&mut self, pos: u16)
-> Result<(), ShortBuf> {
if self.buf.remaining_mut() < 2 {
return Err(ShortBuf)
}
(pos | 0xC000).compose(&mut self.buf);
Ok(())
}
pub fn compose<C>(&mut self, what: &C) -> Result<(), ShortBuf>
where C: Compose + ?Sized {
if self.remaining_mut() < what.compose_len() {
return Err(ShortBuf)
}
what.compose(self);
Ok(())
}
fn add_name(&mut self, name: &Dname, pos: usize) {
if let Some(ref mut map) = self.map {
if pos > 0x3FFF {
return
}
map.insert(name.clone(), pos as u16);
}
}
fn get_pos(&self, name: &Dname) -> Option<u16> {
match self.map {
Some(ref map) => map.get(name).cloned(),
None => None
}
}
pub fn as_slice(&self) -> &[u8] {
self.buf.as_ref()
}
pub fn as_slice_mut(&mut self) -> &mut [u8] {
self.buf.as_mut()
}
fn grow(&mut self) {
if self.page_size == 0 {
let additional = self.limit.checked_sub(self.buf.capacity())
.unwrap();
self.buf.reserve(additional)
}
else {
self.buf.reserve(self.page_size)
}
}
}
impl Default for Compressor {
fn default() -> Self {
Self::new()
}
}
impl AsRef<BytesMut> for Compressor {
fn as_ref(&self) -> &BytesMut {
&self.buf
}
}
impl AsMut<BytesMut> for Compressor {
fn as_mut(&mut self) -> &mut BytesMut {
&mut self.buf
}
}
impl AsRef<[u8]> for Compressor {
fn as_ref(&self) -> &[u8] {
self.buf.as_ref()
}
}
impl AsMut<[u8]> for Compressor {
fn as_mut(&mut self) -> &mut [u8] {
self.buf.as_mut()
}
}
impl ops::Deref for Compressor {
type Target = BytesMut;
fn deref(&self) -> &Self::Target {
&self.buf
}
}
impl ops::DerefMut for Compressor {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buf
}
}
impl BufMut for Compressor {
fn remaining_mut(&self) -> usize {
self.limit - self.buf.len()
}
unsafe fn advance_mut(&mut self, cnt: usize) {
assert!(cnt <= self.remaining_mut());
while cnt > self.buf.remaining_mut() {
self.grow();
}
self.buf.advance_mut(cnt)
}
unsafe fn bytes_mut(&mut self) -> &mut [u8] {
if self.buf.remaining_mut() == 0 && self.remaining_mut() > 0 {
self.grow()
}
self.buf.bytes_mut()
}
}
#[cfg(test)]
mod test {
use super::*;
use bytes::BytesMut;
#[test]
fn compose_endian() {
let mut buf = BytesMut::with_capacity(20);
0x1234u16.compose(&mut buf);
(-0x1234i16).compose(&mut buf);
0x12345678u32.compose(&mut buf);
(-0x12345678i32).compose(&mut buf);
assert_eq!(buf.as_ref(),
b"\x12\x34\xed\xcc\x12\x34\x56\x78\xed\xcb\xa9\x88");
}
#[test]
fn limit() {
let mut buf = Compressor::new();
buf.set_limit(2);
assert_eq!(buf.remaining_mut(), 2);
assert!(buf.compose(&0u32).is_err());
buf.compose(&0u16).unwrap();
assert!(buf.compose(&0u16).is_err());
buf.set_limit(512); assert_eq!(buf.remaining_mut(), 510);
buf.compose(AsRef::<[u8]>::as_ref(&vec![0u8; 508])).unwrap();
assert!(buf.compose(&0u32).is_err());
buf.compose(&0u16).unwrap();
assert!(buf.compose(&0u16).is_err());
let mut buf = Compressor::from_buf(buf.unwrap());
assert_eq!(buf.so_far().len(), 0);
buf.set_limit(512);
buf.set_page_size(16);
assert_eq!(buf.remaining_mut(), 512);
buf.compose(AsRef::<[u8]>::as_ref(&vec![0u8; 510])).unwrap();
assert_eq!(buf.remaining_mut(), 2);
assert_eq!(buf.so_far().len(), 510);
}
#[test]
fn compressed_names() {
let mut buf = Compressor::with_capacity(1024);
buf.enable_compression();
buf.compose(&7u8).unwrap();
let name = Dname::from_slice(b"\x03foo\x03bar\x00").unwrap();
buf.compress_name(&name).unwrap();
buf.compress_name(&name).unwrap();
assert_eq!(buf.so_far(), b"\x07\x03foo\x03bar\x00\xC0\x01");
let mut buf = Compressor::with_capacity(1024);
buf.enable_compression();
buf.compose(&7u8).unwrap();
Dname::from_slice(b"\x03foo\x03bar\x00").unwrap()
.compress(&mut buf).unwrap();
Dname::from_slice(b"\x03baz\x03foo\x03bar\x00").unwrap()
.compress(&mut buf).unwrap();
assert_eq!(buf.so_far(), b"\x07\x03foo\x03bar\x00\x03baz\xC0\x01");
let mut buf = Compressor::with_capacity(1024);
buf.enable_compression();
buf.compose(&7u8).unwrap();
Dname::from_slice(b"\x03foo\x03bar\x00").unwrap()
.compress(&mut buf).unwrap();
Dname::from_slice(b"\x03baz\x03bar\x00").unwrap()
.compress(&mut buf).unwrap();
assert_eq!(buf.so_far(), b"\x07\x03foo\x03bar\x00\x03baz\xC0\x05");
let mut buf = Compressor::with_capacity(1024);
buf.enable_compression();
buf.compose(&7u8).unwrap();
Dname::root().compress(&mut buf).unwrap();
Dname::from_slice(b"\x03foo\x00").unwrap()
.compress(&mut buf).unwrap();
Dname::root().compress(&mut buf).unwrap();
assert_eq!(buf.so_far(), b"\x07\x00\x03foo\x00\x00");
}
}