From fd76e0fa46461e45a7512c76abbe677c178144d3 Mon Sep 17 00:00:00 2001 From: vcoppe Date: Sat, 3 Oct 2026 19:17:58 +0200 Subject: [PATCH] progress --- gpx-rs/engine/src/core/gpx/chunk.rs | 2 +- gpx-rs/engine/src/core/gpx/file.rs | 10 +++++++ .../engine/src/engine/command/file/delete.rs | 2 ++ .../src/engine/command/file/duplicate.rs | 3 +++ .../command/pattern/edit_waypoint_chunks.rs | 3 +++ .../engine/command/pattern/update_selected.rs | 2 ++ .../src/engine/derived/coordinates_cache.rs | 15 +++++++---- .../src/engine/derived/file_structure.rs | 27 +++++++------------ gpx-rs/wasm/src/lib.rs | 2 +- 9 files changed, 42 insertions(+), 24 deletions(-) diff --git a/gpx-rs/engine/src/core/gpx/chunk.rs b/gpx-rs/engine/src/core/gpx/chunk.rs index cf4c6b2a5..3fd661910 100644 --- a/gpx-rs/engine/src/core/gpx/chunk.rs +++ b/gpx-rs/engine/src/core/gpx/chunk.rs @@ -31,7 +31,7 @@ impl TrackpointChunk { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct WaypointChunkId(Uuid); impl Default for WaypointChunkId { diff --git a/gpx-rs/engine/src/core/gpx/file.rs b/gpx-rs/engine/src/core/gpx/file.rs index 0e7d8b0a0..09b1b8f55 100644 --- a/gpx-rs/engine/src/core/gpx/file.rs +++ b/gpx-rs/engine/src/core/gpx/file.rs @@ -13,12 +13,22 @@ impl Default for FileId { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct FileWaypointsRevisionId(pub Uuid); + +impl Default for FileWaypointsRevisionId { + fn default() -> Self { + Self(Uuid::new_v4()) + } +} + #[derive(Debug, Default, Clone, PartialEq)] pub struct File { pub id: FileId, pub info: FileInfo, pub trk: Vec, pub wpt: Vec>, + pub wpt_rev_id: FileWaypointsRevisionId, // TODO routes } diff --git a/gpx-rs/engine/src/engine/command/file/delete.rs b/gpx-rs/engine/src/engine/command/file/delete.rs index e9d6ff0d8..d420168bc 100644 --- a/gpx-rs/engine/src/engine/command/file/delete.rs +++ b/gpx-rs/engine/src/engine/command/file/delete.rs @@ -181,7 +181,9 @@ mod tests { file_id: id, wpt_ids: HashSet::from([ids[1]]), }; + let rev = fx.files[&id].wpt_rev_id; Delete.apply(&mut fx.state()).unwrap(); + assert_ne!(fx.files[&id].wpt_rev_id, rev); let left: Vec<_> = fx.files[&id] .wpt .iter() diff --git a/gpx-rs/engine/src/engine/command/file/duplicate.rs b/gpx-rs/engine/src/engine/command/file/duplicate.rs index 705d422ed..66446bee1 100644 --- a/gpx-rs/engine/src/engine/command/file/duplicate.rs +++ b/gpx-rs/engine/src/engine/command/file/duplicate.rs @@ -161,6 +161,7 @@ fn duplicate_waypoints( chunks }; file.wpt.splice(last_chunk..=last_chunk, replacement); + file.wpt_rev_id = Default::default(); files.insert(file_id, Rc::new(file)); Ok(Selection::Waypoint { file_id, @@ -304,7 +305,9 @@ mod tests { file_id: id, wpt_ids: HashSet::from([ids[0]]), }; + let rev = fx.files[&id].wpt_rev_id; Duplicate.apply(&mut fx.state()).unwrap(); + assert_ne!(fx.files[&id].wpt_rev_id, rev); let all: Vec<_> = fx.files[&id] .wpt .iter() diff --git a/gpx-rs/engine/src/engine/command/pattern/edit_waypoint_chunks.rs b/gpx-rs/engine/src/engine/command/pattern/edit_waypoint_chunks.rs index 919c55d97..4769b740c 100644 --- a/gpx-rs/engine/src/engine/command/pattern/edit_waypoint_chunks.rs +++ b/gpx-rs/engine/src/engine/command/pattern/edit_waypoint_chunks.rs @@ -33,5 +33,8 @@ pub fn edit_waypoint_chunks( } } file.wpt = chunks; + if changed { + file.wpt_rev_id = Default::default(); + } changed } diff --git a/gpx-rs/engine/src/engine/command/pattern/update_selected.rs b/gpx-rs/engine/src/engine/command/pattern/update_selected.rs index e05570003..439fbe527 100644 --- a/gpx-rs/engine/src/engine/command/pattern/update_selected.rs +++ b/gpx-rs/engine/src/engine/command/pattern/update_selected.rs @@ -305,7 +305,9 @@ mod tests { file_id: id, wpt_ids: HashSet::from([ids[1]]), }; + let rev = fx.files[&id].wpt_rev_id; update_selected(&mut fx.state(), &mut Name); + assert_ne!(fx.files[&id].wpt_rev_id, rev); let chunk = &fx.files[&id].wpt[0]; assert_ne!(chunk.id, chunk_id); let named: Vec<_> = chunk.wpt.iter().map(|w| w.name.is_some()).collect(); diff --git a/gpx-rs/engine/src/engine/derived/coordinates_cache.rs b/gpx-rs/engine/src/engine/derived/coordinates_cache.rs index bc8d35289..e74d22846 100644 --- a/gpx-rs/engine/src/engine/derived/coordinates_cache.rs +++ b/gpx-rs/engine/src/engine/derived/coordinates_cache.rs @@ -1,7 +1,7 @@ use std::collections::{HashMap, HashSet}; use crate::{ - FileId, StackEntry as Files, TrackSegmentId, TrackSegmentRevisionId, waypoints_revision, + FileId, FileWaypointsRevisionId, StackEntry as Files, TrackSegmentId, TrackSegmentRevisionId, }; /// Coordinates buffers, as flat `[lng, lat, lng, lat, ...]` arrays so that they can be handed @@ -11,7 +11,7 @@ use crate::{ #[derive(Debug, Default)] pub struct CoordinatesCache { segments: HashMap)>, - waypoints: HashMap)>, + waypoints: HashMap)>, } impl CoordinatesCache { @@ -20,15 +20,19 @@ impl CoordinatesCache { let mut waypoints = HashSet::new(); for file in files.into_iter().flat_map(|files| files.values()) { waypoints.insert(file.id); - let rev = waypoints_revision(file); - if self.waypoints.get(&file.id).is_none_or(|(r, _)| *r != rev) { + if self + .waypoints + .get(&file.id) + .is_none_or(|(r, _)| *r != file.wpt_rev_id) + { let coordinates = file .wpt .iter() .flat_map(|chunk| &chunk.wpt) .flat_map(|wpt| [wpt.coordinates.lng, wpt.coordinates.lat]) .collect(); - self.waypoints.insert(file.id, (rev, coordinates)); + self.waypoints + .insert(file.id, (file.wpt_rev_id, coordinates)); } for seg in file.trk.iter().flat_map(|trk| &trk.trkseg) { segments.insert(seg.id); @@ -131,6 +135,7 @@ mod tests { ..Default::default() }; let mut file = (*fx.files[&id]).clone(); + file.wpt_rev_id = Default::default(); file.wpt = vec![ Rc::new(WaypointChunk { wpt: vec![wpt(1.0, 2.0)], diff --git a/gpx-rs/engine/src/engine/derived/file_structure.rs b/gpx-rs/engine/src/engine/derived/file_structure.rs index 8ca959852..ba17136b0 100644 --- a/gpx-rs/engine/src/engine/derived/file_structure.rs +++ b/gpx-rs/engine/src/engine/derived/file_structure.rs @@ -1,6 +1,7 @@ -use std::hash::{Hash, Hasher}; - -use crate::{File, FileId, TrackId, TrackSegmentId, TrackSegmentRevisionId, WaypointId}; +use crate::{ + File, FileId, FileWaypointsRevisionId, TrackId, TrackSegmentId, TrackSegmentRevisionId, + WaypointId, +}; /// What the UI needs to display a file: its name and the structure of its tracks and waypoints, /// with the ids that reference every element. Coordinates are not part of it, they are read @@ -14,7 +15,7 @@ pub struct FileStructure { pub tracks: Vec, pub waypoints: Vec, /// Changes whenever the waypoints of the file (hence their buffer) change. - pub waypoints_rev: u64, + pub wpt_rev_id: FileWaypointsRevisionId, } #[derive(Debug, Clone, PartialEq)] @@ -69,20 +70,11 @@ impl FileStructure { name: wpt.name.clone(), }) .collect(), - waypoints_rev: waypoints_revision(file), + wpt_rev_id: file.wpt_rev_id, } } } -/// Identifies the current waypoints of a file: chunks are immutable, so their ids are enough. -pub fn waypoints_revision(file: &File) -> u64 { - let mut hasher = std::collections::hash_map::DefaultHasher::new(); - for chunk in &file.wpt { - chunk.id.hash(&mut hasher); - } - hasher.finish() -} - #[cfg(test)] mod tests { use std::rc::Rc; @@ -116,7 +108,8 @@ mod tests { name: Some(n.to_string()), ..Default::default() }; - let before = waypoints_revision(&file); + let before = file.wpt_rev_id; + file.wpt_rev_id = Default::default(); file.wpt = vec![ Rc::new(WaypointChunk { wpt: vec![wpt("a"), wpt("b")], @@ -134,7 +127,7 @@ mod tests { .map(|w| w.name.clone().unwrap()) .collect(); assert_eq!(names, ["a", "b", "c"]); - assert_ne!(node.waypoints_rev, before); - assert_eq!(node.waypoints_rev, waypoints_revision(&file)); + assert_ne!(node.wpt_rev_id, before); + assert_eq!(node.wpt_rev_id, file.wpt_rev_id); } } diff --git a/gpx-rs/wasm/src/lib.rs b/gpx-rs/wasm/src/lib.rs index 195d054b1..b66165ccd 100644 --- a/gpx-rs/wasm/src/lib.rs +++ b/gpx-rs/wasm/src/lib.rs @@ -425,7 +425,7 @@ fn structure_object(file: &engine::FileStructure) -> Object { named_node(wpt.id.0, wpt.name.as_deref()).into() }), ); - set(&node, "waypointsRev", format!("{:x}", file.waypoints_rev)); + set(&node, "waypointsRev", file.wpt_rev_id.0.to_string()); node }