Skip to content

feat(api): #[non_exhaustive] on public value enums + drop dead privacy enums - #736

Merged
jlucaso1 merged 1 commit into
mainfrom
api/value-enums-non-exhaustive
Jun 8, 2026
Merged

jlucaso1 merged 1 commit into
mainfrom
api/value-enums-non-exhaustive

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

What

Continues the 1.0 forward-compat freeze started for error enums in #735, now on the public value enums, plus removes a dead duplicate type cluster.

Changes

  • EventKind and ReceiptType get #[non_exhaustive]. Both are server-driven sets that already grew over time (ReceiptType added EncRekeyRetry, ReadSelf, PlayedSelf, PeerMsg, HistorySync); without the attribute, a downstream exhaustive match breaks the moment a variant is added. The sibling Event enum already carried it, so this closes the asymmetry. Same-crate matches are unaffected.
  • EventKind gains a documented CAPACITY = 64 and a build-time assert!. It is used as a bit index into EventInterest's u64 mask, so a future variant that would overflow the mask now fails compilation instead of silently corrupting it at runtime.
  • Removes the dead PrivacySetting / PrivacySettingType / PrivacySettings types from wacore/src/types/user.rs. They have zero references anywhere in the workspace, superseded by the WireEnum-based wacore::iq::privacy::{PrivacyCategory, PrivacyValue, PrivacySetting} (the live privacy feature). They were also a confusing second public PrivacySetting on the surface and violated the repo's WireEnum convention. The now-orphaned serde import goes with them.

Verification

  • cargo clippy --all-targets -- -D warnings clean
  • cargo test --workspace --exclude e2e-tests green

Resolves gap-analysis api-07, api-16, api-17. Breaking change, acceptable pre-1.0.

…y enums

