From 74ad76f504e057e3a0c3362e273d96b1d3efbfc4 Mon Sep 17 00:00:00 2001
From: Dane Johnson <daneallenjohnson@protonmail.com>
Date: Tue, 3 May 2022 15:41:42 -0500
Subject: [PATCH] Use global state

---
 Cargo.lock  | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 Cargo.toml  |   1 +
 board.zip   | Bin 511836 -> 511876 bytes
 src/main.rs |  52 +++++++------
 4 files changed, 238 insertions(+), 27 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 9a3af60..6c24e3e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -26,6 +26,15 @@ dependencies = [
  "opaque-debug",
 ]
 
+[[package]]
+name = "ansi_term"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
+dependencies = [
+ "winapi",
+]
+
 [[package]]
 name = "autocfg"
 version = "1.1.0"
@@ -67,6 +76,7 @@ dependencies = [
  "image",
  "serde",
  "serde_json",
+ "state",
  "zip",
 ]
 
@@ -328,6 +338,19 @@ version = "0.3.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
 
+[[package]]
+name = "generator"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1d9279ca822891c1a4dae06d185612cf8fc6acfe5dff37781b41297811b12ee"
+dependencies = [
+ "cc",
+ "libc",
+ "log",
+ "rustversion",
+ "winapi",
+]
+
 [[package]]
 name = "generic-array"
 version = "0.14.5"
