event_matcher/error.rs
1//! Error types for Event-matcher operations.
2//!
3//! The crate uses a single sum-type, [`MatchingError`], for every fallible
4//! operation, and a [`Result`] alias to keep call-sites concise.
5//!
6//! The matching engine itself is **infallible**: scoring two events always
7//! produces a [`crate::MatchResult`]. Errors arise from explicit validation
8//! steps such as [`crate::Event::validate`].
9//!
10//! ## Example
11//!
12//! ```
13//! use event_matcher::{MatchingError, Event};
14//!
15//! let empty = Event::builder().build();
16//! match empty.validate() {
17//! Err(MatchingError::MissingField(msg)) => {
18//! assert!(msg.contains("required"));
19//! }
20//! other => panic!("unexpected: {other:?}"),
21//! }
22//! ```
23
24use thiserror::Error;
25
26/// Result alias used throughout the crate.
27///
28/// Equivalent to `std::result::Result<T, MatchingError>`.
29///
30/// ```
31/// use event_matcher::Result;
32/// fn doubled(x: i32) -> Result<i32> { Ok(x * 2) }
33/// assert_eq!(doubled(3).unwrap(), 6);
34/// ```
35pub type Result<T> = std::result::Result<T, MatchingError>;
36
37/// Errors that may be returned by Event-matcher operations.
38///
39/// The matching engine itself is infallible — scoring two events always
40/// produces a [`crate::MatchResult`]. The only fallible operation in the
41/// public surface today is [`crate::Event::validate`], which returns
42/// [`MatchingError::MissingField`] when the primary `name` is absent.
43/// Configuration builders ([`crate::MatchConfig::default`], `strict`,
44/// `lenient`) are infallible.
45///
46/// The enum is `#[non_exhaustive]` so future fallible code paths can add
47/// variants without breaking `SemVer` for downstream pattern-matches.
48///
49/// ```
50/// use event_matcher::MatchingError;
51///
52/// let e = MatchingError::MissingField("name".into());
53/// // `Display` is provided by `thiserror`.
54/// assert!(e.to_string().contains("Missing required field"));
55/// ```
56#[derive(Error, Debug)]
57#[non_exhaustive]
58pub enum MatchingError {
59 /// A required field was absent. Returned by [`crate::Event::validate`].
60 #[error("Missing required field: {0}")]
61 MissingField(String),
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn missing_field_display() {
70 let e = MatchingError::MissingField("name".into());
71 assert_eq!(e.to_string(), "Missing required field: name");
72 }
73
74 #[test]
75 fn result_alias_resolves() {
76 // The wrap is the point: this exercises the crate `Result` alias.
77 #[allow(clippy::unnecessary_wraps)]
78 fn make() -> Result<i32> {
79 Ok(42)
80 }
81 assert_eq!(make().unwrap(), 42);
82 }
83
84 #[test]
85 fn errors_are_send_and_sync() {
86 fn assert_send_sync<T: Send + Sync>() {}
87 assert_send_sync::<MatchingError>();
88 }
89}