Attempt 3 to make mutability-independent UI

This commit is contained in:
Andrew Golovashevich 2026-02-24 00:29:01 +03:00
parent 09b732cfbc
commit 2ea5448ae3
15 changed files with 727 additions and 264 deletions

View File

@ -0,0 +1,36 @@
pub trait GatIterator {
type Item<'x>
where
Self: 'x;
fn next<'s>(&'s mut self) -> Option<Self::Item<'s>>;
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<Item<'x> = I::Item> {
return LambdaIteratorConverter { it };
}
struct LambdaIteratorConverter<I: Iterator> {
it: I,
}
impl<I: Iterator> LambdaIterator for LambdaIteratorConverter<I> {
type Item<'x> = I::Item where Self:'x;
fn next<'s, R>(&mut self, receiver: impl for<'x> FnOnce(I::Item) -> R) -> Option<R> {
return self.it.next().map(receiver);
}
}
*/

View File

@ -93,6 +93,13 @@ impl<T> _PreserveIndexVec<T> {
}); });
} }
pub fn iter_indexes(&self) -> impl Iterator<Item = (usize)> {
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 { pub fn capacity(&self) -> usize {
return self.buffer.len(); return self.buffer.len();
} }

View File

@ -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::egui::{ScrollArea, Ui};
use eframe::emath::Numeric; use eframe::emath::Numeric;
use std::ops::RangeInclusive; use std::ops::RangeInclusive;
@ -61,22 +65,22 @@ impl ConstMutSwitchUi for ConstUI<'_> {
self.ui.separator(); self.ui.separator();
} }
fn scroll_area_2( fn scroll_area_2(&mut self, scope: impl _ConstMutSwitchUiCallback<Self::RefType>) {
&mut self,
scope: impl _ConstMutSwitchUiCallback<Self::RefType>,
) {
ScrollArea::both() ScrollArea::both()
.auto_shrink([false, false]) .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( fn table(
&mut self, &mut self,
vscroll: bool, vscroll: bool,
columns: usize, columns: usize,
header: impl _ConstMutSwitchUiTableHeaderCallback<Self::RefType>, scope: impl _ConstMutSwitchUiTableCallback<Self::RefType>,
) { ) {
super::render_table::<ConstRef, Self>(self.ui, vscroll, columns, header); scope.render_table(
&mut ConstMutSwitchUiTableImplState::<ConstRef, ConstUI>::new(
self.ui, vscroll, columns,
),
);
} }
} }

View File

@ -7,8 +7,10 @@ mod r#trait;
pub use r#const::ConstUI; pub use r#const::ConstUI;
pub use r#mut::MutUI; pub use r#mut::MutUI;
pub use r#ref::{ConstRef, MutRef, RefType}; pub use r#ref::{ConstRef, MutRef, RefType};
use table::render_table; use table::ConstMutSwitchUiTableImplState;
pub use table::{ pub use table::{
_ConstMutSwitchUiTableHeaderCallback, _ConstMutSwitchUiTableRowCallback, ConstMutSwitchUiTableRow, _ConstMutSwitchUiTableCallback, _ConstMutSwitchUiTableHeaderCallback,
_ConstMutSwitchUiTableRowCallback, _ConstMutSwitchUiTableRowsIterator, ConstMutSwitchUiTable,
ConstMutSwitchUiTableRow,
}; };
pub use r#trait::{_ConstMutSwitchUiCallback, ConstMutSwitchUi}; pub use r#trait::{_ConstMutSwitchUiCallback, ConstMutSwitchUi};

View File

