use std::sync::Arc;
use std::vec::Vec;
use crate::base::iana::Class;
use crate::base::name::{Label, ToName};
use crate::zonetree::error::{CnameError, OutOfZone, ZoneCutError};
use crate::zonetree::types::{StoredName, StoredRecord, ZoneCut};
use crate::zonetree::{SharedRr, SharedRrset, Zone};
use super::nodes::{Special, ZoneApex, ZoneNode};
use super::versioned::Version;
pub struct ZoneBuilder {
apex: ZoneApex,
}
impl ZoneBuilder {
#[must_use]
pub fn new(apex_name: StoredName, class: Class) -> Self {
ZoneBuilder {
apex: ZoneApex::new(apex_name, class),
}
}
#[must_use]
pub fn build(self) -> Zone {
Zone::new(self.apex)
}
pub fn insert_rrset(
&mut self,
name: &impl ToName,
rrset: SharedRrset,
) -> Result<(), OutOfZone> {
match self.get_node(self.apex.prepare_name(name)?) {
Ok(node) => node.rrsets().update(rrset, Version::default()),
Err(apex) => apex.rrsets().update(rrset, Version::default()),
}
Ok(())
}
pub fn insert_zone_cut(
&mut self,
name: &impl ToName,
ns: SharedRrset,
ds: Option<SharedRrset>,
glue: Vec<StoredRecord>,
) -> Result<(), ZoneCutError> {
let node = self.get_node(self.apex.prepare_name(name)?)?;
let cut = ZoneCut {
name: name.to_bytes(),
ns,
ds,
glue,
};
node.update_special(Version::default(), Some(Special::Cut(cut)));
Ok(())
}
pub fn insert_cname(
&mut self,
name: &impl ToName,
cname: SharedRr,
) -> Result<(), CnameError> {
let node = self.get_node(self.apex.prepare_name(name)?)?;
node.update_special(Version::default(), Some(Special::Cname(cname)));
Ok(())
}
fn get_node<'l>(
&self,
mut name: impl Iterator<Item = &'l Label>,
) -> Result<Arc<ZoneNode>, &ZoneApex> {
let label = match name.next() {
Some(label) => label,
None => return Err(&self.apex),
};
let mut node = self
.apex
.children()
.with_or_default(label, |node, _| node.clone());
for label in name {
node = node
.children()
.with_or_default(label, |node, _| node.clone());
}
Ok(node)
}
}