use std::iter::Chain;
use std::slice::Iter;
use std::sync::Arc;
use cfg_if::cfg_if;
use crate::authority::{LookupObject, LookupOptions};
use crate::client::rr::LowerName;
use crate::proto::rr::{Record, RecordSet, RecordType, RrsetRecords};
#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
pub enum AuthLookup {
Empty,
Records {
answers: LookupRecords,
additionals: Option<LookupRecords>,
},
SOA(LookupRecords),
AXFR {
start_soa: LookupRecords,
records: LookupRecords,
end_soa: LookupRecords,
},
}
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 take_additionals(&mut self) -> Option<LookupRecords> {
match self {
Self::Records {
ref mut additionals,
..
} => additionals.take(),
_ => None,
}
}
}
impl LookupObject for AuthLookup {
fn is_empty(&self) -> bool {
Self::is_empty(self)
}
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Record> + Send + 'a> {
let boxed_iter = Self::iter(self);
Box::new(boxed_iter)
}
fn take_additionals(&mut self) -> Option<Box<dyn LookupObject>> {
let additionals = Self::take_additionals(self);
additionals.map(|a| Box::new(a) as Box<dyn LookupObject>)
}
}
impl Default for AuthLookup {
fn default() -> Self {
Self::Empty
}
}
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, .. } | AuthLookup::SOA(r) => {
AuthLookupIter::Records(r.into_iter())
}
AuthLookup::AXFR {
start_soa,
records,
end_soa,
} => AuthLookupIter::AXFR(start_soa.into_iter().chain(records).chain(end_soa)),
}
}
}
#[allow(clippy::large_enum_variant)]
pub enum AuthLookupIter<'r> {
Empty,
Records(LookupRecordsIter<'r>),
AXFR(Chain<Chain<LookupRecordsIter<'r>, LookupRecordsIter<'r>>, LookupRecordsIter<'r>>),
}
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::AXFR(i) => i.next(),
}
}
}
impl<'a> Default for AuthLookupIter<'a> {
fn default() -> Self {
AuthLookupIter::Empty
}
}
impl From<LookupRecords> for AuthLookup {
fn from(lookup: LookupRecords) -> Self {
Self::Records {
answers: lookup,
additionals: None,
}
}
}
#[derive(Debug)]
pub struct AnyRecords {
lookup_options: LookupOptions,
rrsets: Vec<Arc<RecordSet>>,
query_type: RecordType,
query_name: LowerName,
}
impl AnyRecords {
pub fn new(
lookup_options: LookupOptions,
rrsets: Vec<Arc<RecordSet>>,
query_type: RecordType,
query_name: LowerName,
) -> Self {
Self {
lookup_options,
rrsets,
query_type,
query_name,
}
}
fn iter(&self) -> AnyRecordsIter<'_> {
self.into_iter()
}
}
impl<'r> IntoIterator for &'r AnyRecords {
type Item = &'r Record;
type IntoIter = AnyRecordsIter<'r>;
fn into_iter(self) -> Self::IntoIter {
AnyRecordsIter {
lookup_options: self.lookup_options,
rrsets: self.rrsets.iter(),
rrset: None,
records: None,
query_type: self.query_type,
query_name: &self.query_name,
}
}
}
#[allow(unused)]
pub struct AnyRecordsIter<'r> {
lookup_options: LookupOptions,
rrsets: Iter<'r, Arc<RecordSet>>,
rrset: Option<&'r RecordSet>,
records: Option<RrsetRecords<'r>>,
query_type: RecordType,
query_name: &'r LowerName,
}
impl<'r> Iterator for AnyRecordsIter<'r> {
type Item = &'r Record;
fn next(&mut self) -> Option<Self::Item> {
use std::borrow::Borrow;
let query_type = self.query_type;
let query_name = self.query_name;
loop {
if let Some(ref mut records) = self.records {
let record = records
.by_ref()
.filter(|rr_set| {
query_type == RecordType::ANY || rr_set.record_type() != RecordType::SOA
})
.find(|rr_set| {
query_type == RecordType::AXFR
|| &LowerName::from(rr_set.name()) == query_name
});
if record.is_some() {
return record;
}
}
self.rrset = self.rrsets.next().map(Borrow::borrow);
self.rrset?;
cfg_if! {
if #[cfg(feature = "dnssec")] {
self.records = Some(
self.rrset
.expect("rrset should not be None at this point")
.records(self.lookup_options.is_dnssec(), self.lookup_options.supported_algorithms()),
);
} else {
self.records = Some(self.rrset.expect("rrset should not be None at this point").records_without_rrsigs());
}
}
}
}
}
#[derive(Debug)]
pub enum LookupRecords {
Empty,
Records {
lookup_options: LookupOptions,
records: Arc<RecordSet>,
},
ManyRecords(LookupOptions, Vec<Arc<RecordSet>>),
AnyRecords(AnyRecords),
}
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 Default for LookupRecords {
fn default() -> Self {
Self::Empty
}
}
impl<'a> IntoIterator for &'a LookupRecords {
type Item = &'a Record;
type IntoIter = LookupRecordsIter<'a>;
#[allow(unused_variables)]
fn into_iter(self) -> Self::IntoIter {
match self {
LookupRecords::Empty => LookupRecordsIter::Empty,
LookupRecords::Records {
lookup_options,
records,
} => LookupRecordsIter::RecordsIter(
lookup_options.rrset_with_supported_algorithms(records),
),
LookupRecords::ManyRecords(lookup_options, r) => LookupRecordsIter::ManyRecordsIter(
r.iter()
.map(|r| lookup_options.rrset_with_supported_algorithms(r))
.collect(),
None,
),
LookupRecords::AnyRecords(r) => LookupRecordsIter::AnyRecordsIter(r.iter()),
}
}
}
pub enum LookupRecordsIter<'r> {
AnyRecordsIter(AnyRecordsIter<'r>),
RecordsIter(RrsetRecords<'r>),
ManyRecordsIter(Vec<RrsetRecords<'r>>, Option<RrsetRecords<'r>>),
Empty,
}
impl<'r> Default for LookupRecordsIter<'r> {
fn default() -> Self {
LookupRecordsIter::Empty
}
}
impl<'r> Iterator for LookupRecordsIter<'r> {
type Item = &'r Record;
fn next(&mut self) -> Option<Self::Item> {
match self {
LookupRecordsIter::Empty => None,
LookupRecordsIter::AnyRecordsIter(current) => current.next(),
LookupRecordsIter::RecordsIter(current) => current.next(),
LookupRecordsIter::ManyRecordsIter(set, ref mut 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;
}
},
}
}
}
impl From<AnyRecords> for LookupRecords {
fn from(rrset_records: AnyRecords) -> Self {
Self::AnyRecords(rrset_records)
}
}
impl LookupObject for LookupRecords {
fn is_empty(&self) -> bool {
Self::was_empty(self)
}
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = &'a Record> + Send + 'a> {
Box::new(self.iter())
}
fn take_additionals(&mut self) -> Option<Box<dyn LookupObject>> {
None
}
}