From 19a4929a80f6a28cbe3ea27dbf7c6267a4dfdf03 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Sat, 14 Nov 2026 15:38:05 +0000 Subject: [PATCH] Ignore reader provenance in numbering equality --- crates/wordmodel/src/numbering.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/crates/wordmodel/src/numbering.rs b/crates/wordmodel/src/numbering.rs index dc2c69a23..91eb221b8 100644 --- a/crates/wordmodel/src/numbering.rs +++ b/crates/wordmodel/src/numbering.rs @@ -70,7 +70,7 @@ impl Default for Level { } } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Default)] +#[derive(Clone, Debug, Serialize, Deserialize, Default)] #[serde(default)] pub struct AbstractNum { pub id: u32, @@ -95,6 +95,20 @@ pub struct AbstractNum { pub multi_level_type: Option, } +// Explicit source-level presence is reader provenance used to distinguish an omitted Word level +// from an effective default. It is intentionally not part of the document model's structural +// equality, just as it is not serialized. +impl PartialEq for AbstractNum { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + && self.name == other.name + && self.levels == other.levels + && self.nsid == other.nsid + && self.tmpl == other.tmpl + && self.multi_level_type == other.multi_level_type + } +} + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Default)] #[serde(default, rename_all = "camelCase")] pub struct Num { @@ -533,6 +547,14 @@ mod tests { assert!(numbering.level_is_defined(id, 1)); } + #[test] + fn explicit_level_metadata_does_not_change_model_equality() { + let mut with_metadata = AbstractNum::default(); + let without_metadata = with_metadata.clone(); + with_metadata.explicit_levels = Some([true; 9]); + assert_eq!(with_metadata, without_metadata); + } + /// Read-only counter APIs retain the renderer's bounds and never advance a list. #[test] fn reference_labels_are_bounded_and_do_not_advance_counters() {