From 2ea5448ae3da9e94533c48c93cb08d0b1b011b41 Mon Sep 17 00:00:00 2001 From: Andrew Golovashevich Date: Tue, 24 Feb 2026 00:29:01 +0300 Subject: [PATCH] Attempt 3 to make mutability-independent UI --- utility/src/gat_iterator.rs | 36 ++++ utility/src/graph/_preserve_index_vec.rs | 7 + utility/src/gui/const_mut_switch/const.rs | 22 +- utility/src/gui/const_mut_switch/mod.rs | 6 +- utility/src/gui/const_mut_switch/mut.rs | 12 +- utility/src/gui/const_mut_switch/table.rs | 142 +++++++++---- utility/src/gui/const_mut_switch/trait.rs | 4 +- .../gui/const_mut_switch/эволюция_костылей.md | 175 ++++++++++++++- utility/src/gui/graph_lengths_table/ctx.rs | 190 +++++++++++++++++ utility/src/gui/graph_lengths_table/mod.rs | 4 + utility/src/gui/graph_lengths_table/ui.rs | 173 +++++++++++++++ utility/src/gui/lengths_table.rs | 201 ------------------ utility/src/gui/mod.rs | 2 +- utility/src/lambda_iterator.rs | 13 +- utility/src/lib.rs | 4 +- 15 files changed, 727 insertions(+), 264 deletions(-) create mode 100644 utility/src/gat_iterator.rs create mode 100644 utility/src/gui/graph_lengths_table/ctx.rs create mode 100644 utility/src/gui/graph_lengths_table/mod.rs create mode 100644 utility/src/gui/graph_lengths_table/ui.rs delete mode 100644 utility/src/gui/lengths_table.rs diff --git a/utility/src/gat_iterator.rs b/utility/src/gat_iterator.rs new file mode 100644 index 0000000..7e7c786 --- /dev/null +++ b/utility/src/gat_iterator.rs @@ -0,0 +1,36 @@ +pub trait GatIterator { + type Item<'x> + where + Self: 'x; + + fn next<'s>(&'s mut self) -> Option>; + + fn forEach(mut self, mut consumer: impl for<'x> FnMut(Self::Item<'x>)) + where + Self: Sized, + { + loop { + match self.next() { + None => return, + Some(i) => consumer(i) + } + } + } +} + +/*pub fn make_lambda<'z, I: Iterator>(it: I) -> impl for<'x> LambdaIterator = I::Item> { + return LambdaIteratorConverter { it }; +} + +struct LambdaIteratorConverter { + it: I, +} + +impl LambdaIterator for LambdaIteratorConverter { + type Item<'x> = I::Item where Self:'x; + + fn next<'s, R>(&mut self, receiver: impl for<'x> FnOnce(I::Item) -> R) -> Option { + return self.it.next().map(receiver); + } +} +*/ diff --git a/utility/src/graph/_preserve_index_vec.rs b/utility/src/graph/_preserve_index_vec.rs index e47c8f8..55db798 100644 --- a/utility/src/graph/_preserve_index_vec.rs +++ b/utility/src/graph/_preserve_index_vec.rs @@ -93,6 +93,13 @@ impl _PreserveIndexVec { }); } + pub fn iter_indexes(&self) -> impl Iterator { + return self.buffer.iter().enumerate().filter_map(|(i, c)| match c { + Cell::Free { .. } => return None, + Cell::Value { value } => return Some(i), + }); + } + pub fn capacity(&self) -> usize { return self.buffer.len(); } diff --git a/utility/src/gui/const_mut_switch/const.rs b/utility/src/gui/const_mut_switch/const.rs index 29ae060..362a1a7 100644 --- a/utility/src/gui/const_mut_switch/const.rs +++ b/utility/src/gui/const_mut_switch/const.rs @@ -1,4 +1,8 @@ -use super::{_ConstMutSwitchUiCallback, ConstMutSwitchUi, ConstRef, RefType, _ConstMutSwitchUiTableHeaderCallback}; +use super::{ + _ConstMutSwitchUiCallback, _ConstMutSwitchUiTableHeaderCallback, + _ConstMutSwitchUiTableCallback, ConstMutSwitchUi, ConstRef, MutRef, MutUI, RefType, +}; +use crate::gui::const_mut_switch::table::ConstMutSwitchUiTableImplState; use eframe::egui::{ScrollArea, Ui}; use eframe::emath::Numeric; use std::ops::RangeInclusive; @@ -61,22 +65,22 @@ impl ConstMutSwitchUi for ConstUI<'_> { self.ui.separator(); } - fn scroll_area_2( - &mut self, - scope: impl _ConstMutSwitchUiCallback, - ) { + fn scroll_area_2(&mut self, scope: impl _ConstMutSwitchUiCallback) { ScrollArea::both() .auto_shrink([false, false]) - .show_viewport(self.ui, |ui, _|scope.render(&mut ConstUI { ui })); + .show_viewport(self.ui, |ui, _| scope.render(&mut ConstUI { ui })); } - fn table( &mut self, vscroll: bool, columns: usize, - header: impl _ConstMutSwitchUiTableHeaderCallback, + scope: impl _ConstMutSwitchUiTableCallback, ) { - super::render_table::(self.ui, vscroll, columns, header); + scope.render_table( + &mut ConstMutSwitchUiTableImplState::::new( + self.ui, vscroll, columns, + ), + ); } } diff --git a/utility/src/gui/const_mut_switch/mod.rs b/utility/src/gui/const_mut_switch/mod.rs index 0b1ffd0..e724213 100644 --- a/utility/src/gui/const_mut_switch/mod.rs +++ b/utility/src/gui/const_mut_switch/mod.rs @@ -7,8 +7,10 @@ mod r#trait; pub use r#const::ConstUI; pub use r#mut::MutUI; pub use r#ref::{ConstRef, MutRef, RefType}; -use table::render_table; +use table::ConstMutSwitchUiTableImplState; pub use table::{ - _ConstMutSwitchUiTableHeaderCallback, _ConstMutSwitchUiTableRowCallback, ConstMutSwitchUiTableRow, + _ConstMutSwitchUiTableCallback, _ConstMutSwitchUiTableHeaderCallback, + _ConstMutSwitchUiTableRowCallback, _ConstMutSwitchUiTableRowsIterator, ConstMutSwitchUiTable, + ConstMutSwitchUiTableRow, }; pub use r#trait::{_ConstMutSwitchUiCallback, ConstMutSwitchUi}; diff --git a/utility/src/gui/const_mut_switch/mut.rs b/utility/src/gui/const_mut_switch/mut.rs index 0c85c19..a5d6c27 100644 --- a/utility/src/gui/const_mut_switch/mut.rs +++ b/utility/src/gui/const_mut_switch/mut.rs @@ -1,4 +1,8 @@ -use super::{_ConstMutSwitchUiTableHeaderCallback, ConstMutSwitchUi, MutRef, RefType}; +use super::{ + _ConstMutSwitchUiTableHeaderCallback, _ConstMutSwitchUiTableCallback, ConstMutSwitchUi, + MutRef, RefType, +}; +use crate::gui::const_mut_switch::table::ConstMutSwitchUiTableImplState; use crate::gui::const_mut_switch::r#trait::_ConstMutSwitchUiCallback; use eframe::egui::{ScrollArea, Ui}; use eframe::emath::Numeric; @@ -68,8 +72,10 @@ impl ConstMutSwitchUi for MutUI<'_> { &mut self, vscroll: bool, columns: usize, - header: impl _ConstMutSwitchUiTableHeaderCallback, + scope: impl _ConstMutSwitchUiTableCallback, ) { - super::render_table::(self.ui, vscroll, columns, header); + scope.render_table(&mut ConstMutSwitchUiTableImplState::::new( + self.ui, vscroll, columns, + )); } } diff --git a/utility/src/gui/const_mut_switch/table.rs b/utility/src/gui/const_mut_switch/table.rs index c98b0ab..d7c484b 100644 --- a/utility/src/gui/const_mut_switch/table.rs +++ b/utility/src/gui/const_mut_switch/table.rs @@ -3,20 +3,32 @@ use super::{ _ConstMutSwitchUiCallback, ConstMutSwitchUi, ConstRef, ConstUI, MutRef, MutUI, RefType, }; -use crate::LambdaIterator; +use crate::{GatIterator, LambdaIterator}; use eframe::egui::Ui; -use egui_extras::{Column, TableBuilder, TableRow}; +use egui_extras::{Column, Table, TableBuilder, TableRow}; use std::marker::PhantomData; -use std::mem::uninitialized; +use std::mem::{swap, uninitialized}; + +pub trait _ConstMutSwitchUiTableCallback { + fn render_table(self, ctx: &mut impl ConstMutSwitchUiTable); +} + +pub trait ConstMutSwitchUiTable { + type RefType: super::RefType; + fn header(&mut self, scope: impl _ConstMutSwitchUiTableHeaderCallback); + fn body(&mut self, scope: impl _ConstMutSwitchUiTableRowsIterator); +} + +pub trait _ConstMutSwitchUiTableRowsIterator { + type Item<'x>: _ConstMutSwitchUiTableRowCallback + where + Self: 'x; + + fn next<'s>(&'s mut self) -> Option>; +} pub trait _ConstMutSwitchUiTableHeaderCallback { - type RowRender: _ConstMutSwitchUiTableRowCallback; - type RowsIterator: LambdaIterator; - - fn render_header( - self, - ctx: &mut impl ConstMutSwitchUiTableRow, - ) -> Self::RowsIterator; + fn render_header(self, ctx: &mut impl ConstMutSwitchUiTableRow); } pub trait _ConstMutSwitchUiTableRowCallback { @@ -70,36 +82,90 @@ impl __SwitchUiConstructor1 for MutUI<'_> { } } -pub(super) fn render_table< - RefType: super::RefType, - Constructor: __SwitchUiConstructor1, ->( - ui: &mut Ui, - vscroll: bool, - columnsCount: usize, - header_render: impl _ConstMutSwitchUiTableHeaderCallback, -) { - let mut rows_it = unsafe { uninitialized() }; - TableBuilder::new(ui) - .striped(true) // Alternating row colors - .resizable(true) - .vscroll(vscroll) - .columns(Column::remainder(), columnsCount) - .header(20.0, |row| { - rows_it = - header_render.render_header(&mut ConstMutSwitchUiTableRowImpl::<_, Constructor> { +pub(super) enum ConstMutSwitchUiTableImplState< + 'a, + RT: RefType, + Constructor: __SwitchUiConstructor1, +> { + Header(TableBuilder<'a>), + Body(Table<'a>), + Done(PhantomData<(RT, Constructor)>), +} + +impl<'a, RT: RefType, Constructor: __SwitchUiConstructor1> + ConstMutSwitchUiTableImplState<'a, RT, Constructor> +{ + pub fn new(ui: &'a mut Ui, vscroll: bool, columns_count: usize) -> Self { + return Self::Header( + TableBuilder::new(ui) + .striped(true) // Alternating row colors + .resizable(true) + .vscroll(vscroll) + .columns(Column::remainder(), columns_count), + ); + } + + #[allow(deprecated)] + fn header_map(&mut self, f: impl FnOnce(TableBuilder) -> Table) { + 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)) + } + } + _ => panic!("Not in header state"), + } + } + + #[allow(deprecated)] + fn body_map(&mut self, f: impl FnOnce(Table)) { + 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()) + } + } + _ => panic!("Not in body state"), + } + } +} + +impl> ConstMutSwitchUiTable + for ConstMutSwitchUiTableImplState<'_, RT, Constructor> +{ + type RefType = RT; + + fn header(&mut self, scope: impl _ConstMutSwitchUiTableHeaderCallback) { + self.header_map(|h| { + return h.header(20.0, |row| { + scope.render_header(&mut ConstMutSwitchUiTableRowImpl::<_, Constructor> { row, __phantom: PhantomData::default(), - }); - }) - .body(|mut body| { - rows_it.consume(|row_render| { - body.row(20.0, |row| { - row_render.render_row(&mut ConstMutSwitchUiTableRowImpl::<_, Constructor> { - row, - __phantom: PhantomData::default(), - }) }) }); - }); + }) + } + + fn body(&mut self, mut scope: impl _ConstMutSwitchUiTableRowsIterator) { + self.body_map(|body| { + body.body(|mut b| { + loop { + match scope.next() { + None => break, + Some(rs) => b.row(20.0, |rn| { + rs.render_row(&mut ConstMutSwitchUiTableRowImpl::<_, Constructor> { + row: rn, + __phantom: PhantomData::default(), + }) + }), + } + } + }); + }) + } } diff --git a/utility/src/gui/const_mut_switch/trait.rs b/utility/src/gui/const_mut_switch/trait.rs index 051a82f..49670c8 100644 --- a/utility/src/gui/const_mut_switch/trait.rs +++ b/utility/src/gui/const_mut_switch/trait.rs @@ -1,4 +1,4 @@ -use super::{_ConstMutSwitchUiTableHeaderCallback, RefType}; +use super::{_ConstMutSwitchUiTableHeaderCallback, RefType, _ConstMutSwitchUiTableCallback}; use eframe::emath::Numeric; use std::ops::RangeInclusive; @@ -41,7 +41,7 @@ pub trait ConstMutSwitchUi { &mut self, vscroll: bool, columns: usize, - header: impl _ConstMutSwitchUiTableHeaderCallback, + scope: impl _ConstMutSwitchUiTableCallback, ); } diff --git a/utility/src/gui/const_mut_switch/эволюция_костылей.md b/utility/src/gui/const_mut_switch/эволюция_костылей.md index cf2b548..1c9a666 100644 --- a/utility/src/gui/const_mut_switch/эволюция_костылей.md +++ b/utility/src/gui/const_mut_switch/эволюция_костылей.md @@ -834,4 +834,177 @@ trait Ctx_Graph { // ... } -``` \ No newline at end of file +``` + +## 7 +Метод `_ConstMutSwitchUiTableHeaderCallback::render_header` принимает в себя контекст отрисовки +строки и возвращает `impl Trait`. По умолчанию компилятор считает, что возвращаемое значение +заимствует все переданные ссылки. Для более тонкой настройки компилятора есть синтаксис +`impl Trait + use<'a, A>`, но так как компилятор не способен реализовать минимум, определяемый +спецификацией языка, в `use` должны быть указаны все типовые параметры (даже неявные). В +данном случае контекст отрисовки туда попадать не должен, так что пришлось отказаться от короткого +и удобно способа и вернуться к этапу `3.1`: ручной вызов отрисовки заголовка и тела таблицы. + +## 8 +### 8.1 + +Попытки победить borrow checker в итераторах привели к идее указывать возвращаемый +тип итератора в параметре трейта, а не ассоциированным типом. +```rust +trait LambdaIterator { + fn next(&mut self, receiver: impl FnOnce(Item) -> R) -> Option; +} +``` +Это помогло решить некоторые +проблемы, но имплементировать такой трейт всё равно не получилось. + +### 8.2 +Gemini рассказал про **Higher-Rank Trait Bounds (HRTB)**, и вроде как это решает проблему +```rust +trait LambdaIterator { + type Item<'x>; + + fn next(&mut self, receiver: impl for<'x> FnOnce(Self::Item<'x>) -> R) -> Option; +} +``` + +### 8.3 +Имплементация итератора в таком варианте выдавала ошибку, которая исправляется вполне логичным +дополнением к трейту: +```rust +trait LambdaIterator { + type Item<'x>: where Self: 'x; + + fn next(&mut self, receiver: impl for<'x> FnOnce(Self::Item<'x>) -> R) -> Option; +} +``` + +### 8.4 +После многочисленных экспериментов был сделан вывод, что язык пока не готов к описанию таких +гениальных вещей: или в компиляторе просто с ошибками эти вещи реализованы; или вывод об +ошибках недостаточно подробный, чтоб разобраться не употребляя те же вещества, что и создатели. +Порождение итератора выглядит следующим образом: +```rust +trait Ctx_Graph { + type RefType: RefType; + + type Vertex<'v>; + + fn iter_vertices<'g>( + &mut self, + graph: &'g mut G + ) -> impl for<'v> LambdaIterator=(&'v mut Self, Self::Vertex<'v>)> + 'g; +} +``` +Корректна ли эта запись на практике проверить не удалось, так как в имплементации компилятор +просчитывает время жизни лямбды (или её компонентов) совсем не так, как ожидается. + + +### 8.5 +Поитогу пришлось откатиться обратно на обычные итераторы. Точнее, на их модифицированную +версию, благо знание об HRTB даёт недосающие инструменты: +```rust +trait GatIterator { + type Item<'x> + where + Self: 'x; + + fn next<'s>(&'s mut self) -> Option>; + + fn forEach(mut self, mut consumer: impl for<'x> FnMut(Self::Item<'x>)) + where + Self: Sized, + { + loop { + match self.next() { + None => return, + Some(i) => consumer(i) + } + } + } +} +``` + +### 8.6 +В целом такая модификация итератора работает сама по себе, но использовать его как часть системы +трейтов, которые явно указывают какой тип должен возвращать такой итератор не получается, из-за +тех же ошибок про неправильное время жизни ассоциированного типа двоюродного племянника бабушки +по папиной/маминой линии детей типового параметра. +```rust +trait Container { + type Item<'x>: Contraint; + + fn iter(&mut self) -> impl for<'x> GatIterator = Self::Item<'x>>; +} +``` +Но если создавать под каждую задачу свой трейт итератора, то это как минимум компилируется, но +опять же, только в случаях когда не нужно указывать тип элемента в месте использования. Такой +модификации подвергся итератор для строк таблицы: +```rust + +pub trait ConstMutSwitchUiTable { + // ... + + fn body(&mut self, scope: impl _ConstMutSwitchUiTableRowsIterator); + + // ... +} + +pub trait _ConstMutSwitchUiTableRowsIterator { + type Item<'x>: _ConstMutSwitchUiTableRowCallback + where + Self: 'x; + + fn next<'s>(&'s mut self) -> Option>; +} +``` + +## 9 +Контекст для работы с графами пришлось несколько раз декомпозировать и изменять, в основном по +той же причине невозможности полноценно использовать `+ use<>`. В конечном итоге он превратился +просто в обёртку над графом (и его частями) без вынесения в контекст. + +```rust + +pub trait Graph { + type RefType: RefType; + + fn iter_vertices(&mut self) -> impl VerticesIterator; + + fn vertices_count(&self) -> usize; +} + +pub trait VerticesIterator { + type RefType: RefType; + + type Vertex<'v>: Vertex + where + Self: 'v; + + fn next<'v>(&'v mut self) -> Option>; +} + +pub trait Vertex { + type RefType: RefType; + + fn iter_edges_or_nothing_sorted(&mut self) -> impl EdgesIterator; + + fn set_vertex_to_update_state(&self, state: &mut UpdatePending); +} + +pub trait EdgesIterator { + type RefType: RefType; + + type Edge<'e>: Edge + where + Self: 'e; + + fn next<'e>(&'e mut self) -> Option>>; +} + +pub trait Edge { + type RefType: RefType; + + fn get_edge_len_ptr<'s>(&'s mut self) -> ::Ref<'s, f64>; +} +``` diff --git a/utility/src/gui/graph_lengths_table/ctx.rs b/utility/src/gui/graph_lengths_table/ctx.rs new file mode 100644 index 0000000..e387ab5 --- /dev/null +++ b/utility/src/gui/graph_lengths_table/ctx.rs @@ -0,0 +1,190 @@ +use crate::graph::{CompleteGraph, EdgesVec}; +use crate::gui::const_mut_switch::{MutRef, RefType}; +use crate::{GatIterator, UpdatePending}; +use std::collections::HashSet; +use std::ops::IndexMut; +use std::ptr::NonNull; + +pub trait Graph { + type RefType: RefType; + + fn iter_vertices(&mut self) -> impl VerticesIterator; + + fn vertices_count(&self) -> usize; +} + +pub trait VerticesIterator { + type RefType: RefType; + + type Vertex<'v>: Vertex + where + Self: 'v; + + fn next<'v>(&'v mut self) -> Option>; +} + +pub trait Vertex { + type RefType: RefType; + + fn iter_edges_or_nothing_sorted(&mut self) -> impl EdgesIterator; + + fn set_vertex_to_update_state(&self, state: &mut UpdatePending); +} + +pub trait EdgesIterator { + type RefType: RefType; + + type Edge<'e>: Edge + where + Self: 'e; + + fn next<'e>(&'e mut self) -> Option>>; +} + +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; + } +} diff --git a/utility/src/gui/graph_lengths_table/mod.rs b/utility/src/gui/graph_lengths_table/mod.rs new file mode 100644 index 0000000..4d790dc --- /dev/null +++ b/utility/src/gui/graph_lengths_table/mod.rs @@ -0,0 +1,4 @@ +mod ui; +mod ctx; + +pub use ctx::{Graph, Vertex, Edge, EdgesIterator, VerticesIterator}; \ 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 new file mode 100644 index 0000000..f3e1f00 --- /dev/null +++ b/utility/src/gui/graph_lengths_table/ui.rs @@ -0,0 +1,173 @@ +use crate::gat_iterator::GatIterator; +use crate::gui::const_mut_switch::{ConstMutSwitchUi, ConstMutSwitchUiTable, ConstMutSwitchUiTableRow, RefType, _ConstMutSwitchUiCallback, _ConstMutSwitchUiTableCallback, _ConstMutSwitchUiTableHeaderCallback, _ConstMutSwitchUiTableRowCallback, _ConstMutSwitchUiTableRowsIterator}; +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, + graph: &mut G, + update: ::Ref<'_, UpdatePending>, +) { + ctx_ui.scroll_area_2(Root { graph, update }); +} +struct Root<'g, 'u, G: Graph> { + graph: &'g mut G, + update: ::Ref<'u, UpdatePending>, +} + +impl _ConstMutSwitchUiCallback for Root<'_, '_, G> { + fn render(self, ctx: &mut impl ConstMutSwitchUi) { + ctx.table(false, self.graph.vertices_count(), self) + } +} + +impl _ConstMutSwitchUiTableCallback for Root<'_, '_, G> { + fn render_table(mut self, ctx: &mut impl ConstMutSwitchUiTable) { + ctx.header(Header { + it: self.graph.iter_vertices(), + update: &mut self.update, + }); + + ctx.body(RowsIterators { + vertices: self.graph.iter_vertices(), + update: self.update, + row_id: 0, + }) + } +} + +struct Header<'u, 'uu, It: VerticesIterator> { + it: It, + update: &'uu mut ::Ref<'u, UpdatePending>, +} + +impl _ConstMutSwitchUiTableHeaderCallback + for Header<'_, '_, It> +{ + fn render_header(mut self, row: &mut impl ConstMutSwitchUiTableRow) { + row.cell(CornerCell {}); + + let mut column_id = 0; + loop { + match self.it.next() { + None => break, + Some(mut v) => { + column_id += 1; + // let update = &mut self.update; + let data = TitleCell { + row_id: column_id, + vertex: &mut v, + update: &mut self.update, + }; + row.cell(data) + } + } + } + } +} +struct RowsIterators<'u, It: VerticesIterator> { + vertices: It, + update: ::Ref<'u, UpdatePending>, + row_id: usize, +} + +impl<'u, It: VerticesIterator> RowsIterators<'u, It> { + fn next<'s>(&'s mut self) -> Option>> { + match self.vertices.next() { + None => return None, + Some(v) => { + self.row_id += 1; + return Some(Row { + vertex: v, + row_id: self.row_id, + update: &mut self.update, + }); + } + } + } +} +impl<'u, It: VerticesIterator> _ConstMutSwitchUiTableRowsIterator for RowsIterators<'u, It> { + type Item<'x> + = Row<'x, 'u, It::Vertex<'x>> + where + Self: 'x; + + fn next<'s>(&'s mut self) -> Option> { + match self.vertices.next() { + None => return None, + Some(v) => { + self.row_id += 1; + return Some(Row { + vertex: v, + row_id: self.row_id, + update: &mut self.update, + }); + } + } + } +} + +struct Row<'uu, 'u: 'uu, V: Vertex> { + vertex: V, + row_id: usize, + update: &'uu mut ::Ref<'u, UpdatePending>, +} + +impl _ConstMutSwitchUiTableRowCallback for Row<'_, '_, V> { + fn render_row(mut self, row: &mut impl ConstMutSwitchUiTableRow) { + row.cell(TitleCell { + row_id: self.row_id, + vertex: &mut self.vertex, + update: self.update, + }); + + let mut it = self.vertex.iter_edges_or_nothing_sorted(); + + loop { + match it.next() { + None => break, + Some(None) => row.cell(EmptyCell {}), + Some(Some(mut e)) => row.cell(LengthCell { + length: &mut e.get_edge_len_ptr(), + }), + } + } + } +} + +struct CornerCell {} +impl _ConstMutSwitchUiCallback for CornerCell { + fn render(self, ctx: &mut impl ConstMutSwitchUi) { + ctx.label("#"); + } +} + +struct TitleCell<'v, 'uu, 'u: 'uu, V: Vertex> { + row_id: usize, + vertex: &'v mut V, + update: &'uu mut ::Ref<'u, UpdatePending>, +} +impl _ConstMutSwitchUiCallback for TitleCell<'_, '_, '_, V> { + fn render(self, ctx: &mut impl ConstMutSwitchUi) { + ctx.label(self.row_id.to_string().as_str()); + ctx.button("-", self.update, |s| { + self.vertex.set_vertex_to_update_state(s) + }); + } +} + +struct LengthCell<'rr, 'r: 'rr, RT: RefType> { + length: &'rr mut RT::Ref<'r, f64>, +} +impl _ConstMutSwitchUiCallback for LengthCell<'_, '_, RT> { + fn render(self, ctx: &mut impl ConstMutSwitchUi) { + ctx.slider(0.0..=10.0, 0.1, self.length); + } +} + +struct EmptyCell {} +impl _ConstMutSwitchUiCallback for EmptyCell { + fn render(self, _: &mut impl ConstMutSwitchUi) {} +} diff --git a/utility/src/gui/lengths_table.rs b/utility/src/gui/lengths_table.rs deleted file mode 100644 index b8e732e..0000000 --- a/utility/src/gui/lengths_table.rs +++ /dev/null @@ -1,201 +0,0 @@ -use crate::gui::const_mut_switch::{ - _ConstMutSwitchUiCallback, _ConstMutSwitchUiTableHeaderCallback, - _ConstMutSwitchUiTableRowCallback, ConstMutSwitchUi, ConstMutSwitchUiTableRow, RefType, -}; -use crate::{LambdaIterator, UpdatePending}; -use std::ptr::NonNull; - -pub trait Ctx_Graph { - type RefType: RefType; - - type Vertex; - type VerticesIterator<'a>: LambdaIterator - where - Self: 'a; - fn iter_vertices(&mut self, graph: &mut G) -> Self::VerticesIterator<'_>; - - type Edge; - fn iter_edges_or_nothing( - &mut self, - vertex: &mut Self::Vertex, - ) -> impl LambdaIterator)>; - - fn get_edge_len_ptr( - &mut self, - edge: &mut Self::Edge, - ) -> ::Ref<'_, f64>; - - fn set_vertex_to_update_state(&self, vertex: &Self::Vertex, state: &mut UpdatePending); - - fn vertices_count(&self) -> usize; -} - -pub fn draw_lengths_table< - G, - CtxUi: ConstMutSwitchUi, - CtxGraph: Ctx_Graph, ->( - ctx_ui: &mut CtxUi, - ctx_graph: &mut CtxGraph, - graph: G, - update: ::Ref<'_, UpdatePending>, -) { - ctx_ui.scroll_area_2(ScrollArea { - ctx_graph, - graph, - update, - }); -} -struct ScrollArea<'g, 'u, G, CtxGraph: Ctx_Graph> { - ctx_graph: &'g mut CtxGraph, - graph: G, - update: ::Ref<'u, UpdatePending>, -} - -impl> _ConstMutSwitchUiCallback -for ScrollArea<'_, '_, G, CtxGraph> -{ - fn render(self, ctx: &mut impl ConstMutSwitchUi) { - ctx.table( - false, - self.ctx_graph.vertices_count(), - Header { - ctx_graph: self.ctx_graph, - graph: self.graph, - update: self.update, - }, - ) - } -} - -struct Header<'g, 'u, G, CtxGraph: Ctx_Graph> { - ctx_graph: &'g mut CtxGraph, - graph: G, - update: ::Ref<'u, UpdatePending>, -} - -impl<'g, 'u, G, CtxGraph: Ctx_Graph> _ConstMutSwitchUiTableHeaderCallback -for Header<'g, 'u, G, CtxGraph> -{ - type RowRender = Row<'g, 'u, G, CtxGraph>; - - type RowsIterator = RowsIterators<'g, 'u, G, CtxGraph>; - - fn render_header( - mut self, - row: &mut impl ConstMutSwitchUiTableRow, - ) -> Self::RowsIterator { - row.cell(CornerCell {}); - - let mut column_id = 0; - self.ctx_graph - .iter_vertices(&mut self.graph) - .consume(|(ctx_graph, v)| { - column_id += 1; - // let update = &mut self.update; - let data = TitleCell { - ctx_graph: ctx_graph, - row_id: column_id, - vertex: &v, - update: &mut self.update, - }; - row.cell(data) - }); - - return RowsIterators { - vertices: self.ctx_graph.iter_vertices(&mut self.graph), - update: self.update, - row_id: 0, - }; - } -} -struct RowsIterators<'g, 'u, G, CtxGraph: Ctx_Graph + 'g> { - vertices: CtxGraph::VerticesIterator<'g>, - update: ::Ref<'u, UpdatePending>, - row_id: usize, -} - -impl<'g, 'u, G, CtxGraph: Ctx_Graph + 'g> LambdaIterator for RowsIterators<'g, 'u, G, CtxGraph> { - type Item = Row<'g, 'u, G, CtxGraph>; - - fn next(&mut self, receiver: impl FnOnce(Self::Item) -> R) -> Option { - return self.vertices.next(|(ctx, v)| { - self.row_id += 1; - return receiver(Row { - ctx_graph: ctx, - vertex: v, - row_id: self.row_id, - update: NonNull::from_mut(&mut self.update), - }); - }); - } -} - -struct Row<'g, 'u, G, CtxGraph: Ctx_Graph> { - ctx_graph: &'g mut CtxGraph, - vertex: CtxGraph::Vertex, - row_id: usize, - update: NonNull<::Ref<'u, UpdatePending>>, -} - -impl> _ConstMutSwitchUiTableRowCallback -for Row<'_, '_, G, CtxGraph> -{ - fn render_row(mut self, row: &mut impl ConstMutSwitchUiTableRow) { - row.cell(TitleCell { - ctx_graph: self.ctx_graph, - row_id: self.row_id, - vertex: &self.vertex, - update: unsafe { self.update.as_mut() }, - }); - - self.ctx_graph - .iter_edges_or_nothing(&mut self.vertex) - .consume(|(ctx_graph, e)| { - match e { - None => row.cell(EmptyCell {}), - Some(mut e) => row.cell(LengthCell { - length: &mut ctx_graph.get_edge_len_ptr(&mut e), - }) - } - }) - } -} - -struct CornerCell {} -impl _ConstMutSwitchUiCallback for CornerCell { - fn render(self, ctx: &mut impl ConstMutSwitchUi) { - ctx.label("#"); - } -} - -struct TitleCell<'g, 'v, 'rr, 'r: 'rr, G, CtxGraph: Ctx_Graph> { - ctx_graph: &'g mut CtxGraph, - row_id: usize, - vertex: &'v CtxGraph::Vertex, - update: &'rr mut ::Ref<'r, UpdatePending>, -} -impl> _ConstMutSwitchUiCallback -for TitleCell<'_, '_, '_, '_, G, CtxGraph> -{ - fn render(self, ctx: &mut impl ConstMutSwitchUi) { - ctx.label(self.row_id.to_string().as_str()); - ctx.button("-", self.update, |s| { - self.ctx_graph.set_vertex_to_update_state(self.vertex, s) - }); - } -} - -struct LengthCell<'rr, 'r: 'rr, RT: RefType> { - length: &'rr mut RT::Ref<'r, f64>, -} -impl _ConstMutSwitchUiCallback for LengthCell<'_, '_, RT> { - fn render(self, ctx: &mut impl ConstMutSwitchUi) { - ctx.slider(0.0..=10.0, 0.1, self.length); - } -} - -struct EmptyCell {} -impl _ConstMutSwitchUiCallback for EmptyCell { - fn render(self, _: &mut impl ConstMutSwitchUi) {} -} diff --git a/utility/src/gui/mod.rs b/utility/src/gui/mod.rs index 9378fdd..d7fd104 100644 --- a/utility/src/gui/mod.rs +++ b/utility/src/gui/mod.rs @@ -1,9 +1,9 @@ mod boot; pub mod const_mut_switch; -pub mod lengths_table; mod render_graph; mod slider; mod subwindow; +mod graph_lengths_table; pub use boot::boot_eframe; pub use render_graph::render_graph; diff --git a/utility/src/lambda_iterator.rs b/utility/src/lambda_iterator.rs index f443534..0faec82 100644 --- a/utility/src/lambda_iterator.rs +++ b/utility/src/lambda_iterator.rs @@ -1,9 +1,9 @@ pub trait LambdaIterator { - type Item; + type Item<'x>: where Self: 'x; - fn next(&mut self, receiver: impl FnOnce(Self::Item) -> R) -> Option; + fn next(&mut self, receiver: impl for<'x> FnOnce(Self::Item<'x>) -> R) -> Option; - fn consume(mut self, mut receiver: impl FnMut(Self::Item)) + fn consume(mut self, mut receiver: impl for<'x> FnMut(Self::Item<'x>)) where Self: Sized, { @@ -11,7 +11,7 @@ pub trait LambdaIterator { } } -pub fn make_lambda(it: I) -> impl LambdaIterator { +/*pub fn make_lambda<'z, I: Iterator>(it: I) -> impl for<'x> LambdaIterator = I::Item> { return LambdaIteratorConverter { it }; } @@ -20,9 +20,10 @@ struct LambdaIteratorConverter { } impl LambdaIterator for LambdaIteratorConverter { - type Item = I::Item; + type Item<'x> = I::Item where Self:'x; - fn next(&mut self, receiver: impl FnOnce(Self::Item) -> R) -> Option { + fn next<'s, R>(&mut self, receiver: impl for<'x> FnOnce(I::Item) -> R) -> Option { return self.it.next().map(receiver); } } +*/ \ No newline at end of file diff --git a/utility/src/lib.rs b/utility/src/lib.rs index d9bd573..55fbcfc 100644 --- a/utility/src/lib.rs +++ b/utility/src/lib.rs @@ -3,7 +3,9 @@ pub mod gui; mod lambda_iterator; mod update_pending; mod weighted_random; +mod gat_iterator; -pub use lambda_iterator::{LambdaIterator, make_lambda}; +pub use lambda_iterator::{LambdaIterator}; +pub use gat_iterator::{GatIterator}; pub use update_pending::{UpdatePending, UpdateTarget}; pub use weighted_random::{weighted_random, weighted_random_index};