From e917272c60f2046567c0da48543f721b20d913e2 Mon Sep 17 00:00:00 2001 From: Vectornaut Date: Fri, 22 Nov 2024 02:25:10 +0000 Subject: [PATCH] Give each element a serial number (#22) Give each `Element` a serial number, which identifies it uniquely. The serial number is assigned by the `Element::new` constructor. Because disallows potentially unsafe global state (at least without explicit `unsafe` blocks), the next serial number is stored in a thread-safe static atomic variable (`assembly::NEXT_ELEMENT_SERIAL`), as suggested in [this StackOverflow answer](https://stackoverflow.com/a/32936288). Since the overhead for keeping track of memory ordering should be minimal, we're using the strongest available ordering: [sequentially consistent](https://marabos.nl/atomics/memory-ordering.html#seqcst). Resolves #20. Co-authored-by: Aaron Fenyes Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/22 Co-authored-by: Vectornaut Co-committed-by: Vectornaut --- app-proto/src/assembly.rs | 25 ++++++++++++++++++++++++- app-proto/src/outline.rs | 2 +- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index 35b4417..59cba41 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -1,7 +1,7 @@ use nalgebra::{DMatrix, DVector}; use rustc_hash::FxHashMap; use slab::Slab; -use std::collections::BTreeSet; +use std::{collections::BTreeSet, sync::atomic::{AtomicU64, Ordering}}; use sycamore::prelude::*; use web_sys::{console, wasm_bindgen::JsValue}; /* DEBUG */ @@ -13,6 +13,13 @@ pub type ConstraintKey = usize; pub type ElementColor = [f32; 3]; +/* KLUDGE */ +// we should reconsider this design when we build a system for switching between +// assemblies. at that point, we might want to switch to hierarchical keys, +// where each each element has a key that identifies it within its assembly and +// each assembly has a key that identifies it within the sesssion +static NEXT_ELEMENT_SERIAL: AtomicU64 = AtomicU64::new(0); + #[derive(Clone, PartialEq)] pub struct Element { pub id: String, @@ -20,6 +27,10 @@ pub struct Element { pub color: ElementColor, pub representation: Signal>, pub constraints: Signal>, + + // a serial number, assigned by `Element::new`, that uniquely identifies + // each element + pub serial: u64, // the configuration matrix column index that was assigned to this element // last time the assembly was realized @@ -33,12 +44,24 @@ impl Element { color: ElementColor, representation: DVector ) -> Element { + // take the next serial number, panicking if that was the last number we + // had left. the technique we use to panic on overflow is taken from + // _Rust Atomics and Locks_, by Mara Bos + // + // https://marabos.nl/atomics/atomics.html#example-handle-overflow + // + let serial = NEXT_ELEMENT_SERIAL.fetch_update( + Ordering::SeqCst, Ordering::SeqCst, + |serial| serial.checked_add(1) + ).expect("Out of serial numbers for elements"); + Element { id: id, label: label, color: color, representation: create_signal(representation), constraints: create_signal(BTreeSet::default()), + serial: serial, column_index: 0 } } diff --git a/app-proto/src/outline.rs b/app-proto/src/outline.rs index ee1603f..e2cf49c 100644 --- a/app-proto/src/outline.rs +++ b/app-proto/src/outline.rs @@ -200,7 +200,7 @@ pub fn Outline() -> View { view=|(key, elt)| view! { ElementOutlineItem(key=key, element=elt) }, - key=|(key, _)| key.clone() + key=|(_, elt)| elt.serial ) } }