Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: impl From<Node<Y>> for Node<X> where Y: Into<X> #653

Open
sidju opened this issue Jan 17, 2022 · 3 comments
Open

Feature request: impl From<Node<Y>> for Node<X> where Y: Into<X> #653

sidju opened this issue Jan 17, 2022 · 3 comments

Comments

@sidju
Copy link

sidju commented Jan 17, 2022

I am home rolling a frontend and deeply enjoying the flexibility offered by seed. I have essentially built a half-isolated component structure with a global Msg (views branch down with parts of the model in a tree structure). Overall this works absurdly well with the APIs, but I'd like to be able to return Node from my component view functions instead of manually wrapping my callbacks into the global Msg type.

The way I envision this could be made possible is by having a general implementation to convert Node into Node if LocalMsg can be converted into Msg (infallibly in most reasonable cases, incl. mine). I expect this might be a bit tricky, but hope it can be done relatively easily.

@sidju
Copy link
Author

sidju commented Jan 21, 2022

Seemingly impossible right now, due to this not being supported by rust:
rust-lang/rfcs#1834

(To clarify, since it cannot be declared that X != Y the suggested impl overlaps with the general implementation that Self implements From (noop), which is a compilation error.)

@sidju
Copy link
Author

sidju commented Jan 22, 2022

Current workaround is to use .map_msg on the Node to covert it.

The mapped function can further contain the Y to X implementation, saving a trait implementation if only called in one location.

Another path to take would be to require that View returns IntoNode instead of Node. This would solve the current implementation collision with Into and enable the frameword to automatically convert as suitable, but this will make the framework a bit more complex and introduce if/else type mismatches if the user doesn't convert on every branch. Right now I can't envision how it would be any better than this workaround.

@MartinKavik
Copy link
Member

I've chosen .map_msg to make it consistent with other entities (e.g. Cmd) and with the primary inspiration - https://package.elm-lang.org/packages/elm/html/1.0.0/Html#map.
Also there is a monster in the code base -

seed/src/lib.rs

Lines 61 to 90 in cce9685

// @TODO Refactor once `optin_builtin_traits` or `negative_impls`
// @TODO is stable (https://github.com/seed-rs/seed/issues/391).
// --
// @TODO Remove `'static` bound from all `MsU`s once `optin_builtin_traits`, `negative_impls`
// @TODO or https://github.com/rust-lang/rust/issues/41875 is stable.
macro_rules! map_callback_return_to_option_ms {
($cb_type:ty, $callback:expr, $panic_text:literal, $output_type:tt) => {{
let t_type = std::any::TypeId::of::<MsU>();
if t_type == std::any::TypeId::of::<Ms>() {
$output_type::new(move |value| {
(&mut Some($callback(value)) as &mut dyn std::any::Any)
.downcast_mut::<Option<Ms>>()
.and_then(Option::take)
})
} else if t_type == std::any::TypeId::of::<Option<Ms>>() {
$output_type::new(move |value| {
(&mut $callback(value) as &mut dyn std::any::Any)
.downcast_mut::<Option<Ms>>()
.and_then(Option::take)
})
} else if t_type == std::any::TypeId::of::<()>() {
$output_type::new(move |value| {
$callback(value);
None
}) as $output_type<$cb_type>
} else {
panic!($panic_text);
}
}};
}
- abusing Any to simulate something like specialiazation. So I can imagine the Seed APIs could be refactored in the future once required Rust features appear in the stable channel. I think your idea could be one of them (if I understand it correctly - I always suggest to write super basic examples in the issue description.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants