diff --git a/api/business.mdx b/api/business.mdx index 7e92415c..45233e60 100644 --- a/api/business.mdx +++ b/api/business.mdx @@ -81,6 +81,7 @@ if let Some(profile) = client.get_business_profile(&jid).await? { ### BusinessProfile ```rust +#[non_exhaustive] pub struct BusinessProfile { pub wid: Option, pub description: String, @@ -92,27 +93,36 @@ pub struct BusinessProfile { } ``` +`BusinessProfile` is `#[non_exhaustive]`: struct-literal construction and exhaustive struct destructuring from outside the crate are both disallowed. Field reads are unaffected; add `..` to any exhaustive destructuring patterns. + ### BusinessCategory ```rust +#[non_exhaustive] pub struct BusinessCategory { pub id: String, pub name: String, } ``` +`BusinessCategory` is `#[non_exhaustive]`: struct-literal construction and exhaustive struct destructuring from outside the crate are both disallowed. Field reads are unaffected; add `..` to any exhaustive destructuring patterns. + ### BusinessHours ```rust +#[non_exhaustive] pub struct BusinessHours { pub timezone: Option, pub business_config: Option>, } ``` +`BusinessHours` is `#[non_exhaustive]`: struct-literal construction and exhaustive struct destructuring from outside the crate are both disallowed. Field reads are unaffected; add `..` to any exhaustive destructuring patterns. + ### BusinessHoursConfig ```rust +#[non_exhaustive] pub struct BusinessHoursConfig { pub day_of_week: DayOfWeek, pub mode: BusinessHourMode, @@ -121,6 +131,8 @@ pub struct BusinessHoursConfig { } ``` +`BusinessHoursConfig` is `#[non_exhaustive]`: struct-literal construction and exhaustive struct destructuring from outside the crate are both disallowed. Field reads are unaffected; add `..` to any exhaustive destructuring patterns. + ### DayOfWeek ```rust diff --git a/api/community.mdx b/api/community.mdx index 20c05e09..68722e6f 100644 --- a/api/community.mdx +++ b/api/community.mdx @@ -309,6 +309,7 @@ Result of creating a community. ```rust #[derive(Debug, Clone)] +#[non_exhaustive] pub struct CreateCommunityResult { pub metadata: GroupMetadata, } @@ -316,6 +317,8 @@ pub struct CreateCommunityResult { The `metadata` field carries the full community parent metadata from the server, with the inline `description: Option` already populated. See [`GroupMetadata`](/api/groups#groupmetadata) for the full field list. +`CreateCommunityResult` is `#[non_exhaustive]`: struct-literal construction and exhaustive struct destructuring from outside the crate are both disallowed. Field reads are unaffected; add `..` to any exhaustive destructuring patterns. + Prior to v0.6 this struct exposed only `gid: Jid` and derived `PartialEq, Eq`. The `Eq` derives were dropped because `GroupMetadata` does not implement them. @@ -326,6 +329,7 @@ A subgroup within a community. Implements `PartialEq` and `Eq`. ```rust #[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] pub struct CommunitySubgroup { pub id: Jid, pub subject: String, @@ -335,6 +339,8 @@ pub struct CommunitySubgroup { } ``` +`CommunitySubgroup` is `#[non_exhaustive]`: struct-literal construction and exhaustive struct destructuring from outside the crate are both disallowed. Field reads are unaffected; add `..` to any exhaustive destructuring patterns. + **Fields:** - `id` — Subgroup JID - `subject` — Subgroup name @@ -348,24 +354,30 @@ Result of linking subgroups to a community. Implements `PartialEq` and `Eq`. ```rust #[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] pub struct LinkSubgroupsResult { pub linked_jids: Vec, pub failed_groups: Vec<(Jid, u32)>, } ``` +`LinkSubgroupsResult` is `#[non_exhaustive]`: struct-literal construction and exhaustive struct destructuring from outside the crate are both disallowed. Field reads are unaffected; add `..` to any exhaustive destructuring patterns. + ### UnlinkSubgroupsResult Result of unlinking subgroups from a community. Implements `PartialEq` and `Eq`. ```rust #[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] pub struct UnlinkSubgroupsResult { pub unlinked_jids: Vec, pub failed_groups: Vec<(Jid, u32)>, } ``` +`UnlinkSubgroupsResult` is `#[non_exhaustive]`: struct-literal construction and exhaustive struct destructuring from outside the crate are both disallowed. Field reads are unaffected; add `..` to any exhaustive destructuring patterns. + ### GroupType Classification of a group within the community hierarchy. Implements `PartialEq` and `Eq`. diff --git a/api/contacts.mdx b/api/contacts.mdx index 64ce63ac..66599430 100644 --- a/api/contacts.mdx +++ b/api/contacts.mdx @@ -176,6 +176,10 @@ pub async fn get_user_info( - `verified_name: Option` - Decoded verified business name certificate, for verified business accounts (see [`is_on_whatsapp`](#is_on_whatsapp) for field details) - `devices: Vec` - Device IDs from the `` sublist the same usync query returns (device `0` is the primary). Empty when the server omits the sublist — no extra request is needed. + +`UserInfo` is `#[non_exhaustive]`, so new fields may be added in future versions without a breaking change. + + **Example:** ```rust let jids = vec![ diff --git a/api/groups.mdx b/api/groups.mdx index aed207d9..4e26331c 100644 --- a/api/groups.mdx +++ b/api/groups.mdx @@ -1302,6 +1302,7 @@ pub struct MembershipRequest { Result of a participant change operation (add, remove, approve, reject). ```rust +#[non_exhaustive] pub struct ParticipantChangeResponse { pub jid: Jid, pub status: Option, @@ -1310,6 +1311,10 @@ pub struct ParticipantChangeResponse { } ``` + +`ParticipantChangeResponse` is `#[non_exhaustive]`. Field reads are unaffected; only exhaustive struct destructuring from outside the crate requires adding `..`. + + `add_request` is populated when the server responds with HTTP 403 carrying an `` child — that happens when a participant has privacy blocked direct adds and the inviter must send them a v4 invite link out-of-band. Since v0.6 the value is preserved instead of being dropped, so consumers can drive the v4 invite flow without parsing the raw IQ. ```rust @@ -1381,11 +1386,16 @@ pub struct GroupProfilePicture { Result of creating a group. ```rust +#[non_exhaustive] pub struct CreateGroupResult { pub metadata: GroupMetadata, } ``` + +`CreateGroupResult` is `#[non_exhaustive]`. Field reads are unaffected; only exhaustive struct destructuring from outside the crate requires adding `..`. + + The `metadata` field carries the full group state returned by the server (same shape as [`get_metadata`](#get_metadata)). `metadata.participants` is `Vec` — note that masked-number `display_name` labels live on `GroupParticipantInfo` (which carries `` children of *notification* events), not on `GroupParticipant` here. @@ -1454,4 +1464,4 @@ match client.groups().set_subject(&group_jid, subject).await { Ok(_) => println!("Subject updated"), Err(e) => eprintln!("Failed to update subject: {}", e), } -``` \ No newline at end of file +``` diff --git a/api/send.mdx b/api/send.mdx index 7e7afe3a..4d05cfff 100644 --- a/api/send.mdx +++ b/api/send.mdx @@ -49,6 +49,7 @@ Result of a successfully sent message. Provides the message ID and a convenience ```rust #[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] pub struct SendResult { pub message_id: String, pub to: Jid, @@ -61,6 +62,8 @@ impl SendResult { } ``` +`SendResult` is `#[non_exhaustive]`: struct-literal construction and exhaustive struct destructuring from outside the crate are both disallowed. Field reads are unaffected; add `..` to any exhaustive destructuring patterns. + ### ChatMessageId Identifies a specific message within a chat. Useful for operations that need both the chat and message ID together. diff --git a/api/upload.mdx b/api/upload.mdx index d9078034..247e77db 100644 --- a/api/upload.mdx +++ b/api/upload.mdx @@ -45,6 +45,7 @@ pub async fn upload( Contains all metadata needed to include the media in a message: ```rust + #[non_exhaustive] pub struct UploadResponse { pub url: String, pub direct_path: String, @@ -68,6 +69,10 @@ pub async fn upload( pub fn file_enc_sha256_vec(&self) -> Vec { ... } } ``` + + + `UploadResponse` is `#[non_exhaustive]`. Field reads are unaffected; only exhaustive struct destructuring from outside the crate requires adding `..`. + Full CDN URL where the encrypted file was uploaded @@ -240,7 +245,7 @@ client.send_message(chat_jid, msg).await?; ``` | Builder | Options struct | Notable fields (all optional) | MIME default | -|---------|----------------|-------------------------------|--------------| +|---------|----------------|-------------------------------|-------------| | `media::image_message(upload, opts)` | `ImageOptions` | `caption`, `mimetype`, `jpeg_thumbnail` | `image/jpeg` | | `media::video_message(upload, opts)` | `VideoOptions` | `caption`, `mimetype`, `jpeg_thumbnail`, `duration_seconds`, `gif_playback` | `video/mp4` | | `media::document_message(upload, opts)` | `DocumentOptions` | `mimetype`, `file_name`, `title`, `caption`, `page_count`, `jpeg_thumbnail` | `application/octet-stream` | diff --git a/changelog/2026-06-09-non-exhaustive.mdx b/changelog/2026-06-09-non-exhaustive.mdx new file mode 100644 index 00000000..e2b194ed --- /dev/null +++ b/changelog/2026-06-09-non-exhaustive.mdx @@ -0,0 +1,36 @@ +--- +title: "June 9, 2026 — Response structs marked #[non_exhaustive]" +description: "All library-returned response and result structs are now #[non_exhaustive], completing the pre-1.0 API stabilisation pass." +--- + +## Breaking changes + +**Response and result structs are `#[non_exhaustive]` ([#794](https://github.com/oxidezap/whatsapp-rust/pull/794))** + +`#[non_exhaustive]` has been applied to all public structs the library returns to consumers but never requires consumers to construct. `IsOnWhatsAppResult` already carried the attribute; this pass extends it to the remaining types before 1.0, while adding new fields is still cheap. + +**Affected types:** + +*wacore:* +- `UserInfo`, `LidQueryResponse` +- `BusinessProfile`, `BusinessHours`, `BusinessHoursConfig`, `BusinessCategory` +- `GroupInfoResponse`, `GroupParticipantResponse`, `GroupParticipatingResponse`, `ParticipantChangeResponse` + +*whatsapp-rust:* +- `SendResult`, `UploadResponse` +- `CreateGroupResult` +- `CreateCommunityResult`, `CommunitySubgroup`, `LinkSubgroupsResult`, `UnlinkSubgroupsResult` + +**What changes:** External crates can no longer construct these types via struct-literal syntax or match them exhaustively without a `..` wildcard. Field reads are unaffected. + +**In practice:** The library constructs all of these — consumers only receive them. The PR confirmed zero struct-literal constructions outside the defining crate, so the attribute enforces the already-intended API contract. + +**Migration:** Add `..` to any exhaustive struct destructuring patterns: + +```rust +// Before (fails to compile outside the crate): +let SendResult { message_id, to } = result; + +// After: +let SendResult { message_id, to, .. } = result; +``` diff --git a/docs.json b/docs.json index 23097e40..5f27981d 100644 --- a/docs.json +++ b/docs.json @@ -139,6 +139,7 @@ "pages": [ "changelog/overview", "changelog/2026-06-09", + "changelog/2026-06-09-non-exhaustive", "changelog/2026-06-08", "changelog/2026-06-06", "changelog/2026-06-05-abprops",