Remove non_exhaustive from Book

This removes the `non_exhaustive` attribute from the `Book` and its
inner types `BookItem` and `Chapter`. These were added in
https://github.com/rust-lang/mdBook/pull/2779. After thinking about it
more, I realized that these types cannot be extended in a
semver-compatible way, so I am fine with allowing them be exhaustive.

The problem is that with CmdPreprocessor, the `Book` will be
re-serialized by a preprocessor, which could potentially be on an older
version. Attempting to add any new fields/variants means that either the
deserialization will fail, or the new fields will be stripped by the
preprocessor.

These could potentially be structured such that they have a
`serde(flatten)` or Other/Unknown variant so that a preprocessor would
at least see the extra fields/variants and pass them along back to the
output. However, a preprocessor or renderer wouldn't know what to do
with those new fields/variants (particularly `BookItem`) which would
itself be a problem. It's still possible to do something like this in
the future, but for now I think it's fine to restrict these to
semver-major changes.
This commit is contained in:
Eric Huss
2025-08-29 18:24:44 -07:00
parent 06af133838
commit 30d3aeb691
2 changed files with 12 additions and 4 deletions

View File

@@ -18,8 +18,11 @@ mod tests;
///
/// [`iter()`]: #method.iter
/// [`for_each_mut()`]: #method.for_each_mut
#[allow(
clippy::exhaustive_structs,
reason = "This cannot be extended without breaking preprocessors."
)]
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Book {
/// The items in this book.
pub items: Vec<BookItem>,
@@ -80,8 +83,11 @@ where
}
/// Enum representing any type of item which can be added to a book.
#[allow(
clippy::exhaustive_enums,
reason = "This cannot be extended without breaking preprocessors."
)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum BookItem {
/// A nested chapter.
Chapter(Chapter),
@@ -99,8 +105,11 @@ impl From<Chapter> for BookItem {
/// The representation of a "chapter", usually mapping to a single file on
/// disk however it may contain multiple sub-chapters.
#[allow(
clippy::exhaustive_structs,
reason = "This cannot be extended without breaking preprocessors."
)]
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Chapter {
/// The chapter's name.
pub name: String,

View File

@@ -687,7 +687,6 @@ fn make_data(
BookItem::Separator => {
chapter.insert("spacer".to_owned(), json!("_spacer_"));
}
_ => panic!("BookItem {item:?} not covered"),
}
chapters.push(chapter);