@ -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 crate::gui::const_mut_switch::r#trait::_ConstMutSwitchUiCallback;
use eframe::egui::{ScrollArea, Ui}; use eframe::egui::{ScrollArea, Ui};
use eframe::emath::Numeric; use eframe::emath::Numeric;
@ -68,8 +72,10 @@ impl ConstMutSwitchUi for MutUI<'_> {
&mut self, &mut self,
vscroll: bool, vscroll: bool,
columns: usize, columns: usize,
header: impl _ConstMutSwitchUiTableHeaderCallback<Self::RefType>, scope: impl _ConstMutSwitchUiTableCallback<Self::RefType>,
) { ) {
super::render_table::<MutRef, Self>(self.ui, vscroll, columns, header); scope.render_table(&mut ConstMutSwitchUiTableImplState::<MutRef, MutUI>::new(
self.ui, vscroll, columns,
));
} }
} }

View File

@ -3,20 +3,32 @@
use super::{ use super::{
_ConstMutSwitchUiCallback, ConstMutSwitchUi, ConstRef, ConstUI, MutRef, MutUI, RefType, _ConstMutSwitchUiCallback, ConstMutSwitchUi, ConstRef, ConstUI, MutRef, MutUI, RefType,
}; };
use crate::LambdaIterator; use crate::{GatIterator, LambdaIterator};
use eframe::egui::Ui; use eframe::egui::Ui;
use egui_extras::{Column, TableBuilder, TableRow}; use egui_extras::{Column, Table, TableBuilder, TableRow};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem::uninitialized; use std::mem::{swap, uninitialized};
pub trait _ConstMutSwitchUiTableCallback<RefType: super::RefType> {
fn render_table(self, ctx: &mut impl ConstMutSwitchUiTable<RefType = RefType>);
}
pub trait ConstMutSwitchUiTable {
type RefType: super::RefType;
fn header(&mut self, scope: impl _ConstMutSwitchUiTableHeaderCallback<Self::RefType>);
fn body(&mut self, scope: impl _ConstMutSwitchUiTableRowsIterator<Self::RefType>);
}
pub trait _ConstMutSwitchUiTableRowsIterator<RefType: super::RefType> {
type Item<'x>: _ConstMutSwitchUiTableRowCallback<RefType>
where
Self: 'x;
fn next<'s>(&'s mut self) -> Option<Self::Item<'s>>;
}
pub trait _ConstMutSwitchUiTableHeaderCallback<RefType: super::RefType> { pub trait _ConstMutSwitchUiTableHeaderCallback<RefType: super::RefType> {
type RowRender: _ConstMutSwitchUiTableRowCallback<RefType>; fn render_header(self, ctx: &mut impl ConstMutSwitchUiTableRow<RefType = RefType>);
type RowsIterator: LambdaIterator<Item = Self::RowRender>;
fn render_header(
self,
ctx: &mut impl ConstMutSwitchUiTableRow<RefType = RefType>,
) -> Self::RowsIterator;
} }
pub trait _ConstMutSwitchUiTableRowCallback<RefType: super::RefType> { pub trait _ConstMutSwitchUiTableRowCallback<RefType: super::RefType> {
@ -70,36 +82,90 @@ impl __SwitchUiConstructor1<MutRef> for MutUI<'_> {
} }
} }
pub(super) fn render_table< pub(super) enum ConstMutSwitchUiTableImplState<
RefType: super::RefType, 'a,
Constructor: __SwitchUiConstructor1<RefType>, RT: RefType,
>( Constructor: __SwitchUiConstructor1<RT>,
ui: &mut Ui, > {
vscroll: bool, Header(TableBuilder<'a>),
columnsCount: usize, Body(Table<'a>),
header_render: impl _ConstMutSwitchUiTableHeaderCallback<RefType>, Done(PhantomData<(RT, Constructor)>),
) { }
let mut rows_it = unsafe { uninitialized() };
impl<'a, RT: RefType, Constructor: __SwitchUiConstructor1<RT>>
ConstMutSwitchUiTableImplState<'a, RT, Constructor>
{
pub fn new(ui: &'a mut Ui, vscroll: bool, columns_count: usize) -> Self {
return Self::Header(
TableBuilder::new(ui) TableBuilder::new(ui)
.striped(true) // Alternating row colors .striped(true) // Alternating row colors
.resizable(true) .resizable(true)
.vscroll(vscroll) .vscroll(vscroll)
.columns(Column::remainder(), columnsCount) .columns(Column::remainder(), columns_count),
.header(20.0, |row| { );
rows_it = }
header_render.render_header(&mut ConstMutSwitchUiTableRowImpl::<_, Constructor> {
row, #[allow(deprecated)]
__phantom: PhantomData::default(), fn header_map(&mut self, f: impl FnOnce(TableBuilder) -> Table) {
}); match self {
}) ConstMutSwitchUiTableImplState::Header(_) => {
.body(|mut body| { let mut local = unsafe { Self::Header(uninitialized()) };
rows_it.consume(|row_render| { swap(self, &mut local);
body.row(20.0, |row| { if let Self::Header(local) = local {
row_render.render_row(&mut ConstMutSwitchUiTableRowImpl::<_, Constructor> { *self = Self::Body(f(local))
row, }
__phantom: PhantomData::default(), }
}) _ => 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<RT: RefType, Constructor: __SwitchUiConstructor1<RT>> ConstMutSwitchUiTable
for ConstMutSwitchUiTableImplState<'_, RT, Constructor>
{
type RefType = RT;
fn header(&mut self, scope: impl _ConstMutSwitchUiTableHeaderCallback<Self::RefType>) {
self.header_map(|h| {
return h.header(20.0, |row| {
scope.render_header(&mut ConstMutSwitchUiTableRowImpl::<_, Constructor> {
row,
__phantom: PhantomData::default(),
})
});
})
}
fn body(&mut self, mut scope: impl _ConstMutSwitchUiTableRowsIterator<Self::RefType>) {
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(),
})
}),
}
}
});
})
}
} }

View File

@ -1,4 +1,4 @@
use super::{_ConstMutSwitchUiTableHeaderCallback, RefType}; use super::{_ConstMutSwitchUiTableHeaderCallback, RefType, _ConstMutSwitchUiTableCallback};
use eframe::emath::Numeric; use eframe::emath::Numeric;
use std::ops::RangeInclusive; use std::ops::RangeInclusive;
@ -41,7 +41,7 @@ pub trait ConstMutSwitchUi {
&mut self, &mut self,
vscroll: bool, vscroll: bool,
columns: usize, columns: usize,
header: impl _ConstMutSwitchUiTableHeaderCallback<Self::RefType>, scope: impl _ConstMutSwitchUiTableCallback<Self::RefType>,
); );
} }

