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

feat: add Methods::merge_replace #1058

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

mattsse
Copy link
Contributor

@mattsse mattsse commented Mar 28, 2023

Closes #1053

add merge_replace that replaces callbacks

@mattsse mattsse requested a review from a team as a code owner March 28, 2023 15:21
CHANGELOG.md Outdated Show resolved Hide resolved
CHANGELOG.md Outdated Show resolved Hide resolved
Co-authored-by: Niklas Adolfsson <niklasadolfsson1@gmail.com>

let callbacks = self.mut_callbacks();
for (name, callback) in other.mut_callbacks().drain() {
callbacks.insert(name, callback);
Copy link
Member

@niklasad1 niklasad1 Mar 29, 2023

Choose a reason for hiding this comment

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

So this is bit tricky to use I reckon now as it's easy to override something and not realize it.

As I see it we could have merge_by as well

enum Insert {
 Yes,
 No,
}

fn merge_by<F: Fn(&str, &str) -> Insert)(&mut self, other: impl Into<Methods>, f: F) { ...  }

// example
methods.merge_by(other, |existing, other| {
   // method names are equal, just throw a warning log if that occurs
   // this may be expected, up to user to decide what's an issue or not
   if existing == other {
      tracing::warn!("Overriding method: `{method}`");
   }
   Insert::Yes
}); 

Copy link
Member

@niklasad1 niklasad1 Mar 29, 2023

Choose a reason for hiding this comment

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

/cc @lexnv @jsdw what do you guys think?

Copy link
Collaborator

@jsdw jsdw Mar 29, 2023

Choose a reason for hiding this comment

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

I could get behind that (I might be tempted to call it .merge_if and have it return a bool, true to merge).

If that existed, could merge be then a simple wrapper around it?
Would this function also need the self.verify_method_name(name)?; check that merge has?

Copy link
Member

@niklasad1 niklasad1 Mar 29, 2023

Choose a reason for hiding this comment

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

Would this function also need the self.verify_method_name(name)?; check that merge has?

no, that only checks if a method with the same name exist and this API leaves that to the user to decide i.e, if two methods with the same name occurs then either replace it with the new one or something else.

With "our existing merge API" the entire RPC module is thrown away if that occurs

Copy link
Contributor

Choose a reason for hiding this comment

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

If we had |existing: &str, other: &str|, what would be the value of existing if the method did not prior to merging exist?

Another idea would be to have the callback fire on collisions only:

fn merge_if<F: Fn(&str) -> bool)(&mut self, other: impl Into<Methods>, f: F) { ...  }

methods.merge_if(other, |collision_name|| {
   if collision_name == "CoreFn" {
       warn!("Don't want to replace `{collision_name}`;
       return false;
   }
   true

Indeed we should fire the callback only if:

  • Entry::Occupied(..) similar to verify_method_name
  • name collides

I feel that both solutions limit the user to pick either the existing or the new method.
For that contributor's use case, the function should always be |_collision_name| { true }.

As a crazy thought, we could probably chain methods, but Id have a hard time arguing the complexity of the code is worth this kind of runtime sorcery:

fn map<F: Fn(&str, &mut MethodCallback )(&mut self, f: F) { ...  }

methods.map(other, |(existing_name, existing_method)| {
   if existing_name == "CoreFn" {
       // Modify existing_method: 
       // Chain it with some other callback, or replace it directly
       info!("Modifying `{existing_name}`;
   }

Copy link
Contributor Author

@mattsse mattsse Mar 29, 2023

Choose a reason for hiding this comment

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

So this is bit tricky to use I reckon now as it's easy to override something and not realize it.

I guess this is true, even if this is to be used as the last "merge" call, this could possibly cause problems.

I think merge_if with a callback that decides whether to replace an existing callback or not makes this explicit.

@niklasad1
Copy link
Member

The CI is borked, not sure if it's the latest tokio release that caused that but not related to this PR

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.

Support overriding existing Methods Callbacks
4 participants