This commit is contained in:
vcoppe
2026-10-03 19:17:58 +02:00
parent 438a87f06f
commit fd76e0fa46
9 changed files with 42 additions and 24 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ impl TrackpointChunk {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct WaypointChunkId(Uuid); pub struct WaypointChunkId(Uuid);
impl Default for WaypointChunkId { impl Default for WaypointChunkId {
+10
View File
@@ -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)] #[derive(Debug, Default, Clone, PartialEq)]
pub struct File { pub struct File {
pub id: FileId, pub id: FileId,
pub info: FileInfo, pub info: FileInfo,
pub trk: Vec<Track>, pub trk: Vec<Track>,
pub wpt: Vec<Rc<WaypointChunk>>, pub wpt: Vec<Rc<WaypointChunk>>,
pub wpt_rev_id: FileWaypointsRevisionId,
// TODO routes // TODO routes
} }
@@ -181,7 +181,9 @@ mod tests {
file_id: id, file_id: id,
wpt_ids: HashSet::from([ids[1]]), wpt_ids: HashSet::from([ids[1]]),
}; };
let rev = fx.files[&id].wpt_rev_id;
Delete.apply(&mut fx.state()).unwrap(); Delete.apply(&mut fx.state()).unwrap();
assert_ne!(fx.files[&id].wpt_rev_id, rev);
let left: Vec<_> = fx.files[&id] let left: Vec<_> = fx.files[&id]
.wpt .wpt
.iter() .iter()
@@ -161,6 +161,7 @@ fn duplicate_waypoints(
chunks chunks
}; };
file.wpt.splice(last_chunk..=last_chunk, replacement); file.wpt.splice(last_chunk..=last_chunk, replacement);
file.wpt_rev_id = Default::default();
files.insert(file_id, Rc::new(file)); files.insert(file_id, Rc::new(file));
Ok(Selection::Waypoint { Ok(Selection::Waypoint {
file_id, file_id,
@@ -304,7 +305,9 @@ mod tests {
file_id: id, file_id: id,
wpt_ids: HashSet::from([ids[0]]), wpt_ids: HashSet::from([ids[0]]),
}; };
let rev = fx.files[&id].wpt_rev_id;
Duplicate.apply(&mut fx.state()).unwrap(); Duplicate.apply(&mut fx.state()).unwrap();
assert_ne!(fx.files[&id].wpt_rev_id, rev);
let all: Vec<_> = fx.files[&id] let all: Vec<_> = fx.files[&id]
.wpt .wpt
.iter() .iter()
@@ -33,5 +33,8 @@ pub fn edit_waypoint_chunks(
} }
} }
file.wpt = chunks; file.wpt = chunks;
if changed {
file.wpt_rev_id = Default::default();
}
changed changed
} }
@@ -305,7 +305,9 @@ mod tests {
file_id: id, file_id: id,
wpt_ids: HashSet::from([ids[1]]), wpt_ids: HashSet::from([ids[1]]),
}; };
let rev = fx.files[&id].wpt_rev_id;
update_selected(&mut fx.state(), &mut Name); update_selected(&mut fx.state(), &mut Name);
assert_ne!(fx.files[&id].wpt_rev_id, rev);
let chunk = &fx.files[&id].wpt[0]; let chunk = &fx.files[&id].wpt[0];
assert_ne!(chunk.id, chunk_id); assert_ne!(chunk.id, chunk_id);
let named: Vec<_> = chunk.wpt.iter().map(|w| w.name.is_some()).collect(); let named: Vec<_> = chunk.wpt.iter().map(|w| w.name.is_some()).collect();
@@ -1,7 +1,7 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use crate::{ 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 /// Coordinates buffers, as flat `[lng, lat, lng, lat, ...]` arrays so that they can be handed
@@ -11,7 +11,7 @@ use crate::{
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct CoordinatesCache { pub struct CoordinatesCache {
segments: HashMap<TrackSegmentId, (TrackSegmentRevisionId, Vec<f64>)>, segments: HashMap<TrackSegmentId, (TrackSegmentRevisionId, Vec<f64>)>,
waypoints: HashMap<FileId, (u64, Vec<f64>)>, waypoints: HashMap<FileId, (FileWaypointsRevisionId, Vec<f64>)>,
} }
impl CoordinatesCache { impl CoordinatesCache {
@@ -20,15 +20,19 @@ impl CoordinatesCache {
let mut waypoints = HashSet::new(); let mut waypoints = HashSet::new();
for file in files.into_iter().flat_map(|files| files.values()) { for file in files.into_iter().flat_map(|files| files.values()) {
waypoints.insert(file.id); waypoints.insert(file.id);
let rev = waypoints_revision(file); if self
if self.waypoints.get(&file.id).is_none_or(|(r, _)| *r != rev) { .waypoints
.get(&file.id)
.is_none_or(|(r, _)| *r != file.wpt_rev_id)
{
let coordinates = file let coordinates = file
.wpt .wpt
.iter() .iter()
.flat_map(|chunk| &chunk.wpt) .flat_map(|chunk| &chunk.wpt)
.flat_map(|wpt| [wpt.coordinates.lng, wpt.coordinates.lat]) .flat_map(|wpt| [wpt.coordinates.lng, wpt.coordinates.lat])
.collect(); .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) { for seg in file.trk.iter().flat_map(|trk| &trk.trkseg) {
segments.insert(seg.id); segments.insert(seg.id);
@@ -131,6 +135,7 @@ mod tests {
..Default::default() ..Default::default()
}; };
let mut file = (*fx.files[&id]).clone(); let mut file = (*fx.files[&id]).clone();
file.wpt_rev_id = Default::default();
file.wpt = vec![ file.wpt = vec![
Rc::new(WaypointChunk { Rc::new(WaypointChunk {
wpt: vec![wpt(1.0, 2.0)], wpt: vec![wpt(1.0, 2.0)],
@@ -1,6 +1,7 @@
use std::hash::{Hash, Hasher}; use crate::{
File, FileId, FileWaypointsRevisionId, TrackId, TrackSegmentId, TrackSegmentRevisionId,
use crate::{File, FileId, TrackId, TrackSegmentId, TrackSegmentRevisionId, WaypointId}; WaypointId,
};
/// What the UI needs to display a file: its name and the structure of its tracks and waypoints, /// 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 /// 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<TrackNode>, pub tracks: Vec<TrackNode>,
pub waypoints: Vec<WaypointNode>, pub waypoints: Vec<WaypointNode>,
/// Changes whenever the waypoints of the file (hence their buffer) change. /// Changes whenever the waypoints of the file (hence their buffer) change.
pub waypoints_rev: u64, pub wpt_rev_id: FileWaypointsRevisionId,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@@ -69,20 +70,11 @@ impl FileStructure {
name: wpt.name.clone(), name: wpt.name.clone(),
}) })
.collect(), .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)] #[cfg(test)]
mod tests { mod tests {
use std::rc::Rc; use std::rc::Rc;
@@ -116,7 +108,8 @@ mod tests {
name: Some(n.to_string()), name: Some(n.to_string()),
..Default::default() ..Default::default()
}; };
let before = waypoints_revision(&file); let before = file.wpt_rev_id;
file.wpt_rev_id = Default::default();
file.wpt = vec![ file.wpt = vec![
Rc::new(WaypointChunk { Rc::new(WaypointChunk {
wpt: vec![wpt("a"), wpt("b")], wpt: vec![wpt("a"), wpt("b")],
@@ -134,7 +127,7 @@ mod tests {
.map(|w| w.name.clone().unwrap()) .map(|w| w.name.clone().unwrap())
.collect(); .collect();
assert_eq!(names, ["a", "b", "c"]); assert_eq!(names, ["a", "b", "c"]);
assert_ne!(node.waypoints_rev, before); assert_ne!(node.wpt_rev_id, before);
assert_eq!(node.waypoints_rev, waypoints_revision(&file)); assert_eq!(node.wpt_rev_id, file.wpt_rev_id);
} }
} }
+1 -1
View File
@@ -425,7 +425,7 @@ fn structure_object(file: &engine::FileStructure) -> Object {
named_node(wpt.id.0, wpt.name.as_deref()).into() 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 node
} }