View File

@ -835,3 +835,176 @@ trait Ctx_Graph<G> {
// ... // ...
} }
``` ```
## 7
Метод `_ConstMutSwitchUiTableHeaderCallback::render_header` принимает в себя контекст отрисовки
строки и возвращает `impl Trait`. По умолчанию компилятор считает, что возвращаемое значение
заимствует все переданные ссылки. Для более тонкой настройки компилятора есть синтаксис
`impl Trait + use<'a, A>`, но так как компилятор не способен реализовать минимум, определяемый
спецификацией языка, в `use` должны быть указаны все типовые параметры (даже неявные). В
данном случае контекст отрисовки туда попадать не должен, так что пришлось отказаться от короткого
и удобно способа и вернуться к этапу `3.1`: ручной вызов отрисовки заголовка и тела таблицы.
## 8
### 8.1
Попытки победить borrow checker в итераторах привели к идее указывать возвращаемый
тип итератора в параметре трейта, а не ассоциированным типом.
```rust
trait LambdaIterator<Item> {
fn next<R>(&mut self, receiver: impl FnOnce(Item) -> R) -> Option<R>;
}
```
Это помогло решить некоторые
проблемы, но имплементировать такой трейт всё равно не получилось.
### 8.2
Gemini рассказал про **Higher-Rank Trait Bounds (HRTB)**, и вроде как это решает проблему
```rust
trait LambdaIterator {
type Item<'x>;
fn next<R>(&mut self, receiver: impl for<'x> FnOnce(Self::Item<'x>) -> R) -> Option<R>;
}
```
### 8.3
Имплементация итератора в таком варианте выдавала ошибку, которая исправляется вполне логичным
дополнением к трейту:
```rust
trait LambdaIterator {
type Item<'x>: where Self: 'x;
fn next<R>(&mut self, receiver: impl for<'x> FnOnce(Self::Item<'x>) -> R) -> Option<R>;
}
```
### 8.4
После многочисленных экспериментов был сделан вывод, что язык пока не готов к описанию таких
гениальных вещей: или в компиляторе просто с ошибками эти вещи реализованы; или вывод об
ошибках недостаточно подробный, чтоб разобраться не употребляя те же вещества, что и создатели.
Порождение итератора выглядит следующим образом:
```rust
trait Ctx_Graph<G> {
type RefType: RefType;
type Vertex<'v>;
fn iter_vertices<'g>(
&mut self,
graph: &'g mut G
) -> impl for<'v> LambdaIterator<Item<'v>=(&'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<Self::Item<'s>>;
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<Item<'x> = Self::Item<'x>>;
}
```
Но если создавать под каждую задачу свой трейт итератора, то это как минимум компилируется, но
опять же, только в случаях когда не нужно указывать тип элемента в месте использования. Такой
модификации подвергся итератор для строк таблицы:
```rust
pub trait ConstMutSwitchUiTable {
// ...
fn body(&mut self, scope: impl _ConstMutSwitchUiTableRowsIterator<Self::RefType>);
// ...
}
pub trait _ConstMutSwitchUiTableRowsIterator<RefType: super::RefType> {
type Item<'x>: _ConstMutSwitchUiTableRowCallback<RefType>
where
Self: 'x;
fn next<'s>(&'s mut self) -> Option<Self::Item<'s>>;
}
```
## 9
Контекст для работы с графами пришлось несколько раз декомпозировать и изменять, в основном по
той же причине невозможности полноценно использовать `+ use<>`. В конечном итоге он превратился
просто в обёртку над графом (и его частями) без вынесения в контекст.
```rust
pub trait Graph {
type RefType: RefType;
fn iter_vertices(&mut self) -> impl VerticesIterator<RefType = Self::RefType>;
fn vertices_count(&self) -> usize;
}
pub trait VerticesIterator {
type RefType: RefType;
type Vertex<'v>: Vertex<RefType = Self::RefType>
where
Self: 'v;
fn next<'v>(&'v mut self) -> Option<Self::Vertex<'v>>;
}
pub trait Vertex {
type RefType: RefType;
fn iter_edges_or_nothing_sorted(&mut self) -> impl EdgesIterator<RefType = Self::RefType>;
fn set_vertex_to_update_state(&self, state: &mut UpdatePending);
}
pub trait EdgesIterator {
type RefType: RefType;
type Edge<'e>: Edge<RefType = Self::RefType>
where
Self: 'e;
fn next<'e>(&'e mut self) -> Option<Option<Self::Edge<'e>>>;
}
pub trait Edge {
type RefType: RefType;
fn get_edge_len_ptr<'s>(&'s mut self) -> <Self::RefType as RefType>::Ref<'s, f64>;
}
```

