Commit Graph

12 Commits

Author SHA1 Message Date
Olivier FAURE bc8e9fecd2
Switch to Edition 2024 (#880)
I've ignored most of the changes and the projects still compile and test
fine. Changes I did commit:

Add `+ use<>` after functions.
Remove `ref mut` from some patterns.
Bump MSRV.
Apply new rustfmt format.
2025-03-05 13:15:47 +00:00
Daniel McNab de92da4320
Fix `clippy::default_trait_access` (#868)
This is a new addition to the "editor period lints". See #867 for
context.
2025-02-14 18:22:29 +00:00
Olivier FAURE 066d4319e8
Use nightly rustfmt to format imports (#838) 2025-01-20 13:19:26 +00:00
Bruce Mitchener ee4411467c
Fix and un-allow `clippy::use_self` lints (#799) 2024-12-19 13:45:57 +00:00
Philipp Mildenberger 30cb5fb6a6
xilem_web: Add `ViewCtx::as_owned` to allow composing the view context in custom view contexts (#749)
Also adds `MessageThunk::enqueue_message` for convenience (basically
`MessageThunk::push_message` delayed with `queueMicrotask`).

See https://github.com/slowtec/xilem-leaflet/pull/4 for a use-case of
this.
2024-11-18 12:29:19 +00:00
Philipp Mildenberger 53a5354c2d
xilem_web: Rewrite modifiers (`Attributes`, `Classes` and `Styles`), and cleanup/extend docs (#699)
Previously the modifier systems had design issues i.e. bugs (non-deleted
styles/classes/attributes), and were unnecessary complex.
This aims to solve this (partly) by not using separate traits, but
concrete types and a different mechanism that is closer to how
`ElementSplice` works.

There's a few fundamental properties that composable type-based
modifiers need to support to avoid surprising/buggy behavior:

* Minimize actual changes to the underlying element, as DOM traffic is
expensive.
* Be compatible to memoization: e.g. a `Rotate` view should still be
applicable to possibly memoized transform values of the underlying
element.
* Recreation when the underlying element has changed (e.g. with a change
of variants of a `OneOf`).

To support all this, the modifier system needs to retain modifiers for
each modifier-view, and track its changes of the corresponding view.
Previously all elements were directly written and separated with markers
into a `Vec` to limit the boundaries of such views, but this had issues,
when e.g. all modifiers were deleted (e.g. clearing a `Vec` of classes),
by not reacting to this (I noticed that issue in the todomvc example
with the footer).

With this PR, the count of modifiers of a modifier-view are directly
stored either (hardcoded) in the view impl or its view state, which
cleans up the concrete modifier elements (such as `AttributeModifier`,
not including a separate `Marker` variant), and makes it less prone for
errors (and is slightly less memory-intensive).

The API to use these modifiers in modifier-views was also redesigned to
hopefully be more straight-forward/idiomatic. But as mentioned above
there's still challenges, which introduce complexity (which I'd like to
hide at least for simpler cases than these modifiers, likely in a future
PR).
All of this should now be documented in the new `modifier` module, where
now the modifiers `Attributes`, `Classes` and `Styles` reside. Other
views (like events) may also end up there...

One interesting aspect compared to the previous system is the use of a
new trait `With` for modifiers.
Instead of (roughly) `Element: WithStyle`, it works with `Element:
With<Styles>`.
This prevents all kinds of reimplementations of something like
`WithStyle` for elements.
This gets especially visible in the `one_of` module, which now can be
covered by a single blanket implementation.

Further the cargo-feature "hydration" was deleted, as it causes more
headaches to maintain than it really brings benefits (minimally less
binary size), depending on the future, it may or may not make sense to
reintroduce this.
2024-10-23 18:24:43 +00:00
Philipp Mildenberger 88ac491900
xilem_web: Optimize modifiers (allocs mostly), and fix hydrating SVG elements (#620)
With the risk of wasting time with micro-optimizations...

Honestly the diff bigger and more complex than I would like it to be for
the effect that this change does, so I'm sorry to reviewers.
FWIW, I tested all the examples with the feature "hydration" disabled
and enabled.

In effect this reduces the amount of allocs and the size of allocs of
all the modifiers (since Vec allocs at least 4 elements) by:

* Adding a size hint in modifier views, to give the actual element props
a hint how much memory is needed in the relevant modifier, so that only
one allocation occurs when the actual modifier is added/created.
* Using bitflags encoded in the `start_idx` to avoid extra 4 bytes for
just two booleans in each modifier, and also use `u16` instead of
`usize` to save another 4 bytes.
* Avoiding `updated_modifiers` allocations when building the element
(with the `CREATING` bitflag).
* Reduce allocations when rebuilding, by skipping non-changed modifiers
(before this, `Cow` was cloned, which for example with a `String` as an
attribute value resulted in an additional allocation).

This minimally increases the wasm binary size (though I'm pretty sure in
a constant fashion, roughly 500bytes compressed) in exchange for faster
creation of elements and less memory usage (in the 10k
js-framework-bench roughly 10% less memory usage, and 7-8% faster).

I've also noticed that all the kurbo SVG views weren't hydrated yet,
which I think results in buggy behavior when using it e.g. in a
`Templated` view, this is kind of drive-by fix (which I didn't want to
separate because of additional work...)
2024-10-01 17:10:32 +00:00
Philipp Mildenberger 5ae36200b3
xilem_web: Document a lot and remove `start_<modifier>` as it doesn't do anything in `View::build` and may be misleading (#517)
I think I've covered every pub item at the top level.

It also renames (taking `Attributes` as example)
`start_attribute_modifier` -> `rebuild_attribute_modifier`,
and `end_attribute_modifier` -> `mark_end_of_attribute_modifier`, as I
think that makes it more clear what these methods do.
`start_attribute_modifier` was a noop in `View::build` and may lead to
buggy behavior when `DomNode::apply_props` is called before every parent
`View::build` has done modifying the props. This should make
`DomNode::apply_props` robust. And `AfterBuild` is fixed now with that.
2024-08-16 09:51:33 +00:00
Philipp Mildenberger 411acc12aa
xilem_web: Add hydration support, and a new view using it `Templated` (#495)
This is mostly a first step towards SSR.
But we can use hydration to speed up creation of long (non-virtualized)
lists with the `Templated` view.
`Templated` stores a deep copy of the DOM node of the first occurence of
its `impl DomView` based on the `TypeId` in the `ViewCtx`,
and reuses it on every further invocation, where it will be hydrated and
updated based on the new attributes.
As it uses an `Rc` to achieve this, it also supports memoization,
similar to an `Arc<impl View>`.

Hydration is currently feature-gated, as it produces a little bit more
binary bloat. Though it's little enough to this being justified as
default.

---------

Co-authored-by: Markus Kohlhase <markus.kohlhase@slowtec.de>
2024-08-15 15:37:57 +00:00
Philipp Mildenberger 544a4a1ca9
xilem_web: Fix `DomChildrenSplice::with_scratch` (#484)
I'm surprised that this was not noticed yet,
`DomChildrenSplice::with_scratch` previously only appended new elements
to the end of the children of an element in the DOM tree, whereas it
should've inserted it at the current index of the `ElementSplice`. This
should fix this, using a `DocumentFragment` which is shared on the
`ViewCtx` to avoid unnecessary allocations.
2024-08-05 09:08:34 +00:00
Philipp Mildenberger b33a2a680d
Rewrite xilem_web to support new xilem_core (#403)
This ports xilem_web to the new xilem_core.

There's also a lot of cleanup internally:
* Get rid of all of the complex macros to support DOM interfaces, and
instead use associated type bounds on the `View::Element`.
* Introduce an extendable modifier based system, which should also work
on top of memoization (`Arc`, `Memoize`) and `OneOf` views with an
intersection of the modifiable properties.
* This modifier based system gets rid of the hacky way to propagate
attributes to elements, and takes inspiration by masonrys `WidgetMut`
type to apply changes.
* Currently that means `Attributes`, `Classes` and `Styles` to reflect
what xilem_web previously offered.

Downsides (currently, needs some investigation):

~~Due to more internal type complexity via associated types this suffers
from https://github.com/rust-lang/rust/issues/105900. The new trait
solver should hopefully mitigate some of that, but it seems currently it
completely stalls in the todomvc example (not in other examples).~~
~~The deep, possibly completely static composition via associated
type-bounds of the view and element tree unfortunately can take some
time to compile, this gets (already) obvious in the todomvc example. The
other examples don't seem to suffer that bad yet from that issue,
probably because they're quite simple.~~

~~I really hope we can mitigate this mostly, because I think this is the
idiomatic (and more correct) way to implement what the previous API has
offered.~~

One idea is to add a `Box<dyn AnyViewSequence>`, as every element takes
a "type-erased" `ViewSequence` as parameter, so this may solve most of
the issues (at the slight cost of dynamic dispatch/allocations).

Edit: idea was mostly successful, see comment right below.

I think it also closes #274

It's a draft, as there's a lot of changes in xilem_core that should be
upstreamed (and cleaned up) via separate PRs and I would like to
(mostly) fix the slow-compile time issue.

---------

Co-authored-by: Daniel McNab <36049421+DJMcNab@users.noreply.github.com>
2024-06-28 08:30:18 +00:00
Olivier FAURE ef5d36e8fc
Move crates to the repository root (#302)
Follows the convention proposed in this discussion:

https://xi.zulipchat.com/#narrow/stream/419691-linebender/topic/Standardizing.20multi-package.20repos
2024-05-11 21:59:03 +00:00