xilem
xilem copied to clipboard
`enum` state is very unergonomic (`lens` ergonomics?)
Example:
struct AState;
impl AState {
fn ui_logic(&mut self) -> impl WidgetView<Self> + use<> {
label("A")
}
}
struct BState;
impl BState {
fn ui_logic(&mut self) -> impl WidgetView<Self> + use<> {
label("B")
}
}
enum MyState {
A(AState),
B(BState)
}
impl MyState {
fn ui_logic(&mut self) -> impl WidgetView<Self> + use<> {
use xilem_core::one_of::Either;
match self {
Self::A(_a) => Either::A(lens(AState::ui_logic, |state: &mut Self| match state {
Self::A(a) => a,
_ => unreachable!(),
}))
Self::B(_b) => Either::B(lens(BState::ui_logic, |state: &mut Self| match state {
Self::B(b) => b,
_ => unreachable!(),
}))
}
}
}
The same goes for matching Options and Results.
_a and _b also go unused. Is that desired? Should map_state be used instead for efficiency?
See also:
- You can't "split" a lens, i.e. you can't have a lens from
AppStateso the child can access bothstate.aandstate.b.- Matching on enums in lenses is unergonomic (and also currently broken - see #xilem > Incoherent state issues), because you can't avoid the lens needing to know the type of the enum. There are possible janky solutions, but I've not reasoned about them carefully.
https://github.com/linebender/xilem/pull/1032#issuecomment-3034983835
Related to lensing multiple states: xilem_core::map_action and returning an action from button()'s callback seems to work as an alternative to passing multiple states via impl WidgetView<State>.
Yeah, we don't have a good answer here at the moment; I agree that it's very rough, though.
For druid I did some exploration, in case you're interested: https://github.com/linebender/druid/issues/1135.
- I concluded that druid-enums (https://github.com/linebender/druid/issues/1135#issuecomment-716332150) was better;
- There was also a comparison to switcher (https://github.com/linebender/druid/issues/1135#issuecomment-827673747);
- I think mixing lenses and prisms (https://github.com/linebender/druid/issues/1135#issuecomment-678936891) is still cool XD
Not sure that I found a right place, but went into similar issue:
fn main_view(dizola: &mut Dizola) -> impl WidgetView<Dizola> + use<> {
lens(
|state| match state {
ImState::Initial => OneOf2::A(label("LETSGO!")),
ImState::Dictionary(dictionary_state) => OneOf::B(dictionary_view(dictionary_state)),
},
|dizola: &mut Dizola| &mut dizola.state,
)
}
when I try to draw a view for enum with inner state, it breaks the xilem:
error[E0277]: the trait bound `impl WidgetView<DictionaryState>: View<ImState, (), ViewCtx>` is not satisfied
--> gui/src/lib.rs:43:38
|
43 | fn main_view(dizola: &mut Dizola) -> impl WidgetView<Dizola> + use<> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `View<ImState, (), ViewCtx>` is not implemented for `impl WidgetView<DictionaryState>`
44 | / lens(
45 | | |state| match state {
46 | | ImState::Initial => OneOf2::A(label("LETSGO!")),
47 | | ImState::Dictionary(dictionary_state) => OneOf::B(dictionary_view(dictionary_state)),
48 | | },
49 | | |dizola: &mut Dizola| &mut dizola.state,
50 | | )
| |_____- return type was inferred to be `Lens<{[email protected]:45:9}, OneOf<Label, ..., ..., ..., ..., ..., ..., ..., ...>, ..., ..., ..., _, ...>` here
The problem (or my lack of xilem knowledge) is that
fn dictionary_view(dictionary_state: &mut DictionaryState) -> impl WidgetView<ImState> + use<> {
label("Dictionary")
}
can't return DictionaryState generic of WidgetView, it only "captures" ImState enum as a whole.
I wonder if we should create a meta-issue of the current ergonomic issues of Xilem. I think we need a bird's eye view of these problems.
It looks like you could use something like Ambassador (But I am not a Xilem expert)
https://github.com/hobofan/ambassador