View File

@ -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<RefType = Self::RefType>;
fn vertices_count(&self) -> usize;
}
pub trait VerticesIterator {
type RefType: RefType;
type Vertex<'v>: Vertex<RefType = Self::RefType>
where
Self: 'v;
fn next<'v>(&'v mut self) -> Option<Self::Vertex<'v>>;
}
pub trait Vertex {
type RefType: RefType;
fn iter_edges_or_nothing_sorted(&mut self) -> impl EdgesIterator<RefType = Self::RefType>;
fn set_vertex_to_update_state(&self, state: &mut UpdatePending);
}
pub trait EdgesIterator {
type RefType: RefType;
type Edge<'e>: Edge<RefType = Self::RefType>
where
Self: 'e;
fn next<'e>(&'e mut self) -> Option<Option<Self::Edge<'e>>>;
}
pub trait Edge {
type RefType: RefType;
fn get_edge_len_ptr<'s>(&'s mut self) -> <Self::RefType as RefType>::Ref<'s, f64>;
}
struct MutableGraph<'g> {
graph: &'g mut CompleteGraph<()>,
}
impl Graph for MutableGraph<'_> {
type RefType = MutRef;
fn iter_vertices(&mut self) -> impl VerticesIterator<RefType = Self::RefType> {
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<Item = (usize, &'g mut HashSet<usize>)>> {
ee: &'g mut EdgesVec<()>,
it: It,
ordinal: usize,
}
impl<'g, It: Iterator<Item = (usize, &'g mut HashSet<usize>)>> VerticesIterator
for MutableVerticesIterator<'g, It>
{
type RefType = MutRef;
type Vertex<'v>
= MutableVertex<'v>
where
Self: 'v;
fn next<'v>(&'v mut self) -> Option<Self::Vertex<'v>> {
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<usize>,
all_edges: &'g mut EdgesVec<()>,
}
impl Vertex for MutableVertex<'_> {
type RefType = MutRef;
fn iter_edges_or_nothing_sorted(&mut self) -> impl EdgesIterator<RefType = Self::RefType> {
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::<Vec<_>>();
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<E, It: Iterator<Item = E>> {
hole: Option<usize>,
it: It,
}
impl<E, It: Iterator<Item = E>> Iterator for IteratorWithHole<E, It> {
type Item = Option<E>;
fn next(&mut self) -> Option<Self::Item> {
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<Item = Option<(&'g mut f64)>>> {
it: It,
}
impl<'g, It: Iterator<Item = Option<(&'g mut f64)>>> EdgesIterator
for MutableEdgesIterator<'g, It>
{
type RefType = MutRef;
type Edge<'x>
= MutableEdge<'x>
where
Self: 'x;
fn next<'s>(&'s mut self) -> Option<Option<Self::Edge<'s>>> {
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) -> <Self::RefType as RefType>::Ref<'s, f64> {
return self.len;
}
}

