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

Support multiple on_end_tag callbacks on Element. #177

Merged

Conversation

orium
Copy link
Member

@orium orium commented Apr 24, 2023

No description provided.

@@ -45,7 +45,7 @@ pub struct Element<'r, 't> {
start_tag: &'r mut StartTag<'t>,
end_tag_mutations: Option<Mutations>,
modified_end_tag_name: Option<Bytes<'static>>,
end_tag_handler: Option<EndTagHandler<'static>>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it matter that we're getting rid of the Option here? What about Vec<Option<EndTagHandler<'static>>>?

Copy link
Member Author

@orium orium Apr 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Option<_> here was just to make a container of 0 or 1 elements. Using a Vec<_> we generalize to any number of elements.

@orium orium force-pushed the multiple_element_on_end_tag_callbacks branch from c8c861c to 6f4f170 Compare April 24, 2023 14:48
@orium orium marked this pull request as ready for review April 24, 2023 14:48
@orium orium requested review from a team, jongiddy and Noah-Kennedy as code owners April 24, 2023 14:48
Copy link
Collaborator

@jongiddy jongiddy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether end_tag_handler should be a struct that contains the handler function and an Option<Box<Self>> that points to earlier handlers.

This would remove the double allocations of using a Vec<Box<FnOnce>>. It would also make the natural order of processing be last-first, which feels right for nested data. (But I can't think of a good example where the order matters).

Comment on lines 492 to 493
/// Subsequent calls to the method on the same element replace the previous handler. If you
/// want to run multiple handlers use [`Element::add_on_end_tag`].
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Subsequent calls to the method on the same element replace the previous handler. If you
/// want to run multiple handlers use [`Element::add_on_end_tag`].
/// This method replaces all previous end tag handlers on the same element. To add
/// multiple handlers use [`Element::add_on_end_tag`].

@orium
Copy link
Member Author

orium commented Apr 24, 2023

I wonder whether end_tag_handler should be a struct that contains the handler function and an Option<Box> that points to earlier handlers.

This would remove the double allocations of using a Vec<Box<FnOnce>>. It would also make the natural order of processing be last-first, which feels right for nested data. (But I can't think of a good example where the order matters).

We would still need to allocate the box with the FnOnce and the box with Self. So we would have 2 memory allocations, as opposed to 1 memory allocations + vec resize which is happens a logarithmic number of times. i.e. amortized, for n calls, we currently do n + ⌈log(n)⌉ allocations. Having such a struct would make it 2⋅n allocations.

@jongiddy
Copy link
Collaborator

We would still need to allocate the box with the FnOnce and the box with Self.

Yes, you're right. I somehow thought through the idea thinking the Box<Self> would contain the FnOnce without a Box.

Do you currently need the handlers to run in a specific order? If not, I'd suggest keeping the order explicitly undefined until we have a use case, since either order could be reasonable.

@orium
Copy link
Member Author

orium commented Apr 25, 2023

Do you currently need the handlers to run in a specific order?

Yes, in my case I need to have a specific since the callbacks interact with each other.

@orium orium force-pushed the multiple_element_on_end_tag_callbacks branch from 6f4f170 to 57772e0 Compare April 25, 2023 09:17
@@ -489,7 +489,7 @@ impl<'r, 't> Element<'r, 't> {

/// Sets a handler to run when the end tag is reached.
///
/// Subsequent calls to the method on the same element replace the previous handler.
/// Multiple handlers can be registered and will run in the order of registration.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to clarify here that consecutive calls to the function add more handlers

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

@orium orium force-pushed the multiple_element_on_end_tag_callbacks branch from 57772e0 to 2ca0585 Compare April 25, 2023 09:32
@inikulin inikulin merged commit 379da4b into cloudflare:master Apr 25, 2023
@kentonv
Copy link
Member

kentonv commented May 18, 2023

Hi, this seems to be a breaking change. We have tests in the Workers codebase that explicitly verify the last-call-wins behavior, and they fail after this change. Regardless of whether the behavior is desirable, if there's any chance that this might break already-deployed Workers in production then we won't be able to roll it out without guarding it behind a compatibility flag.

How should we handle this?

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

Successfully merging this pull request may close these issues.

5 participants