#![deny(missing_docs)]
#![doc = include_str!("../README.md")]
mod ber;
mod ber_ref;
mod buffer;
mod contents;
mod contents_ref;
mod der;
mod der_ref;
mod id_tags;
mod identifier;
mod identifier_ref;
mod length;
mod length_buffer;
mod misc;
pub use ber::Ber;
pub use ber_ref::BerRef;
pub use buffer::Buffer;
pub use contents::Contents;
pub use contents_ref::ContentsRef;
pub use der::Der;
pub use der_ref::DerRef;
pub use id_tags::{ClassTag, PCTag, TagNumber};
pub use identifier::Id;
pub use identifier_ref::IdRef;
pub use length::Length;
use length_buffer::LengthBuffer;
use std::fmt;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
UnterminatedBytes,
RedundantBytes,
OverFlow,
IndefiniteLength,
BadEoc,
ExtraContentsOctet,
UnmatchedId,
InvalidUtf8,
InvalidDerBooleanContents,
InvalidKeyValuePair,
Io(std::io::Error),
Anyhow(anyhow::Error),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnterminatedBytes => f.write_str("The bytes finish before the last octet."),
Self::RedundantBytes => f.write_str("The bytes include some redundant octet(s)."),
Self::OverFlow => f.write_str("Over flow is occurred to parse bytes as a number."),
Self::IndefiniteLength => f.write_str("'Indefinite Length' is used where not allowed."),
Self::BadEoc => f.write_str("'Indefinite Length BER' includes a bad 'EOC.'"),
Self::ExtraContentsOctet => {
f.write_str("Contents include (an) invlid octet(s) at the end.")
}
Self::UnmatchedId => f.write_str("The identifier does not match to that of data type."),
Self::InvalidUtf8 => f.write_str("Invalid as UTF-8."),
Self::InvalidDerBooleanContents => {
f.write_str("The contents of DER BOOLEAN must be 0x00 or 0xFF.")
}
Self::InvalidKeyValuePair => f.write_str("SEQUENCE of key-value pair is required."),
Self::Io(err) => err.fmt(f),
Self::Anyhow(err) => err.fmt(f),
}
}
}
impl std::error::Error for Error {}
impl PartialEq for Error {
fn eq(&self, other: &Self) -> bool {
match self {
Self::UnterminatedBytes => matches!(other, Self::UnterminatedBytes),
Self::RedundantBytes => matches!(other, Self::RedundantBytes),
Self::OverFlow => matches!(other, Self::OverFlow),
Self::IndefiniteLength => matches!(other, Self::IndefiniteLength),
Self::BadEoc => matches!(other, Self::BadEoc),
Self::ExtraContentsOctet => matches!(other, Self::ExtraContentsOctet),
Self::UnmatchedId => matches!(other, Self::UnmatchedId),
Self::InvalidUtf8 => matches!(other, Self::InvalidUtf8),
Self::InvalidDerBooleanContents => matches!(other, Self::InvalidDerBooleanContents),
Self::InvalidKeyValuePair => matches!(other, Self::InvalidKeyValuePair),
Self::Io(_) => false,
Self::Anyhow(_) => false,
}
}
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Self::Io(err)
}
}
impl From<anyhow::Error> for Error {
fn from(err: anyhow::Error) -> Self {
Self::Anyhow(err)
}
}
impl Error {
pub fn into_anyhow(self) -> anyhow::Error {
match self {
Self::Anyhow(err) => err,
_ => anyhow::Error::new(self),
}
}
pub fn as_anyhow(&self) -> Option<&anyhow::Error> {
match self {
Self::Anyhow(err) => Some(err),
_ => None,
}
}
pub fn context<C>(self, context: C) -> Self
where
C: fmt::Display + Send + Sync + 'static,
{
self.into_anyhow().context(context).into()
}
pub fn root_cause(&self) -> &Self {
match self {
Self::Anyhow(err) => {
let mut ret = self;
for cause in err.chain() {
if let Some(e) = cause.downcast_ref::<Self>() {
ret = e;
} else {
break;
}
}
return ret;
}
_ => self,
}
}
}