View File

@ -0,0 +1,4 @@
mod ui;
mod ctx;
pub use ctx::{Graph, Vertex, Edge, EdgesIterator, VerticesIterator};

View File

@ -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<G: Graph, CtxUi: ConstMutSwitchUi<RefType = G::RefType>>(
ctx_ui: &mut CtxUi,
graph: &mut G,
update: <CtxUi::RefType as RefType>::Ref<'_, UpdatePending>,
) {
ctx_ui.scroll_area_2(Root { graph, update });
}
struct Root<'g, 'u, G: Graph> {
graph: &'g mut G,
update: <G::RefType as RefType>::Ref<'u, UpdatePending>,
}
impl<G: Graph> _ConstMutSwitchUiCallback<G::RefType> for Root<'_, '_, G> {
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType = G::RefType>) {
ctx.table(false, self.graph.vertices_count(), self)
}
}
impl<G: Graph> _ConstMutSwitchUiTableCallback<G::RefType> for Root<'_, '_, G> {
fn render_table(mut self, ctx: &mut impl ConstMutSwitchUiTable<RefType = G::RefType>) {
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 <It::RefType as RefType>::Ref<'u, UpdatePending>,
}
impl<It: VerticesIterator> _ConstMutSwitchUiTableHeaderCallback<It::RefType>
for Header<'_, '_, It>
{
fn render_header(mut self, row: &mut impl ConstMutSwitchUiTableRow<RefType = It::RefType>) {
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: <It::RefType as RefType>::Ref<'u, UpdatePending>,
row_id: usize,
}
impl<'u, It: VerticesIterator> RowsIterators<'u, It> {
fn next<'s>(&'s mut self) -> Option<Row<'s, 'u, It::Vertex<'s>>> {
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<It::RefType> for RowsIterators<'u, It> {
type Item<'x>
= Row<'x, 'u, It::Vertex<'x>>
where
Self: 'x;
fn next<'s>(&'s mut self) -> Option<Self::Item<'s>> {
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 <V::RefType as RefType>::Ref<'u, UpdatePending>,
}
impl<V: Vertex> _ConstMutSwitchUiTableRowCallback<V::RefType> for Row<'_, '_, V> {
fn render_row(mut self, row: &mut impl ConstMutSwitchUiTableRow<RefType = V::RefType>) {
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<RT: RefType> _ConstMutSwitchUiCallback<RT> for CornerCell {
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType = RT>) {
ctx.label("#");
}
}
struct TitleCell<'v, 'uu, 'u: 'uu, V: Vertex> {
row_id: usize,
vertex: &'v mut V,
update: &'uu mut <V::RefType as RefType>::Ref<'u, UpdatePending>,
}
impl<V: Vertex> _ConstMutSwitchUiCallback<V::RefType> for TitleCell<'_, '_, '_, V> {
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType = V::RefType>) {
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<RT: RefType> _ConstMutSwitchUiCallback<RT> for LengthCell<'_, '_, RT> {
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType = RT>) {
ctx.slider(0.0..=10.0, 0.1, self.length);
}
}
struct EmptyCell {}
impl<RT: RefType> _ConstMutSwitchUiCallback<RT> for EmptyCell {
fn render(self, _: &mut impl ConstMutSwitchUi<RefType = RT>) {}
}