Continues the 1.0 forward-compat freeze started for error enums (#735), now on the
public value enums, and removes a dead duplicate type cluster.

- EventKind and ReceiptType get #[non_exhaustive] so adding a variant stays additive
  after 1.0 (these are server-driven sets that already grew). The sibling Event enum
  already carried it; this closes the asymmetry. Same-crate matches are unaffected.
- EventKind also gains a documented CAPACITY = 64 and a build-time assert: it is used
  as a bit index into EventInterest's u64 mask, so a future variant that would overflow
  the mask now fails compilation instead of corrupting it at runtime.
- Removes the dead PrivacySetting / PrivacySettingType / PrivacySettings types from
  wacore/src/types/user.rs. They have zero references anywhere (superseded by the
  WireEnum-based wacore::iq::privacy::{PrivacyCategory, PrivacyValue, PrivacySetting}),
  were a confusing second public PrivacySetting on the surface, and violated the repo's
  WireEnum convention. The orphaned serde import goes with them.

Verified: clippy --all-targets -- -D warnings clean; cargo test --workspace
--exclude e2e-tests green.
@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Refactor
    • Updated event type handling with capacity constraints and future expansion support.
    • Updated receipt type definition for future extensibility.
    • Removed unused privacy-related type definitions from the user module.

Walkthrough

The PR hardens the public API contracts of core type enums by marking EventKind and ReceiptType as non-exhaustive while enforcing a 64-kind discriminant ceiling for bitmask safety. Privacy configuration types are removed from the user module, with corresponding import updates.

Changes

Type System API Hardening

Layer / File(s) Summary
EventKind capacity ceiling and non-exhaustive constraint
wacore/src/types/events.rs
EventKind enum is now #[non_exhaustive]. A compile-time assertion verifies that MexNotification's discriminant remains below CAPACITY (64), enforcing the u64 bitmask ceiling required by EventInterest.
ReceiptType non-exhaustive marking
wacore/src/types/presence.rs
ReceiptType enum is marked #[non_exhaustive] to prevent exhaustive downstream pattern matching, while variant definitions and parsing logic remain unchanged.
Privacy types removal and import refactoring
wacore/src/types/user.rs
Public privacy types (PrivacySetting, PrivacySettingType, PrivacySettings) are removed. Module imports are updated to use chrono::{DateTime, Utc} instead of serde utilities.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

The changes involve breaking API modifications—non-exhaustive markers on widely-used public enums require careful downstream impact assessment. The privacy type removals are straightforward but need verification that no internal or external code depends on those exports. The capacity constraint is a critical safety assertion that needs careful verification against EventInterest bitmask usage.

Possibly Related PRs

Suggested Labels

api-design, breaking-change

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: adding #[non_exhaustive] to public value enums and removing dead privacy types.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the rationale, specific changes, and verification steps performed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch api/value-enums-non-exhaustive

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown

Benchmark Results

67 unchanged benchmark(s)
Benchmark Current Baseline Change
reporting_token_benchmark::content_extraction_group::bench_content_extraction simple:setup_simple_message() 2,925 2,925 +0.0%
reporting_token_benchmark::content_extraction_group::bench_content_extraction extended:setup_extended_message() 8,446 8,446 +0.0%
reporting_token_benchmark::key_derivation_group::bench_key_derivation 31,317 31,317 +0.0%
reporting_token_benchmark::token_calculation_group::bench_token_calculation 13,827 13,827 +0.0%
reporting_token_benchmark::full_generation_group::bench_full_token_generation simple:setup_full_gen_simple() 49,485 49,485 +0.0%
reporting_token_benchmark::full_generation_group::bench_full_token_generation extended:setup_full_gen_extended() 55,001 55,001 +0.0%
reporting_token_benchmark::message_encoding_group::bench_message_encoding simple:setup_simple_message() 1,679 1,679 +0.0%
reporting_token_benchmark::message_encoding_group::bench_message_encoding extended:setup_extended_message() 4,393 4,393 +0.0%
send_receive_benchmark::dm_send::bench_dm_send text:setup_dm_send() 113,052 113,212 -0.1%
send_receive_benchmark::dm_recv::bench_dm_recv text:setup_dm_recv() 1,656,623 1,656,627 -0.0%
send_receive_benchmark::group_send::bench_group_send group_10:setup_group_send_10() 651,781 651,797 -0.0%
send_receive_benchmark::group_send::bench_group_send group_50:setup_group_send_50() 875,843 875,717 +0.0%
send_receive_benchmark::group_send::bench_group_send group_256:setup_group_send_256() 2,083,570 2,083,632 -0.0%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_10:setup_group_skdm_10() 749,065 748,890 +0.0%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_50:setup_group_skdm_50() 1,329,832 1,329,901 -0.0%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_256:setup_group_skdm_256() 4,373,727 4,359,643 +0.3%
send_receive_benchmark::group_recv::bench_group_recv text:setup_group_recv() 519,239 513,532 +1.1%
binary_benchmark::marshal_group::bench_marshal_allocating 45,395 45,395 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_allocating 45,445 45,445 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_allocating 66,348 66,348 +0.0%
binary_benchmark::marshal_group::bench_marshal_reusing_buffer 43,506 43,506 +0.0%
binary_benchmark::marshal_group::bench_marshal_reusing_buffer_vec_writer 45,501 45,501 +0.0%
binary_benchmark::marshal_group::bench_marshal_long_string 4,936 4,936 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_long_string 4,967 4,967 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_long_string 6,738 6,738 +0.0%
binary_benchmark::marshal_group::bench_marshal_huge_bytes_allocating 528,539 528,539 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_huge_bytes_allocating 528,152 528,152 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_huge_bytes_allocating 529,398 529,398 +0.0%
binary_benchmark::marshal_group::bench_marshal_many_children_allocating 5,417,742 5,417,742 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_many_children_allocating 5,362,091 5,362,091 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_many_children_allocating 13,276,430 13,276,430 +0.0%
binary_benchmark::unmarshal_group::bench_unmarshal small:setup_small_marshaled() 1,850 1,850 +0.0%
binary_benchmark::unmarshal_group::bench_unmarshal large:setup_large_marshaled() 29,217 29,217 +0.0%
binary_benchmark::unpack_group::bench_unpack_uncompressed 618 618 +0.0%
binary_benchmark::unpack_group::bench_unpack_compressed 672,890 672,890 +0.0%
binary_benchmark::attr_parser_group::bench_attr_parser attr_lookup:setup_attr_marshaled() 3,736 3,736 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip small:setup_small_marshaled() 3,840 3,840 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip large:setup_large_marshaled() 48,274 48,274 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_auto small:setup_small_marshaled() 3,866 3,866 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_auto large:setup_large_marshaled() 48,335 48,335 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_exact small:setup_small_marshaled() 5,206 5,206 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_exact large:setup_large_marshaled() 66,659 66,659 +0.0%
binary_benchmark::child_iteration_group::bench_get_children_by_tag 310,312 310,312 +0.0%
binary_benchmark::jid_optimization_group::bench_jid_to_owned_access jid_access:setup_jid_heavy_marshaled() 8,282 8,282 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_u32 254 254 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_u32 91 91 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_u64 292 292 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_u64 137 137 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_i64 317 317 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_i64 145 145 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_loop_100_u64 27,425 27,425 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_loop_100_u64 10,725 10,725 +0.0%
libsignal_benchmark::dm_group::bench_dm_session_establishment setup:setup_dm_users() 4,141,808 4,142,586 -0.0%
libsignal_benchmark::dm_group::bench_dm_encrypt_first_message first_msg:setup_dm_session() 100,131 100,133 -0.0%
libsignal_benchmark::dm_group::bench_dm_decrypt_first_message decrypt_prekey:setup_dm_with_first_message() 4,264,189 4,264,189 +0.0%
libsignal_benchmark::dm_group::bench_dm_encrypt_subsequent_message subsequent:setup_established_dm_session() 100,399 100,399 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_create_distribution_message create:setup_group_sender() 210,262 210,262 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_encrypt_message encrypt:setup_group_with_distribution() 496,921 496,908 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_decrypt_message decrypt:setup_group_with_encrypted_message() 507,495 507,496 -0.0%
libsignal_benchmark::conversation_group::bench_full_dm_conversation full:setup_conversation_data() 11,979,713 11,973,779 +0.0%
libsignal_benchmark::signature_group::bench_signature_creation sign:setup_keypair_with_message() 2,466,138 2,466,138 +0.0%
libsignal_benchmark::signature_group::bench_signature_verification verify:setup_keypair_with_message() 4,904,352 4,872,282 +0.7%
libsignal_benchmark::signature_group::bench_key_generation keygen 2,043,397 2,043,397 +0.0%
libsignal_benchmark::session_optimization_group::bench_decrypt_with_previous_session previous_session:setup_with_archived_sessions() 37,414 37,404 +0.0%
libsignal_benchmark::session_optimization_group::bench_out_of_order_decryption out_of_order:setup_out_of_order_messages() 3,617,967 3,617,967 +0.0%
libsignal_benchmark::session_optimization_group::bench_promote_matching_session promote:setup_promote_matching_session() 230,658 230,648 +0.0%
libsignal_benchmark::session_optimization_group::bench_message_key_eviction eviction:setup_message_key_eviction() 9,980,959 9,980,959 +0.0%
No significant changes detected.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@wacore/src/types/events.rs`:
- Around line 262-264: Add a unit test that programmatically counts EventKind
variants and asserts the count is <= EventKind::CAPACITY to catch forgotten
updates automatically; implement the test (e.g., using a derived iterator like
strum::EnumVariantNames/EnumIter or by constructing a list of EventKind::...
variants) and assert!(count <= EventKind::CAPACITY as usize), referencing
EventKind and EventInterest/CAPACITY so the CI fails if the enum grows beyond
the u64 bitmask capacity.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b06c8cff-d0bd-4d62-aea2-eb00bca177bb

📥 Commits

Reviewing files that changed from the base of the PR and between a673a3e and 841efd8.

📒 Files selected for processing (3)
  • wacore/src/types/events.rs
  • wacore/src/types/presence.rs
  • wacore/src/types/user.rs
💤 Files with no reviewable changes (1)
  • wacore/src/types/user.rs

Comment on lines +262 to +264
// Build-time tripwire: a new variant that would overflow EventInterest's bitmask
// fails compilation instead of silently corrupting the mask at runtime.
const _: () = assert!((EventKind::MexNotification as u8) < EventKind::CAPACITY);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Consider adding an automated variant count check.

Listen, this assertion is smart, but it relies on developers remembering to update it manually whenever they add a variant. If someone adds EventKind::NewVariant but forgets to change MexNotification to NewVariant in this assertion, the check won't catch overflow until we hit 64+ variants.

The comment tells people what to do, and that's good. But we can do better. Consider adding a unit test that programmatically counts EventKind variants and asserts the total is ≤ 64. That way we get automated enforcement without relying on human discipline.

Something like:

#[test]
fn event_kind_capacity_enforced() {
    // If this test fails, we've exceeded EventInterest's u64 bitmask capacity.
    // Solution: either remove variants or switch EventInterest to u128.
    let count = /* derive variant count or maintain a manual list in test */;
    assert!(count <= EventKind::CAPACITY as usize);
}

This gives you defense in depth. The const assertion catches it if the last variant is updated correctly; the test catches it if someone forgets.

We need WhatsApp to scale. Manual processes don't scale.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wacore/src/types/events.rs` around lines 262 - 264, Add a unit test that
programmatically counts EventKind variants and asserts the count is <=
EventKind::CAPACITY to catch forgotten updates automatically; implement the test
(e.g., using a derived iterator like strum::EnumVariantNames/EnumIter or by
constructing a list of EventKind::... variants) and assert!(count <=
EventKind::CAPACITY as usize), referencing EventKind and EventInterest/CAPACITY
so the CI fails if the enum grows beyond the u64 bitmask capacity.

@jlucaso1
jlucaso1 merged commit df901a6 into main Jun 8, 2026
12 checks passed
@jlucaso1
jlucaso1 deleted the api/value-enums-non-exhaustive branch June 8, 2026 00:06
@mintlify

mintlify Bot commented Jun 8, 2026

Copy link
Copy Markdown

Docs PR opened: oxidezap/whatsapp-rust-docs#271

Documented that EventKind and ReceiptType are now non_exhaustive and surfaced the new EventKind::CAPACITY constant in the events guide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant