rlx_core/preset/schema/error.rs
1//! [`PresetError`]: why a preset failed to load.
2//!
3//! Every variant is recoverable. A bad preset returns `Err` and never panics,
4//! so the caller degrades to the last good preset (ADR-0002 / NFR 10).
5
6// A continuation of one module split across several files, so it needs the
7// names `preset/schema/mod.rs` has in scope.
8use super::*;
9
10/// Why a preset failed to load. Every variant is recoverable — the caller
11/// keeps the previous good preset.
12#[derive(Debug)]
13pub enum PresetError {
14 /// The TOML itself was malformed.
15 Toml(toml::de::Error),
16 /// `system` named a built-in that does not exist.
17 UnknownSystem(String),
18 /// A parameter's expression failed to compile.
19 Expr {
20 /// The parameter whose expression was invalid.
21 param: String,
22 /// The compile error.
23 err: ExprError,
24 },
25 /// A structural-config table (`[curve]`/`[generator]`) was invalid — an
26 /// unknown family, an out-of-range value, an undefined grammar symbol.
27 Config(String),
28 /// The preset file could not be read (message from the I/O error).
29 Io(String),
30}
31
32impl PresetError {
33 /// The byte range in the preset source this error points at, when the parser
34 /// gave one.
35 ///
36 /// Only the TOML arm can have one: every other variant is raised by the
37 /// loader's own validation, which runs against parsed values rather than
38 /// against the document, and a value carries no position. A caller turns the
39 /// offset into a line and column against the source it read — which it still
40 /// has and this module never did.
41 pub fn span(&self) -> Option<std::ops::Range<usize>> {
42 match self {
43 PresetError::Toml(err) => err.span(),
44 _ => None,
45 }
46 }
47
48 /// The parameter whose expression failed to compile, for the arm that has
49 /// one.
50 ///
51 /// The name is already in [`Display`](fmt::Display)'s sentence; this is the
52 /// same fact as a field, so a structured consumer does not have to read it
53 /// back out of prose.
54 pub fn param(&self) -> Option<&str> {
55 match self {
56 PresetError::Expr { param, .. } => Some(param),
57 _ => None,
58 }
59 }
60}
61
62impl fmt::Display for PresetError {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 match self {
65 PresetError::Toml(e) => write!(f, "invalid preset TOML: {e}"),
66 PresetError::UnknownSystem(s) => write!(f, "unknown system '{s}'"),
67 PresetError::Expr { param, err } => {
68 write!(f, "parameter '{param}' has an invalid expression: {err}")
69 }
70 PresetError::Config(msg) => write!(f, "invalid structural config: {msg}"),
71 PresetError::Io(msg) => write!(f, "could not read preset file: {msg}"),
72 }
73 }
74}
75
76impl std::error::Error for PresetError {}