use derive_more::{Display, IsVariant, TryUnwrap, Unwrap};
use crate::{name::LabelTooLongDetail, wire::*};
cfg_heap! {
use crate::{Name, QueryHandle, ServiceHandle};
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Display, thiserror::Error)]
#[display("buffer too short: needed {needed} bytes at offset {at}, had {have}")]
pub struct BufferTooShortDetail {
needed: usize,
at: usize,
have: usize,
}
impl BufferTooShortDetail {
#[inline(always)]
pub const fn new(needed: usize, at: usize, have: usize) -> Self {
Self { needed, at, have }
}
#[inline(always)]
pub const fn needed(&self) -> usize {
self.needed
}
#[inline(always)]
pub const fn at(&self) -> usize {
self.at
}
#[inline(always)]
pub const fn have(&self) -> usize {
self.have
}
#[inline(always)]
pub const fn is_empty(&self) -> bool {
self.have == 0
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Display, thiserror::Error)]
#[display("output buffer too small: needed {needed} bytes, have {have}")]
pub struct BufferTooSmallDetail {
needed: usize,
have: usize,
}
impl BufferTooSmallDetail {
#[inline(always)]
pub const fn new(needed: usize, have: usize) -> Self {
Self { needed, have }
}
#[inline(always)]
pub const fn needed(&self) -> usize {
self.needed
}
#[inline(always)]
pub const fn have(&self) -> usize {
self.have
}
#[inline(always)]
pub const fn is_empty(&self) -> bool {
self.have == 0
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Display, thiserror::Error)]
#[display("compression pointer points forward: ptr {ptr} > current {at}")]
pub struct PointerForwardDetail {
ptr: u16,
at: u16,
}
impl PointerForwardDetail {
#[inline(always)]
pub const fn new(ptr: u16, at: u16) -> Self {
Self { ptr, at }
}
#[inline(always)]
pub const fn ptr(&self) -> u16 {
self.ptr
}
#[inline(always)]
pub const fn at(&self) -> u16 {
self.at
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Display, thiserror::Error)]
#[display("rdlength {rdlen} at offset {at} exceeds remaining {rem} bytes")]
pub struct RdlengthOverrunDetail {
rdlen: u16,
at: usize,
rem: usize,
}
impl RdlengthOverrunDetail {
#[inline(always)]
pub const fn new(rdlen: u16, at: usize, rem: usize) -> Self {
Self { rdlen, at, rem }
}
#[inline(always)]
pub const fn rdlen(&self) -> u16 {
self.rdlen
}
#[inline(always)]
pub const fn at(&self) -> usize {
self.at
}
#[inline(always)]
pub const fn rem(&self) -> usize {
self.rem
}
}
#[derive(Debug, Clone, IsVariant, Unwrap, TryUnwrap, thiserror::Error)]
#[unwrap(ref)]
#[try_unwrap(ref)]
#[non_exhaustive]
pub enum ParseError {
#[error(transparent)]
BufferTooShort(BufferTooShortDetail),
#[error(transparent)]
LabelTooLong(LabelTooLongDetail),
#[error("name exceeds max length {0} bytes")]
NameTooLong(usize),
#[error("name compression pointer cycle detected")]
PointerCycle,
#[error("name compression pointer chain exceeded {0} hops")]
PointerChainTooLong(u8),
#[error(transparent)]
PointerForward(PointerForwardDetail),
#[error("unknown label kind in byte {0:#010b}")]
InvalidLabelKind(u8),
#[error(transparent)]
RdlengthOverrun(RdlengthOverrunDetail),
#[error(transparent)]
IntegerConversion(#[from] core::num::TryFromIntError),
#[error("unsupported name-bearing record type {0}")]
UnsupportedNameBearingType(u16),
}
#[derive(Debug, Clone, IsVariant, Unwrap, TryUnwrap, thiserror::Error)]
#[unwrap(ref)]
#[try_unwrap(ref)]
#[non_exhaustive]
pub enum EncodeError {
#[error(transparent)]
BufferTooSmall(BufferTooSmallDetail),
#[error(transparent)]
IntegerConversion(#[from] core::num::TryFromIntError),
}
#[derive(Debug, Clone, IsVariant, Unwrap, TryUnwrap, thiserror::Error)]
#[unwrap(ref)]
#[try_unwrap(ref)]
#[non_exhaustive]
pub enum HandleTimeoutError {
#[error("deadline arithmetic overflow")]
Overflow,
}
#[derive(Debug, Clone, IsVariant, Unwrap, TryUnwrap, thiserror::Error)]
#[unwrap(ref)]
#[try_unwrap(ref)]
#[non_exhaustive]
pub enum TransmitError {
#[error(transparent)]
BufferTooSmall(BufferTooSmallDetail),
}
#[derive(Debug, Clone, Eq, PartialEq, thiserror::Error)]
#[non_exhaustive]
#[error("pool capacity exceeded")]
pub struct StorageFullError;
#[derive(Debug, Clone, IsVariant, Unwrap, TryUnwrap, thiserror::Error)]
#[unwrap(ref)]
#[try_unwrap(ref)]
#[non_exhaustive]
pub enum HandleError {
#[error(transparent)]
Parse(#[from] ParseError),
#[error("incoming opcode `{0}` is not Query")]
InvalidOpcode(Opcode),
#[error("incoming response code `{0}` is not NoError")]
InvalidResponseCode(ResponseCode),
}
cfg_heap! {
#[derive(Debug, Clone, IsVariant, Unwrap, TryUnwrap, thiserror::Error)]
#[unwrap(ref)]
#[try_unwrap(ref)]
#[non_exhaustive]
pub enum RegisterServiceError {
#[error("service `{0}` already registered")]
NameAlreadyRegistered(crate::Name),
#[error(transparent)]
StorageFull(#[from] StorageFullError),
}
}
#[derive(Debug, Clone, IsVariant, Unwrap, TryUnwrap, thiserror::Error)]
#[unwrap(ref)]
#[try_unwrap(ref)]
#[non_exhaustive]
pub enum StartQueryError {
#[error(transparent)]
StorageFull(#[from] StorageFullError),
}
cfg_heap! {
#[derive(Debug, Clone, IsVariant, Unwrap, TryUnwrap, thiserror::Error)]
#[unwrap(ref)]
#[try_unwrap(ref)]
#[non_exhaustive]
pub enum HandleServiceRenamedError {
#[error("name `{0}` is already registered to a different service")]
NameAlreadyRegistered(Name),
#[error("service handle {0} not found")]
ServiceNotFound(ServiceHandle),
}
#[derive(Debug, Clone, IsVariant, Unwrap, TryUnwrap, thiserror::Error)]
#[unwrap(ref)]
#[try_unwrap(ref)]
#[non_exhaustive]
pub enum CancelQueryError {
#[error("query handle {0} not found")]
QueryNotFound(QueryHandle),
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests;