Files
gpx.studio/gpx-rs/engine/src/core/gpx/chunk.rs
T

160 lines
3.7 KiB
Rust
Raw Normal View History

2026-10-01 18:42:31 +02:00
use uuid::Uuid;
2026-10-03 10:03:22 +02:00
use crate::{Trackpoint, Waypoint};
2026-09-23 19:53:39 +02:00
2026-10-07 18:22:30 +02:00
/// A run of items, shared between the successive versions of a [`crate::Chunked`] list: a chunk
/// that is not touched by an edit is not copied.
///
/// Chunks are equal when they have the same identity, which is cheap to compare and changes
/// whenever the content does (a modified chunk is a new one).
pub trait Chunk {
type Item: Clone;
/// Maximum number of items of a chunk.
const MAX_SIZE: usize;
/// A chunk with a new identity, holding `items`.
fn new(items: Vec<Self::Item>) -> Self;
fn items(&self) -> &Vec<Self::Item>;
fn items_mut(&mut self) -> &mut Vec<Self::Item>;
fn is_full(&self) -> bool {
self.items().len() >= Self::MAX_SIZE
}
}
2026-10-03 20:54:05 +02:00
const MAX_TRKPT_CHUNK_SIZE: usize = 4096;
2026-09-23 19:53:39 +02:00
2026-10-02 18:06:45 +02:00
#[derive(Debug, PartialEq, Eq)]
pub struct TrackpointChunkId(Uuid);
impl Default for TrackpointChunkId {
fn default() -> Self {
Self(Uuid::new_v4())
}
2026-09-23 19:53:39 +02:00
}
2026-10-02 18:06:45 +02:00
#[derive(Debug, Default)]
pub struct TrackpointChunk {
pub id: TrackpointChunkId,
pub trkpt: Vec<Trackpoint>,
2026-10-01 18:42:31 +02:00
}
impl PartialEq for TrackpointChunk {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
2026-10-07 18:22:30 +02:00
impl Chunk for TrackpointChunk {
type Item = Trackpoint;
const MAX_SIZE: usize = MAX_TRKPT_CHUNK_SIZE;
fn new(trkpt: Vec<Trackpoint>) -> Self {
Self {
trkpt,
..Default::default()
}
}
fn items(&self) -> &Vec<Trackpoint> {
&self.trkpt
}
fn items_mut(&mut self) -> &mut Vec<Trackpoint> {
&mut self.trkpt
2026-09-23 19:53:39 +02:00
}
}
2026-10-03 19:17:58 +02:00
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2026-10-02 18:06:45 +02:00
pub struct WaypointChunkId(Uuid);
2026-09-23 19:53:39 +02:00
2026-10-02 18:06:45 +02:00
impl Default for WaypointChunkId {
fn default() -> Self {
Self(Uuid::new_v4())
}
2026-09-23 19:53:39 +02:00
}
2026-10-03 20:54:05 +02:00
const MAX_WPT_CHUNK_SIZE: usize = 128;
2026-10-02 18:06:45 +02:00
#[derive(Debug, Default)]
pub struct WaypointChunk {
pub id: WaypointChunkId,
pub wpt: Vec<Waypoint>,
2026-10-01 18:42:31 +02:00
}
impl PartialEq for WaypointChunk {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
2026-10-07 18:22:30 +02:00
impl Chunk for WaypointChunk {
type Item = Waypoint;
const MAX_SIZE: usize = MAX_WPT_CHUNK_SIZE;
fn new(wpt: Vec<Waypoint>) -> Self {
Self {
wpt,
..Default::default()
}
}
fn items(&self) -> &Vec<Waypoint> {
&self.wpt
}
fn items_mut(&mut self) -> &mut Vec<Waypoint> {
&mut self.wpt
2026-09-23 19:53:39 +02:00
}
}
2026-10-03 16:16:47 +02:00
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_trackpoint_chunk_full() {
let mut chunk = TrackpointChunk::default();
assert!(!chunk.is_full());
for _ in 0..MAX_TRKPT_CHUNK_SIZE - 1 {
chunk.trkpt.push(Trackpoint::default());
}
assert!(!chunk.is_full());
chunk.trkpt.push(Trackpoint::default());
assert!(chunk.is_full());
}
#[test]
fn test_waypoint_chunk_full() {
let mut chunk = WaypointChunk::default();
assert!(!chunk.is_full());
for _ in 0..MAX_WPT_CHUNK_SIZE {
chunk.wpt.push(Waypoint::default());
}
assert!(chunk.is_full());
}
2026-10-07 18:22:30 +02:00
#[test]
fn test_new_chunks_have_their_own_identity() {
let a = TrackpointChunk::new(vec![Trackpoint::default()]);
let b = TrackpointChunk::new(vec![Trackpoint::default()]);
assert_ne!(a, b);
assert_eq!(a.items().len(), 1);
assert_ne!(WaypointChunk::new(vec![]), WaypointChunk::new(vec![]));
}
2026-10-03 16:16:47 +02:00
#[test]
fn test_chunk_equality_is_by_id() {
let a = TrackpointChunk::default();
let b = TrackpointChunk::default();
assert_ne!(a, b);
2026-10-03 20:54:05 +02:00
let c = TrackpointChunk {
id: TrackpointChunkId(a.id.0),
trkpt: vec![Trackpoint::default()],
};
2026-10-03 16:16:47 +02:00
assert_eq!(a, c);
}
}