1#![deny(missing_docs)]
18#![doc = include_str!("../README.md")]
19
20mod ber;
21mod ber_ref;
22mod buffer;
23mod contents;
24mod contents_ref;
25mod der;
26mod der_ref;
27mod id_tags;
28mod identifier;
29mod identifier_ref;
30mod length;
31mod length_buffer;
32mod misc;
33
34pub use ber::Ber;
35pub use ber_ref::BerRef;
36pub use buffer::Buffer;
37pub use contents::Contents;
38pub use contents_ref::ContentsRef;
39pub use der::Der;
40pub use der_ref::DerRef;
41pub use id_tags::{ClassTag, PCTag, TagNumber};
42pub use identifier::Id;
43pub use identifier_ref::IdRef;
44pub use length::Length;
45use length_buffer::LengthBuffer;
46use std::fmt;
47
48#[derive(Debug)]
50#[non_exhaustive]
51pub enum Error {
52 UnterminatedBytes,
54 RedundantBytes,
57 OverFlow,
59 IndefiniteLength,
62 BadEoc,
64 ExtraContentsOctet,
66 UnmatchedId,
68 InvalidUtf8,
70 InvalidDerBooleanContents,
72 InvalidKeyValuePair,
74 Io(std::io::Error),
79 Anyhow(anyhow::Error),
84}
85
86impl fmt::Display for Error {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 match self {
89 Self::UnterminatedBytes => f.write_str("The bytes finish before the last octet."),
90 Self::RedundantBytes => f.write_str("The bytes include some redundant octet(s)."),
91 Self::OverFlow => f.write_str("Over flow is occurred to parse bytes as a number."),
92 Self::IndefiniteLength => f.write_str("'Indefinite Length' is used where not allowed."),
93 Self::BadEoc => f.write_str("'Indefinite Length BER' includes a bad 'EOC.'"),
94 Self::ExtraContentsOctet => {
95 f.write_str("Contents include (an) invlid octet(s) at the end.")
96 }
97 Self::UnmatchedId => f.write_str("The identifier does not match to that of data type."),
98 Self::InvalidUtf8 => f.write_str("Invalid as UTF-8."),
99 Self::InvalidDerBooleanContents => {
100 f.write_str("The contents of DER BOOLEAN must be 0x00 or 0xFF.")
101 }
102 Self::InvalidKeyValuePair => f.write_str("SEQUENCE of key-value pair is required."),
103 Self::Io(err) => err.fmt(f),
104 Self::Anyhow(err) => err.fmt(f),
105 }
106 }
107}
108
109impl std::error::Error for Error {}
110
111impl PartialEq for Error {
112 fn eq(&self, other: &Self) -> bool {
113 match self {
114 Self::UnterminatedBytes => matches!(other, Self::UnterminatedBytes),
115 Self::RedundantBytes => matches!(other, Self::RedundantBytes),
116 Self::OverFlow => matches!(other, Self::OverFlow),
117 Self::IndefiniteLength => matches!(other, Self::IndefiniteLength),
118 Self::BadEoc => matches!(other, Self::BadEoc),
119 Self::ExtraContentsOctet => matches!(other, Self::ExtraContentsOctet),
120 Self::UnmatchedId => matches!(other, Self::UnmatchedId),
121 Self::InvalidUtf8 => matches!(other, Self::InvalidUtf8),
122 Self::InvalidDerBooleanContents => matches!(other, Self::InvalidDerBooleanContents),
123 Self::InvalidKeyValuePair => matches!(other, Self::InvalidKeyValuePair),
124 Self::Io(_) => false,
125 Self::Anyhow(_) => false,
126 }
127 }
128}
129
130impl From<std::io::Error> for Error {
131 fn from(err: std::io::Error) -> Self {
132 Self::Io(err)
133 }
134}
135
136impl From<anyhow::Error> for Error {
137 fn from(err: anyhow::Error) -> Self {
138 Self::Anyhow(err)
139 }
140}
141
142impl Error {
143 pub fn into_anyhow(self) -> anyhow::Error {
148 match self {
149 Self::Anyhow(err) => err,
150 _ => anyhow::Error::new(self),
151 }
152 }
153
154 pub fn as_anyhow(&self) -> Option<&anyhow::Error> {
157 match self {
158 Self::Anyhow(err) => Some(err),
159 _ => None,
160 }
161 }
162
163 pub fn context<C>(self, context: C) -> Self
165 where
166 C: fmt::Display + Send + Sync + 'static,
167 {
168 self.into_anyhow().context(context).into()
169 }
170
171 pub fn root_cause(&self) -> &Self {
174 match self {
175 Self::Anyhow(err) => {
176 let mut ret = self;
177 for cause in err.chain() {
178 if let Some(e) = cause.downcast_ref::<Self>() {
179 ret = e;
180 } else {
181 break;
182 }
183 }
184 return ret;
185 }
186 _ => self,
187 }
188 }
189}