M3.9: an edit that only allocates ids still counts as a change

`Project::same_content` ignored `next_id`, so an edit that only took an id was dropped as a
no-op and the id could be handed out again (an edit may keep it beyond the project).
`guard::tests::the_session_survives_a_panicking_edit`, merged after M3.9, failed on main for
this reason. Ids now count; setting a value to what it already is still records nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic 2026-10-05 06:43:10 +07:00
parent cb892b5239
commit a965d8df49
2 changed files with 7 additions and 5 deletions

View File

@ -1104,9 +1104,9 @@ impl Project {
}
self.next_id = m;
}
/// Whether `other` holds the same content (ids allocated but not used don't count). Shared
/// compositions compare by pointer first, so after a copy-on-write edit only the comps it
/// touched are compared field by field.
/// Whether `other` holds the same content. An allocated id counts (an edit may hand it out
/// beyond the project, so it must stay taken). Shared compositions compare by pointer first,
/// so after a copy-on-write edit only the comps it touched are compared field by field.
pub fn same_content(&self, other: &Project) -> bool {
let item_eq = |a: &Item, b: &Item| {
let kind = match (&a.kind, &b.kind) {
@ -1116,6 +1116,7 @@ impl Project {
kind && a.id == b.id && a.name == b.name && a.label == b.label && a.comment == b.comment && a.parent == b.parent && a.proxy == b.proxy
};
self.schema == other.schema
&& self.next_id == other.next_id
&& self.settings == other.settings
&& self.items.len() == other.items.len()
&& self.items.iter().zip(&other.items).all(|((ka, a), (kb, b))| ka == kb && item_eq(a, b))

View File

@ -86,12 +86,13 @@ fn camera_and_light_layers_build() {
}
#[test]
fn same_content_ignores_unused_ids_and_sees_comp_edits() {
fn same_content_sees_allocated_ids_and_comp_edits() {
let (p, cid) = project_with_layer();
let mut q = p.clone();
assert!(q.same_content(&p));
q.alloc();
assert!(q.same_content(&p), "an allocated but unused id is not a change");
assert!(!q.same_content(&p), "an allocated id stays taken");
let mut q = p.clone();
// A comp copied on write but left equal is the same; a changed one is not.
let _ = q.comp_mut(cid).unwrap();
assert!(q.same_content(&p));