#![allow(unknown_lints)]
#![allow(rustdoc::private_intra_doc_links)]
#[cfg_attr(doctest, macro_export)]
macro_rules! builder {
{
@method_real ($b:lifetime $P:ident) ($builder:ident) ($($state:ident)?) ($(#[$meta:meta])*) ($vis:vis) ($method:ident) ($($($fgeneric:tt)+)?) ($self:ident $($arg:tt)*) ($($ret:ty)?) ($($body:tt)*) } => {
$(#[$meta])*
#[allow(unused_mut)]
$vis fn $method $(<$($fgeneric)+>)? (mut $self $($arg)*) $(-> $ret)? { $($body)* }
};
{
@method ($b:lifetime $P:ident) ($builder:ident) ($($state:ident)?) $_:tt $meta:tt $vis:tt $method:tt $fgeneric:tt $args:tt ($($ret:ty)?) ({$($body:tt)*}) } => {
builder! {
@method_real ($b $P)
($builder) ($($state)?)
$meta $vis $method
$fgeneric $args
($($ret)?)
({$($body)*})
}
};
{
@method ($b:lifetime $P:ident) ($builder:ident) ($($state:ident)?) ($parent:ty) $meta:tt $vis:tt $method:tt $fgeneric:tt $args:tt () ( [into $state2:tt] {$($body:tt)*} ) } => {
builder! {
@method_real ($b $P)
($builder) ($($state)?)
$meta $vis $method
$fgeneric $args
($builder<$b, $parent, $state2>)
({$($body)*}.into())
}
};
{
@method ($b:lifetime $P:ident) ($builder:ident) ($($state:ident)?) ($parent:ty) $meta:tt $vis:tt $method:tt $fgeneric:tt $args:tt () ( [try_into $state2:tt | $etype:ident] {$($body:tt)*} ) } => {
builder! {
@method_real ($b $P)
($builder) ($($state)?)
$meta $vis $method
$fgeneric $args
(Result<$builder<$b, $parent, $state2>, $etype>)
({$($body)*}.try_into())
}
};
{
@method ($b:lifetime $P:ident) ($builder:ident) ($($state:ident)?) ($parent:ty) $meta:tt $vis:tt $method:tt $fgeneric:tt $args:tt () ( [push $builder2:ident$(<$state2:tt>)? | $etype:ident::$evariant:ident] {$($body:tt)*} ) } => {
builder!{
@method_real ($b $P)
($builder) ($($state)?)
$meta $vis $method
$fgeneric $args
(Result<
$builder2<$b, $builder<$b, $parent $(, $state)?> $(, $state2)?>,
$etype
>)
($builder2::push({$($body)*}).map_err($etype::$evariant))
}
};
{
@impl ($b:lifetime $P:ident) ($($bgeneric:tt)+) ($builder:ident) $state:tt ($parent:ty) ($($($igeneric:tt)+)?) $(($($item:tt)*))* } => {
impl<$b, $P: Builder<$b> $(, $($igeneric)+)?>
$builder<$($bgeneric)+> {
$(builder! {
@method ($b $P)
($builder) $state
($parent)
$($item)*
})*
}
};
{
<$b:lifetime, $P:ident> $builder:ident {
$(Builder $([$($bgeneric:tt)+])?;)?
$(@ <$parent:ty> $($state:ident)? $([$($igeneric:tt)+])?: $(
$(#[$meta:meta])* $vis:vis fn $method:ident
$([$($fgeneric:tt)+])? (mut $self:ident $($arg:tt)*)
$(-> $ret:ty)? =
$([$($special:tt)+])?
{$($body:tt)*}
)*)*
}
} => {
$(impl<$b, $P: Builder<$b> $(, $($bgeneric)+)?>
Builder<$b> for $builder<$b, $P $(, $($bgeneric)+)?> {
fn sink(&mut self) -> &mut Sink<$b> {
self.parent.sink()
}
})?
$(builder! {
@impl ($b $P)
($b, $parent $(, $state)?)
($builder) ($($state)?)
($parent)
($($($igeneric)+)?)
$((
($(#[$meta])*) ($vis) ($method)
($($($fgeneric)+)?) ($self $($arg)*)
($($ret)?)
($([$($special)+])? {$($body)*})
))*
})*
};
}
macro_rules! transition {
{$($builder:ident.$field:ident {$(($($extra:ident),*) $from:ident -> $to:ident;)*})*} => {$($(
impl<'b, P: Builder<'b>> From<$builder<'b, P, $from>> for $builder<'b, P, $to> {
fn from(builder: $builder<'b, P, $from>) -> Self {
$builder {
$field: $to,
$($extra: builder.$extra,)*
}
}
}
)*)*};
}
#[cfg(test)]
pub mod example;
pub mod extension;
pub mod message;
pub mod name;
pub mod question;
pub mod record;
use crate::view::Message;
pub use self::extension::ExtensionBuilder;
pub use self::message::MessageBuilder;
pub use self::name::NameBuilder;
pub use self::question::QuestionBuilder;
pub use self::record::RecordBuilder;
use core::num::NonZeroU16;
use core::ops::{DerefMut, Range};
use arrayvec::ArrayVec;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
pub trait Buffer: DerefMut<Target = [u8]> {
fn resize_zero(&mut self, len: usize);
fn capacity_limit(&self) -> Option<usize>;
}
pub struct Sink<'b> {
inner: &'b mut dyn Buffer,
limit: Option<NonZeroU16>,
}
error!(SinkError);
#[derive(Debug, displaydoc::Display)]
#[prefix_enum_doc_attributes]
pub enum SinkError {
InnerNotEmpty(usize),
LimitTooHigh(Option<NonZeroU16>, usize),
CapacityLimitTooHigh(usize),
}
error!(GrowError);
#[derive(Debug, displaydoc::Display)]
#[prefix_enum_doc_attributes]
pub enum GrowError {
Overflow(usize, usize),
Limit(usize, usize, NonZeroU16),
}
impl<'b> Sink<'b> {
pub fn new(inner: &'b mut dyn Buffer) -> Result<Self, SinkError> {
let limit = Self::capacity_limit(inner)?;
Self::with_limit(inner, limit)
}
pub fn with_limit(
inner: &'b mut dyn Buffer,
limit: impl Into<Option<u16>>,
) -> Result<Self, SinkError> {
Self::new0(inner, limit.into())
}
pub fn limit(&self) -> Option<NonZeroU16> {
self.limit
}
pub fn finish(self) -> &'b mut dyn Buffer {
self.inner
}
fn new0(inner: &'b mut dyn Buffer, limit: Option<u16>) -> Result<Self, SinkError> {
if !inner.is_empty() {
return Err(SinkError::InnerNotEmpty(inner.len()));
}
let limit = limit
.map(|x| x.max(512))
.map(|x| NonZeroU16::new(x))
.map(|x| x.expect("clamp to [512, ∞) makes this infallible"));
match (limit, inner.capacity_limit()) {
(None, Some(x)) => return Err(SinkError::LimitTooHigh(None, x)),
(Some(y), Some(x)) if usize::from(u16::from(y)) > x => {
return Err(SinkError::LimitTooHigh(Some(y), x))
}
_ => {}
}
Ok(Sink { inner, limit })
}
fn grow_range(&mut self, delta: usize) -> Result<Range<usize>, GrowError> {
let start = self.inner().len();
let stop = start
.checked_add(delta)
.ok_or_else(|| GrowError::Overflow(start, delta))?;
if let Some(limit) = self.limit {
if stop > usize::from(limit.get()) {
return Err(GrowError::Limit(start, delta, limit));
}
}
self.inner.resize_zero(stop);
Ok(start..stop)
}
fn grow_mut(&mut self, delta: usize) -> Result<&mut [u8], GrowError> {
let result = self.grow_range(delta)?;
Ok(&mut self.inner_mut()[result])
}
fn inner(&self) -> &[u8] {
&*self.inner
}
fn inner_mut(&mut self) -> &mut [u8] {
&mut *self.inner
}
}
impl Sink<'_> {
pub fn capacity_limit(buffer: &dyn Buffer) -> Result<Option<u16>, SinkError> {
Ok(match buffer.capacity_limit() {
Some(x) => Some(u16::try_from(x).map_err(|_| SinkError::CapacityLimitTooHigh(x))?),
None => None,
})
}
pub fn response_limit(
buffer: &dyn Buffer,
udp: bool,
query: &Message,
) -> Result<Option<u16>, SinkError> {
let capacity_limit = Self::capacity_limit(buffer);
if !udp {
return capacity_limit;
}
Ok(Some(match capacity_limit {
Ok(Some(x)) => x.min(query.udp_limit()),
Ok(None) => query.udp_limit(),
Err(SinkError::CapacityLimitTooHigh(_)) => query.udp_limit(),
Err(_) => unreachable!(),
}))
}
}
impl<const N: usize> Buffer for ArrayVec<u8, N> {
fn resize_zero(&mut self, len: usize) {
self.truncate(len);
while self.len() < len {
self.push(0);
}
}
fn capacity_limit(&self) -> Option<usize> {
Some(self.capacity())
}
}
#[cfg(feature = "alloc")]
impl Buffer for Vec<u8> {
fn resize_zero(&mut self, len: usize) {
self.truncate(len);
if self.len() < len {
self.resize(len, 0);
}
}
fn capacity_limit(&self) -> Option<usize> {
None
}
}
impl<'b, const N: usize> TryFrom<&'b mut ArrayVec<u8, N>> for Sink<'b> {
type Error = SinkError;
fn try_from(inner: &'b mut ArrayVec<u8, N>) -> Result<Self, Self::Error> {
Self::new(inner)
}
}
#[cfg(feature = "alloc")]
impl<'b> TryFrom<&'b mut Vec<u8>> for Sink<'b> {
type Error = SinkError;
fn try_from(inner: &'b mut Vec<u8>) -> Result<Self, Self::Error> {
Self::new(inner)
}
}
#[must_use]
pub trait Builder<'b>: Sized {
fn sink(&mut self) -> &mut Sink<'b>;
}
pub trait ChildBuilder<'b, P: Builder<'b>>: Builder<'b> {
fn parent(&mut self) -> &mut P;
}
pub trait PushBuilder<'b, P: Builder<'b>>: ChildBuilder<'b, P> {
type Error;
fn push(parent: P) -> Result<Self, Self::Error>;
}
pub trait NewBuilder<'b>: PushBuilder<'b, Sink<'b>> {
fn new(sink: Sink<'b>) -> Result<Self, Self::Error> {
Ok(Self::push(sink)?)
}
}
impl<'b, T: PushBuilder<'b, Sink<'b>>> NewBuilder<'b> for T {}
impl<'b> Builder<'b> for Sink<'b> {
fn sink(&mut self) -> &mut Sink<'b> {
self
}
}
#[cfg(test)]
mod test {
use arrayvec::ArrayVec;
use assert_matches::assert_matches;
use crate::core::{Class, Rcode, Type};
use crate::view::{Message, View};
use super::message::{MessageBuilder, MessageError};
use super::name::NameBuilder;
use super::{NewBuilder, Sink, SinkError};
declare_any_error!(AnyError);
fn a12() -> ArrayVec<u8, 4096> {
ArrayVec::new()
}
fn a16() -> ArrayVec<u8, 65536> {
ArrayVec::new()
}
#[test]
fn empty() {
assert_matches!(
Sink::try_from(&mut ArrayVec::from([0])).and(Ok(())),
Err(SinkError::InnerNotEmpty(1))
);
}
#[rustfmt::skip]
#[test]
fn limit() -> Result<(), AnyError> {
use core::num::NonZeroU16;
assert_eq!(Sink::new(&mut a12())?.limit.map(NonZeroU16::get), Some(4096));
assert_matches!(Sink::new(&mut a16()).and(Ok(())), Err(SinkError::CapacityLimitTooHigh(65536)));
assert_eq!(Sink::with_limit(&mut a16(), 65535)?.limit.map(NonZeroU16::get), Some(65535));
assert_eq!(Sink::with_limit(&mut a12(), 0)?.limit.map(NonZeroU16::get), Some(512));
assert_eq!(Sink::with_limit(&mut a12(), 1)?.limit.map(NonZeroU16::get), Some(512));
assert_eq!(Sink::with_limit(&mut a12(), 511)?.limit.map(NonZeroU16::get), Some(512));
assert_eq!(Sink::with_limit(&mut a12(), 512)?.limit.map(NonZeroU16::get), Some(512));
assert_eq!(Sink::with_limit(&mut a12(), 513)?.limit.map(NonZeroU16::get), Some(513));
assert_eq!(Sink::with_limit(&mut a12(), 4096)?.limit.map(NonZeroU16::get), Some(4096));
assert_matches!(Sink::with_limit(&mut a12(), 4097).and(Ok(())), Err(SinkError::LimitTooHigh(Some(x), 4096)) if x == NonZeroU16::new(4097).unwrap());
Ok(())
}
#[cfg(feature = "alloc")]
#[rustfmt::skip]
#[test]
fn limit_alloc() -> Result<(), AnyError> {
use core::num::NonZeroU16;
use alloc::vec;
assert_eq!(Sink::new(&mut vec![])?.limit, None);
assert_eq!(Sink::with_limit(&mut vec![], 0)?.limit.map(NonZeroU16::get), Some(512));
assert_eq!(Sink::with_limit(&mut vec![], 1)?.limit.map(NonZeroU16::get), Some(512));
assert_eq!(Sink::with_limit(&mut vec![], 511)?.limit.map(NonZeroU16::get), Some(512));
assert_eq!(Sink::with_limit(&mut vec![], 512)?.limit.map(NonZeroU16::get), Some(512));
assert_eq!(Sink::with_limit(&mut vec![], 513)?.limit.map(NonZeroU16::get), Some(513));
assert_eq!(Sink::with_limit(&mut vec![], 65535)?.limit.map(NonZeroU16::get), Some(65535));
Ok(())
}
#[test]
#[rustfmt::skip]
fn message() -> Result<(), AnyError> {
assert_eq!(**MessageBuilder::new((&mut a12()).try_into()?)?.finish()?.finish(), [0; 12]);
MessageBuilder::new((&mut a12()).try_into()?)?
.question()?.qname()?.finish_question(Type::ANY, Class::IN)?
.question()?.qname()?.finish_question(Type::ANY, Class::IN)?
.into_an()
.record()?.name()?.try_into_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.finish()?
.into_ns()
.record()?.name()?.try_into_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.finish()?
.into_ar()
.record()?.name()?.try_into_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.finish()?
.finish()?.finish();
let mut buffer = a12();
let result = MessageBuilder::new((&mut buffer).try_into()?)?.rcode(Rcode::Refused).finish()?.finish();
let (result, _) = Message::view(&result, ..)?;
assert_eq!(result.rcode(), Rcode::Refused);
let mut buffer = a12();
assert_matches!(MessageBuilder::new((&mut buffer).try_into()?)?.rcode(Rcode::BADVERS)
.extension()?.finish()?.finish().err(),
None);
let mut buffer = a12();
assert_matches!(MessageBuilder::new((&mut buffer).try_into()?)?.rcode(Rcode::BADVERS)
.finish().err(),
Some(MessageError::ExtensionRequired(16)));
Ok(())
}
#[cfg(feature = "alloc")]
#[test]
#[rustfmt::skip]
fn message_alloc() -> Result<(), AnyError> {
use alloc::vec;
use crate::core::{Type, Class};
let mut buffer = vec![];
let mut result = MessageBuilder::new((&mut buffer).try_into()?)?;
for _ in 0..65535 { result = result.question()?.finish(Type::new(0), Class::new(0))?; }
assert_matches!(result.question().err(), Some(MessageError::QdTooManyQuestions));
let mut buffer = vec![];
let mut result = MessageBuilder::new((&mut buffer).try_into()?)?.into_an();
for _ in 0..65535 { result = result.record()?.try_into_rdata()?.finish()?; }
assert_matches!(result.record().err(), Some(MessageError::AnTooManyRecords));
let mut buffer = vec![];
let mut result = MessageBuilder::new((&mut buffer).try_into()?)?.into_ns();
for _ in 0..65535 { result = result.record()?.try_into_rdata()?.finish()?; }
assert_matches!(result.record().err(), Some(MessageError::NsTooManyRecords));
let mut buffer = vec![];
let mut result = MessageBuilder::new((&mut buffer).try_into()?)?.into_ar();
for _ in 0..65535 { result = result.record()?.try_into_rdata()?.finish()?; }
assert_matches!(result.record().err(), Some(MessageError::ArTooManyRecords));
Ok(())
}
#[test]
fn question() -> Result<(), AnyError> {
#[rustfmt::skip]
assert_eq!(**MessageBuilder::new((&mut a12()).try_into()?)?.question()?.qname()?.finish_question(Type::ANY, Class::IN)?.finish()?.finish(),
*b"\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\0\x00\xFF\x00\x01");
Ok(())
}
#[test]
fn extension() -> Result<(), AnyError> {
#[rustfmt::skip]
assert_eq!(**MessageBuilder::new((&mut a12()).try_into()?)?.rcode(Rcode::new(0xABC)?).extension()?.udp(0x1234).version(0x56).r#do(true).finish()?.finish()?.finish(),
*b"\x00\x00\x00\x0C\x00\x00\x00\x00\x00\x00\x00\x01\0\x00\x29\x12\x34\xAB\x56\x80\x00\x00\x00");
Ok(())
}
#[rustfmt::skip]
#[test]
fn name() -> Result<(), AnyError> {
use super::name::NameError;
assert_matches!(NameBuilder::new((&mut a12()).try_into()?)?.label(&[0; 0]).and(Ok(())),
Err(NameError::EmptyLabel));
assert_matches!(NameBuilder::new((&mut a12()).try_into()?)?.label(&[0; 1]).and(Ok(())),
Ok(()));
assert_matches!(NameBuilder::new((&mut a12()).try_into()?)?.label(&[0; 63]).and(Ok(())),
Ok(()));
assert_matches!(NameBuilder::new((&mut a12()).try_into()?)?.label(&[0; 64]).and(Ok(())),
Err(NameError::LabelTooLong));
NameBuilder::new((&mut a12()).try_into()?)?
.label(&[0; 63])?.label(&[0; 63])?.label(&[0; 63])?.label(&[0; 62])?
.finish()?.finish();
assert_matches!(
NameBuilder::new((&mut a12()).try_into()?)?
.label(&[0; 63])?
.label(&[0; 63])?
.label(&[0; 63])?
.label(&[0; 63])
.and(Ok(())),
Err(NameError::NameTooLong));
assert_eq!(**NameBuilder::new((&mut a12()).try_into()?)?.label(b"daria")?.label(b"daz")?.label(b"cat")?.finish()?.finish(),
*b"\x05daria\x03daz\x03cat\0");
assert_eq!(**NameBuilder::new((&mut a12()).try_into()?)?.labels(br"")?.finish()?.finish(), *b"\0");
assert_eq!(**NameBuilder::new((&mut a12()).try_into()?)?.labels(br"daria.daz.cat.")?.finish()?.finish(), *b"\x05daria\x03daz\x03cat\0");
assert_eq!(**NameBuilder::new((&mut a12()).try_into()?)?.labels(br"Action\.domains.")?.finish()?.finish(), *b"\x0EAction.domains\0");
assert_eq!(**NameBuilder::new((&mut a12()).try_into()?)?.labels(br"\000.")?.finish()?.finish(), *b"\x01\0\0");
assert_eq!(**NameBuilder::new((&mut a12()).try_into()?)?.labels(br"\255.")?.finish()?.finish(), *b"\x01\xFF\0");
assert_matches!(NameBuilder::new((&mut a12()).try_into()?)?.labels(br".").and(Ok(())), Err(NameError::EmptyLabel));
assert_matches!(NameBuilder::new((&mut a12()).try_into()?)?.labels(br"x").and(Ok(())), Err(NameError::UnfinishedLabel));
assert_matches!(NameBuilder::new((&mut a12()).try_into()?)?.labels(br"\").and(Ok(())), Err(NameError::UnfinishedEscape));
assert_matches!(NameBuilder::new((&mut a12()).try_into()?)?.labels(br"\0").and(Ok(())), Err(NameError::UnfinishedEscape));
assert_matches!(NameBuilder::new((&mut a12()).try_into()?)?.labels(br"\00").and(Ok(())), Err(NameError::UnfinishedEscape));
assert_matches!(NameBuilder::new((&mut a12()).try_into()?)?.labels(br"\00.").and(Ok(())), Err(NameError::DecimalEscapeSyntax(b'.')));
assert_matches!(NameBuilder::new((&mut a12()).try_into()?)?.labels(br"\256").and(Ok(())), Err(NameError::DecimalEscapeRange(256)));
Ok(())
}
}
#[cfg(all(test, feature = "bench"))]
mod bench {
mod build {
extern crate test;
use test::Bencher;
use super::super::message::MessageBuilder;
use super::super::name::NameBuilder;
use super::super::{Buffer, NewBuilder, Sink};
use crate::core::{Class, Ttl, Type};
declare_any_error!(AnyError);
fn query<B: Buffer, F: Fn() -> B>(bencher: &mut Bencher, buffer: F) {
bencher.iter(|| -> Result<usize, AnyError> {
Ok(MessageBuilder::new(Sink::new(&mut buffer())?)?
.id(0x1313)
.qr(false)
.rd(true)
.question()?
.qname()?
.labels(b"daria.daz.cat.")?
.finish_question(Type::A, Class::IN)?
.extension()?
.finish()?
.finish()?
.finish()
.len())
});
}
#[bench]
fn query_vec(bencher: &mut Bencher) {
query(bencher, || alloc::vec![])
}
#[bench]
fn query_arrayvec(bencher: &mut Bencher) {
query(bencher, || arrayvec::ArrayVec::<_, 4096>::new())
}
#[rustfmt::skip]
fn roots<B: Buffer, F: Fn() -> B>(bencher: &mut Bencher, buffer: F) {
bencher.iter(|| -> Result<usize, AnyError> {
Ok(MessageBuilder::new(Sink::new(&mut buffer())?)?
.id(0x1313)
.qr(true)
.rd(true)
.ra(true)
.question()?.qname()?.finish_question(Type::NS, Class::IN)?
.into_an()
.record()?.name()?.try_into_rdata()?.r#type(Type::NS).class(Class::IN).ttl(Ttl::new(518400)).build_rdata::<NameBuilder<_>>()?.labels(b"a.root-servers.net.")?.return_to_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.r#type(Type::NS).class(Class::IN).ttl(Ttl::new(518400)).build_rdata::<NameBuilder<_>>()?.labels(b"b.root-servers.net.")?.return_to_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.r#type(Type::NS).class(Class::IN).ttl(Ttl::new(518400)).build_rdata::<NameBuilder<_>>()?.labels(b"c.root-servers.net.")?.return_to_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.r#type(Type::NS).class(Class::IN).ttl(Ttl::new(518400)).build_rdata::<NameBuilder<_>>()?.labels(b"d.root-servers.net.")?.return_to_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.r#type(Type::NS).class(Class::IN).ttl(Ttl::new(518400)).build_rdata::<NameBuilder<_>>()?.labels(b"e.root-servers.net.")?.return_to_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.r#type(Type::NS).class(Class::IN).ttl(Ttl::new(518400)).build_rdata::<NameBuilder<_>>()?.labels(b"f.root-servers.net.")?.return_to_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.r#type(Type::NS).class(Class::IN).ttl(Ttl::new(518400)).build_rdata::<NameBuilder<_>>()?.labels(b"g.root-servers.net.")?.return_to_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.r#type(Type::NS).class(Class::IN).ttl(Ttl::new(518400)).build_rdata::<NameBuilder<_>>()?.labels(b"h.root-servers.net.")?.return_to_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.r#type(Type::NS).class(Class::IN).ttl(Ttl::new(518400)).build_rdata::<NameBuilder<_>>()?.labels(b"i.root-servers.net.")?.return_to_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.r#type(Type::NS).class(Class::IN).ttl(Ttl::new(518400)).build_rdata::<NameBuilder<_>>()?.labels(b"j.root-servers.net.")?.return_to_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.r#type(Type::NS).class(Class::IN).ttl(Ttl::new(518400)).build_rdata::<NameBuilder<_>>()?.labels(b"k.root-servers.net.")?.return_to_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.r#type(Type::NS).class(Class::IN).ttl(Ttl::new(518400)).build_rdata::<NameBuilder<_>>()?.labels(b"l.root-servers.net.")?.return_to_rdata()?.finish()?
.record()?.name()?.try_into_rdata()?.r#type(Type::NS).class(Class::IN).ttl(Ttl::new(518400)).build_rdata::<NameBuilder<_>>()?.labels(b"m.root-servers.net.")?.return_to_rdata()?.finish()?
.extension()?.finish()?
.finish()?
.finish()
.len())
});
}
#[bench]
fn roots_vec(bencher: &mut Bencher) {
roots(bencher, || alloc::vec![])
}
#[bench]
fn roots_arrayvec(bencher: &mut Bencher) {
roots(bencher, || arrayvec::ArrayVec::<_, 4096>::new())
}
fn name<B: Buffer, F: Fn() -> B>(bencher: &mut Bencher, buffer: F) {
bencher.iter(|| -> Result<usize, AnyError> {
Ok(NameBuilder::new(Sink::new(&mut buffer())?)?
.label(b"daria")?
.label(b"daz")?
.label(b"cat")?
.finish()?
.finish()
.len())
});
}
#[bench]
fn name_vec(bencher: &mut Bencher) {
name(bencher, || alloc::vec![])
}
#[bench]
fn name_arrayvec(bencher: &mut Bencher) {
name(bencher, || arrayvec::ArrayVec::<_, 4096>::new())
}
}
mod parse {
extern crate test;
use test::Bencher;
use super::super::name::NameBuilder;
use super::super::NewBuilder;
use crate::core::{Class, Type};
declare_any_error!(AnyError);
#[bench]
fn name(bencher: &mut Bencher) {
bencher.iter(|| -> Result<usize, AnyError> {
Ok(NameBuilder::new((&mut alloc::vec![]).try_into()?)?
.labels(b"daria.daz.cat.")?
.finish()?
.finish()
.len())
});
}
#[bench]
fn r#type(bencher: &mut Bencher) {
bencher.iter(|| "cname".parse::<Type>());
}
#[bench]
fn class(bencher: &mut Bencher) {
bencher.iter(|| "hs".parse::<Class>());
}
}
}