use std::mem;
use std::slice::Iter;
use std::sync::Arc;
use crate::proto::{
op::Message,
rr::{Record, RecordSet, RecordType, RrsetRecords},
};
#[cfg(feature = "resolver")]
use crate::resolver::lookup::Lookup;
use crate::zone_handler::LookupOptions;
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Default)]
#[non_exhaustive]
pub enum AuthLookup {
#[default]
Empty,
Records {
answers: LookupRecords,
additionals: Option<LookupRecords>,
},
#[cfg(feature = "resolver")]
Resolved(Lookup),
Response(Message),
}
impl AuthLookup {
pub fn answers(answers: LookupRecords, additionals: Option<LookupRecords>) -> Self {
Self::Records {
answers,
additionals,
}
}
pub fn is_empty(&self) -> bool {
self.was_empty()
}
pub fn was_empty(&self) -> bool {
self.iter().count() == 0
}
pub fn iter(&self) -> AuthLookupIter<'_> {
self.into_iter()
}
pub fn unwrap_records(self) -> LookupRecords {
match self {
Self::Records { answers, .. } => answers,
_ => LookupRecords::default(),
}
}
pub fn authorities(&self) -> Option<LookupRecordsIter<'_>> {
match self {
Self::Response(message) => {
Some(LookupRecordsIter::SliceIter(message.authorities.iter()))
}
_ => None,
}
}
pub fn additionals(&self) -> Option<LookupRecordsIter<'_>> {
match self {
Self::Records { additionals, .. } => additionals.as_ref().map(|l| l.iter()),
Self::Response(message) => {
Some(LookupRecordsIter::SliceIter(message.additionals.iter()))
}
_ => None,
}
}
pub fn take_additionals(&mut self) -> Option<LookupRecords> {
match self {
Self::Records { additionals, .. } => additionals.take(),
Self::Response(message) => {
Some(LookupRecords::Section(mem::take(&mut message.additionals)))
}
_ => None,
}
}
}
#[cfg(feature = "resolver")]
impl From<Lookup> for AuthLookup {
fn from(lookup: Lookup) -> Self {
Self::Resolved(lookup)
}
}
impl<'a> IntoIterator for &'a AuthLookup {
type Item = &'a Record;
type IntoIter = AuthLookupIter<'a>;
fn into_iter(self) -> Self::IntoIter {
match self {
AuthLookup::Empty => AuthLookupIter::Empty,
AuthLookup::Records { answers: r, .. } => AuthLookupIter::Records(r.into_iter()),
#[cfg(feature = "resolver")]
AuthLookup::Resolved(lookup) => AuthLookupIter::Response(lookup.answers().iter()),
AuthLookup::Response(message) => AuthLookupIter::Response(message.answers.iter()),
}
}
}
#[derive(Default)]
pub enum AuthLookupIter<'r> {
#[default]
Empty,
Records(LookupRecordsIter<'r>),
Response(Iter<'r, Record>),
}
impl<'r> Iterator for AuthLookupIter<'r> {
type Item = &'r Record;
fn next(&mut self) -> Option<Self::Item> {
match self {
AuthLookupIter::Empty => None,
AuthLookupIter::Records(i) => i.next(),
AuthLookupIter::Response(i) => i.next(),
}
}
}
impl From<LookupRecords> for AuthLookup {
fn from(lookup: LookupRecords) -> Self {
Self::Records {
answers: lookup,
additionals: None,
}
}
}
#[derive(Debug)]
pub struct AxfrRecords {
dnssec_ok: bool,
rrsets: Vec<Arc<RecordSet>>,
}
impl AxfrRecords {
pub fn new(dnssec_ok: bool, rrsets: Vec<Arc<RecordSet>>) -> Self {
Self { dnssec_ok, rrsets }
}
fn iter(&self) -> AxfrRecordsIter<'_> {
self.into_iter()
}
}
impl<'r> IntoIterator for &'r AxfrRecords {
type Item = &'r Record;
type IntoIter = AxfrRecordsIter<'r>;
fn into_iter(self) -> Self::IntoIter {
AxfrRecordsIter {
dnssec_ok: self.dnssec_ok,
rrsets: self.rrsets.iter(),
records: None,
}
}
}
pub struct AxfrRecordsIter<'r> {
#[cfg_attr(not(feature = "__dnssec"), allow(dead_code))]
dnssec_ok: bool,
rrsets: Iter<'r, Arc<RecordSet>>,
records: Option<RrsetRecords<'r>>,
}
impl<'r> Iterator for AxfrRecordsIter<'r> {
type Item = &'r Record;
fn next(&mut self) -> Option<Self::Item> {
loop {
if let Some(records) = &mut self.records {
if let Some(record) = records
.by_ref()
.find(|record| record.record_type() != RecordType::SOA)
{
return Some(record);
}
}
let rrset = self.rrsets.next()?;
#[cfg(feature = "__dnssec")]
let records = rrset.records(self.dnssec_ok);
#[cfg(not(feature = "__dnssec"))]
let records = rrset.records_without_rrsigs();
self.records = Some(records);
}
}
}
#[derive(Debug, Default)]
pub enum LookupRecords {
#[default]
Empty,
Records {
lookup_options: LookupOptions,
records: Arc<RecordSet>,
},
ManyRecords(LookupOptions, Vec<Arc<RecordSet>>),
Section(Vec<Record>),
}
impl LookupRecords {
pub fn new(lookup_options: LookupOptions, records: Arc<RecordSet>) -> Self {
Self::Records {
lookup_options,
records,
}
}
pub fn many(lookup_options: LookupOptions, mut records: Vec<Arc<RecordSet>>) -> Self {
records.reverse();
Self::ManyRecords(lookup_options, records)
}
pub fn was_empty(&self) -> bool {
self.iter().count() == 0
}
pub fn iter(&self) -> LookupRecordsIter<'_> {
self.into_iter()
}
}
impl<'a> IntoIterator for &'a LookupRecords {
type Item = &'a Record;
type IntoIter = LookupRecordsIter<'a>;
fn into_iter(self) -> Self::IntoIter {
match self {
LookupRecords::Empty => LookupRecordsIter::Empty,
LookupRecords::Records {
lookup_options,
records,
} => LookupRecordsIter::RecordsIter(lookup_options.rrset_with_rrigs(records)),
LookupRecords::ManyRecords(lookup_options, r) => LookupRecordsIter::ManyRecordsIter(
r.iter()
.map(|r| lookup_options.rrset_with_rrigs(r))
.collect(),
None,
),
LookupRecords::Section(vec) => LookupRecordsIter::SliceIter(vec.iter()),
}
}
}
#[derive(Default)]
pub enum LookupRecordsIter<'r> {
RecordsIter(RrsetRecords<'r>),
ManyRecordsIter(Vec<RrsetRecords<'r>>, Option<RrsetRecords<'r>>),
SliceIter(Iter<'r, Record>),
#[default]
Empty,
}
impl<'r> Iterator for LookupRecordsIter<'r> {
type Item = &'r Record;
fn next(&mut self) -> Option<Self::Item> {
match self {
LookupRecordsIter::Empty => None,
LookupRecordsIter::RecordsIter(current) => current.next(),
LookupRecordsIter::SliceIter(current) => current.next(),
LookupRecordsIter::ManyRecordsIter(set, current) => loop {
if let Some(o) = current.as_mut().and_then(Iterator::next) {
return Some(o);
}
*current = set.pop();
if current.is_none() {
return None;
}
},
}
}
}
#[derive(Debug)]
pub struct ZoneTransfer {
pub start_soa: LookupRecords,
pub records: AxfrRecords,
pub end_soa: LookupRecords,
}
impl ZoneTransfer {
pub fn iter(&self) -> impl Iterator<Item = &Record> {
self.start_soa
.iter()
.chain(self.records.iter())
.chain(self.end_soa.iter())
}
}