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
Use generics for broken link callback #701
Conversation
Thanks, I will try to review and analyze it in the next days. |
Generally this sounds good to me. It's always a tradeoff, but I think if there is a concern over monomorphization, it's possible to use I was concerned about making the type of the parser more complex, but I see it was already generic on the callback lifetime, so I don't think making it generic on the callback itself is any worse. |
Right, I should add that impl. |
I added I also considered replacing |
Turns out my use case naturally evolved into having two different instantiations of
Release binary size before this PR was 742 KB, and 766 KB after. I don't know if I can meaningfully measure performance with my setup. |
Sorry for the delay, this seems good to me! |
After merging this PR, it no longer works |
Thanks for the feedback, fixed in #746. |
As discussed in #508, #509 and #697, the current broken link callback API is a little clunky. This PR changes it to use generics instead of dynamic dispatch.
I haven't considered the performance or binary size implications of this. There should be no difference when not using the callback (all instances use
DefaultBrokenLinkCallback
), but when using it, all the parser's methods will be monomorphized somewhat unnecessarily. Ultimately it's up to you (the maintainers) to decide.On the flip side, this solution provides the most flexible API.
Parser
will now transitively implementSend
&Sync
if the callback does. It can also accept'static
callbacks:Alternative solutions with less performance and binary size implications:
Box<dyn FnMut>
(doesn't allowSend
&Sync
)F = Box<dyn FnMut>
, and only getting different monomorphizations by opting in with a separate method likenew_with_generic_broken_link_callback
.Some details that I'm unsure of:
new_with_broken_link_callback
still takes anOption
, though it could just accept the callback directly. Doing it like this reduces API breakage as the previous signatureOption<&mut dyn FnMut>
is still accepted.BrokenLinkCallback
to be a trait with a methodhandle_broken_link
. It could also be a "trait alias" with anFnMut
bound so that the separate function name wouldn't be exposed. I feel having the method makes the no-opDefaultBrokenLinkCallback
cleaner, but it could also be a function.BrokenLinkCallback
could be more general – if it is decided to add other types of callbacks later, it would be convenient to add them to a broader "Callback
" trait. In this case the blanket impl forT: FnMut
would be questionable though.Closes #508, #697