mf2_runtime/error.rs
1//! Formatting errors: small plain values (`plans/03-runtime.md` §2.2). They
2//! derive `thiserror::Error` for server and test use; its `Display` is never
3//! reached from the client path (B12).
4
5use mf2_model::ErrorKind;
6
7/// An error reported while formatting. Formatting still produces output.
8#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, thiserror::Error)]
9#[repr(u8)]
10#[non_exhaustive]
11pub enum FormatError {
12 /// Unresolved Variable: no value for a variable.
13 #[error("unresolved variable")]
14 UnresolvedVariable,
15 /// Unknown Function: the registry has no handler for a function.
16 #[error("unknown function")]
17 UnknownFunction,
18 /// Bad Selector: a selector's value does not support selection.
19 #[error("bad selector")]
20 BadSelector,
21 /// Bad Operand: a function cannot take its operand.
22 #[error("bad operand")]
23 BadOperand,
24 /// Bad Option: an option or its value is not valid for the function.
25 #[error("bad option")]
26 BadOption,
27 /// Bad Variant Key: a key a selector cannot compare against.
28 #[error("bad variant key")]
29 BadVariantKey,
30 /// Unsupported Operation: valid, but not supported by this handler or
31 /// configuration (or past an implementation limit).
32 #[error("unsupported operation")]
33 UnsupportedOperation,
34 /// Any other failure of a function handler.
35 #[error("message function error")]
36 MessageFunctionError,
37 /// No variant matched — only a catalog built from an invalid model (no
38 /// fallback variant, or key counts unlike the selector count) has one.
39 /// The message formats as `{�}`.
40 #[error("no variant matched (missing fallback variant)")]
41 MissingFallbackVariant,
42 /// The id is not in this catalog. Nothing is written.
43 #[error("missing message")]
44 MissingMessage,
45 /// The message's catalog record is malformed: `{�}` in its place, and
46 /// the message ends there.
47 #[error("malformed catalog record")]
48 Malformed,
49}
50
51impl FormatError {
52 /// The MF2 error kind (`mf2_model::ErrorKind`); `None` for
53 /// [`FormatError::MissingMessage`] and [`FormatError::Malformed`], which
54 /// are about the catalog, not the message.
55 pub const fn kind(self) -> Option<ErrorKind> {
56 Some(match self {
57 FormatError::UnresolvedVariable => ErrorKind::UnresolvedVariable,
58 FormatError::UnknownFunction => ErrorKind::UnknownFunction,
59 FormatError::BadSelector => ErrorKind::BadSelector,
60 FormatError::BadOperand => ErrorKind::BadOperand,
61 FormatError::BadOption => ErrorKind::BadOption,
62 FormatError::BadVariantKey => ErrorKind::BadVariantKey,
63 FormatError::UnsupportedOperation => ErrorKind::UnsupportedOperation,
64 FormatError::MessageFunctionError => ErrorKind::MessageFunctionError,
65 FormatError::MissingFallbackVariant => ErrorKind::MissingFallbackVariant,
66 FormatError::MissingMessage | FormatError::Malformed => return None,
67 })
68 }
69}