1use crate::prelude::Integer;
2use crate::types::constraints::{Bounded, Size};
3use snafu::Snafu;
4#[cfg(feature = "backtraces")]
5use snafu::{Backtrace, GenerateImplicitData};
6
7use alloc::{boxed::Box, string::ToString};
8
9#[derive(Debug)]
11#[non_exhaustive]
12pub enum CodecEncodeError {
13 Ber(BerEncodeErrorKind),
14 Cer(CerEncodeErrorKind),
15 Der(DerEncodeErrorKind),
16 Uper(UperEncodeErrorKind),
17 Aper(AperEncodeErrorKind),
18 Jer(JerEncodeErrorKind),
19 Coer(CoerEncodeErrorKind),
20}
21macro_rules! impl_from {
22 ($variant:ident, $error_kind:ty) => {
23 impl From<$error_kind> for EncodeError {
24 fn from(error: $error_kind) -> Self {
25 Self::from_codec_kind(CodecEncodeError::$variant(error))
26 }
27 }
28 };
29}
30
31impl_from!(Ber, BerEncodeErrorKind);
33impl_from!(Cer, CerEncodeErrorKind);
34impl_from!(Der, DerEncodeErrorKind);
35impl_from!(Uper, UperEncodeErrorKind);
36impl_from!(Aper, AperEncodeErrorKind);
37impl_from!(Jer, JerEncodeErrorKind);
38impl_from!(Coer, CoerEncodeErrorKind);
39
40impl From<CodecEncodeError> for EncodeError {
41 fn from(error: CodecEncodeError) -> Self {
42 Self::from_codec_kind(error)
43 }
44}
45
46#[derive(Debug)]
104#[allow(clippy::module_name_repetitions)]
105pub struct EncodeError {
106 pub kind: Box<EncodeErrorKind>,
107 pub codec: crate::Codec,
108 #[cfg(feature = "backtraces")]
109 pub backtrace: Backtrace,
110}
111impl core::fmt::Display for EncodeError {
112 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
113 writeln!(f, "Error Kind: {}", self.kind)?;
114 writeln!(f, "Codec: {}", self.kind)?;
115 #[cfg(feature = "backtraces")]
116 write!(f, "\nBacktrace:\n{}", self.backtrace)?;
117
118 Ok(())
119 }
120}
121impl EncodeError {
122 #[must_use]
123 pub fn alphabet_constraint_not_satisfied(
124 reason: super::strings::PermittedAlphabetError,
125 codec: crate::Codec,
126 ) -> Self {
127 Self::from_kind(
128 EncodeErrorKind::AlphabetConstraintNotSatisfied { reason },
129 codec,
130 )
131 }
132 #[must_use]
133 pub fn size_constraint_not_satisfied(
134 size: usize,
135 expected: &Size,
136 codec: crate::Codec,
137 ) -> Self {
138 Self::from_kind(
139 EncodeErrorKind::SizeConstraintNotSatisfied {
140 size,
141 expected: (**expected),
142 },
143 codec,
144 )
145 }
146 #[must_use]
147 pub fn value_constraint_not_satisfied(
148 value: Integer,
149 expected: &Bounded<i128>,
150 codec: crate::Codec,
151 ) -> Self {
152 Self::from_kind(
153 EncodeErrorKind::ValueConstraintNotSatisfied {
154 value,
155 expected: (*expected),
156 },
157 codec,
158 )
159 }
160 pub fn check_length(length: usize, expected: &Size, codec: crate::Codec) -> Result<(), Self> {
161 expected.contains_or_else(&length, || Self {
162 kind: Box::new(EncodeErrorKind::InvalidLength {
163 length,
164 expected: **expected,
165 }),
166 codec,
167 #[cfg(feature = "backtraces")]
168 backtrace: Backtrace::generate(),
169 })
170 }
171 #[must_use]
172 pub fn length_exceeds_platform_size(codec: crate::Codec) -> Self {
173 Self::from_kind(EncodeErrorKind::LengthExceedsPlatformSize, codec)
174 }
175 #[must_use]
177 pub fn integer_type_conversion_failed(msg: alloc::string::String, codec: crate::Codec) -> Self {
178 Self::from_kind(EncodeErrorKind::IntegerTypeConversionFailed { msg }, codec)
179 }
180 #[must_use]
181 pub fn invalid_length(length: usize, expected: Bounded<usize>, codec: crate::Codec) -> Self {
182 Self::from_kind(EncodeErrorKind::InvalidLength { length, expected }, codec)
183 }
184 #[must_use]
185 pub fn opaque_conversion_failed(msg: alloc::string::String, codec: crate::Codec) -> Self {
186 Self::from_kind(EncodeErrorKind::OpaqueConversionFailed { msg }, codec)
187 }
188 #[must_use]
189 pub fn variant_not_in_choice(codec: crate::Codec) -> Self {
190 Self::from_kind(EncodeErrorKind::VariantNotInChoice, codec)
191 }
192 #[must_use]
193 pub fn from_kind(kind: EncodeErrorKind, codec: crate::Codec) -> Self {
194 Self {
195 kind: Box::new(kind),
196 codec,
197 #[cfg(feature = "backtraces")]
198 backtrace: Backtrace::generate(),
199 }
200 }
201 #[must_use]
202 fn from_codec_kind(inner: CodecEncodeError) -> Self {
203 let codec = match inner {
204 CodecEncodeError::Ber(_) => crate::Codec::Ber,
205 CodecEncodeError::Cer(_) => crate::Codec::Cer,
206 CodecEncodeError::Der(_) => crate::Codec::Der,
207 CodecEncodeError::Uper(_) => crate::Codec::Uper,
208 CodecEncodeError::Aper(_) => crate::Codec::Aper,
209 CodecEncodeError::Jer(_) => crate::Codec::Jer,
210 CodecEncodeError::Coer(_) => crate::Codec::Coer,
211 };
212 Self {
213 kind: Box::new(EncodeErrorKind::CodecSpecific { inner }),
214 codec,
215 #[cfg(feature = "backtraces")]
216 backtrace: Backtrace::generate(),
217 }
218 }
219}
220
221#[derive(Snafu, Debug)]
223#[snafu(visibility(pub))]
224#[non_exhaustive]
225pub enum EncodeErrorKind {
226 #[snafu(display("Failed to convert BIT STRING unused bits to u8: {err}"))]
227 FailedBitStringUnusedBitsToU8 { err: core::num::TryFromIntError },
228 #[snafu(display("invalid length, expected: {expected}; actual: {length}"))]
229 InvalidLength {
230 length: usize,
232 expected: Bounded<usize>,
234 },
235 #[snafu(display("invalid length, exceeds platform maximum size usize::MAX"))]
236 LengthExceedsPlatformSize,
237 #[snafu(display("Integer does not fit to the reserved octets {expected}; actual: {value}"))]
238 MoreBytesThanExpected { value: usize, expected: usize },
239 #[snafu(display("custom error:\n{}", msg))]
240 Custom { msg: alloc::string::String },
241 #[snafu(display("Wrapped codec-specific encode error"))]
242 CodecSpecific { inner: CodecEncodeError },
243 #[snafu(display("Alphabet constraint not satisfied: {reason}"))]
244 AlphabetConstraintNotSatisfied {
245 reason: super::strings::PermittedAlphabetError,
247 },
248 #[snafu(display("Size constraint not satisfied: expected: {expected}; actual: {size}"))]
249 SizeConstraintNotSatisfied {
250 size: usize,
252 expected: Bounded<usize>,
254 },
255 #[snafu(display("Value constraint not satisfied: expected: {expected}; actual: {value}"))]
256 ValueConstraintNotSatisfied {
257 value: Integer,
259 expected: Bounded<i128>,
261 },
262 #[snafu(display("Failed to cast integer to another integer type: {msg} "))]
263 IntegerTypeConversionFailed { msg: alloc::string::String },
264 #[snafu(display("Conversion to Opaque type failed: {msg}"))]
265 OpaqueConversionFailed { msg: alloc::string::String },
266 #[snafu(display("Selected Variant not found from Choice"))]
267 VariantNotInChoice,
268}
269#[derive(Snafu, Debug)]
271#[snafu(visibility(pub))]
272#[non_exhaustive]
273pub enum BerEncodeErrorKind {
274 #[snafu(display("Cannot encode `ANY` types in `SET` fields"))]
275 AnyInSet,
276 #[snafu(display(
278 "Invalid Object Identifier: must have at least two components and first octet must be 0, 1 or 2. Provided: {:?}", oid
279 ))]
280 InvalidObjectIdentifier { oid: alloc::vec::Vec<u32> },
281}
282impl BerEncodeErrorKind {
283 #[must_use]
284 pub fn invalid_object_identifier(oid: alloc::vec::Vec<u32>) -> Self {
285 Self::InvalidObjectIdentifier { oid }
286 }
287}
288
289#[derive(Snafu, Debug)]
292#[snafu(visibility(pub))]
293#[non_exhaustive]
294pub enum CerEncodeErrorKind {}
295
296#[derive(Snafu, Debug)]
298#[snafu(visibility(pub))]
299#[non_exhaustive]
300pub enum DerEncodeErrorKind {}
301
302#[derive(Snafu, Debug)]
304#[snafu(visibility(pub))]
305#[non_exhaustive]
306pub enum JerEncodeErrorKind {
307 JsonEncodingError { upstream: alloc::string::String },
309 #[snafu(display("No encoded JSON root value found!"))]
311 NoRootValueFound,
312 #[snafu(display("Error in JSON encoder: {}", msg))]
314 JsonEncoder {
315 msg: alloc::string::String,
317 },
318 #[snafu(display("Exceeds supported integer range -2^63..2^63 ({:?}).", value))]
319 ExceedsSupportedIntSize {
320 value: num_bigint::BigInt,
322 },
323 #[snafu(display("Invalid character: {:?}", error))]
324 InvalidCharacter {
325 error: alloc::string::FromUtf8Error,
327 },
328}
329
330#[derive(Snafu, Debug)]
332#[snafu(visibility(pub))]
333#[non_exhaustive]
334pub enum UperEncodeErrorKind {}
335
336#[derive(Snafu, Debug)]
338#[snafu(visibility(pub))]
339#[non_exhaustive]
340pub enum AperEncodeErrorKind {}
341
342#[derive(Snafu, Debug)]
343#[snafu(visibility(pub))]
344#[non_exhaustive]
345pub enum CoerEncodeErrorKind {
346 #[snafu(display("Provided data is too long to be encoded with COER."))]
347 TooLongValue { length: u128 },
348 #[snafu(display(
349 "Provided length in not correct format. Should be bits as multiple of 8. {remainder}; actual: {length}"
350 ))]
351 LengthNotAsBitLength { length: usize, remainder: usize },
352 #[snafu(display("Provided integer exceeds limits of the constrained word sizes."))]
353 InvalidConstrainedIntegerOctetSize,
354}
355
356impl crate::enc::Error for EncodeError {
357 fn custom<D: core::fmt::Display>(msg: D, codec: crate::Codec) -> Self {
358 Self {
359 kind: Box::new(EncodeErrorKind::Custom {
360 msg: msg.to_string(),
361 }),
362 codec,
363 #[cfg(feature = "backtraces")]
364 backtrace: Backtrace::generate(),
365 }
366 }
367}
368
369#[cfg(test)]
370mod tests {
371 use super::*;
372 use crate::prelude::*;
373
374 #[test]
375 fn test_ber_error() {
376 use crate::ber::enc;
377 use crate::enc::Encoder;
378
379 let oid = ObjectIdentifier::new(vec![2, 5, 4, 3]);
380 assert!(oid.is_some());
381 let oid_encoded = crate::Codec::Ber.encode_to_binary(&oid);
383 assert!(oid_encoded.is_ok());
384
385 let oid = vec![3, 5, 4, 3];
386
387 let mut enc = enc::Encoder::new(enc::EncoderOptions::ber());
388 let result = enc.encode_object_identifier(Tag::OBJECT_IDENTIFIER, &oid);
389 assert!(result.is_err());
390 match result {
391 Err(e) => match *e.kind {
392 EncodeErrorKind::CodecSpecific {
393 inner: CodecEncodeError::Ber(BerEncodeErrorKind::InvalidObjectIdentifier { .. }),
394 } => {}
395 _ => {
396 panic!("Expected invalid object identifier error of specific type!");
397 }
398 },
399 _ => panic!("Unexpected OK!"),
400 }
401 }
420 #[test]
421 fn test_uper_constrained_string_error() {
422 use crate as rasn;
423 use rasn::codec::Codec;
424 use rasn::error::{strings::PermittedAlphabetError, EncodeErrorKind};
425 #[derive(AsnType, Clone, Debug, Decode, Encode, PartialEq)]
426 #[rasn(delegate, from("a..z"))]
427 struct MyConstrainedString(VisibleString);
428
429 let constrained_str = MyConstrainedString(VisibleString::try_from("abcD").unwrap());
430 let encoded = Codec::Uper.encode_to_binary(&constrained_str);
431 match encoded {
432 Ok(_) => {}
433 Err(e) => {
434 match *e.kind {
436 EncodeErrorKind::AlphabetConstraintNotSatisfied {
437 reason: PermittedAlphabetError::CharacterNotFound { .. },
438 } => {}
439 _ => {
440 panic!("Unexpected error!");
441 }
442 }
443 }
444 }
445 }
446}