diff --git a/Cargo.lock b/Cargo.lock index 0ea0e54..a31bb14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,16 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" +[[package]] +name = "accesskit" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3d3b8f9bae46a948369bc4a03e815d4ed6d616bd00de4051133a5019dc31c5a" +dependencies = [ + "enumn", + "serde", +] + [[package]] name = "addr2line" version = "0.24.2" @@ -42,6 +52,7 @@ dependencies = [ "cfg-if", "getrandom", "once_cell", + "serde", "version_check", "zerocopy", ] @@ -215,6 +226,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -256,6 +273,9 @@ name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] [[package]] name = "block" @@ -651,6 +671,7 @@ checksum = "7d72e9c39f6e11a2e922d04a34ec5e7ef522ea3f5a1acfca7a19d16ad5fe50f5" dependencies = [ "bytemuck", "emath", + "serde", ] [[package]] @@ -669,6 +690,7 @@ dependencies = [ "glow 0.16.0", "glutin", "glutin-winit", + "home", "image", "js-sys", "log", @@ -679,6 +701,8 @@ dependencies = [ "percent-encoding", "profiling", "raw-window-handle", + "ron", + "serde", "static_assertions", "wasm-bindgen", "wasm-bindgen-futures", @@ -695,12 +719,15 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "252d52224d35be1535d7fd1d6139ce071fb42c9097773e79f7665604f5596b5e" dependencies = [ + "accesskit", "ahash", "emath", "epaint", "log", "nohash-hasher", "profiling", + "ron", + "serde", ] [[package]] @@ -735,6 +762,7 @@ dependencies = [ "log", "profiling", "raw-window-handle", + "serde", "smithay-clipboard", "web-time", "webbrowser", @@ -766,6 +794,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4fe73c1207b864ee40aa0b0c038d6092af1030744678c60188a05c28553515d" dependencies = [ "bytemuck", + "serde", +] + +[[package]] +name = "enumn" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", ] [[package]] @@ -807,6 +847,7 @@ dependencies = [ "nohash-hasher", "parking_lot", "profiling", + "serde", ] [[package]] @@ -2425,6 +2466,7 @@ dependencies = [ "env_logger", "log", "plate-tool-lib", + "serde", ] [[package]] @@ -2693,6 +2735,18 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags 2.6.0", + "serde", + "serde_derive", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -2823,7 +2877,7 @@ version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ - "base64", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", diff --git a/plate-tool-eframe/Cargo.toml b/plate-tool-eframe/Cargo.toml index b86bdab..02bfef1 100644 --- a/plate-tool-eframe/Cargo.toml +++ b/plate-tool-eframe/Cargo.toml @@ -9,7 +9,9 @@ eframe = { version = "0.30", default-features = false, features = [ "default_fonts", "glow", "wayland", + "persistence", ]} log = "0.4" env_logger = "0.11" +serde = { version = "1.0", features = ["derive"] } diff --git a/plate-tool-eframe/src/app.rs b/plate-tool-eframe/src/app.rs index 28ba704..05eda8c 100644 --- a/plate-tool-eframe/src/app.rs +++ b/plate-tool-eframe/src/app.rs @@ -4,76 +4,14 @@ use std::sync::Mutex; use eframe::egui::{self}; use plate_tool_lib::plate::PlateFormat; -use plate_tool_lib::plate_instances; -use crate::plate::{add_grid, PlateUiState}; +use crate::plate::{add_plate, PlateUiState}; use crate::transfer_menu::{self, transfer_menu, CurrentTransferState, TransferMenuState}; - -#[derive(Default)] -pub struct MainState { - pub source_plates: Vec, - pub destination_plates: Vec, - pub transfers: Vec, -} - -fn construct_fake_mainstate() -> MainState { - let src_plate: plate_tool_lib::plate_instances::PlateInstance = - plate_instances::PlateInstance::new( - plate_tool_lib::plate::PlateType::Source, - PlateFormat::W96, - "src1".to_owned(), - ); - let dest_plate: plate_tool_lib::plate_instances::PlateInstance = - plate_instances::PlateInstance::new( - plate_tool_lib::plate::PlateType::Destination, - PlateFormat::W96, - "dest1".to_owned(), - ); - let well_a1 = plate_tool_lib::Well { row: 1, col: 1 }; - let well_c3 = plate_tool_lib::Well { row: 3, col: 3 }; - let well_a5 = plate_tool_lib::Well { row: 1, col: 5 }; - - let transfer1_region: plate_tool_lib::transfer_region::TransferRegion = - plate_tool_lib::transfer_region::TransferRegion { - source_plate: src_plate.plate, - source_region: plate_tool_lib::transfer_region::Region::Rect(well_a1, well_c3), - dest_plate: dest_plate.plate, - dest_region: plate_tool_lib::transfer_region::Region::Point(well_a1), - interleave_source: (1, 1), - interleave_dest: (1, 1), - }; - let transfer1: plate_tool_lib::transfer::Transfer = plate_tool_lib::transfer::Transfer::new( - src_plate.clone(), - dest_plate.clone(), - transfer1_region, - "Shrimp".to_owned(), - ); - - let transfer2_region: plate_tool_lib::transfer_region::TransferRegion = - plate_tool_lib::transfer_region::TransferRegion { - source_plate: src_plate.plate, - source_region: plate_tool_lib::transfer_region::Region::Rect(well_a1, well_c3), - dest_plate: dest_plate.plate, - dest_region: plate_tool_lib::transfer_region::Region::Point(well_a5), - interleave_source: (1, 1), - interleave_dest: (2, 2), - }; - let transfer2: plate_tool_lib::transfer::Transfer = plate_tool_lib::transfer::Transfer::new( - src_plate.clone(), - dest_plate.clone(), - transfer2_region, - "Shrimp".to_owned(), - ); - - - MainState { - source_plates: vec![src_plate], - destination_plates: vec![dest_plate], - transfers: vec![transfer1, transfer2], - } -} +use crate::main_state::{MainState, construct_fake_mainstate}; +use crate::tree::tree; #[non_exhaustive] +#[derive(Debug, serde::Serialize, serde::Deserialize)] struct MainWindowState { show_side_panel: bool, } @@ -87,12 +25,15 @@ impl Default for MainWindowState { } #[non_exhaustive] +#[derive(Debug, serde::Serialize, serde::Deserialize)] pub struct PlateToolEframe { source_plate_state: Mutex, destination_plate_state: Mutex, main_window_state: MainWindowState, current_transfer_state: CurrentTransferState, + #[serde(skip)] transfer_menu_state: TransferMenuState, + #[serde(skip)] transfer_region_cache: plate_tool_lib::transfer_region_cache::TransferRegionCache, main_state: MainState, } @@ -115,21 +56,24 @@ impl Default for PlateToolEframe { impl PlateToolEframe { pub fn new(cc: &eframe::CreationContext<'_>) -> Self { // Would load state here + if let Some(storage) = cc.storage { + return eframe::get_value(storage, eframe::APP_KEY).unwrap_or_default(); + } else { + let pte: PlateToolEframe = Default::default(); + pte.transfer_region_cache.generate_cache(&pte.main_state.transfers); - let pte: PlateToolEframe = Default::default(); - pte.transfer_region_cache.generate_cache(&pte.main_state.transfers); + pte + } - pte } } impl eframe::App for PlateToolEframe { // State storage - /* fn save(&mut self, storage: &mut dyn eframe::Storage) { - unimplemented!() - }; - */ + log::info!("Saving state"); + eframe::set_value(storage, eframe::APP_KEY, self); + } fn update(&mut self, ctx: &eframe::egui::Context, _frame: &mut eframe::Frame) { let ordered_ids: Vec = { @@ -179,6 +123,8 @@ impl eframe::App for PlateToolEframe { if self.main_window_state.show_side_panel { egui::SidePanel::left("side_menus").show(ctx, |ui| { ui.vertical(|ui| { + tree(ui, &mut self.main_state, &self.current_transfer_state); + ui.separator(); transfer_menu(ui, &self.current_transfer_state, &mut self.transfer_menu_state); }); }); @@ -192,7 +138,7 @@ impl eframe::App for PlateToolEframe { x.y /= 2.0; x }; - add_grid( + add_plate( half_height, PlateFormat::W96, &self.main_state.transfers, @@ -203,7 +149,7 @@ impl eframe::App for PlateToolEframe { ui, self.source_plate_state.lock().unwrap().deref_mut(), ); - add_grid( + add_plate( half_height, PlateFormat::W96, &self.main_state.transfers, diff --git a/plate-tool-eframe/src/lib.rs b/plate-tool-eframe/src/lib.rs index a6adf38..4340019 100644 --- a/plate-tool-eframe/src/lib.rs +++ b/plate-tool-eframe/src/lib.rs @@ -2,4 +2,5 @@ mod app; mod plate; mod tree; mod transfer_menu; +mod main_state; pub use app::PlateToolEframe; diff --git a/plate-tool-eframe/src/main_state.rs b/plate-tool-eframe/src/main_state.rs new file mode 100644 index 0000000..f09f921 --- /dev/null +++ b/plate-tool-eframe/src/main_state.rs @@ -0,0 +1,123 @@ +use plate_tool_lib::plate_instances; +use plate_tool_lib::plate::PlateFormat; + +#[derive(Default, Debug, serde::Serialize, serde::Deserialize)] +pub struct MainState { + /// Stores all plates and transfers + /// + /// It is not guaranteed that the current_* variables will refer + /// to UUIDs that exist in the lists, only that they did at one time. + /// This can happen if a plate or transfer is removed and set_* is not called. + pub source_plates: Vec, + pub destination_plates: Vec, + pub transfers: Vec, + current_source: Option, + current_destination: Option, + current_transfer: Option, +} +impl MainState { + pub fn get_current_source(&self) -> Option { + self.current_source + } + pub fn get_current_destination(&self) -> Option { + self.current_destination + } + pub fn get_current_transfer(&self) -> Option { + self.current_transfer + } + + pub fn set_current_source(&mut self, id: plate_tool_lib::uuid::Uuid) -> bool { + if self.source_plates.iter().map(|x| x.get_uuid()).find(|x| *x == id).is_some() { + self.current_source = Some(id); + true + } else { + false + } + } + pub fn set_current_destination(&mut self, id: plate_tool_lib::uuid::Uuid) -> bool { + if self.destination_plates.iter().map(|x| x.get_uuid()).find(|x| *x == id).is_some() { + self.current_destination = Some(id); + true + } else { + false + } + } + pub fn set_current_transfer(&mut self, id: plate_tool_lib::uuid::Uuid) -> bool { + if self.transfers.iter().map(|x| x.get_uuid()).find(|x| *x == id).is_some() { + self.current_transfer = Some(id); + true + } else { + false + } + } + pub fn set_no_current_source(&mut self) { + self.current_source = None; + } + pub fn set_no_current_destination(&mut self) { + self.current_destination = None; + } + pub fn set_no_current_transfer(&mut self) { + self.current_transfer = None; + } +} + +pub fn construct_fake_mainstate() -> MainState { + let src_plate: plate_tool_lib::plate_instances::PlateInstance = + plate_instances::PlateInstance::new( + plate_tool_lib::plate::PlateType::Source, + PlateFormat::W96, + "src1".to_owned(), + ); + let dest_plate: plate_tool_lib::plate_instances::PlateInstance = + plate_instances::PlateInstance::new( + plate_tool_lib::plate::PlateType::Destination, + PlateFormat::W96, + "dest1".to_owned(), + ); + let well_a1 = plate_tool_lib::Well { row: 1, col: 1 }; + let well_c3 = plate_tool_lib::Well { row: 3, col: 3 }; + let well_a5 = plate_tool_lib::Well { row: 1, col: 5 }; + + let transfer1_region: plate_tool_lib::transfer_region::TransferRegion = + plate_tool_lib::transfer_region::TransferRegion { + source_plate: src_plate.plate, + source_region: plate_tool_lib::transfer_region::Region::Rect(well_a1, well_c3), + dest_plate: dest_plate.plate, + dest_region: plate_tool_lib::transfer_region::Region::Point(well_a1), + interleave_source: (1, 1), + interleave_dest: (1, 1), + }; + let transfer1: plate_tool_lib::transfer::Transfer = plate_tool_lib::transfer::Transfer::new( + src_plate.clone(), + dest_plate.clone(), + transfer1_region, + "Shrimp".to_owned(), + ); + + let transfer2_region: plate_tool_lib::transfer_region::TransferRegion = + plate_tool_lib::transfer_region::TransferRegion { + source_plate: src_plate.plate, + source_region: plate_tool_lib::transfer_region::Region::Rect(well_a1, well_c3), + dest_plate: dest_plate.plate, + dest_region: plate_tool_lib::transfer_region::Region::Point(well_a5), + interleave_source: (1, 1), + interleave_dest: (2, 2), + }; + let transfer2: plate_tool_lib::transfer::Transfer = plate_tool_lib::transfer::Transfer::new( + src_plate.clone(), + dest_plate.clone(), + transfer2_region, + "Shrimp".to_owned(), + ); + + + MainState { + source_plates: vec![src_plate], + destination_plates: vec![dest_plate], + transfers: vec![transfer1, transfer2], + current_source: None, + current_destination: None, + current_transfer: None, + } +} + diff --git a/plate-tool-eframe/src/plate.rs b/plate-tool-eframe/src/plate.rs index 547dd1e..bce82ba 100644 --- a/plate-tool-eframe/src/plate.rs +++ b/plate-tool-eframe/src/plate.rs @@ -20,7 +20,7 @@ static STROKE_SELECT: LazyLock = static STROKE_HOVER: LazyLock = LazyLock::new(|| egui::Stroke::new(3.0, egui::Color32::from_gray(255))); -#[derive(Clone, Debug)] +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct PlateUiState { pub drag_start_position: Option, } @@ -109,8 +109,8 @@ fn calculate_shading_for_wells( for transfer in transfers { let cache_result = match plate_type { - plate_tool_lib::plate::PlateType::Source => cache.get_source(transfer), - plate_tool_lib::plate::PlateType::Destination => cache.get_destination(transfer), + plate_tool_lib::plate::PlateType::Source => cache.get_or_calculate_source(transfer), + plate_tool_lib::plate::PlateType::Destination => cache.get_or_calculate_destination(transfer), }; if let Some(wells) = cache_result { for well in wells.iter().filter(|x| x.row <= rows && x.col <= columns) { @@ -138,7 +138,7 @@ fn f64_to_color32(x: [f64; 3]) -> Color32 { Color32::from_rgb(r, g, b) } -fn add_grid_sub( +fn add_plate_sub( size: egui::Vec2, rows: u8, columns: u8, @@ -226,7 +226,9 @@ fn add_grid_sub( } }; let well_infos = { + // Get non-active transfer info let mut well_infos = calculate_shading_for_wells(rows, columns, transfers, plate_type, ordered_ids, cache); + // Get wells in the current transfer to tack on to well_infos separately let current_transfer_wells: Option> = { (match plate_type { @@ -351,7 +353,7 @@ fn add_grid_sub( } } -pub fn add_grid( +pub fn add_plate( size: egui::Vec2, pf: PlateFormat, transfers: &Vec, @@ -363,7 +365,7 @@ pub fn add_grid( state: &mut PlateUiState, ) { match pf { - PlateFormat::W96 => add_grid_sub( + PlateFormat::W96 => add_plate_sub( size, 8, 12, @@ -375,7 +377,7 @@ pub fn add_grid( ui, state, ), - PlateFormat::W384 => add_grid_sub( + PlateFormat::W384 => add_plate_sub( size, 16, 24, @@ -387,7 +389,7 @@ pub fn add_grid( ui, state, ), - PlateFormat::W1536 => add_grid_sub( + PlateFormat::W1536 => add_plate_sub( size, 32, 48, diff --git a/plate-tool-eframe/src/transfer_menu.rs b/plate-tool-eframe/src/transfer_menu.rs index 9c242aa..b92a6a9 100644 --- a/plate-tool-eframe/src/transfer_menu.rs +++ b/plate-tool-eframe/src/transfer_menu.rs @@ -1,9 +1,12 @@ use eframe::egui; -use plate_tool_lib::transfer_region::{Region, TransferRegion}; +use plate_tool_lib::transfer_region::{self, Region, TransferRegion}; use std::sync::{Arc, Mutex}; use std::hash::{DefaultHasher, Hash, Hasher}; +use crate::main_state::MainState; + pub type CurrentTransferState = Arc>; +#[derive(Debug, serde::Serialize, serde::Deserialize)] pub struct CurrentTransferStateInterior { pub transfer_name: String, pub source_region: plate_tool_lib::transfer_region::Region, @@ -15,8 +18,11 @@ pub struct CurrentTransferStateInterior { pub destination_row_interleave: i8, pub destination_column_interleave: i8, pub volume: f32, + #[serde(skip)] transfer_hash: Option, + #[serde(skip)] source_wells: Option>, + #[serde(skip)] destination_wells: Option>, } impl Default for CurrentTransferStateInterior { @@ -96,8 +102,40 @@ impl CurrentTransferStateInterior { interleave_dest: (self.destination_row_interleave, self.destination_column_interleave), } } + + pub fn try_new_from_main_state_transfer(ms: &MainState) -> Option { + let transfer_id = ms.get_current_transfer(); + let transfer = ms.transfers.iter().find(|x| Some(x.get_uuid()) == transfer_id); + if let Some(transfer) = transfer { + let volume: f32 = match transfer.volume { + plate_tool_lib::transfer_volume::TransferVolume::Single(x) => x, + plate_tool_lib::transfer_volume::TransferVolume::WellMap(_) => { + log::debug!("COOL BUG: I genuinely don't know when this variant is used and honestly assume that it just never is constructed! Anyway, here's main state:\n{:?}", ms); + unreachable!("It better not!"); + }, + _ => unreachable!() + }; + return Some(Self { + transfer_name: transfer.name.clone(), + source_region: transfer.transfer_region.source_region.clone(), + destination_region: transfer.transfer_region.dest_region.clone(), + source_plate: transfer.transfer_region.source_plate, + destination_plate: transfer.transfer_region.dest_plate, + source_row_interleave: transfer.transfer_region.interleave_source.0, + source_column_interleave: transfer.transfer_region.interleave_source.1, + destination_row_interleave: transfer.transfer_region.interleave_dest.0, + destination_column_interleave: transfer.transfer_region.interleave_dest.1, + volume, + source_wells: None, + destination_wells: None, + transfer_hash: None, + }) + } + None + } } +#[derive(Debug)] pub struct TransferMenuState { pub source_region_string: String, pub destination_region_string: String, diff --git a/plate-tool-eframe/src/tree.rs b/plate-tool-eframe/src/tree.rs index e69de29..62a8d2a 100644 --- a/plate-tool-eframe/src/tree.rs +++ b/plate-tool-eframe/src/tree.rs @@ -0,0 +1,103 @@ +use eframe::egui; + +use crate::{main_state::MainState, transfer_menu::{CurrentTransferState, CurrentTransferStateInterior}}; + +use std::sync::LazyLock; + +static SELECT_COLOR: LazyLock = + LazyLock::new(|| egui::Color32::from_hex("#aa0000").unwrap()); + +pub fn tree(ui: &mut egui::Ui, ms: &mut MainState, cts: &CurrentTransferState) { + // Add all source plates + ui.vertical(|ui| { + ui.heading("Source Plates"); + let mut new_uuid: Option = None; + for (name, uuid) in ms.source_plates.iter().map(|x| (&x.name, x.get_uuid())) { + let f = { + let mut f = egui::Frame::none(); + if ms.get_current_source().is_some_and(|x| x == uuid) { + f = f.fill(*SELECT_COLOR); + } + f + }; + f.show(ui, |ui| { + let r = ui.add( + egui::Label::new(name) + .sense(egui::Sense::click()) + .selectable(false), + ); + if r.clicked() { + new_uuid = Some(uuid); + log::info!("{:?}", uuid); + } + }); + } + if let Some(uuid) = new_uuid { + ms.set_current_source(uuid); + } + }); + + // Add all destination plates + ui.vertical(|ui| { + ui.heading("Destination Plates"); + let mut new_uuid: Option = None; + for (name, uuid) in ms + .destination_plates + .iter() + .map(|x| (&x.name, x.get_uuid())) + { + let f = { + let mut f = egui::Frame::none(); + if ms.get_current_destination().is_some_and(|x| x == uuid) { + f = f.fill(*SELECT_COLOR); + } + f + }; + f.show(ui, |ui| { + let r = ui.add( + egui::Label::new(name) + .sense(egui::Sense::click()) + .selectable(false), + ); + if r.clicked() { + new_uuid = Some(uuid); + log::info!("{:?}", uuid); + } + }); + } + if let Some(uuid) = new_uuid { + ms.set_current_destination(uuid); + } + }); + // Add all transfers + ui.vertical(|ui| { + ui.heading("Transfers"); + let mut new_uuid: Option = None; + for (name, uuid) in ms.transfers.iter().map(|x| (&x.name, x.get_uuid())) { + let f = { + let mut f = egui::Frame::none(); + if ms.get_current_transfer().is_some_and(|x| x == uuid) { + f = f.fill(*SELECT_COLOR); + } + f + }; + f.show(ui, |ui| { + let r = ui.add( + egui::Label::new(name) + .sense(egui::Sense::click()) + .selectable(false), + ); + if r.clicked() { + new_uuid = Some(uuid); + log::info!("{:?}", uuid); + } + }); + } + if let Some(uuid) = new_uuid { + ms.set_current_transfer(uuid); + if let Some(new_cts) = CurrentTransferStateInterior::try_new_from_main_state_transfer(ms) { + *cts.lock().unwrap() = new_cts; + } + } + }); +} diff --git a/plate-tool-lib/src/transfer_region_cache.rs b/plate-tool-lib/src/transfer_region_cache.rs index db20014..e857bd7 100644 --- a/plate-tool-lib/src/transfer_region_cache.rs +++ b/plate-tool-lib/src/transfer_region_cache.rs @@ -11,6 +11,11 @@ pub struct TransferRegionCache { interior: Arc>, } +impl Default for TransferRegionCache { + fn default() -> Self { + Self::new() + } +} impl TransferRegionCache { pub fn new() -> Self { TransferRegionCache { @@ -46,10 +51,22 @@ impl TransferRegionCache { pub fn get_source(&self, tr: &Transfer) -> Option> { self.get(tr, true) } + pub fn get_or_calculate_source(&self, tr: &Transfer) -> Option> { + if !self.has(tr) { + self.add_overwrite(tr); + } + self.get_source(tr) + } pub fn get_destination(&self, tr: &Transfer) -> Option> { self.get(tr, false) } + pub fn get_or_calculate_destination(&self, tr: &Transfer) -> Option> { + if !self.has(tr) { + self.add_overwrite(tr); + } + self.get_destination(tr) + } fn get(&self, tr: &Transfer, is_source: bool) -> Option> { if let Ok(interior) = self.interior.lock() { @@ -63,6 +80,13 @@ impl TransferRegionCache { None } } + fn has(&self, tr: &Transfer) -> bool { + if let Ok(interior) = self.interior.lock() { + interior.cache.contains_key(&tr.get_uuid()) + } else { + false + } + } } impl Clone for TransferRegionCache {