@@ -484,6 +507,30 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "loom"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edc5c7d328e32cc4954e8e01193d7f0ef5ab257b5090b70a964e099a36034309"
+dependencies = [
+ "cfg-if",
+ "generator",
+ "scoped-tls",
+ "serde",
+ "serde_json",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "matchers"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
+dependencies = [
+ "regex-automata",
+]
+
 [[package]]
 name = "memoffset"
 version = "0.6.5"
@@ -571,6 +618,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "once_cell"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
+
 [[package]]
 name = "opaque-debug"
 version = "0.3.0"
@@ -626,6 +679,12 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "pin-project-lite"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
+
 [[package]]
 name = "pkg-config"
 version = "0.3.25"
@@ -692,12 +751,48 @@ dependencies = [
  "num_cpus",
 ]
 
+[[package]]
+name = "regex"
+version = "1.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
+dependencies = [
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
+dependencies = [
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+
+[[package]]
+name = "rustversion"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
+
 [[package]]
 name = "ryu"
 version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
 
+[[package]]
+name = "scoped-tls"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
+
 [[package]]
 name = "scoped_threadpool"
 version = "0.1.9"
@@ -763,6 +858,15 @@ dependencies = [
  "digest",
 ]
 
+[[package]]
+name = "sharded-slab"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
+dependencies = [
+ "lazy_static",
+]
+
 [[package]]
 name = "smallvec"
 version = "1.8.0"
@@ -778,6 +882,15 @@ dependencies = [
  "lock_api",
 ]
 
+[[package]]
+name = "state"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b"
+dependencies = [
+ "loom",
+]
+
 [[package]]
 name = "subtle"
 version = "2.4.1"
@@ -795,6 +908,15 @@ dependencies = [
  "unicode-xid",
 ]
 
+[[package]]
+name = "thread_local"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
+dependencies = [
+ "once_cell",
+]
+
 [[package]]
 name = "threadpool"
 version = "1.8.1"
@@ -833,6 +955,68 @@ version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
 
+[[package]]
+name = "tracing"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09"
+dependencies = [
+ "cfg-if",
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f"
+dependencies = [
+ "lazy_static",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
+dependencies = [
+ "lazy_static",
+ "log",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596"
+dependencies = [
+ "ansi_term",
+ "lazy_static",
+ "matchers",
+ "regex",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+]
+
 [[package]]
 name = "ttf-parser"
 version = "0.15.0"
@@ -851,6 +1035,12 @@ version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
 
+[[package]]
+name = "valuable"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+
 [[package]]
 name = "version_check"
 version = "0.9.4"
@@ -923,6 +1113,28 @@ version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c97e489d8f836838d497091de568cf16b117486d529ec5579233521065bd5e4"
 
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
 [[package]]
 name = "zip"
 version = "0.6.2"
diff --git a/Cargo.toml b/Cargo.toml
index 7b9c7f3..c285a1b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
 [dependencies]
 
 fltk = "1.3.6"
+state = "0.5.3"
 serde = { version = "1.0.136", features = ["derive"] }
 serde_json = "1.0.79"
 zip = "0.6.2"
diff --git a/board.zip b/board.zip
index a7533b3f087033a2e07b72206603c1a53797bb64..bc4d9b841250a7433d23d16eb7f7e78716347efd 100644
GIT binary patch
delta 417
zcmcaJPrhZoe0_j7Gm8iV0|N)cuO*8^OsW~aiZe1WtY%_h-~x)K7bO;C=w%h>=ha?3
z=yyaxfbBteriJj~DUA!OqlMR31w1}jk)WHEoGa|L==HMqdbzuF$|mdbHnQydb66%K
zyL_GOjb{c$*S>C@J*{Wi%l6zOp^=kTI4Gz8u3W8}$^3D}-}<7Q!|!$_)Lu3|7xUNd
zZtXRhomCHKN+(XVN$hc4EY4@rprkl?d+ys0nZ|tAMAWq6<{eM+RCV;Ya<Zz(xnQ5R
z+-|iUyLRxKxqNb2pL!x?kx=T?pmXx7Kev5<_}Kc>(dN(lIQQO9*IS!dTID;ZJt{%O
zi_!Ns>%NWCl^@TV);aB>-zt+!POmfk>ldxx`#1L%_tV#FYI>d?o~Tvm*BLpv>|FaE
z?-S>Lg{bi@Z8|k0*+5~bCbyY=+Q!<?XS4lI{eNKbj}avRn^hRwRTx2-35c12m<5Pg
sftYQ(3M2devwWzbJpJQ2b}eS0*mSw`?9z<()2+_4%dq`F#|{j80P1A400000

delta 420
zcmZpfFMnsAe0_j7Gm8iV0|N(xWBuHa*dGZg?}5Buj0_B1KsvoBu^>Y)t2jTe_QFBG
zBMJg+55hB_-H}*!hT(0l@1Cl_#|JAMx^L~+#;JO-^m6(3D|!p7BNS9*{^{Enx720a
z<v1(2s^YJM@;VQrYsaP(bm+IvnwqAyaC<zT)DGF29~x!#`TMH31~g^gSN@<ff4Pu>
z;)*TnJg%*7%8IO7U9;Oz<omhbdOZIoBwn0!a#GXIuqFPz9tAchcYXV|{r3E$nyWwU
zzrG`-(`k~|$KyL&Ki7V|P=0Xh(bx@%VcVqC*Dgx^yy~p0L}|^sTfKYN1U_+j)MD7y
z<CW}`qMLH5tlGNnS@JP8iSV2EGvtitxdmUm)VAqQ_vb|BDaFm1znD=1rrC$F-G>o`
znShuXh*^M`6^Plk`!KTaKg)+2debG(vuinm!~{~St7o2NXZU%Joq-b=qA;+eQ5+b?
dnYoGSsd@!@=>guXY#=EnAj}8S*MZ6z7yx=*tD*n^

diff --git a/src/main.rs b/src/main.rs
index 31e5dae..801af48 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -9,14 +9,18 @@ extern crate image;
 use image::io::Reader as ImageReader;
 use image::{ DynamicImage };
 
+use state::Storage;
+
 use std::collections::{HashMap, HashSet};
 
-use std::cell::RefCell;
-use std::rc::Rc;
+use std::sync::Mutex;
 
 use std::io::{ Write, Read, Cursor };
 use std::fs::File;
 
+//////////////////// Global State ////////////////////
+// Don't @ me...
+static STATE: Storage<Mutex<AppState>> = Storage::new();
 
 //////////////////// Data Layout ////////////////////
 
@@ -131,14 +135,16 @@ fn node_create_dialog(state: &mut AppState, pos_x: f32, pos_y: f32) {
 mod dispatch {
     use super::*;
     type Coords = (f32, f32);
-    pub(super) fn node_press(state: &mut AppState, coords: Coords) {
+    pub(super) fn node_press(coords: Coords) {
 	let (pos_x, pos_y) = coords;
 	if app::event_button() == 1 {
 	    let name = dialog::input_default("Node", "");
 	    if let Some(name) = name {
+		let mut state = STATE.get().lock().unwrap();
 		state.board.add_node(pos_x, pos_y, name);
 	    }
 	} else if app::event_button() == 3 {
+	    let mut state = STATE.get().lock().unwrap();
 	    let id = state.board.nearest_node(pos_x, pos_y);
 	    if let Some(id) = id {
 		state.board.remove_node(id);
@@ -146,8 +152,9 @@ mod dispatch {
 	}
 	app::redraw();
     }
-    pub(super) fn edge_press(state: &mut AppState, coords: Coords) {
+    pub(super) fn edge_press(coords: Coords) {
 	let (pos_x, pos_y) = coords;
+	let mut state = STATE.get().lock().unwrap();
 	if app::event_button() == 1 {
 	    match (state.selected_node, state.board.nearest_node(pos_x, pos_y)) {
 		(Some(selected), Some(nearest)) => {
@@ -218,7 +225,7 @@ impl CoordTransformer for frame::Frame {
 }
 
 //////////////////// App State ////////////////////
-
+#[derive(Clone, Copy)]
 enum EditMode {
     Node,
     Edge,
@@ -245,6 +252,8 @@ impl AppState {
 //////////////////// Procedural App Creation ////////////////////
 
 fn main() {
+    // State
+    STATE.set(Mutex::new(AppState::new()));
     // App setup
     let app = app::App::default()
 	.with_scheme(app::Scheme::Gtk);
@@ -255,17 +264,12 @@ fn main() {
 	.size_of_parent();
     flex.set_type(group::FlexType::Column);
 
-    // State
-    let state = Rc::new(RefCell::new(AppState::new()));
-
     // Menu
     let mut menubar = menu::MenuBar::default();
-    let state_clone = Rc::clone(&state);
     menubar.add("File/New", Shortcut::None, menu::MenuFlag::Normal, move |_| {
-	state_clone.replace(AppState::new());
+	*STATE.get().lock().unwrap() = AppState::new();
 	app::redraw();
     });
-    let state_clone = Rc::clone(&state);
     menubar.add("File/Open...", Shortcut::None, menu::MenuFlag::Normal, move |_| {
 	let mut fc = dialog::NativeFileChooser::new(dialog::NativeFileChooserType::BrowseFile);
 	fc.show();
@@ -285,9 +289,8 @@ fn main() {
 	    state.image_raw = Some(image);
 	    app::redraw();
 	}
-	state_clone.replace(state);
+	*STATE.get().lock().unwrap() = state;
     });
-    let state_clone = Rc::clone(&state);
     menubar.add("File/Open Image...", Shortcut::None, menu::MenuFlag::Normal, move |_| {
 	let mut fc = dialog::NativeFileChooser::new(dialog::NativeFileChooserType::BrowseFile);
 	fc.show();
@@ -295,7 +298,7 @@ fn main() {
 
 	match ImageReader::open(filename).map(|i| i.decode()) {
 	    Ok(Ok(image)) => {
-		let mut state = state_clone.borrow_mut();
+		let mut state = STATE.get().lock().unwrap();
 		let data = encode_png(&image);
 		state.image = Some(PngImage::from_data(&data).unwrap());
 		state.image_raw = Some(image);
@@ -304,7 +307,6 @@ fn main() {
 	    _ => dialog::alert_default("Error opening file"),
 	}
     });
-    let state_clone = Rc::clone(&state);
     menubar.add("File/Save As ...", Shortcut::None, menu::MenuFlag::Normal, move |_| {
 	let mut fc = dialog::NativeFileChooser::new(dialog::NativeFileChooserType::BrowseSaveFile);
 	fc.show();
@@ -312,7 +314,7 @@ fn main() {
 	let file = File::create(fc.filename()).unwrap();
 	let mut ar = zip::ZipWriter::new(file);
 	let options = zip::write::FileOptions::default();
-	let state = state_clone.borrow();
+	let mut state = STATE.get().lock().unwrap();
 
 	ar.start_file("graph.json", options).ok();
 	ar.write(&serde_json::to_vec(&state.board).unwrap()).ok();
@@ -324,14 +326,12 @@ fn main() {
 	}
 	ar.finish().ok();
     });
-    let state_clone = Rc::clone(&state);
     menubar.add("Edit/Edit Nodes", Shortcut::None, menu::MenuFlag::Normal, move |_| {
-	let mut state = state_clone.borrow_mut();
+	let mut state = STATE.get().lock().unwrap();
 	state.edit_mode = EditMode::Node;
     });
-    let state_clone = Rc::clone(&state);
     menubar.add("Edit/Edit Edges", Shortcut::None, menu::MenuFlag::Normal, move |_| {
-	let mut state = state_clone.borrow_mut();
+	let mut state = STATE.get().lock().unwrap();
 	state.edit_mode = EditMode::Edge;
     });
     
@@ -339,10 +339,9 @@ fn main() {
 
     // Canvas
     let mut frame = frame::Frame::default();
-    let state_clone = Rc::clone(&state);
     frame.draw(move |f| {
 	use draw::*;
-	let mut state = state_clone.borrow_mut();
+	let mut state = STATE.get().lock().unwrap();
 	// Background
 	let image = &mut state.image;
 	if let Some(image) = image.as_mut() {
@@ -369,16 +368,15 @@ fn main() {
 	    }
 	}
     });
-    let state_clone = Rc::clone(&state);
     frame.handle(move |f, e| {
 	match e {
 	    Event::Push => {
-		let mut state = state_clone.borrow_mut();
+		let edit_mode = STATE.get().lock().unwrap().edit_mode;
 		let coords = f.to_coords(app::event_x(), app::event_y());
 
-		match state.edit_mode {
-		    EditMode::Node => dispatch::node_press(&mut state, coords),
-		    EditMode::Edge => dispatch::edge_press(&mut state, coords),
+		match edit_mode {
+		    EditMode::Node => dispatch::node_press(coords),
+		    EditMode::Edge => dispatch::edge_press(coords),
 		}
 		true
 	    }