use crate::{
Error, Result,
bytes::{Cursor, Reader},
constants::HEADER_LENGTH,
message::{
Header, Question, RecordsSection,
reader::{Questions, Records},
},
};
#[derive(Debug)]
pub struct MessageIterator<'a> {
buf: &'a [u8],
header: Header,
offsets: [usize; 3],
}
impl MessageIterator<'_> {
#[inline]
pub fn new(buf: &[u8]) -> Result<MessageIterator<'_>> {
let mut cursor = Cursor::new(buf);
let header: Header = cursor.read()?;
let mut mi = MessageIterator {
buf,
header,
offsets: [0, 0, 0],
};
mi.section_offset(RecordsSection::Answer)?;
Ok(mi)
}
#[inline]
pub fn header(&self) -> &Header {
&self.header
}
#[inline]
pub fn question(&self) -> Result<Question> {
let mut questions = self.questions();
if let Some(res) = questions.next() {
return res;
}
Err(Error::BadQuestionsCount(0))
}
#[inline]
pub fn questions(&self) -> Questions<'_> {
Questions::new(
Cursor::with_pos(self.buf, HEADER_LENGTH),
self.header.qd_count,
)
}
#[inline]
pub fn records(&self) -> Records<'_> {
Records::new(
Cursor::with_pos(self.buf, self.offsets[RecordsSection::Answer as usize]),
&self.header,
)
}
fn section_offset(&mut self, section: RecordsSection) -> Result<usize> {
use RecordsSection::*;
let existing_value = self.offsets[section as usize];
if existing_value != 0 {
return Ok(existing_value);
}
match section {
Answer => {
let mut c = Cursor::with_pos(self.buf, HEADER_LENGTH);
for _ in 0..self.header.qd_count {
c.skip_question()?;
}
let offset = c.pos();
self.offsets[Answer as usize] = offset;
Ok(offset)
}
Authority => {
let answer_offset = self.section_offset(Answer)?;
let mut c = Cursor::with_pos(self.buf, answer_offset);
for _ in 0..self.header.an_count {
c.skip_rr()?;
}
let offset = c.pos();
self.offsets[Authority as usize] = offset;
Ok(offset)
}
Additional => {
let authority_offset = self.section_offset(Authority)?;
let mut c = Cursor::with_pos(self.buf, authority_offset);
for _ in 0..self.header.ns_count {
c.skip_rr()?;
}
let offset = c.pos();
self.offsets[Additional as usize] = offset;
Ok(offset)
}
}
}
}