diff --git a/lab3/src/gui/data.rs b/lab3/src/gui/data.rs index a84b65e..b46e7c2 100644 --- a/lab3/src/gui/data.rs +++ b/lab3/src/gui/data.rs @@ -1,8 +1,15 @@ -use bgtu_ai_utility::graph::CompleteGraph; -use bgtu_ai_utility::UpdatePending; use crate::algo::{AntsSimulationConfig, AntsSimulationState}; +use bgtu_ai_utility::UpdatePending; +use bgtu_ai_utility::graph::CompleteGraph; +use std::pin::Pin; +use std::ptr::NonNull; -pub(crate) enum AntsVisualisationData<'cfg> { +pub(crate) struct AntsVisualisationData { + pub config: AntsSimulationConfig, + pub graph: CompleteGraph<()>, +} + +pub(crate) enum AntsVisualisationState<'cfg> { Edit { config: &'cfg mut AntsSimulationConfig, graph: &'cfg mut CompleteGraph<()>, @@ -15,28 +22,31 @@ pub(crate) enum AntsVisualisationData<'cfg> { vertex_locations: Vec<(f32, f32)>, }, } -pub(crate) struct MyApp<'cfg> { - pub state: AntsVisualisationData<'cfg>, - pub ants_per_vertex: usize, + +pub(crate) struct AntsVisualisationApp { + pub data: Pin>, + pub state: AntsVisualisationState<'static /* actually not but fuck rust */>, } -impl MyApp { - pub(crate) fn new() -> Self { - return Self { - simulation: AntsSimulationState { - graph: CompleteGraph::new(), - ants: Vec::new(), - }, - vertex_update: UpdatePending::NoChange, +impl AntsVisualisationApp { + pub fn new() -> Self { + let mut data = Box::pin(AntsVisualisationData { config: AntsSimulationConfig { ferment_weight: 0.5, heuristic_coefficient: 0.5, q: 1.0, r: 0.5, }, - state: AntsVisualisationData::Edit {}, - vertex_locations: Vec::new(), + graph: CompleteGraph::new(), + }); + + let state = AntsVisualisationState::Edit { + config: unsafe { NonNull::from_mut(&mut data.config).as_mut() }, + graph: unsafe { NonNull::from_mut(&mut data.graph).as_mut() }, ants_per_vertex: 1, + vertex_update: UpdatePending::NoChange, }; + + return Self { data, state }; } -} \ No newline at end of file +} diff --git a/lab3/src/gui/graph.rs b/lab3/src/gui/graph.rs index 38cfff4..f691204 100644 --- a/lab3/src/gui/graph.rs +++ b/lab3/src/gui/graph.rs @@ -1,37 +1,36 @@ -use super::{AntsVisualisationData, MyApp}; -use crate::algo::updateState; +use crate::algo::AntsSimulationState; use bgtu_ai_utility::gui::render_graph; use eframe::egui::Ui; +use rand::{Rng, rng}; -pub(crate) fn graph_with_controls(ui: &mut Ui, data: &mut MyApp) { +pub(crate) fn graph_with_controls( + ui: &mut Ui, + vertex_locations: &mut [(f32, f32)], + data: &mut AntsSimulationState, + exit: &mut bool, +) { ui.vertical(|ui| { ui.horizontal(|ui| { if ui.button("Exit").clicked() { - data.state = AntsVisualisationData::Edit + *exit = true; } if ui.button("Step").clicked() { - updateState(&mut data.simulation, &mut data.config, &mut rand::rng()); + data.update1(&mut rng()); } ui.label(""); }); - draw_ants(ui, data); + draw_ants(ui, vertex_locations, data); if ui.input(|i| i.viewport().close_requested()) { - data.state = AntsVisualisationData::Edit + *exit = true; } }); } -fn draw_ants(ui: &mut Ui, data: &mut MyApp) { +fn draw_ants(ui: &mut Ui, vertex_locations: &mut [(f32, f32)], data: &mut AntsSimulationState) { let mut cap: f64 = 0.000000000001; - for w in data - .simulation - .graph - .edges - .iter() - .map(|e| e.extra.ferment_intensity) - { + for w in data.graph.edges.iter_indexes().map(|i| data.ferments[i]) { if w > cap { cap = w } @@ -39,9 +38,20 @@ fn draw_ants(ui: &mut Ui, data: &mut MyApp) { render_graph( ui, - &data.simulation.graph.vertices, - data.vertex_locations.as_mut_slice(), - &data.simulation.graph.edges, - |e| e.extra.ferment_intensity / cap, + &data.graph.vertices, + vertex_locations, + &data.graph.edges, + |ei, _| data.ferments[ei] / cap, ) } + +pub(crate) fn gen_vertex_locations(rng: &mut impl Rng, count: usize) -> Vec<(f32, f32)> { + let mut v = Vec::new(); + for _ in 0..count { + v.push(( + rng.random::() * 0.8 + 0.1, + rng.random::() * 0.8 + 0.1, + )); + } + return v; +} diff --git a/lab3/src/gui/input.rs b/lab3/src/gui/input.rs index 5ff4bd6..077f2b9 100644 --- a/lab3/src/gui/input.rs +++ b/lab3/src/gui/input.rs @@ -1,23 +1,24 @@ use crate::algo::AntsSimulationConfig; use bgtu_ai_utility::UpdatePending; use bgtu_ai_utility::graph::CompleteGraph; -use bgtu_ai_utility::gui::const_mut_switch::{_ConstMutSwitchUiCallback, ConstMutSwitchUi, RefType, RefGetter}; +use bgtu_ai_utility::gui::const_mut_switch::{ + _ConstMutSwitchUiCallback, ConstMutSwitchUi, MutUI, RefType, +}; +use bgtu_ai_utility::gui::graph_lengths_table::{Graph, draw_lengths_table}; -pub(crate) fn input( +pub(crate) fn input( ctx: &mut Ctx, - mut config: Ctx::Ref<'_, AntsSimulationConfig>, - mut graph: Ctx::RefType::Ref<'_, CompleteGraph<()>>, - mut ants_per_vertex: Ctx::RefType::Ref<'_, usize>, - mut vertex_update: Ctx::RefType::Ref<'_, UpdatePending>, - mut launch: Ctx::RefType::Ref<'_, bool>, + mut config: ::Ref<'_, AntsSimulationConfig>, + graph: &mut impl Graph, + mut ants_per_vertex: ::Ref<'_, usize>, + mut vertex_update: ::Ref<'_, UpdatePending>, + mut launch: ::Ref<'_, bool>, ) { - type Ref<'a, T> = <::RefType as RefType>::Ref<'a, T>; - ctx.labeled_slider( "Ferment weight", 0.0..=1.0, 0.001, - &mut Ctx::_get( + &mut Ctx::RefType::_get( &mut config, |config| &config.ferment_weight, |config| &mut config.ferment_weight, @@ -30,7 +31,7 @@ pub(crate) fn input( "Heuristic coefficient", 0.0..=1.0, 0.001, - &mut Ctx::_get( + &mut Ctx::RefType::_get( &mut config, |config| &config.heuristic_coefficient, |config| &mut config.heuristic_coefficient, @@ -43,7 +44,7 @@ pub(crate) fn input( "Q", 0.0..=1.0, 0.001, - &mut Ctx::_get(&mut config, |config| &config.q, |config| &mut config.q), + &mut Ctx::RefType::_get(&mut config, |config| &config.q, |config| &mut config.q), ); ctx.space(); @@ -52,7 +53,7 @@ pub(crate) fn input( "R", 0.0..=1.0, 0.001, - &mut Ctx::_get(&mut config, |config| &config.r, |config| &mut config.r), + &mut Ctx::RefType::_get(&mut config, |config| &config.r, |config| &mut config.r), ); ctx.space(); @@ -61,63 +62,28 @@ pub(crate) fn input( "Ants per vertex", 1..=100, 1.0, - &mut Ctx::_get(&mut ants_per_vertex, |apv| apv, |apv| apv), + &mut Ctx::RefType::_get(&mut ants_per_vertex, |apv| apv, |apv| apv), ); ctx.space(); - struct ControlsRow {} - impl _ConstMutSwitchUiCallback for ControlsRow { - type Clojure = (Ref<'_, UpdatePending>, Ref<'_, bool>); + ctx.horizontal(ControlsRow { + update: &mut vertex_update, + run: &mut launch, + }); - fn render>( - ctx: &mut SubCtx, - mut clojure: (Ref<'_, UpdatePending>, Ref<'_, bool>), - ) { - ctx.button("Add vertex", &mut clojure.0, |d| *d = UpdatePending::Add); - ctx.separator(); - ctx.button("Run", &mut clojure.1, |d| *d = true); - } - } - - ctx.horizontal::(&mut (vertex_update, launch)) - - /* - - draw_lengths_table( - ui, - &mut data.simulation.graph.vertices, - &mut data.simulation.graph.edges, - &mut data.vertex_update, - ); - - if run { - let mut coords = vec![(0.0, 0.0); data.simulation.graph.vertices.capacity()]; - - for (i, _) in data.simulation.graph.vertices.iter_indexed() { - coords[i] = ( - rand::random::() * 0.8 + 0.1, - rand::random::() * 0.8 + 0.1, - ) - } - - data.state = AntsVisualisationData::Running; - data.vertex_locations = coords; - - let allowed_locations = data - .simulation - .graph - .vertices - .iter_indexed() - .map(|(i, _)| i) - .collect::>(); - - let mut ants = Vec::new(); - for (i, _) in data.simulation.graph.vertices.iter_indexed() { - for _ in 0..data.ants_per_vertex { - ants.push(Ant::new(i, allowed_locations.clone())) - } - } - data.simulation.ants = ants; - }*/ + draw_lengths_table(ctx, graph, vertex_update) +} + +struct ControlsRow<'uu, 'u, 'rr, 'r, RT: RefType> { + update: &'uu mut RT::Ref<'u, UpdatePending>, + run: &'rr mut RT::Ref<'r, bool>, +} + +impl _ConstMutSwitchUiCallback for ControlsRow<'_, '_, '_, '_, RT> { + fn render(self, ctx: &mut impl ConstMutSwitchUi) { + ctx.button("Add vertex", self.update, |d| *d = UpdatePending::Add); + ctx.separator(); + ctx.button("Run", self.run, |d| *d = true); + } } diff --git a/lab3/src/gui/mod.rs b/lab3/src/gui/mod.rs index 3ef4294..9df5f10 100644 --- a/lab3/src/gui/mod.rs +++ b/lab3/src/gui/mod.rs @@ -1,7 +1,7 @@ mod data; -mod input; mod graph; +mod input; -pub(crate) use data::{MyApp, AntsVisualisationData}; +pub(crate) use data::{AntsVisualisationApp, AntsVisualisationData, AntsVisualisationState}; +pub(crate) use graph::{graph_with_controls, gen_vertex_locations}; pub(crate) use input::input; -pub(crate) use graph::graph_with_controls; \ No newline at end of file diff --git a/lab3/src/main.rs b/lab3/src/main.rs index 9280e26..5611235 100644 --- a/lab3/src/main.rs +++ b/lab3/src/main.rs @@ -3,42 +3,105 @@ mod algo; mod gui; -use crate::algo::EdgeExtraData; +use crate::algo::AntsSimulationState; use bgtu_ai_utility::gui::boot_eframe; +use bgtu_ai_utility::gui::const_mut_switch::{ConstUI, MutUI}; +use bgtu_ai_utility::gui::graph_lengths_table::{ConstGraph, MutableGraph}; use bgtu_ai_utility::gui::subwindow; use bgtu_ai_utility::UpdatePending; use eframe::egui; +use rand::rng; +use std::ptr::NonNull; fn main() -> eframe::Result { - return boot_eframe("Ants simulation", || gui::MyApp::new()); + return boot_eframe("Ants simulation", || gui::AntsVisualisationApp::new()); } -impl eframe::App for gui::MyApp { +impl eframe::App for gui::AntsVisualisationApp { fn update(&mut self, ui: &eframe::egui::Context, _frame: &mut eframe::Frame) { - egui::CentralPanel::default().show(ui, |ui| match self.state { - gui::AntsVisualisationData::Edit {} => { - match self.vertex_update { + let state_ptr = NonNull::from_mut(&mut self.state); + egui::CentralPanel::default().show(ui, |ui| match &mut self.state { + gui::AntsVisualisationState::Edit { + config, + graph, + ants_per_vertex, + vertex_update, + } => { + match vertex_update { UpdatePending::NoChange => {} UpdatePending::Add => { - self.simulation.graph.add_vertex(|| EdgeExtraData { - ferment_intensity: 0.0, - }); - self.vertex_update = UpdatePending::NoChange; + graph.add_vertex(|| ()); + *vertex_update = UpdatePending::NoChange; } UpdatePending::Remove(vi) => { - self.simulation.graph.remove_vertex(vi); - self.vertex_update = UpdatePending::NoChange; + graph.remove_vertex(*vi); + *vertex_update = UpdatePending::NoChange; + } + } + + let mut run = false; + gui::input( + &mut MutUI { ui }, + *config, + &mut MutableGraph { graph }, + ants_per_vertex, + vertex_update, + &mut run, + ); + + if run { + let ns = gui::AntsVisualisationState::Running { + simulation: AntsSimulationState::new(*graph, *config, *ants_per_vertex), + ants_per_vertex: *ants_per_vertex, + vertex_locations: gui::gen_vertex_locations( + &mut rng(), + (*graph).vertex_count(), + ), + }; + unsafe { + state_ptr.write(ns); } } - gui::input(ui, self) } - gui::AntsVisualisationData::Running { .. } => { - ui.add_enabled_ui(false, |ui| gui::input(ui, self)); + gui::AntsVisualisationState::Running { + simulation, + ants_per_vertex, + vertex_locations, + } => { + gui::input( + &mut ConstUI { ui }, + &simulation.cfg, + &mut ConstGraph { + graph: &simulation.graph, + }, + ants_per_vertex, + &UpdatePending::NoChange, + &false, + ); + + let mut exit = false; subwindow( - ui, "visualisation", "Visualisation", + ui, + "visualisation", + "Visualisation", |vb| vb.with_inner_size([640.0, 480.0]), - |ui| gui::graph_with_controls(ui, self), - ).on_close(|| self.state = gui::AntsVisualisationData::Edit); + |ui| gui::graph_with_controls(ui, vertex_locations, simulation, &mut exit), + ) + .on_close(|| exit = true); + + if exit { + let ns = gui::AntsVisualisationState::Edit { + config: unsafe { + NonNull::from_mut(&mut self.data.config).as_mut() + }, + graph: unsafe { NonNull::from_mut(&mut self.data.graph).as_mut() }, + ants_per_vertex: *ants_per_vertex, + vertex_update: UpdatePending::NoChange, + }; + unsafe { + state_ptr.write(ns); + } + } } }); } diff --git a/utility/src/graph/complete_graph.rs b/utility/src/graph/complete_graph.rs index 79a7762..b6d4de4 100644 --- a/utility/src/graph/complete_graph.rs +++ b/utility/src/graph/complete_graph.rs @@ -34,6 +34,7 @@ impl CompleteGraph { } self.vertices.remove(vi); } + pub fn vertex_count(&self) -> usize { return self.vertices.len(); } diff --git a/utility/src/graph/edges.rs b/utility/src/graph/edges.rs index cb7fa5e..4aa4d8b 100644 --- a/utility/src/graph/edges.rs +++ b/utility/src/graph/edges.rs @@ -36,7 +36,7 @@ impl EdgesVec { vertex1_index: vertex1, vertex2_index: vertex2, length, - extra + extra, }; return self.data.add(|_, _| data); } @@ -46,18 +46,25 @@ impl EdgesVec { } pub fn iter(&self) -> impl Iterator> { return self.data.iter(); + } + pub fn iter_indexed(&self) -> impl Iterator)> { + return self.data.iter_indexed(); } pub fn iter_mut(&mut self) -> impl Iterator> { return self.data.iter_mut(); } + pub fn iter_indexes(&self) -> impl Iterator { + return self.data.iter_indexes(); + } + pub fn capacity(&self) -> usize { - return self.data.capacity() + return self.data.capacity(); } } -impl Index for EdgesVec { +impl Index for EdgesVec { type Output = Edge; fn index(&self, index: usize) -> &Self::Output { @@ -65,7 +72,7 @@ impl Index for EdgesVec { } } -impl IndexMut for EdgesVec { +impl IndexMut for EdgesVec { fn index_mut(&mut self, index: usize) -> &mut Self::Output { return self.data.index_mut(index); } diff --git a/utility/src/gui/const_mut_switch/const.rs b/utility/src/gui/const_mut_switch/const.rs index 362a1a7..ba8d986 100644 --- a/utility/src/gui/const_mut_switch/const.rs +++ b/utility/src/gui/const_mut_switch/const.rs @@ -8,7 +8,7 @@ use eframe::emath::Numeric; use std::ops::RangeInclusive; pub struct ConstUI<'ui> { - ui: &'ui mut Ui, + pub ui: &'ui mut Ui, } impl<'ui> ConstUI<'ui> { diff --git a/utility/src/gui/const_mut_switch/mut.rs b/utility/src/gui/const_mut_switch/mut.rs index a5d6c27..c368c94 100644 --- a/utility/src/gui/const_mut_switch/mut.rs +++ b/utility/src/gui/const_mut_switch/mut.rs @@ -9,7 +9,7 @@ use eframe::emath::Numeric; use std::ops::RangeInclusive; pub struct MutUI<'ui> { - ui: &'ui mut Ui, + pub ui: &'ui mut Ui, } impl<'ui> MutUI<'ui> { diff --git a/utility/src/gui/const_mut_switch/table.rs b/utility/src/gui/const_mut_switch/table.rs index d7c484b..25dc6c6 100644 --- a/utility/src/gui/const_mut_switch/table.rs +++ b/utility/src/gui/const_mut_switch/table.rs @@ -8,6 +8,7 @@ use eframe::egui::Ui; use egui_extras::{Column, Table, TableBuilder, TableRow}; use std::marker::PhantomData; use std::mem::{swap, uninitialized}; +use std::ptr::NonNull; pub trait _ConstMutSwitchUiTableCallback { fn render_table(self, ctx: &mut impl ConstMutSwitchUiTable); @@ -107,13 +108,10 @@ impl<'a, RT: RefType, Constructor: __SwitchUiConstructor1> #[allow(deprecated)] fn header_map(&mut self, f: impl FnOnce(TableBuilder) -> Table) { + let sp = NonNull::from_mut(self); match self { - ConstMutSwitchUiTableImplState::Header(_) => { - let mut local = unsafe { Self::Header(uninitialized()) }; - swap(self, &mut local); - if let Self::Header(local) = local { - *self = Self::Body(f(local)) - } + ConstMutSwitchUiTableImplState::Header(h) => { + unsafe { sp.write(Self::Body(f(NonNull::from_mut(h).read()))) }; } _ => panic!("Not in header state"), } @@ -121,14 +119,13 @@ impl<'a, RT: RefType, Constructor: __SwitchUiConstructor1> #[allow(deprecated)] fn body_map(&mut self, f: impl FnOnce(Table)) { + let sp = NonNull::from_mut(self); match self { - ConstMutSwitchUiTableImplState::Header(_) => { - let mut local = unsafe { Self::Body(uninitialized()) }; - swap(self, &mut local); - if let Self::Body(local) = local { - f(local); - *self = Self::Done(PhantomData::default()) - } + ConstMutSwitchUiTableImplState::Body(b) => { + unsafe { + f(NonNull::from_mut(b).read()); + sp.write(Self::Done(PhantomData::default())) + }; } _ => panic!("Not in body state"), } diff --git a/utility/src/gui/const_mut_switch/эволюция_костылей.md b/utility/src/gui/const_mut_switch/эволюция_костылей.md index 1c9a666..10818c5 100644 --- a/utility/src/gui/const_mut_switch/эволюция_костылей.md +++ b/utility/src/gui/const_mut_switch/эволюция_костылей.md @@ -1008,3 +1008,59 @@ pub trait Edge { fn get_edge_len_ptr<'s>(&'s mut self) -> ::Ref<'s, f64>; } ``` + +## 10 +Работа с состояниями это отдельный вид искусства. Если внутри енама есть что-то, без поддержки +копирования, но это что-то нужно использовать для вычисления следующего состояния, то borrow +checker вынудит откатиться в ~~каменный век~~ обратно в C/C++ с ручной реализацией растовских +енамов. + +### 10.1 +Первый опробованный трюк: +```rust +enum State {A(AA), B(BB)} + +impl State { + fn map(&mut self, f: impl FnOnce(AA) -> BB) { + match self { + Self::A(_) => { + let mut local = unsafe { Self::A(uninitialized()) }; + swap(self, &mut local); + if let Self::A(local) = local { + *self = Self::BB(f(local)) + } + } + _ => todo!() + } + } +} +``` +успехом не увенчался, в отладочной сборке компилятор кидает панику в районе `swap` из-за того +что переменная `local` не инициализированна. + +### 10.2 +Следующий трюк уже рабочий, но вопросы к безопасности очень большие: +```rust +enum State {A(AA), B(BB)} + +impl State { + fn map(&mut self, f: impl FnOnce(AA) -> BB) { + let sp = NonNull::from_mut(self); + match self { + Self::A(aa) => { + unsafe { sp.write(Self::BB(f(NonNull::from_mut(aa).read()))) }; + } + _ => todo!() + } + } +} +``` + + +## Выводы +Идея с безопасностью через строгие проверки времени жизни на этапе компиляции интересная, но +в текущем виде не рабочая. Язык получился таким же низкоуровневым, как C# или Kotlin/Native: +работать с указателями и линковаться напрямую с функциями из C можно, но в любой сколько-нибудь +сложной ситуации компилятор вынуждает пользоваться динамической памятью даже там, где можно +обойтись без этого или городить костыли, которые сводят на нет всю безопасность языка. Поитогу +получился "безопасный" и многословный Python. \ No newline at end of file diff --git a/utility/src/gui/graph_lengths_table/ctx.rs b/utility/src/gui/graph_lengths_table/ctx.rs index e387ab5..8f78d3d 100644 --- a/utility/src/gui/graph_lengths_table/ctx.rs +++ b/utility/src/gui/graph_lengths_table/ctx.rs @@ -45,146 +45,4 @@ pub trait Edge { type RefType: RefType; fn get_edge_len_ptr<'s>(&'s mut self) -> ::Ref<'s, f64>; -} - -struct MutableGraph<'g> { - graph: &'g mut CompleteGraph<()>, -} - -impl Graph for MutableGraph<'_> { - type RefType = MutRef; - - fn iter_vertices(&mut self) -> impl VerticesIterator { - return MutableVerticesIterator { - ee: &mut self.graph.edges, - it: self.graph.vertices.iter_indexed_mut(), - ordinal: 0, - }; - } - - fn vertices_count(&self) -> usize { - return self.graph.vertex_count(); - } -} - -struct MutableVerticesIterator<'g, It: Iterator)>> { - ee: &'g mut EdgesVec<()>, - it: It, - ordinal: usize, -} - -impl<'g, It: Iterator)>> VerticesIterator - for MutableVerticesIterator<'g, It> -{ - type RefType = MutRef; - type Vertex<'v> - = MutableVertex<'v> - where - Self: 'v; - - fn next<'v>(&'v mut self) -> Option> { - return self.it.next().map(|(i, e)| { - let v = MutableVertex { - id: i, - local_edges: e, - all_edges: self.ee, - ordinal: self.ordinal, - }; - self.ordinal += 1; - return v; - }); - } -} - -struct MutableVertex<'g> { - ordinal: usize, - id: usize, - local_edges: &'g mut HashSet, - all_edges: &'g mut EdgesVec<()>, -} - -impl Vertex for MutableVertex<'_> { - type RefType = MutRef; - - fn iter_edges_or_nothing_sorted(&mut self) -> impl EdgesIterator { - let mut local_edges = self - .local_edges - .iter() - .map(|i| { - (i, unsafe { - NonNull::from_mut(self.all_edges.index_mut(0)).as_mut() - }) - }) - .map(|(i, e)| (e.another(self.id), i, &mut e.length)) - .collect::>(); - local_edges.sort_by_key(|(k, _, _)| *k); - - return MutableEdgesIterator { - it: IteratorWithHole { - it: local_edges.into_iter().map(|(_, _, x)| x), - hole: Some(self.ordinal), - }, - }; - } - - fn set_vertex_to_update_state(&self, state: &mut UpdatePending) { - *state = UpdatePending::Remove(self.id) - } -} - -struct IteratorWithHole> { - hole: Option, - it: It, -} - -impl> Iterator for IteratorWithHole { - type Item = Option; - - fn next(&mut self) -> Option { - match self.hole { - None => return self.it.next().map(|e| Some(e)), - Some(v) => { - if v == 0 { - self.hole = None; - return Some(None); - } else { - self.hole = Some(v - 1); - return self.it.next().map(|e| Some(e)); - } - } - } - } -} - -struct MutableEdgesIterator<'g, It: Iterator>> { - it: It, -} - -impl<'g, It: Iterator>> EdgesIterator - for MutableEdgesIterator<'g, It> -{ - type RefType = MutRef; - type Edge<'x> - = MutableEdge<'x> - where - Self: 'x; - - fn next<'s>(&'s mut self) -> Option>> { - return self - .it - .next() - .map(|oi| oi.map(|len| MutableEdge { len: len })); - } -} - -struct MutableEdge<'g> { - len: &'g mut f64, -} - -impl Edge for MutableEdge<'_> { - type RefType = MutRef; - - fn get_edge_len_ptr<'s>(&'s mut self) -> ::Ref<'s, f64> { - return self.len; - } -} +} \ No newline at end of file diff --git a/utility/src/gui/graph_lengths_table/impl_const.rs b/utility/src/gui/graph_lengths_table/impl_const.rs new file mode 100644 index 0000000..2b777bf --- /dev/null +++ b/utility/src/gui/graph_lengths_table/impl_const.rs @@ -0,0 +1,123 @@ +use super::{Edge, EdgesIterator, Graph, IteratorWithHole, Vertex, VerticesIterator}; +use crate::UpdatePending; +use crate::graph::{CompleteGraph, EdgesVec}; +use crate::gui::const_mut_switch::{ConstRef, RefType}; +use std::collections::HashSet; +use std::ops::Index; +use std::ptr::NonNull; + +pub struct ConstGraph<'g> { + pub graph: &'g CompleteGraph<()>, +} + +impl Graph for ConstGraph<'_> { + type RefType = ConstRef; + + fn iter_vertices(&mut self) -> impl VerticesIterator { + return ConstVerticesIterator { + ee: &self.graph.edges, + it: self.graph.vertices.iter_indexed(), + ordinal: 0, + }; + } + + fn vertices_count(&self) -> usize { + return self.graph.vertex_count(); + } +} + +struct ConstVerticesIterator<'g, It: Iterator)>> { + ee: &'g EdgesVec<()>, + it: It, + ordinal: usize, +} + +impl<'g, It: Iterator)>> VerticesIterator + for ConstVerticesIterator<'g, It> +{ + type RefType = ConstRef; + type Vertex<'v> + = ConstVertex<'v> + where + Self: 'v; + + fn next<'v>(&'v mut self) -> Option> { + return self.it.next().map(|(i, e)| { + let v = ConstVertex { + id: i, + local_edges: e, + all_edges: self.ee, + ordinal: self.ordinal, + }; + self.ordinal += 1; + return v; + }); + } +} + +struct ConstVertex<'g> { + ordinal: usize, + id: usize, + local_edges: &'g HashSet, + all_edges: &'g EdgesVec<()>, +} + +impl Vertex for ConstVertex<'_> { + type RefType = ConstRef; + + fn iter_edges_or_nothing_sorted(&mut self) -> impl EdgesIterator { + let mut local_edges = self + .local_edges + .iter() + .map(|i| { + (i, unsafe { + NonNull::from_ref(self.all_edges.index(*i)).as_ref() + }) + }) + .map(|(i, e)| (e.another(self.id), i, &e.length)) + .collect::>(); + local_edges.sort_by_key(|(k, _, _)| *k); + + return ConstEdgesIterator { + it: IteratorWithHole { + it: local_edges.into_iter().map(|(_, _, x)| x), + hole: Some(self.ordinal), + }, + }; + } + + fn set_vertex_to_update_state(&self, state: &mut UpdatePending) { + *state = UpdatePending::Remove(self.id) + } +} + +struct ConstEdgesIterator<'g, It: Iterator>> { + it: It, +} + +impl<'g, It: Iterator>> EdgesIterator for ConstEdgesIterator<'g, It> { + type RefType = ConstRef; + type Edge<'x> + = ConstEdge<'x> + where + Self: 'x; + + fn next<'s>(&'s mut self) -> Option>> { + return self + .it + .next() + .map(|oi| oi.map(|len| ConstEdge { len: len })); + } +} + +struct ConstEdge<'g> { + len: &'g f64, +} + +impl Edge for ConstEdge<'_> { + type RefType = ConstRef; + + fn get_edge_len_ptr<'s>(&'s mut self) -> ::Ref<'s, f64> { + return self.len; + } +} diff --git a/utility/src/gui/graph_lengths_table/impl_mut.rs b/utility/src/gui/graph_lengths_table/impl_mut.rs new file mode 100644 index 0000000..808c8e3 --- /dev/null +++ b/utility/src/gui/graph_lengths_table/impl_mut.rs @@ -0,0 +1,125 @@ +use super::{Edge, EdgesIterator, Graph, IteratorWithHole, Vertex, VerticesIterator}; +use crate::graph::{CompleteGraph, EdgesVec}; +use crate::gui::const_mut_switch::{MutRef, RefType}; +use crate::{UpdatePending}; +use std::collections::HashSet; +use std::ops::IndexMut; +use std::ptr::NonNull; + +pub struct MutableGraph<'g> { + pub graph: &'g mut CompleteGraph<()>, +} + +impl Graph for MutableGraph<'_> { + type RefType = MutRef; + + fn iter_vertices(&mut self) -> impl VerticesIterator { + return MutableVerticesIterator { + ee: &mut self.graph.edges, + it: self.graph.vertices.iter_indexed_mut(), + ordinal: 0, + }; + } + + fn vertices_count(&self) -> usize { + return self.graph.vertex_count(); + } +} + +struct MutableVerticesIterator<'g, It: Iterator)>> { + ee: &'g mut EdgesVec<()>, + it: It, + ordinal: usize, +} + +impl<'g, It: Iterator)>> VerticesIterator + for MutableVerticesIterator<'g, It> +{ + type RefType = MutRef; + type Vertex<'v> + = MutableVertex<'v> + where + Self: 'v; + + fn next<'v>(&'v mut self) -> Option> { + return self.it.next().map(|(i, e)| { + let v = MutableVertex { + id: i, + local_edges: e, + all_edges: self.ee, + ordinal: self.ordinal, + }; + self.ordinal += 1; + return v; + }); + } +} + +struct MutableVertex<'g> { + ordinal: usize, + id: usize, + local_edges: &'g mut HashSet, + all_edges: &'g mut EdgesVec<()>, +} + +impl Vertex for MutableVertex<'_> { + type RefType = MutRef; + + fn iter_edges_or_nothing_sorted(&mut self) -> impl EdgesIterator { + let mut local_edges = self + .local_edges + .iter() + .map(|i| { + (i, unsafe { + NonNull::from_mut(self.all_edges.index_mut(*i)).as_mut() + }) + }) + .map(|(i, e)| (e.another(self.id), i, &mut e.length)) + .collect::>(); + local_edges.sort_by_key(|(k, _, _)| *k); + + return MutableEdgesIterator { + it: IteratorWithHole { + it: local_edges.into_iter().map(|(_, _, x)| x), + hole: Some(self.ordinal), + }, + }; + } + + fn set_vertex_to_update_state(&self, state: &mut UpdatePending) { + *state = UpdatePending::Remove(self.id) + } +} + +struct MutableEdgesIterator<'g, It: Iterator>> { + it: It, +} + +impl<'g, It: Iterator>> EdgesIterator + for MutableEdgesIterator<'g, It> +{ + type RefType = MutRef; + type Edge<'x> + = MutableEdge<'x> + where + Self: 'x; + + fn next<'s>(&'s mut self) -> Option>> { + return self + .it + .next() + .map(|oi| oi.map(|len| MutableEdge { len: len })); + } +} + +struct MutableEdge<'g> { + len: &'g mut f64, +} + +impl Edge for MutableEdge<'_> { + type RefType = MutRef; + + fn get_edge_len_ptr<'s>(&'s mut self) -> ::Ref<'s, f64> { + return self.len; + } +} diff --git a/utility/src/gui/graph_lengths_table/mod.rs b/utility/src/gui/graph_lengths_table/mod.rs index 4d790dc..5c4ca17 100644 --- a/utility/src/gui/graph_lengths_table/mod.rs +++ b/utility/src/gui/graph_lengths_table/mod.rs @@ -1,4 +1,36 @@ -mod ui; mod ctx; +mod impl_mut; +mod ui; +mod impl_const; -pub use ctx::{Graph, Vertex, Edge, EdgesIterator, VerticesIterator}; \ No newline at end of file +pub use ctx::Graph; +use ctx::{Edge, EdgesIterator, Vertex, VerticesIterator}; +pub use impl_mut::MutableGraph; +pub use impl_const::ConstGraph; +pub use ui::draw_lengths_table; + + + +struct IteratorWithHole> { + hole: Option, + it: It, +} + +impl> Iterator for IteratorWithHole { + type Item = Option; + + fn next(&mut self) -> Option { + match self.hole { + None => return self.it.next().map(|e| Some(e)), + Some(v) => { + if v == 0 { + self.hole = None; + return Some(None); + } else { + self.hole = Some(v - 1); + return self.it.next().map(|e| Some(e)); + } + } + } + } +} \ No newline at end of file diff --git a/utility/src/gui/graph_lengths_table/ui.rs b/utility/src/gui/graph_lengths_table/ui.rs index f3e1f00..c9b79bd 100644 --- a/utility/src/gui/graph_lengths_table/ui.rs +++ b/utility/src/gui/graph_lengths_table/ui.rs @@ -1,9 +1,13 @@ -use crate::gat_iterator::GatIterator; -use crate::gui::const_mut_switch::{ConstMutSwitchUi, ConstMutSwitchUiTable, ConstMutSwitchUiTableRow, RefType, _ConstMutSwitchUiCallback, _ConstMutSwitchUiTableCallback, _ConstMutSwitchUiTableHeaderCallback, _ConstMutSwitchUiTableRowCallback, _ConstMutSwitchUiTableRowsIterator}; +use crate::UpdatePending; +use crate::gui::const_mut_switch::{ + _ConstMutSwitchUiCallback, _ConstMutSwitchUiTableCallback, + _ConstMutSwitchUiTableHeaderCallback, _ConstMutSwitchUiTableRowCallback, + _ConstMutSwitchUiTableRowsIterator, ConstMutSwitchUi, ConstMutSwitchUiTable, + ConstMutSwitchUiTableRow, RefType, +}; use crate::gui::graph_lengths_table::ctx::EdgesIterator; use crate::gui::graph_lengths_table::ctx::VerticesIterator; use crate::gui::graph_lengths_table::{Edge, Graph, Vertex}; -use crate::{LambdaIterator, UpdatePending}; pub fn draw_lengths_table>( ctx_ui: &mut CtxUi, @@ -19,7 +23,7 @@ struct Root<'g, 'u, G: Graph> { impl _ConstMutSwitchUiCallback for Root<'_, '_, G> { fn render(self, ctx: &mut impl ConstMutSwitchUi) { - ctx.table(false, self.graph.vertices_count(), self) + ctx.table(false, self.graph.vertices_count() + 1, self) } } @@ -88,7 +92,9 @@ impl<'u, It: VerticesIterator> RowsIterators<'u, It> { } } } -impl<'u, It: VerticesIterator> _ConstMutSwitchUiTableRowsIterator for RowsIterators<'u, It> { +impl<'u, It: VerticesIterator> _ConstMutSwitchUiTableRowsIterator + for RowsIterators<'u, It> +{ type Item<'x> = Row<'x, 'u, It::Vertex<'x>> where diff --git a/utility/src/gui/mod.rs b/utility/src/gui/mod.rs index d7fd104..ccd8e1c 100644 --- a/utility/src/gui/mod.rs +++ b/utility/src/gui/mod.rs @@ -3,7 +3,7 @@ pub mod const_mut_switch; mod render_graph; mod slider; mod subwindow; -mod graph_lengths_table; +pub mod graph_lengths_table; pub use boot::boot_eframe; pub use render_graph::render_graph; diff --git a/utility/src/gui/render_graph.rs b/utility/src/gui/render_graph.rs index dd90396..398c822 100644 --- a/utility/src/gui/render_graph.rs +++ b/utility/src/gui/render_graph.rs @@ -8,7 +8,7 @@ pub fn render_graph( vertices: &VerticesVec, vertex_locations: &mut [(f32, f32)], edges: &EdgesVec, - normalized_intensity: impl Fn(&Edge) -> f64, + normalized_intensity: impl Fn(usize, &Edge) -> f64, ) { let canvas = ui.painter(); let rect = ui.available_size(); @@ -17,7 +17,7 @@ pub fn render_graph( let rect = Rect::from_min_max(start.min, rect.to_pos2()); canvas.rect_filled(rect, CornerRadius::same(0), Color32::from_rgb(0, 0, 0)); - for e in edges.iter() { + for (ei, e) in edges.iter_indexed() { let p1 = vertex_locations[e.vertex1_index]; let p2 = vertex_locations[e.vertex2_index]; @@ -32,7 +32,7 @@ pub fn render_graph( p2.1 * rect.height() + rect.min.y, ), ], - Stroke::new(1.0, intensity2color(normalized_intensity(e))), + Stroke::new(1.0, intensity2color(normalized_intensity(ei, e))), ); } let font_id = &ui.style().text_styles[&egui::TextStyle::Body];