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

Add experimental options to equals() to include extensions and others #1029

Conversation

timostamm
Copy link
Member

The function equals from @bufbuild/protobuf compares two messages of the same type.

This PR adds an options argument to enable comparison of extensions, unknown fields, and semantic comparison of google.protobuf.Any:

interface EqualsOptions {
  /**
   * A registry to look up extensions, and messages packed in Any.
   *
   * @private Experimental API, does not follow semantic versioning.
   */
  registry: Registry;
  /**
   * Unpack google.protobuf.Any before comparing.
   * If a type is not in the registry, comparison falls back to comparing the
   * fields of Any.
   *
   * @private Experimental API, does not follow semantic versioning.
   */
  unpackAny?: boolean;
  /**
   * Consider extensions when comparing.
   *
   * @private Experimental API, does not follow semantic versioning.
   */
  extensions?: boolean;
  /**
   * Consider unknown fields when comparing.
   * The registry is used to distinguish between extensions, and unknown fields
   * caused by schema changes.
   *
   * @private Experimental API, does not follow semantic versioning.
   */
  unknown?: boolean;
}

For now, the feature is an experimental API, and it's marked @private. This means it's possible to use the API, but at your own risk: It is possible that we change the API, or remove it again.

@timostamm timostamm requested a review from jhump December 2, 2024 17:04
Copy link
Member

@jhump jhump left a comment

Choose a reason for hiding this comment

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

Minor remarks/questions. LGTM.

return (msg.getUnknown() ?? [])
.map((uf) => registry.getExtensionFor(msg.desc, uf.no))
.filter((e) => !!e)
.filter((e, index, arr) => arr.indexOf(e) === index);
Copy link
Member

Choose a reason for hiding this comment

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

This expression seems like a tautology. What is this trying to filter out? Is this just removing duplicates (where arr.indexOf(e) might return an earlier index)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it's removing duplicates. This expression is widely used, for better or worse.

Comment on lines +123 to 136
const mapA = a.get(f);
const mapB = b.get(f);
const keys: unknown[] = [];
for (const k of mapA.keys()) {
if (!mapB.has(k)) {
return false;
}
keysA.push(k);
keys.push(k);
}
for (const k of mb.keys()) {
if (!ma.has(k)) {
for (const k of mapB.keys()) {
if (!mapA.has(k)) {
return false;
}
}
Copy link
Member

Choose a reason for hiding this comment

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

You have a more efficient/concise way to test this below, for extensions: instead of scanning through both sets of keys, check that they both have the same number of keys and then just scan a, verifying that each key is also present in b.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is a facade to access an object like a map type. I think the logic is trying to avoid some expensive operations. I've added a comment.

@timostamm timostamm merged commit 5f90581 into main Dec 3, 2024
21 checks passed
@timostamm timostamm deleted the tstamm/Add-experimental-options-to-equals()-to-include-extensions-and-others branch December 3, 2024 15:37
@timostamm timostamm mentioned this pull request Dec 9, 2024
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.

2 participants