Skip to main content

max / makeover-layout

Make Fill and Depth non_exhaustive so the vocabulary can grow Adding Fill::Sunken in 0.3.0 was correct and is earning its keep: it is the unchosen tab, live in the stylesheet makeover-webview emits, and it cannot be Well, which is derived by inverting against content and carries an edge where sunken is authored and flat. What was wrong is what it cost. Both exhaustive matchers, makeover-tui and makeover-immediate, failed to compile on an additive member, and neither could move until the other published. That is the wrong default for a description layer whose whole premise is that the vocabulary grows and the renderers need not resemble each other. A renderer that has no drawing for a depth should pay a wildcard arm, not a compile error and a wait. Verified against makeover-tui: on this version it builds with a single wildcard arm, no new palette member, and therefore no breaking change of its own. The wildcard is not a hole. Fill resolves through a fallible lookup and a missing intent is answered with structure rather than a substituted colour, which is a rule this crate already had and already relies on for Well against makeover before 2.3.0. Breaking, so 0.4.0. The other fourteen public enums are left exhaustive: the same argument reaches them, but silent degradation is only safe where a missing member has a defined answer, and that wants deciding per enum rather than in one sweep.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-30 04:19 UTC
Signed with PGP, not checked
Commit: 5a46428e5b06b09a44024b1760556080e8babfee
Parent: a9857ca
2 files changed, +18 insertions, -1 deletion
M Cargo.toml +1 -1
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "makeover-layout"
3 - version = "0.3.0"
3 + version = "0.4.0"
4 4 edition = "2024"
5 5 description = "The renderer-agnostic half of the make-family design system: what a thing IS, named as intents and relationships and never as values. Colour defers to makeover, spacing to makeover-geometry; what is left is composition."
6 6 license = "MIT"
M src/lib.rs +17
@@ -141,7 +141,20 @@
141 141 }
142 142
143 143 /// A surface intent a region is filled with.
144 + ///
145 + /// `#[non_exhaustive]`, so a renderer must carry a wildcard arm and a new
146 + /// member is additive rather than breaking. Added 0.4.0, after [`Sunken`]
147 + /// (an additive member, 0.3.0) hard-broke `makeover-tui` and
148 + /// `makeover-immediate` at compile time and left neither able to move until
149 + /// both published. The vocabulary exists to grow and the renderers exist to
150 + /// disagree about how much of it they answer, so growth must not be a
151 + /// lockstep event. The renderer's wildcard is not a hole: [`Fill`] is
152 + /// resolved through a fallible lookup, and a missing intent is answered with
153 + /// structure rather than with a substituted colour.
154 + ///
155 + /// [`Sunken`]: Fill::Sunken
144 156 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
157 + #[non_exhaustive]
145 158 pub enum Fill {
146 159 /// The page behind everything.
147 160 Page,
@@ -196,7 +209,11 @@
196 209 /// and recorded the bug in its doc comment, and Balanced Breakfast still had
197 210 /// twelve of them a year later. A single name for the pair makes that
198 211 /// unrepresentable.
212 + /// `#[non_exhaustive]` for the same reason as [`Fill`], and in the same
213 + /// release: a depth this renderer has no drawing for should cost it a
214 + /// wildcard arm, not a compile error and a wait on someone else's publish.
199 215 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
216 + #[non_exhaustive]
200 217 pub enum Depth {
201 218 /// Level with its surroundings. No edge.
202 219 Flat,