use std::{mem, ops};
use bytes::{BigEndian, BufMut, ByteOrder, Bytes, BytesMut};
use super::compose::Compose;
use super::header::{Header, HeaderCounts, HeaderSection};
use super::message::Message;
use super::name::ToDname;
use super::opt::{OptData, OptHeader};
use super::question::Question;
#[derive(Clone, Debug)]
pub struct QueryBuilder {
target: BytesMut,
additional: usize,
}
impl QueryBuilder {
pub fn new<N: ToDname, Q: Into<Question<N>>>(question: Q) -> Self {
let mut header = HeaderSection::default();
header.header_mut().set_random_id();
header.counts_mut().set_qdcount(1);
let question = question.into();
let len = header.compose_len() + question.compose_len();
let mut target = BytesMut::with_capacity(len + 2);
target.put_u16_be(len as u16);
header.compose(&mut target);
question.compose(&mut target);
QueryBuilder {
additional: target.len(),
target
}
}
pub fn header(&self) -> &Header {
Header::for_message_slice(&self.target.as_ref()[2..])
}
pub fn header_mut(&mut self) -> &mut Header {
Header::for_message_slice_mut(&mut self.target.as_mut()[2..])
}
fn counts_mut(&mut self) -> &mut HeaderCounts {
HeaderCounts::for_message_slice_mut(&mut self.target.as_mut()[2..])
}
pub fn set_rd(&mut self, value: bool) {
self.header_mut().set_rd(value)
}
fn update_shim(&mut self) {
let len = self.target.len() - 2;
assert!(len <= ::std::u16::MAX as usize);
BigEndian::write_u16(self.target.as_mut(), len as u16);
}
pub fn add_opt<F>(&mut self, op: F)
where F: FnOnce(&mut OptBuilder) {
op(&mut OptBuilder::new(self))
}
pub fn revert_additional(&mut self) {
self.target.truncate(self.additional);
self.counts_mut().set_adcount(0);
self.update_shim();
}
pub fn freeze(self) -> QueryMessage {
let bytes = self.target.freeze();
QueryMessage {
message: Message::from_bytes(bytes.slice_from(2)).unwrap(),
bytes,
additional: self.additional
}
}
}
#[derive(Debug)]
pub struct OptBuilder<'a> {
query: &'a mut QueryBuilder,
pos: usize,
}
impl<'a> OptBuilder<'a> {
fn new(query: &'a mut QueryBuilder) -> Self {
let pos = query.target.len();
let header = OptHeader::default();
query.target.reserve(header.compose_len() + 2);
header.compose(&mut query.target);
0u16.compose(&mut query.target);
query.counts_mut().inc_arcount();
query.update_shim();
OptBuilder { query, pos }
}
pub fn header(&self) -> &OptHeader {
OptHeader::for_record_slice(&self.query.target.as_ref()[self.pos..])
}
pub fn header_mut(&mut self) -> &mut OptHeader {
OptHeader::for_record_slice_mut(&mut self.query.target.as_mut()
[self.pos..])
}
pub fn push<O: OptData>(&mut self, option: &O) {
option.code().compose(&mut self.query.target);
let len = option.compose_len();
assert!(len <= ::std::u16::MAX.into());
(len as u16).compose(&mut self.query.target);
option.compose(&mut self.query.target);
self.update_length();
}
fn update_length(&mut self) {
let len = self.query.target.len()
- (self.pos + mem::size_of::<OptHeader>() + 2);
assert!(len <= ::std::u16::MAX.into());
let count_pos = self.pos + mem::size_of::<OptHeader>();
BigEndian::write_u16(
&mut self.query.target.as_mut()[count_pos..],
len as u16
);
self.query.update_shim();
}
}
#[derive(Clone, Debug)]
pub struct QueryMessage {
bytes: Bytes,
message: Message,
additional: usize
}
impl QueryMessage {
pub fn unfreeze(self) -> QueryBuilder {
drop(self.message);
let mut res = QueryBuilder {
target: self.bytes.into(),
additional: self.additional
};
res.header_mut().set_random_id();
res
}
pub fn as_stream_slice(&self) -> &[u8] {
self.bytes.as_ref()
}
pub fn as_dgram_slice(&self) -> &[u8] {
&self.bytes.as_ref()[2..]
}
}
impl ops::Deref for QueryMessage {
type Target = Message;
fn deref(&self) -> &Message {
&self.message
}
}
impl AsRef<Message> for QueryMessage {
fn as_ref(&self) -> &Message {
&self.message
}
}
#[derive(Clone, Debug)]
pub struct DgramQueryMessage(QueryMessage);
impl DgramQueryMessage {
pub fn new(query: QueryMessage) -> DgramQueryMessage {
DgramQueryMessage(query)
}
pub fn unwrap(self) -> QueryMessage {
self.0
}
pub fn unfreeze(self) -> QueryBuilder {
self.unwrap().unfreeze()
}
}
impl From<QueryMessage> for DgramQueryMessage {
fn from(query: QueryMessage) -> DgramQueryMessage {
Self::new(query)
}
}
impl AsRef<[u8]> for DgramQueryMessage {
fn as_ref(&self) -> &[u8] {
self.0.as_dgram_slice()
}
}
#[derive(Clone, Debug)]
pub struct StreamQueryMessage(QueryMessage);
impl StreamQueryMessage {
pub fn new(query: QueryMessage) -> StreamQueryMessage {
StreamQueryMessage(query)
}
pub fn unwrap(self) -> QueryMessage {
self.0
}
pub fn unfreeze(self) -> QueryBuilder {
self.unwrap().unfreeze()
}
}
impl From<QueryMessage> for StreamQueryMessage {
fn from(query: QueryMessage) -> StreamQueryMessage {
Self::new(query)
}
}
impl AsRef<[u8]> for StreamQueryMessage {
fn as_ref(&self) -> &[u8] {
self.0.as_stream_slice()
}
}