diff --git a/gpx-rs/Cargo.lock b/gpx-rs/Cargo.lock
index 624382ae3..9acce6566 100644
--- a/gpx-rs/Cargo.lock
+++ b/gpx-rs/Cargo.lock
@@ -11,6 +11,15 @@ dependencies = [
"libc",
]
+[[package]]
+name = "atomic-polyfill"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
+dependencies = [
+ "critical-section",
+]
+
[[package]]
name = "autocfg"
version = "1.5.1"
@@ -23,6 +32,12 @@ version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
[[package]]
name = "cc"
version = "1.4.6"
@@ -52,6 +67,15 @@ dependencies = [
"windows-link",
]
+[[package]]
+name = "cobs"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
+dependencies = [
+ "thiserror",
+]
+
[[package]]
name = "console_error_panic_hook"
version = "0.1.7"
@@ -68,6 +92,30 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+[[package]]
+name = "critical-section"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
+
+[[package]]
+name = "embedded-io"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
+
+[[package]]
+name = "embedded-io"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
[[package]]
name = "find-msvc-tools"
version = "0.1.12"
@@ -114,7 +162,9 @@ name = "gpx-engine"
version = "0.1.0"
dependencies = [
"chrono",
+ "postcard",
"quick-xml",
+ "serde",
"uuid",
]
@@ -124,9 +174,40 @@ version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"gpx-engine",
+ "idb",
"js-sys",
"uuid",
"wasm-bindgen",
+ "wasm-bindgen-futures",
+]
+
+[[package]]
+name = "hash32"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
+
+[[package]]
+name = "heapless"
+version = "0.7.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
+dependencies = [
+ "atomic-polyfill",
+ "hash32",
+ "rustc_version",
+ "serde",
+ "spin",
+ "stable_deref_trait",
]
[[package]]
@@ -153,6 +234,31 @@ dependencies = [
"cc",
]
+[[package]]
+name = "idb"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6554f394e990a1af530a528a7fdcad6e01b29cb1b990f89df3ffd62cf15f7828"
+dependencies = [
+ "indexmap",
+ "js-sys",
+ "num-traits",
+ "thiserror",
+ "tokio",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
[[package]]
name = "js-sys"
version = "0.3.106"
@@ -170,6 +276,15 @@ version = "0.2.189"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
+[[package]]
+name = "lock_api"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
+dependencies = [
+ "scopeguard",
+]
+
[[package]]
name = "log"
version = "0.4.34"
@@ -203,6 +318,19 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+[[package]]
+name = "postcard"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
+dependencies = [
+ "cobs",
+ "embedded-io 0.4.0",
+ "embedded-io 0.6.1",
+ "heapless",
+ "serde",
+]
+
[[package]]
name = "proc-macro2"
version = "1.0.106"
@@ -236,12 +364,63 @@ version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
[[package]]
name = "rustversion"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "semver"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
+
+[[package]]
+name = "serde"
+version = "1.0.229"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.229"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.229"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.6",
+]
+
[[package]]
name = "shlex"
version = "2.0.1"
@@ -254,6 +433,21 @@ version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
+[[package]]
+name = "spin"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e"
+dependencies = [
+ "lock_api",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+
[[package]]
name = "syn"
version = "2.0.118"
@@ -276,6 +470,35 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "thiserror"
+version = "2.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.6",
+]
+
+[[package]]
+name = "tokio"
+version = "1.53.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e95f91fcc7a621e8b030f6aa23c71fe9838ae2fb4d8118b75602a328f5144044"
+dependencies = [
+ "pin-project-lite",
+]
+
[[package]]
name = "unicode-ident"
version = "1.0.24"
@@ -290,6 +513,7 @@ checksum = "2ef6dac1e96601b4fb3acccccff2139741fcb757cb9a36089bf5be91cfb285ce"
dependencies = [
"getrandom",
"js-sys",
+ "serde_core",
"wasm-bindgen",
]
@@ -306,6 +530,17 @@ dependencies = [
"wasm-bindgen-shared",
]
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3cbab34de2d982e9b48e18d216d04c4a6f641066ff19ffb699980f591ee3610e"
+dependencies = [
+ "js-sys",
+ "tokio",
+ "wasm-bindgen",
+]
+
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.129"
@@ -338,6 +573,16 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "web-sys"
+version = "0.3.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
[[package]]
name = "windows-core"
version = "0.62.2"
diff --git a/gpx-rs/engine/Cargo.toml b/gpx-rs/engine/Cargo.toml
index 2edb870f9..f6e72066f 100644
--- a/gpx-rs/engine/Cargo.toml
+++ b/gpx-rs/engine/Cargo.toml
@@ -5,5 +5,7 @@ edition = "2024"
[dependencies]
chrono = "0.4.45"
+postcard = { version = "1.1.3", features = ["use-std"] }
quick-xml = "0.42.0"
-uuid = { version = "1.26.1", features = ["v4"] }
+serde = { version = "1.0.229", features = ["derive"] }
+uuid = { version = "1.26.1", features = ["serde", "v4"] }
diff --git a/gpx-rs/engine/data/with_route_extensions.gpx b/gpx-rs/engine/data/with_route_extensions.gpx
new file mode 100644
index 000000000..9236a8246
--- /dev/null
+++ b/gpx-rs/engine/data/with_route_extensions.gpx
@@ -0,0 +1,23 @@
+
+
+
+ with extensions
+
+ 10
+
+
+
+
+
+
+
+
+ 20
+
+
+
+
+
+ empty
+
+
diff --git a/gpx-rs/engine/src/core/gpx/categories.rs b/gpx-rs/engine/src/core/gpx/categories.rs
index ad0f3097d..fc88378eb 100644
--- a/gpx-rs/engine/src/core/gpx/categories.rs
+++ b/gpx-rs/engine/src/core/gpx/categories.rs
@@ -3,7 +3,7 @@
///
/// The codes are the positions of the names in the order of first appearance. The table only
/// grows: a code never changes meaning, so it stays valid in every state of the history.
-#[derive(Debug, Default, Clone, PartialEq)]
+#[derive(Debug, Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Categories(Vec);
impl Categories {
@@ -36,7 +36,7 @@ impl Categories {
/// The categories of the data of the trackpoints. There is one table per engine, shared by all
/// its files.
-#[derive(Debug, Default, Clone, PartialEq)]
+#[derive(Debug, Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct TrackpointCategories {
pub surface: Categories,
pub highway: Categories,
diff --git a/gpx-rs/engine/src/core/gpx/chunk.rs b/gpx-rs/engine/src/core/gpx/chunk.rs
index bdf1e981f..f727e2429 100644
--- a/gpx-rs/engine/src/core/gpx/chunk.rs
+++ b/gpx-rs/engine/src/core/gpx/chunk.rs
@@ -5,8 +5,8 @@ use crate::{Trackpoint, Waypoint};
/// 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).
+/// A chunk has an identity, which changes whenever the content does (a modified chunk is a new
+/// one): what is derived from a chunk, or kept of it, is up to date as long as the identity is.
pub trait Chunk {
type Item: Clone;
@@ -27,8 +27,8 @@ pub trait Chunk {
const MAX_TRKPT_CHUNK_SIZE: usize = 4096;
-#[derive(Debug, PartialEq, Eq)]
-pub struct TrackpointChunkId(Uuid);
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
+pub struct TrackpointChunkId(pub Uuid);
impl Default for TrackpointChunkId {
fn default() -> Self {
@@ -42,12 +42,6 @@ pub struct TrackpointChunk {
pub trkpt: Vec,
}
-impl PartialEq for TrackpointChunk {
- fn eq(&self, other: &Self) -> bool {
- self.id == other.id
- }
-}
-
impl Chunk for TrackpointChunk {
type Item = Trackpoint;
const MAX_SIZE: usize = MAX_TRKPT_CHUNK_SIZE;
@@ -68,8 +62,8 @@ impl Chunk for TrackpointChunk {
}
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct WaypointChunkId(Uuid);
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
+pub struct WaypointChunkId(pub Uuid);
impl Default for WaypointChunkId {
fn default() -> Self {
@@ -85,12 +79,6 @@ pub struct WaypointChunk {
pub wpt: Vec,
}
-impl PartialEq for WaypointChunk {
- fn eq(&self, other: &Self) -> bool {
- self.id == other.id
- }
-}
-
impl Chunk for WaypointChunk {
type Item = Waypoint;
const MAX_SIZE: usize = MAX_WPT_CHUNK_SIZE;
@@ -141,20 +129,8 @@ mod tests {
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_ne!(a.id, b.id);
assert_eq!(a.items().len(), 1);
- assert_ne!(WaypointChunk::new(vec![]), WaypointChunk::new(vec![]));
- }
-
- #[test]
- fn test_chunk_equality_is_by_id() {
- let a = TrackpointChunk::default();
- let b = TrackpointChunk::default();
- assert_ne!(a, b);
- let c = TrackpointChunk {
- id: TrackpointChunkId(a.id.0),
- trkpt: vec![Trackpoint::default()],
- };
- assert_eq!(a, c);
+ assert_ne!(WaypointChunk::new(vec![]).id, WaypointChunk::new(vec![]).id);
}
}
diff --git a/gpx-rs/engine/src/core/gpx/chunked.rs b/gpx-rs/engine/src/core/gpx/chunked.rs
index 116d1142c..4e72d6824 100644
--- a/gpx-rs/engine/src/core/gpx/chunked.rs
+++ b/gpx-rs/engine/src/core/gpx/chunked.rs
@@ -6,7 +6,7 @@ use crate::Chunk;
/// copies the chunks around the change, so that a version costs little more than the change.
///
/// There are no empty chunks.
-#[derive(Debug, PartialEq)]
+#[derive(Debug)]
pub struct Chunked {
chunks: Vec>,
cumul_length: Vec,
diff --git a/gpx-rs/engine/src/core/gpx/common.rs b/gpx-rs/engine/src/core/gpx/common.rs
index 62b00f049..0e10bf026 100644
--- a/gpx-rs/engine/src/core/gpx/common.rs
+++ b/gpx-rs/engine/src/core/gpx/common.rs
@@ -1,10 +1,10 @@
-#[derive(Debug, Default, Clone, PartialEq, Eq)]
+#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct Link {
pub href: String,
pub text: Option,
}
-#[derive(Debug, Default, Clone, Copy)]
+#[derive(Debug, Default, Clone, Copy, serde::Serialize, serde::Deserialize)]
pub struct LngLat {
pub lng: f64,
pub lat: f64,
diff --git a/gpx-rs/engine/src/core/gpx/file.rs b/gpx-rs/engine/src/core/gpx/file.rs
index 3d2960a48..99dcc6954 100644
--- a/gpx-rs/engine/src/core/gpx/file.rs
+++ b/gpx-rs/engine/src/core/gpx/file.rs
@@ -2,7 +2,7 @@ use uuid::Uuid;
use crate::{Link, Track, Waypoints};
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct FileId(pub Uuid);
impl Default for FileId {
@@ -11,16 +11,15 @@ impl Default for FileId {
}
}
-#[derive(Debug, Default, Clone, PartialEq)]
+#[derive(Debug, Default, Clone)]
pub struct File {
pub id: FileId,
pub info: FileInfo,
pub trk: Vec