Skip to main content

stix_ffi/
error.rs

1//! The facade's flat error type, mappable onto host-language exceptions.
2
3/// A coarse category each binding maps to its own exception type.
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum ErrorCode {
6    /// The pattern failed to lex or parse.
7    Parse,
8    /// A STIX object or bundle failed to deserialize or validate.
9    Model,
10    /// Pattern evaluation failed (e.g. an unsupported feature).
11    Match,
12    /// An input failed facade-level validation.
13    Validation,
14}
15
16/// A flat, FFI-friendly error: a category plus a human-readable message.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct FfiError {
19    /// The error's coarse category.
20    pub code: ErrorCode,
21    /// A human-readable description of what went wrong.
22    pub message: String,
23}
24
25impl FfiError {
26    /// Creates an error from a category and message.
27    pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
28        FfiError {
29            code,
30            message: message.into(),
31        }
32    }
33}
34
35impl std::fmt::Display for FfiError {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        write!(f, "{:?}: {}", self.code, self.message)
38    }
39}
40
41impl std::error::Error for FfiError {}
42
43impl From<stix::pattern::ParseError> for FfiError {
44    fn from(e: stix::pattern::ParseError) -> Self {
45        FfiError::new(ErrorCode::Parse, e.to_string())
46    }
47}
48
49impl From<stix::model::ModelError> for FfiError {
50    fn from(e: stix::model::ModelError) -> Self {
51        FfiError::new(ErrorCode::Model, e.to_string())
52    }
53}
54
55impl From<stix::matcher::MatchError> for FfiError {
56    fn from(e: stix::matcher::MatchError) -> Self {
57        FfiError::new(ErrorCode::Match, e.to_string())
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn parse_error_maps_to_parse_code() {
67        let e = stix::parse("[bad").unwrap_err();
68        let f: FfiError = e.into();
69        assert_eq!(f.code, ErrorCode::Parse);
70        assert!(!f.message.is_empty());
71    }
72
73    #[test]
74    fn display_includes_code_and_message() {
75        let f = FfiError::new(ErrorCode::Validation, "missing field");
76        let s = format!("{f}");
77        assert!(s.contains("Validation"));
78        assert!(s.contains("missing field"));
79    }
80}