wasm first steps

This commit is contained in:
vcoppe
2026-07-14 18:36:30 +02:00
parent 86f4fc3394
commit ed6264444f
11 changed files with 398 additions and 3 deletions
+2
View File
@@ -0,0 +1,2 @@
target/
pkg/
+114
View File
@@ -0,0 +1,114 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "bumpalo"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "gpx-rs"
version = "0.1.0"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustversion"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "wasm-bindgen"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24"
dependencies = [
"unicode-ident",
]
+10
View File
@@ -0,0 +1,10 @@
[package]
name = "gpx-rs"
version = "0.1.0"
edition = "2024"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
+27
View File
@@ -0,0 +1,27 @@
use std::rc::Rc;
use wasm_bindgen::prelude::*;
use crate::{stack::Stack, types::GPXFile};
#[wasm_bindgen]
pub struct Controller {
stack: Stack,
}
#[wasm_bindgen]
impl Controller {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Self {
stack: Stack::default(),
}
}
#[wasm_bindgen]
pub fn create_file(&mut self, name: &str) {
let id = self.stack.get_new_file_id();
let file = Rc::new(GPXFile::new(id, name));
self.stack.update(&[file]);
}
}
+3
View File
@@ -0,0 +1,3 @@
mod controller;
mod stack;
mod types;
+101
View File
@@ -0,0 +1,101 @@
use std::{collections::HashMap, rc::Rc};
use crate::types::{GPXFile, GPXFileId};
#[derive(Default)]
pub struct Stack {
entries: Vec<StackEntry>,
index: Option<usize>,
}
impl Stack {
pub fn current(&self) -> Option<&StackEntry> {
match self.index {
Some(i) => Some(&self.entries[i]),
None => None,
}
}
pub fn get_new_file_id(&self) -> GPXFileId {
if let Some(current) = self.current() {
for id in 0..current.len() {
if !current.contains_key(&id) {
return id;
}
}
current.len() as GPXFileId
} else {
0
}
}
pub fn update(&mut self, files: &[Rc<GPXFile>]) {
let mut next = match self.current() {
Some(current) => current.clone(),
None => StackEntry::default(),
};
for file in files {
next.insert(file.id, file.clone());
}
self.push(next);
}
pub fn delete(&mut self, files: &[GPXFileId]) {
if let Some(current) = self.current() {
let mut next = current.clone();
for file in files {
next.remove(file);
}
self.push(next);
}
}
pub fn can_undo(&self) -> bool {
self.index.is_some()
}
pub fn can_redo(&self) -> bool {
match self.index {
Some(i) => i + 1 < self.entries.len(),
None => !self.entries.is_empty(),
}
}
pub fn undo(&mut self) {
if let Some(i) = self.index {
if i == 0 {
self.index = None;
} else {
self.index = Some(i - 1);
}
}
}
pub fn redo(&mut self) {
match self.index {
Some(i) => {
if i + 1 < self.entries.len() {
self.index = Some(i + 1);
}
}
None => {
if !self.entries.is_empty() {
self.index = Some(0);
}
}
}
}
fn push(&mut self, entry: StackEntry) {
if let Some(i) = self.index {
if i + 1 < self.entries.len() {
self.entries.truncate(i + 1);
}
}
self.entries.push(entry);
self.index = Some(self.entries.len() - 1);
}
}
pub type StackEntry = HashMap<GPXFileId, Rc<GPXFile>>;
+106
View File
@@ -0,0 +1,106 @@
use std::rc::Rc;
pub type GPXFileId = usize;
pub struct GPXFile {
pub id: GPXFileId,
pub info: Rc<GPXFileInfo>,
pub trk: Vec<Track>,
pub wpt: Vec<Rc<WaypointChunk>>,
}
impl GPXFile {
pub fn new(id: GPXFileId, name: &str) -> Self {
Self {
id,
info: Rc::new(GPXFileInfo::new(name)),
trk: Vec::new(),
wpt: Vec::new(),
}
}
}
pub struct GPXFileInfo {
pub name: String,
pub desc: Option<String>,
pub author: Option<Author>,
pub link: Option<Link>,
pub time: Option<i64>,
}
impl GPXFileInfo {
pub fn new(name: &str) -> Self {
Self {
name: name.to_owned(),
desc: None,
author: None,
link: None,
time: None,
}
}
}
pub struct Author {
pub name: Option<String>,
pub email: Option<String>,
pub link: Option<Link>,
}
pub struct Link {
pub href: String,
pub text: Option<String>,
pub type_: Option<String>,
}
pub struct Track {
pub info: Rc<TrackInfo>,
pub trkseg: Vec<TrackSegment>,
}
pub struct TrackInfo {
name: Option<String>,
cmt: Option<String>,
desc: Option<String>,
src: Option<String>,
link: Option<Link>,
type_: Option<String>,
color: Option<String>,
opacity: Option<f64>,
width: Option<f64>,
}
pub struct TrackSegment {
pub trkpt: Vec<Rc<TrackPointChunk>>,
}
pub type TrackPointChunk = Vec<TrackPoint>;
pub struct TrackPoint {
pub coordinates: LngLat,
pub ele: f64,
pub time: Option<i64>,
pub hr: Option<u16>,
pub cad: Option<u16>,
pub power: Option<u16>,
pub atemp: Option<i16>,
// TODO OSM data? or store intervals at a higher level?
}
pub type WaypointChunk = Vec<Waypoint>;
pub struct Waypoint {
pub coordinates: LngLat,
pub ele: f64,
pub time: Option<i64>,
pub name: Option<String>,
pub cmt: Option<String>,
pub desc: Option<String>,
pub link: Option<Link>,
pub sym: Option<String>,
pub type_: Option<String>,
}
pub struct LngLat {
pub lng: f64,
pub lat: f64,
}