synta 0.1.1

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
//! Error types and handling
//!
//! All errors include position information for debugging.

use crate::Tag;

/// Result type for ASN.1 operations
pub type Result<T> = core::result::Result<T, Error>;

/// ASN.1 error types
#[derive(Debug, Clone)]
pub enum Error {
    /// Unexpected end of input
    UnexpectedEof {
        /// Position in input where EOF was encountered
        position: usize,
    },

    /// Invalid tag encoding
    InvalidTag {
        /// Position in input where the invalid tag was found
        position: usize,
        /// The invalid byte value
        byte: u8,
    },

    /// Invalid length encoding
    InvalidLength {
        /// Position in input where the invalid length was found
        position: usize,
    },

    /// Length overflow during calculation
    LengthOverflow,

    /// Length exceeds configured maximum
    LengthExceedsMaximum {
        /// Position in input where the length was found
        position: usize,
        /// The length value that was too large
        length: usize,
        /// The configured maximum length
        max_length: usize,
    },

    /// Maximum nesting depth exceeded
    MaxDepthExceeded {
        /// Position in input where the depth was exceeded
        position: usize,
        /// The configured maximum depth
        max_depth: usize,
    },

    /// Unexpected tag (expected X, got Y)
    UnexpectedTag {
        /// Position in input where the unexpected tag was found
        position: usize,
        /// The tag that was expected
        expected: Tag,
        /// The tag that was actually found
        actual: Tag,
    },

    /// Invalid encoding for type
    #[cfg(feature = "std")]
    InvalidEncoding {
        /// Position in input where the invalid encoding was found
        position: usize,
        /// The tag of the invalid element
        tag: Tag,
        /// Description of why the encoding is invalid
        reason: String,
    },
    #[cfg(not(feature = "std"))]
    InvalidEncoding {
        /// Position in input where the invalid encoding was found
        position: usize,
        /// The tag of the invalid element
        tag: Tag,
        /// Description of why the encoding is invalid
        reason: &'static str,
    },

    /// Integer overflow when converting to native type
    IntegerOverflow {
        /// Position in input where the integer was found
        position: usize,
    },

    /// Invalid OID encoding
    InvalidOid {
        /// Position in input where the OID was found
        position: usize,
    },

    /// Invalid string encoding
    #[cfg(feature = "std")]
    InvalidString {
        /// Position in input where the string was found
        position: usize,
        /// The type of string (e.g., "PrintableString", "UTF8String")
        string_type: &'static str,
        /// Description of why the string is invalid
        reason: String,
    },
    #[cfg(not(feature = "std"))]
    InvalidString {
        /// Position in input where the string was found
        position: usize,
        /// The type of string (e.g., "PrintableString", "UTF8String")
        string_type: &'static str,
        /// Description of why the string is invalid
        reason: &'static str,
    },

    /// Invalid time format
    InvalidTime {
        /// Position in input where the time was found
        position: usize,
    },

    /// DER compliance violation
    #[cfg(feature = "std")]
    DerViolation {
        /// Position in input where the violation was found
        position: usize,
        /// Description of the DER violation
        reason: String,
    },
    #[cfg(not(feature = "std"))]
    DerViolation {
        /// Position in input where the violation was found
        position: usize,
        /// Description of the DER violation
        reason: &'static str,
    },

    /// Indefinite length not allowed in DER
    IndefiniteLengthInDer {
        /// Position in input where indefinite length was found
        position: usize,
    },

    /// CER compliance violation
    #[cfg(feature = "std")]
    CerViolation {
        /// Position in input where the violation was found
        position: usize,
        /// Description of the CER violation
        reason: String,
    },
    #[cfg(not(feature = "std"))]
    CerViolation {
        /// Position in input where the violation was found
        position: usize,
        /// Description of the CER violation
        reason: &'static str,
    },

    /// Constructed encoder not properly finished
    UnfinishedConstructed,

    /// No constructed element to finish
    NoConstructedToFinish,

    /// Length too large to encode
    LengthTooLarge,

    /// Custom error
    #[cfg(feature = "std")]
    Custom(String),
    #[cfg(not(feature = "std"))]
    Custom(&'static str),
}

impl Error {
    /// Get the position in the input where the error occurred, if available
    pub fn position(&self) -> Option<usize> {
        match self {
            Error::UnexpectedEof { position }
            | Error::InvalidTag { position, .. }
            | Error::InvalidLength { position }
            | Error::LengthExceedsMaximum { position, .. }
            | Error::MaxDepthExceeded { position, .. }
            | Error::UnexpectedTag { position, .. }
            | Error::InvalidEncoding { position, .. }
            | Error::IntegerOverflow { position }
            | Error::InvalidOid { position }
            | Error::InvalidString { position, .. }
            | Error::InvalidTime { position }
            | Error::DerViolation { position, .. }
            | Error::IndefiniteLengthInDer { position }
            | Error::CerViolation { position, .. } => Some(*position),
            _ => None,
        }
    }
}

impl core::fmt::Display for Error {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Error::UnexpectedEof { position } => {
                write!(f, "Unexpected end of input at position {}", position)
            }
            Error::InvalidTag { position, byte } => {
                write!(
                    f,
                    "Invalid tag byte 0x{:02X} at position {}",
                    byte, position
                )
            }
            Error::InvalidLength { position } => {
                write!(f, "Invalid length encoding at position {}", position)
            }
            Error::LengthOverflow => {
                write!(f, "Length calculation overflow")
            }
            Error::LengthExceedsMaximum {
                position,
                length,
                max_length,
            } => {
                write!(
                    f,
                    "Length {} exceeds maximum {} at position {}",
                    length, max_length, position
                )
            }
            Error::MaxDepthExceeded {
                position,
                max_depth,
            } => {
                write!(
                    f,
                    "Maximum nesting depth {} exceeded at position {}",
                    max_depth, position
                )
            }
            Error::UnexpectedTag {
                position,
                expected,
                actual,
            } => {
                write!(
                    f,
                    "Unexpected tag at position {}: expected {:?}, got {:?}",
                    position, expected, actual
                )
            }
            Error::InvalidEncoding {
                position,
                tag,
                reason,
            } => {
                write!(
                    f,
                    "Invalid encoding for {:?} at position {}: {}",
                    tag, position, reason
                )
            }
            Error::IntegerOverflow { position } => {
                write!(f, "Integer overflow at position {}", position)
            }
            Error::InvalidOid { position } => {
                write!(f, "Invalid OID encoding at position {}", position)
            }
            Error::InvalidString {
                position,
                string_type,
                reason,
            } => {
                write!(
                    f,
                    "Invalid {} at position {}: {}",
                    string_type, position, reason
                )
            }
            Error::InvalidTime { position } => {
                write!(f, "Invalid time format at position {}", position)
            }
            Error::DerViolation { position, reason } => {
                write!(f, "DER violation at position {}: {}", position, reason)
            }
            Error::IndefiniteLengthInDer { position } => {
                write!(
                    f,
                    "Indefinite length not allowed in DER at position {}",
                    position
                )
            }
            Error::CerViolation { position, reason } => {
                write!(f, "CER violation at position {}: {}", position, reason)
            }
            Error::UnfinishedConstructed => {
                write!(f, "Constructed encoder not properly finished")
            }
            Error::NoConstructedToFinish => {
                write!(f, "No constructed element to finish")
            }
            Error::LengthTooLarge => {
                write!(f, "Length too large to encode")
            }
            Error::Custom(msg) => {
                write!(f, "{}", msg)
            }
        }
    }
}

#[cfg(feature = "std")]
impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        None
    }
}