diff --git a/api/contacts.mdx b/api/contacts.mdx index 72086ce4..3a54fc87 100644 --- a/api/contacts.mdx +++ b/api/contacts.mdx @@ -245,6 +245,10 @@ The implementation automatically: - Includes tokens in profile picture requests - Skips tokens for groups and newsletters +## Async compatibility + +`is_on_whatsapp` and `get_user_info` work correctly when called from `#[async_trait]` implementations or any context that boxes the returned future (`Box`). Earlier versions produced a compile error (`"implementation of FnOnce is not general enough"`) that could not be worked around in user code. Fixed in [#826](https://github.com/oxidezap/whatsapp-rust/pull/826) with no API changes. + ## Error handling All methods return `Result`. Common errors: diff --git a/changelog/2026-06-10-hrtb-closures.mdx b/changelog/2026-06-10-hrtb-closures.mdx new file mode 100644 index 00000000..e8882ff8 --- /dev/null +++ b/changelog/2026-06-10-hrtb-closures.mdx @@ -0,0 +1,24 @@ +--- +title: "June 10, 2026 — Contacts: fix async_trait / boxed-future compilation error" +description: "is_on_whatsapp() and get_user_info() now compile correctly when called from #[async_trait] implementations or any context that boxes the returned future." +--- + +## Bug Fix + +**Contacts: `is_on_whatsapp` and `get_user_info` compile in `#[async_trait]` contexts ([#826](https://github.com/oxidezap/whatsapp-rust/pull/826))** + +Calling either method from an `#[async_trait]` implementation — or any other context that boxes the returned future — previously produced a hard compiler error: + +``` +error: implementation of `FnOnce` is not general enough + = note: closure with signature `fn(&'0 IsOnWhatsAppResult) -> (&Jid, Option<&Jid>)` + must implement `FnOnce<(&'1 IsOnWhatsAppResult,)>`, for any two lifetimes `'0` and `'1`... +``` + +The root cause was inside the library: the internal `persist_lid_mappings` helper received closures that returned references tied to a concrete lifetime. Rust infers such closures at a single lifetime rather than the higher-ranked `for<'r> Fn(&'r _)` form. Because the closure types were embedded in the public methods' future types, the unprovable HRTB obligation leaked to every boxing consumer — nothing in user code could work around it. + +**Fix.** The three offending closures are now named `fn` items (`forward_lid_pair`, `reverse_lid_pair`, `user_info_lid_pair`), which implement `Fn` for every lifetime by construction. No API changes, no extra allocations, identical behavior. + +A compile-time regression guard (`tests/async_trait_boxed_future_compat.rs`) was added that reproduces the exact consumer shape from the original report — an `#[async_trait]` impl holding an `RwLock>>` — and fails to compile if the issue is ever reintroduced. + +**No breaking changes.** Fixes [#825](https://github.com/oxidezap/whatsapp-rust/issues/825). diff --git a/docs.json b/docs.json index a44eb554..f06472b2 100644 --- a/docs.json +++ b/docs.json @@ -138,6 +138,7 @@ "group": "Changelog", "pages": [ "changelog/overview", + "changelog/2026-06-10-hrtb-closures", "changelog/2026-06-10-server-aware-lookup-probe", "changelog/2026-06-10-phash-arena-sort", "changelog/2026-06-10-attrs-inline-smallvec",