View File

@ -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<G> {
type RefType: RefType;
type Vertex;
type VerticesIterator<'a>: LambdaIterator<Item=(&'a mut Self, Self::Vertex)>
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<Item=(&mut Self, Option<Self::Edge>)>;
fn get_edge_len_ptr(
&mut self,
edge: &mut Self::Edge,
) -> <Self::RefType as RefType>::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<G, RefType=CtxUi::RefType>,
>(
ctx_ui: &mut CtxUi,
ctx_graph: &mut CtxGraph,
graph: G,
update: <CtxUi::RefType as RefType>::Ref<'_, UpdatePending>,
) {
ctx_ui.scroll_area_2(ScrollArea {
ctx_graph,
graph,
update,
});
}
struct ScrollArea<'g, 'u, G, CtxGraph: Ctx_Graph<G>> {
ctx_graph: &'g mut CtxGraph,
graph: G,
update: <CtxGraph::RefType as RefType>::Ref<'u, UpdatePending>,
}
impl<G, CtxGraph: Ctx_Graph<G>> _ConstMutSwitchUiCallback<CtxGraph::RefType>
for ScrollArea<'_, '_, G, CtxGraph>
{
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType=CtxGraph::RefType>) {
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<G>> {
ctx_graph: &'g mut CtxGraph,
graph: G,
update: <CtxGraph::RefType as RefType>::Ref<'u, UpdatePending>,
}
impl<'g, 'u, G, CtxGraph: Ctx_Graph<G>> _ConstMutSwitchUiTableHeaderCallback<CtxGraph::RefType>
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<RefType=CtxGraph::RefType>,
) -> 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> + 'g> {
vertices: CtxGraph::VerticesIterator<'g>,
update: <CtxGraph::RefType as RefType>::Ref<'u, UpdatePending>,
row_id: usize,
}
impl<'g, 'u, G, CtxGraph: Ctx_Graph<G> + 'g> LambdaIterator for RowsIterators<'g, 'u, G, CtxGraph> {
type Item = Row<'g, 'u, G, CtxGraph>;
fn next<R>(&mut self, receiver: impl FnOnce(Self::Item) -> R) -> Option<R> {
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<G>> {
ctx_graph: &'g mut CtxGraph,
vertex: CtxGraph::Vertex,
row_id: usize,
update: NonNull<<CtxGraph::RefType as RefType>::Ref<'u, UpdatePending>>,
}
impl<G, CtxGraph: Ctx_Graph<G>> _ConstMutSwitchUiTableRowCallback<CtxGraph::RefType>
for Row<'_, '_, G, CtxGraph>
{
fn render_row(mut self, row: &mut impl ConstMutSwitchUiTableRow<RefType=CtxGraph::RefType>) {
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<RT: RefType> _ConstMutSwitchUiCallback<RT> for CornerCell {
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType=RT>) {
ctx.label("#");
}
}
struct TitleCell<'g, 'v, 'rr, 'r: 'rr, G, CtxGraph: Ctx_Graph<G>> {
ctx_graph: &'g mut CtxGraph,
row_id: usize,
vertex: &'v CtxGraph::Vertex,
update: &'rr mut <CtxGraph::RefType as RefType>::Ref<'r, UpdatePending>,
}
impl<G, CtxGraph: Ctx_Graph<G>> _ConstMutSwitchUiCallback<CtxGraph::RefType>
for TitleCell<'_, '_, '_, '_, G, CtxGraph>
{
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType=CtxGraph::RefType>) {
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<RT: RefType> _ConstMutSwitchUiCallback<RT> for LengthCell<'_, '_, RT> {
fn render(self, ctx: &mut impl ConstMutSwitchUi<RefType=RT>) {
ctx.slider(0.0..=10.0, 0.1, self.length);
}
}
struct EmptyCell {}
impl<RT: RefType> _ConstMutSwitchUiCallback<RT> for EmptyCell {
fn render(self, _: &mut impl ConstMutSwitchUi<RefType=RT>) {}
}

View File

@ -1,9 +1,9 @@
mod boot; mod boot;
pub mod const_mut_switch; pub mod const_mut_switch;
pub mod lengths_table;
mod render_graph; mod render_graph;
mod slider; mod slider;
mod subwindow; mod subwindow;
mod graph_lengths_table;
pub use boot::boot_eframe; pub use boot::boot_eframe;
pub use render_graph::render_graph; pub use render_graph::render_graph;

View File

@ -1,9 +1,9 @@
pub trait LambdaIterator { pub trait LambdaIterator {
type Item; type Item<'x>: where Self: 'x;
fn next<R>(&mut self, receiver: impl FnOnce(Self::Item) -> R) -> Option<R>; fn next<R>(&mut self, receiver: impl for<'x> FnOnce(Self::Item<'x>) -> R) -> Option<R>;
fn consume(mut self, mut receiver: impl FnMut(Self::Item)) fn consume(mut self, mut receiver: impl for<'x> FnMut(Self::Item<'x>))
where where
Self: Sized, Self: Sized,
{ {
@ -11,7 +11,7 @@ pub trait LambdaIterator {
} }
} }
pub fn make_lambda<I: Iterator>(it: I) -> impl LambdaIterator<Item = I::Item> { /*pub fn make_lambda<'z, I: Iterator>(it: I) -> impl for<'x> LambdaIterator<Item<'x> = I::Item> {
return LambdaIteratorConverter { it }; return LambdaIteratorConverter { it };
} }
@ -20,9 +20,10 @@ struct LambdaIteratorConverter<I: Iterator> {
} }
impl<I: Iterator> LambdaIterator for LambdaIteratorConverter<I> { impl<I: Iterator> LambdaIterator for LambdaIteratorConverter<I> {
type Item = I::Item; type Item<'x> = I::Item where Self:'x;
fn next<R>(&mut self, receiver: impl FnOnce(Self::Item) -> R) -> Option<R> { fn next<'s, R>(&mut self, receiver: impl for<'x> FnOnce(I::Item) -> R) -> Option<R> {
return self.it.next().map(receiver); return self.it.next().map(receiver);
} }
} }
*/

View File

@ -3,7 +3,9 @@ pub mod gui;
mod lambda_iterator; mod lambda_iterator;
mod update_pending; mod update_pending;
mod weighted_random; 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 update_pending::{UpdatePending, UpdateTarget};
pub use weighted_random::{weighted_random, weighted_random_index}; pub use weighted_random::{weighted_random, weighted_random_index};