lattice_mode/error.rs
1//! Errors surfaced by the registry's activation / deactivation
2//! path.
3
4use thiserror::Error;
5
6use crate::capability::CapabilitySet;
7use crate::mode::ModeId;
8
9/// Why an activation failed.
10///
11/// Two routes, and they reach different places. The registry validates
12/// registration, kind, capabilities, conflicts and dependency presence
13/// **synchronously** before any lifecycle hook runs: those variants are the
14/// `Err` of `activate_major` / `activate_minor`, nothing ran, nothing was
15/// published, and the active set is unchanged. An error returned **by
16/// `on_activate`** (normally [`LifecycleFailed`](Self::LifecycleFailed))
17/// arrives after the activate call has already returned `Ok`; it is
18/// published as [`ModeEvent::ModeActivationFailed`](crate::ModeEvent::ModeActivationFailed)
19/// and the host rolls back.
20#[derive(Debug, Error, Clone, PartialEq, Eq)]
21pub enum ModeActivationError {
22 /// `mode` is not in the registry. Either typo'd or not
23 /// registered yet.
24 #[error("mode `{0}` is not registered")]
25 NotRegistered(ModeId),
26
27 /// Buffer lacks one or more capabilities the mode requires.
28 /// `missing` is the bitfield of the absent capabilities
29 /// (i.e. `mode.required_capabilities() - buffer_capabilities`).
30 #[error("mode `{mode}` requires capabilities `{missing:?}` that the buffer lacks")]
31 MissingCapability {
32 /// The mode that could not activate.
33 mode: ModeId,
34 /// The required capabilities the buffer does not offer.
35 missing: CapabilitySet,
36 },
37
38 /// Activating `mode` would conflict with `active` -- a
39 /// declared `conflicts_with` entry on either side. Raised when
40 /// activating a minor (directly or via an `implies` cascade); the
41 /// registry never auto-deactivates the other mode, so the caller
42 /// must deactivate it and retry if the swap is wanted.
43 #[error("mode `{mode}` conflicts with active mode `{active}`")]
44 Conflict {
45 /// The mode being activated.
46 mode: ModeId,
47 /// The already-active mode it conflicts with.
48 active: ModeId,
49 },
50
51 /// `mode` declares an `implies` dependency on `dep`, but
52 /// `dep` is not registered. Indicates a build-config bug
53 /// (a feature crate registered the parent without its
54 /// dependency).
55 #[error("mode `{mode}` implies `{dep}` which is not registered")]
56 UnregisteredDependency {
57 /// The mode declaring the dependency.
58 mode: ModeId,
59 /// The implied mode that is not registered.
60 dep: ModeId,
61 },
62
63 /// Wrong kind: caller invoked `activate_major` on a minor
64 /// mode or vice versa. Indicates a type-bug in the caller;
65 /// the trait's `kind()` answers what's expected.
66 #[error("mode `{mode}` is the wrong kind for this operation")]
67 WrongKind {
68 /// The mode whose kind did not match the call.
69 mode: ModeId,
70 },
71
72 /// A mode's `on_activate` failed. The variant a mode constructs
73 /// itself (with its own id and a human-readable reason) when setup
74 /// cannot complete — return it rather than panicking.
75 #[error("mode `{mode}` lifecycle hook failed: {reason}")]
76 LifecycleFailed {
77 /// The mode whose hook failed.
78 mode: ModeId,
79 /// Why, for the user and the log.
80 reason: String,
81 },
82
83 /// A mode tried to write a buffer-local owned by a
84 /// different mode (M.3.2.a). Reserved for the checked
85 /// `ModeContext::set_local` / `remove_local` surface the design
86 /// describes (comparing `T::OWNER_MODE` against the activating mode's
87 /// id); that surface is not implemented, so nothing constructs this
88 /// variant today. See [`BufferLocal`](crate::BufferLocal).
89 #[error("mode `{current}` cannot write buffer-local `{local}` (owner is `{owner}`)")]
90 WrongOwnerMode {
91 /// The currently-activating mode that attempted the
92 /// write.
93 current: ModeId,
94 /// The local's display name (`T::NAME`).
95 local: &'static str,
96 /// The local's declared owner mode (`T::OWNER_MODE`).
97 owner: &'static str,
98 },
99}