From d18a73ddbf70e68da02cbf263fd183f6a23f08de Mon Sep 17 00:00:00 2001 From: Nerixyz Date: Thu, 27 Oct 2022 16:54:02 +0200 Subject: [PATCH 1/8] feat(refs): part 1 - non paginating parts --- src/helix/client/client_ext.rs | 231 ++++++++++-------- .../endpoints/bits/get_bits_leaderboard.rs | 23 +- src/helix/endpoints/bits/get_cheermotes.rs | 13 +- .../endpoints/channels/add_channel_vip.rs | 18 +- .../endpoints/channels/get_channel_editors.rs | 15 +- .../channels/get_channel_information.rs | 15 +- src/helix/endpoints/channels/get_vips.rs | 37 ++- .../channels/modify_channel_information.rs | 41 ++-- .../endpoints/channels/remove_channel_vip.rs | 18 +- .../endpoints/channels/start_commercial.rs | 36 +-- .../endpoints/chat/get_channel_chat_badges.rs | 13 +- .../endpoints/chat/get_channel_emotes.rs | 13 +- src/helix/endpoints/chat/get_chat_settings.rs | 18 +- src/helix/endpoints/chat/get_chatters.rs | 20 +- src/helix/endpoints/chat/get_emote_sets.rs | 29 +-- .../endpoints/chat/get_user_chat_color.rs | 26 +- .../endpoints/chat/send_chat_announcement.rs | 37 +-- .../endpoints/chat/update_chat_settings.rs | 18 +- .../endpoints/chat/update_user_chat_color.rs | 16 +- src/helix/endpoints/clips/get_clips.rs | 54 ++-- .../eventsub/create_eventsub_subscription.rs | 21 +- .../eventsub/delete_eventsub_subscription.rs | 13 +- .../eventsub/get_eventsub_subscriptions.rs | 13 +- src/helix/endpoints/games/get_games.rs | 45 ++-- src/helix/endpoints/games/get_top_games.rs | 13 +- .../endpoints/goals/get_creator_goals.rs | 16 +- .../hypetrain/get_hypetrain_events.rs | 18 +- .../endpoints/moderation/add_blocked_term.rs | 37 +-- .../moderation/add_channel_moderator.rs | 18 +- src/helix/endpoints/moderation/ban_user.rs | 42 ++-- .../moderation/check_automod_status.rs | 54 ++-- .../moderation/delete_chat_messages.rs | 23 +- .../endpoints/moderation/get_banned_users.rs | 34 ++- .../endpoints/moderation/get_blocked_terms.rs | 20 +- .../endpoints/moderation/get_moderators.rs | 34 ++- .../manage_held_automod_messages.rs | 41 ++-- .../moderation/remove_blocked_term.rs | 23 +- .../moderation/remove_channel_moderator.rs | 18 +- src/helix/endpoints/moderation/unban_user.rs | 23 +- .../endpoints/points/create_custom_rewards.rs | 36 +-- .../endpoints/points/delete_custom_reward.rs | 19 +- .../endpoints/points/get_custom_reward.rs | 31 ++- .../points/get_custom_reward_redemption.rs | 20 +- src/helix/endpoints/points/mod.rs | 2 +- .../endpoints/points/update_custom_reward.rs | 37 +-- .../points/update_redemption_status.rs | 23 +- src/helix/endpoints/polls/create_poll.rs | 62 ++--- src/helix/endpoints/polls/end_poll.rs | 33 ++- src/helix/endpoints/polls/get_polls.rs | 33 ++- .../predictions/create_prediction.rs | 50 ++-- .../endpoints/predictions/end_prediction.rs | 38 +-- .../endpoints/predictions/get_predictions.rs | 34 ++- src/helix/endpoints/raids/cancel_a_raid.rs | 13 +- src/helix/endpoints/raids/start_a_raid.rs | 18 +- .../create_channel_stream_schedule_segment.rs | 56 ++--- .../delete_channel_stream_schedule_segment.rs | 18 +- .../schedule/get_channel_stream_schedule.rs | 30 ++- .../update_channel_stream_schedule.rs | 34 ++- .../update_channel_stream_schedule_segment.rs | 46 ++-- .../endpoints/search/search_categories.rs | 18 +- src/helix/endpoints/search/search_channels.rs | 15 +- .../endpoints/streams/get_followed_streams.rs | 18 +- .../endpoints/streams/get_stream_tags.rs | 13 +- src/helix/endpoints/streams/get_streams.rs | 66 ++--- .../endpoints/streams/replace_stream_tags.rs | 46 ++-- .../subscriptions/check_user_subscription.rs | 32 +-- .../get_broadcaster_subscriptions.rs | 30 +-- .../get_broadcaster_subscriptions_events.rs | 37 ++- .../endpoints/tags/get_all_stream_tags.rs | 32 ++- .../endpoints/teams/get_channel_teams.rs | 13 +- src/helix/endpoints/teams/get_teams.rs | 18 +- src/helix/endpoints/users/block_user.rs | 17 +- .../endpoints/users/get_user_block_list.rs | 15 +- src/helix/endpoints/users/get_users.rs | 51 ++-- .../endpoints/users/get_users_follows.rs | 24 +- src/helix/endpoints/users/unblock_user.rs | 13 +- src/helix/endpoints/videos/delete_videos.rs | 27 +- src/helix/endpoints/videos/get_videos.rs | 44 ++-- src/helix/endpoints/whispers/send_whisper.rs | 36 ++- 79 files changed, 1250 insertions(+), 1145 deletions(-) diff --git a/src/helix/client/client_ext.rs b/src/helix/client/client_ext.rs index eaceb051ab..e09dfbbd7a 100644 --- a/src/helix/client/client_ext.rs +++ b/src/helix/client/client_ext.rs @@ -12,42 +12,48 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Get [User](helix::users::User) from user login pub async fn get_user_from_login( &'a self, - login: impl Into, + login: impl AsRef, token: &T, ) -> Result, ClientError<'a, C>> where T: TwitchToken + ?Sized, { - self.req_get(helix::users::GetUsersRequest::login(login), token) - .await - .map(|response| response.first()) + self.req_get( + helix::users::GetUsersRequest::logins(&[login.as_ref()][..]), + token, + ) + .await + .map(|response| response.first()) } /// Get [User](helix::users::User) from user id pub async fn get_user_from_id( &'a self, - id: impl Into, + id: impl AsRef, token: &T, ) -> Result, ClientError<'a, C>> where T: TwitchToken + ?Sized, { - self.req_get(helix::users::GetUsersRequest::id(id), token) - .await - .map(|response| response.first()) + self.req_get( + helix::users::GetUsersRequest::ids(&[id.as_ref()][..]), + token, + ) + .await + .map(|response| response.first()) } /// Get [ChannelInformation](helix::channels::ChannelInformation) from a broadcasters login pub async fn get_channel_from_login( &'a self, - login: impl Into, + login: impl AsRef, token: &T, ) -> Result, ClientError<'a, C>> where T: TwitchToken + ?Sized, { if let Some(user) = self.get_user_from_login(login, token).await? { - self.get_channel_from_id(user.id, token).await + self.get_channel_from_id(&user.id, token).await } else { Ok(None) } @@ -56,14 +62,14 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Get [ChannelInformation](helix::channels::ChannelInformation) from a broadcasters id pub async fn get_channel_from_id( &'a self, - id: impl Into, + id: impl AsRef, token: &T, ) -> Result, ClientError<'a, C>> where T: TwitchToken + ?Sized, { self.req_get( - helix::channels::GetChannelInformationRequest::broadcaster_id(id), + helix::channels::GetChannelInformationRequest::broadcaster_id(id.as_ref()), token, ) .await @@ -91,8 +97,8 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// ``` pub fn get_chatters( &'a self, - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + moderator_id: impl Into<&'a types::UserIdRef>, batch_size: impl Into>, token: &'a T, ) -> std::pin::Pin< @@ -128,7 +134,7 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// ``` pub fn search_categories( &'a self, - query: impl Into, + query: impl Into<&'a str>, token: &'a T, ) -> std::pin::Pin< Box>> + 'a>, @@ -159,7 +165,7 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// ``` pub fn search_channels( &'a self, - query: impl Into, + query: impl Into<&'a str>, live_only: bool, token: &'a T, ) -> std::pin::Pin< @@ -194,8 +200,8 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// ``` pub fn get_follow_relationships( &'a self, - to_id: impl Into>, - from_id: impl Into>, + to_id: impl Into>, + from_id: impl Into>, token: &'a T, ) -> std::pin::Pin< Box< @@ -322,7 +328,7 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// ``` pub fn get_moderators_in_channel_from_id( &'a self, - broadcaster_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, token: &'a T, ) -> std::pin::Pin< Box< @@ -357,7 +363,7 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// ``` pub fn get_banned_users_in_channel_from_id( &'a self, - broadcaster_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, token: &'a T, ) -> std::pin::Pin< Box< @@ -376,14 +382,14 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Get a users, with login, follow count pub async fn get_total_followers_from_login( &'a self, - login: impl Into, + login: impl AsRef, token: &T, ) -> Result, ClientError<'a, C>> where T: TwitchToken + ?Sized, { if let Some(user) = self.get_user_from_login(login, token).await? { - self.get_total_followers_from_id(user.id, token) + self.get_total_followers_from_id(&user.id, token) .await .map(Some) } else { @@ -398,7 +404,7 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// This returns zero if the user doesn't exist pub async fn get_total_followers_from_id( &'a self, - to_id: impl Into, + to_id: impl AsRef, token: &T, ) -> Result> where @@ -406,7 +412,7 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { { let resp = self .req_get( - helix::users::GetUsersFollowsRequest::followers(to_id), + helix::users::GetUsersFollowsRequest::followers(to_id.as_ref()), token, ) .await?; @@ -417,13 +423,13 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Get games by ID. Can only be at max 100 ids. pub async fn get_games_by_id( &'a self, - ids: impl IntoIterator>, + ids: impl AsRef<[&'a types::CategoryIdRef]>, token: &T, ) -> Result, ClientError<'a, C>> where T: TwitchToken + ?Sized, { - let ids: Vec<_> = ids.into_iter().take(101).map(Into::into).collect(); + let ids = ids.as_ref(); if ids.len() > 100 { return Err(ClientRequestError::Custom("too many IDs, max 100".into())); } @@ -442,7 +448,7 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Block a user pub async fn block_user( &'a self, - target_user_id: impl Into, + target_user_id: impl AsRef, token: &T, ) -> Result> where @@ -450,7 +456,7 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { { Ok(self .req_put( - helix::users::BlockUserRequest::block_user(target_user_id), + helix::users::BlockUserRequest::block_user(target_user_id.as_ref()), helix::EmptyBody, token, ) @@ -461,7 +467,7 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Unblock a user pub async fn unblock_user( &'a self, - target_user_id: impl Into, + target_user_id: impl AsRef, token: &T, ) -> Result> where @@ -469,7 +475,7 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { { Ok(self .req_delete( - helix::users::UnblockUserRequest::unblock_user(target_user_id), + helix::users::UnblockUserRequest::unblock_user(target_user_id.as_ref()), token, ) .await? @@ -479,11 +485,11 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Ban a user pub async fn ban_user( &'a self, - target_user_id: impl Into, - reason: impl std::fmt::Display, + target_user_id: impl AsRef, + reason: impl AsRef, duration: impl Into>, - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl AsRef, + moderator_id: impl AsRef, token: &T, ) -> Result> where @@ -491,8 +497,15 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { { Ok(self .req_post( - helix::moderation::BanUserRequest::new(broadcaster_id, moderator_id), - helix::moderation::BanUserBody::new(target_user_id, reason.to_string(), duration), + helix::moderation::BanUserRequest::new( + broadcaster_id.as_ref(), + moderator_id.as_ref(), + ), + helix::moderation::BanUserBody::new( + target_user_id.as_ref(), + reason.as_ref(), + duration, + ), token, ) .await? @@ -502,9 +515,9 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Unban a user pub async fn unban_user( &'a self, - target_user_id: impl Into, - broadcaster_id: impl Into, - moderator_id: impl Into, + target_user_id: impl AsRef, + broadcaster_id: impl AsRef, + moderator_id: impl AsRef, token: &T, ) -> Result> where @@ -513,9 +526,9 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { Ok(self .req_delete( helix::moderation::UnbanUserRequest::new( - broadcaster_id, - moderator_id, - target_user_id, + broadcaster_id.as_ref(), + moderator_id.as_ref(), + target_user_id.as_ref(), ), token, ) @@ -554,7 +567,7 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// ``` pub fn get_channel_schedule( &'a self, - broadcaster_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, token: &'a T, ) -> std::pin::Pin< Box>> + 'a>, @@ -582,27 +595,27 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Get channel emotes in channel with user id pub async fn get_channel_emotes_from_id( &'a self, - user_id: impl Into, + user_id: impl AsRef, token: &T, ) -> Result, ClientError<'a, C>> where T: TwitchToken + ?Sized, { - let req = helix::chat::GetChannelEmotesRequest::broadcaster_id(user_id); + let req = helix::chat::GetChannelEmotesRequest::broadcaster_id(user_id.as_ref()); Ok(self.req_get(req, token).await?.data) } /// Get channel emotes in channel with user login pub async fn get_channel_emotes_from_login( &'a self, - login: impl Into, + login: impl AsRef, token: &T, ) -> Result>, ClientError<'a, C>> where T: TwitchToken + ?Sized, { if let Some(user) = self.get_user_from_login(login, token).await? { - self.get_channel_emotes_from_id(user.id, token) + self.get_channel_emotes_from_id(&user.id, token) .await .map(Some) } else { @@ -613,27 +626,27 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Get emotes in emote set pub async fn get_emote_sets( &'a self, - emote_sets: impl IntoIterator>, + emote_sets: impl AsRef<[&'a types::EmoteSetIdRef]>, token: &T, ) -> Result, ClientError<'a, C>> where T: TwitchToken + ?Sized, { - let req = helix::chat::GetEmoteSetsRequest::emote_set_ids(emote_sets); + let req = helix::chat::GetEmoteSetsRequest::emote_set_ids(emote_sets.as_ref()); Ok(self.req_get(req, token).await?.data) } /// Get a broadcaster's chat settings pub async fn get_chat_settings( &'a self, - broadcaster_id: impl Into, - moderator_id: impl Into>, + broadcaster_id: impl AsRef, + moderator_id: impl Into>, token: &T, ) -> Result> where T: TwitchToken + ?Sized, { - let mut req = helix::chat::GetChatSettingsRequest::broadcaster_id(broadcaster_id); + let mut req = helix::chat::GetChatSettingsRequest::broadcaster_id(broadcaster_id.as_ref()); if let Some(moderator_id) = moderator_id.into() { req = req.moderator_id(moderator_id); } @@ -643,17 +656,20 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Send a chat announcement pub async fn send_chat_announcement( &'a self, - broadcaster_id: impl Into, - moderator_id: impl Into, - message: impl std::fmt::Display, + broadcaster_id: impl AsRef, + moderator_id: impl AsRef, + message: impl AsRef, color: impl std::convert::TryInto, token: &T, ) -> Result> where T: TwitchToken + ?Sized, { - let req = helix::chat::SendChatAnnouncementRequest::new(broadcaster_id, moderator_id); - let body = helix::chat::SendChatAnnouncementBody::new(message.to_string(), color)?; + let req = helix::chat::SendChatAnnouncementRequest::new( + broadcaster_id.as_ref(), + moderator_id.as_ref(), + ); + let body = helix::chat::SendChatAnnouncementBody::new(message.as_ref(), color)?; Ok(self .req_post(req, body, token) .await @@ -664,16 +680,19 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Delete a specific chat message pub async fn delete_chat_message( &'a self, - broadcaster_id: impl Into, - moderator_id: impl Into, - message_id: impl Into, + broadcaster_id: impl AsRef, + moderator_id: impl AsRef, + message_id: impl AsRef, token: &T, ) -> Result> where T: TwitchToken + ?Sized, { - let req = helix::moderation::DeleteChatMessagesRequest::new(broadcaster_id, moderator_id) - .message_id(message_id); + let req = helix::moderation::DeleteChatMessagesRequest::new( + broadcaster_id.as_ref(), + moderator_id.as_ref(), + ) + .message_id(message_id.as_ref()); Ok(self.req_delete(req, token).await?.data) } @@ -681,64 +700,72 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Delete all chat messages in a broadcasters chat room pub async fn delete_all_chat_message( &'a self, - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl AsRef, + moderator_id: impl AsRef, token: &T, ) -> Result> where T: TwitchToken + ?Sized, { - let req = helix::moderation::DeleteChatMessagesRequest::new(broadcaster_id, moderator_id); + let req = helix::moderation::DeleteChatMessagesRequest::new( + broadcaster_id.as_ref(), + moderator_id.as_ref(), + ); Ok(self.req_delete(req, token).await?.data) } /// Start a raid pub async fn start_a_raid( &'a self, - from_broadcaster_id: impl Into, - to_broadcaster_id: impl Into, + from_broadcaster_id: impl AsRef, + to_broadcaster_id: impl AsRef, token: &T, ) -> Result> where T: TwitchToken + ?Sized, { - let req = helix::raids::StartARaidRequest::new(from_broadcaster_id, to_broadcaster_id); + let req = helix::raids::StartARaidRequest::new( + from_broadcaster_id.as_ref(), + to_broadcaster_id.as_ref(), + ); Ok(self.req_post(req, helix::EmptyBody, token).await?.data) } /// Cancel a raid pub async fn cancel_a_raid( &'a self, - broadcaster_id: impl Into, + broadcaster_id: impl AsRef, token: &T, ) -> Result> where T: TwitchToken + ?Sized, { - let req = helix::raids::CancelARaidRequest::broadcaster_id(broadcaster_id); + let req = helix::raids::CancelARaidRequest::broadcaster_id(broadcaster_id.as_ref()); Ok(self.req_delete(req, token).await?.data) } /// Get a users chat color pub async fn get_user_chat_color( &'a self, - user_id: impl Into, + user_id: impl AsRef, token: &T, ) -> Result, ClientError<'a, C>> where T: TwitchToken + ?Sized, { - let req = helix::chat::GetUserChatColorRequest { - user_id: vec![user_id.into()], - }; - - Ok(self.req_get(req, token).await?.first()) + Ok(self + .req_get( + helix::chat::GetUserChatColorRequest::user_ids(&[user_id.as_ref()][..]), + token, + ) + .await? + .first()) } /// Get a users chat color pub async fn update_user_chat_color( &'a self, - user_id: impl Into, + user_id: impl AsRef, color: impl Into>, token: &T, ) -> Result> @@ -746,7 +773,7 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { T: TwitchToken + ?Sized, { let req = helix::chat::UpdateUserChatColorRequest { - user_id: user_id.into(), + user_id: user_id.as_ref(), color: color.into(), }; @@ -756,13 +783,13 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Get multiple users chat colors pub async fn get_users_chat_colors( &'a self, - user_ids: impl IntoIterator>, + user_ids: impl AsRef<[&'a types::UserIdRef]>, token: &T, ) -> Result, ClientError<'a, C>> where T: TwitchToken + ?Sized, { - let req = helix::chat::GetUserChatColorRequest::user_ids(user_ids); + let req = helix::chat::GetUserChatColorRequest::user_ids(user_ids.as_ref()); Ok(self.req_get(req, token).await?.data) } @@ -770,16 +797,16 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Add a channel moderator pub async fn add_channel_moderator( &'a self, - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl AsRef, + moderator_id: impl AsRef, token: &T, ) -> Result> where T: TwitchToken + ?Sized, { let req = helix::moderation::AddChannelModeratorRequest { - broadcaster_id: broadcaster_id.into(), - moderator_id: moderator_id.into(), + broadcaster_id: broadcaster_id.as_ref(), + moderator_id: moderator_id.as_ref(), }; Ok(self.req_post(req, helix::EmptyBody, token).await?.data) @@ -788,16 +815,16 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Remove a channel moderator pub async fn remove_channel_moderator( &'a self, - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl AsRef, + moderator_id: impl AsRef, token: &T, ) -> Result> where T: TwitchToken + ?Sized, { let req = helix::moderation::RemoveChannelModeratorRequest { - broadcaster_id: broadcaster_id.into(), - moderator_id: moderator_id.into(), + broadcaster_id: broadcaster_id.as_ref(), + moderator_id: moderator_id.as_ref(), }; Ok(self.req_delete(req, token).await?.data) @@ -806,7 +833,7 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Get channel VIPs pub fn get_vips_in_channel( &'a self, - broadcaster_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, token: &'a T, ) -> std::pin::Pin< Box>> + 'a>, @@ -822,16 +849,16 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Add a channel vip pub async fn add_channel_vip( &'a self, - broadcaster_id: impl Into, - user_id: impl Into, + broadcaster_id: impl AsRef, + user_id: impl AsRef, token: &T, ) -> Result> where T: TwitchToken + ?Sized, { let req = helix::channels::AddChannelVipRequest { - broadcaster_id: broadcaster_id.into(), - user_id: user_id.into(), + broadcaster_id: broadcaster_id.as_ref(), + user_id: user_id.as_ref(), }; Ok(self.req_post(req, helix::EmptyBody, token).await?.data) @@ -840,16 +867,16 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Remove a channel vip pub async fn remove_channel_vip( &'a self, - broadcaster_id: impl Into, - user_id: impl Into, + broadcaster_id: impl AsRef, + user_id: impl AsRef, token: &T, ) -> Result> where T: TwitchToken + ?Sized, { let req = helix::channels::RemoveChannelVipRequest { - broadcaster_id: broadcaster_id.into(), - user_id: user_id.into(), + broadcaster_id: broadcaster_id.as_ref(), + user_id: user_id.as_ref(), }; Ok(self.req_delete(req, token).await?.data) @@ -858,16 +885,16 @@ impl<'a, C: crate::HttpClient<'a> + Sync> HelixClient<'a, C> { /// Send a whisper pub async fn send_whisper( &'a self, - from: impl Into, - to: impl Into, - message: impl std::fmt::Display, + from: impl AsRef, + to: impl AsRef, + message: impl AsRef, token: &T, ) -> Result> where T: TwitchToken + ?Sized, { - let req = helix::whispers::SendWhisperRequest::new(from, to); - let body = helix::whispers::SendWhisperBody::new(message); + let req = helix::whispers::SendWhisperRequest::new(from.as_ref(), to.as_ref()); + let body = helix::whispers::SendWhisperBody::new(message.as_ref()); Ok(self.req_post(req, body, token).await?.data) } diff --git a/src/helix/endpoints/bits/get_bits_leaderboard.rs b/src/helix/endpoints/bits/get_bits_leaderboard.rs index e17e653016..62057f5e19 100644 --- a/src/helix/endpoints/bits/get_bits_leaderboard.rs +++ b/src/helix/endpoints/bits/get_bits_leaderboard.rs @@ -44,7 +44,7 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetBitsLeaderboardRequest { +pub struct GetBitsLeaderboardRequest<'a> { /// Number of results to be returned. Maximum: 100. Default: 10. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub count: Option, @@ -57,16 +57,19 @@ pub struct GetBitsLeaderboardRequest { /// * "year" – 00:00:00 on the first day of the year specified in started_at, through 00:00:00 on the first day of the following year. /// * "all" – The lifetime of the broadcaster's channel. If this is specified (or used by default), started_at is ignored. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub period: Option, + #[serde(borrow)] + pub period: Option<&'a str>, /// Timestamp for the period over which the returned data is aggregated. Must be in RFC 3339 format. If this is not provided, data is aggregated over the current period; e.g., the current day/week/month/year. This value is ignored if period is "all". #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub started_at: Option, + #[serde(borrow)] + pub started_at: Option<&'a types::TimestampRef>, /// ID of the user whose results are returned; i.e., the person who paid for the Bits. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub user_id: Option, + #[serde(borrow)] + pub user_id: Option<&'a types::UserIdRef>, } -impl GetBitsLeaderboardRequest { +impl<'a> GetBitsLeaderboardRequest<'a> { /// Number of results to be returned. Maximum: 100. Default: 10. pub fn count(self, count: i32) -> Self { Self { @@ -76,7 +79,7 @@ impl GetBitsLeaderboardRequest { } /// Get loaderboard for this period. Valid values: `"day"`, `"week"`, `"month"`, `"year"`, `"all"` - pub fn period(self, period: String) -> Self { + pub fn period(self, period: &'a str) -> Self { Self { period: Some(period), ..self @@ -84,7 +87,7 @@ impl GetBitsLeaderboardRequest { } /// Get leaderboard starting at this timestamp - pub fn started_at(self, started_at: impl Into) -> Self { + pub fn started_at(self, started_at: impl Into<&'a types::TimestampRef>) -> Self { Self { started_at: Some(started_at.into()), ..self @@ -92,7 +95,7 @@ impl GetBitsLeaderboardRequest { } /// Get leaderboard where this user is included (if they are on the leaderboard) - pub fn user_id(self, user_id: impl Into) -> Self { + pub fn user_id(self, user_id: impl Into<&'a types::UserIdRef>) -> Self { Self { user_id: Some(user_id.into()), ..self @@ -146,7 +149,7 @@ pub struct LeaderboardUser { pub user_login: types::UserName, } -impl Request for GetBitsLeaderboardRequest { +impl Request for GetBitsLeaderboardRequest<'_> { type Response = BitsLeaderboard; const PATH: &'static str = "bits/leaderboard"; @@ -154,7 +157,7 @@ impl Request for GetBitsLeaderboardRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetBitsLeaderboardRequest { +impl RequestGet for GetBitsLeaderboardRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, diff --git a/src/helix/endpoints/bits/get_cheermotes.rs b/src/helix/endpoints/bits/get_cheermotes.rs index 24df38eb1d..4bd577427e 100644 --- a/src/helix/endpoints/bits/get_cheermotes.rs +++ b/src/helix/endpoints/bits/get_cheermotes.rs @@ -44,18 +44,19 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetCheermotesRequest { +pub struct GetCheermotesRequest<'a> { /// ID for the broadcaster who might own specialized Cheermotes. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub broadcaster_id: Option, + #[serde(borrow)] + pub broadcaster_id: Option<&'a types::UserIdRef>, } -impl GetCheermotesRequest { +impl<'a> GetCheermotesRequest<'a> { /// Get available Cheermotes. pub fn new() -> Self { Self::default() } /// Get Cheermotes in a specific broadcasters channel. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: Some(broadcaster_id.into()), } @@ -176,7 +177,7 @@ pub struct CheermoteImageArray { #[serde(transparent)] pub struct Level(pub String); -impl Request for GetCheermotesRequest { +impl Request for GetCheermotesRequest<'_> { type Response = Vec; const PATH: &'static str = "bits/cheermotes"; @@ -184,7 +185,7 @@ impl Request for GetCheermotesRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetCheermotesRequest {} +impl RequestGet for GetCheermotesRequest<'_> {} #[cfg(test)] #[test] diff --git a/src/helix/endpoints/channels/add_channel_vip.rs b/src/helix/endpoints/channels/add_channel_vip.rs index e4f9c28554..449acf8c4c 100644 --- a/src/helix/endpoints/channels/add_channel_vip.rs +++ b/src/helix/endpoints/channels/add_channel_vip.rs @@ -41,20 +41,22 @@ use helix::RequestPost; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct AddChannelVipRequest { +pub struct AddChannelVipRequest<'a> { /// The ID of the broadcaster that’s granting VIP status to the user. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of the user to add as a VIP in the broadcaster’s chat room. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub user_id: types::UserId, + #[serde(borrow)] + pub user_id: &'a types::UserIdRef, } -impl AddChannelVipRequest { +impl<'a> AddChannelVipRequest<'a> { /// Add a channel VIP pub fn new( - broadcaster_id: impl Into, - user_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + user_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -74,7 +76,7 @@ pub enum AddChannelVipResponse { Success, } -impl Request for AddChannelVipRequest { +impl Request for AddChannelVipRequest<'_> { type Response = AddChannelVipResponse; const PATH: &'static str = "channels/vips"; @@ -82,7 +84,7 @@ impl Request for AddChannelVipRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManageVips]; } -impl RequestPost for AddChannelVipRequest { +impl RequestPost for AddChannelVipRequest<'_> { type Body = helix::EmptyBody; fn parse_inner_response( diff --git a/src/helix/endpoints/channels/get_channel_editors.rs b/src/helix/endpoints/channels/get_channel_editors.rs index 93a4a5f85e..cc66f3947f 100644 --- a/src/helix/endpoints/channels/get_channel_editors.rs +++ b/src/helix/endpoints/channels/get_channel_editors.rs @@ -43,15 +43,16 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetChannelEditorsRequest { +pub struct GetChannelEditorsRequest<'a> { /// Broadcaster’s user ID associated with the channel. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, } -impl GetChannelEditorsRequest { +impl<'a> GetChannelEditorsRequest<'a> { /// Get specified broadcasters channel editors - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), } @@ -73,7 +74,7 @@ pub struct Editor { pub created_at: types::Timestamp, } -impl Request for GetChannelEditorsRequest { +impl Request for GetChannelEditorsRequest<'_> { type Response = Vec; const PATH: &'static str = "channels/editors"; @@ -81,13 +82,13 @@ impl Request for GetChannelEditorsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelReadEditors]; } -impl RequestGet for GetChannelEditorsRequest {} +impl RequestGet for GetChannelEditorsRequest<'_> {} #[cfg(test)] #[test] fn test_request() { use helix::*; - let req = GetChannelEditorsRequest::broadcaster_id("44445592".to_string()); + let req = GetChannelEditorsRequest::broadcaster_id("44445592"); // From twitch docs let data = br#" diff --git a/src/helix/endpoints/channels/get_channel_information.rs b/src/helix/endpoints/channels/get_channel_information.rs index 041e516d84..2f615e65f0 100644 --- a/src/helix/endpoints/channels/get_channel_information.rs +++ b/src/helix/endpoints/channels/get_channel_information.rs @@ -43,15 +43,16 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetChannelInformationRequest { +pub struct GetChannelInformationRequest<'a> { /// ID of the channel #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, } -impl GetChannelInformationRequest { +impl<'a> GetChannelInformationRequest<'a> { /// Get channel information for a specific broadcaster. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), } @@ -87,7 +88,7 @@ pub struct ChannelInformation { pub delay: i64, } -impl Request for GetChannelInformationRequest { +impl Request for GetChannelInformationRequest<'_> { type Response = Option; const PATH: &'static str = "channels"; @@ -95,7 +96,7 @@ impl Request for GetChannelInformationRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetChannelInformationRequest { +impl RequestGet for GetChannelInformationRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, @@ -128,7 +129,7 @@ impl RequestGet for GetChannelInformationRequest { #[test] fn test_request() { use helix::*; - let req = GetChannelInformationRequest::broadcaster_id("44445592".to_string()); + let req = GetChannelInformationRequest::broadcaster_id("44445592"); // From twitch docs let data = br#" diff --git a/src/helix/endpoints/channels/get_vips.rs b/src/helix/endpoints/channels/get_vips.rs index 81912b2f9c..ce3a5018a0 100644 --- a/src/helix/endpoints/channels/get_vips.rs +++ b/src/helix/endpoints/channels/get_vips.rs @@ -36,6 +36,7 @@ //! and parse the [`http::Response`] with [`GetVipsRequest::parse_response(None, &request.get_uri(), response)`](GetVipsRequest::parse_response) use super::*; use helix::RequestGet; +use std::borrow::Cow; /// Query Parameters for [Get VIPs](super::get_vips) /// @@ -43,13 +44,15 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetVipsRequest { +pub struct GetVipsRequest<'a> { /// The ID of the broadcaster whose list of VIPs you want to get. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Filters the list for specific VIPs. To specify more than one user, include the user_id parameter for each user to get. For example, &user_id=1234&user_id=5678. The maximum number of IDs that you may specify is 100. Ignores those users in the list that aren’t VIPs. #[cfg_attr(feature = "typed-builder", builder(default))] - pub user_id: Vec, + #[serde(borrow)] + pub user_id: Cow<'a, [&'a types::UserIdRef]>, /// The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100. The default is 20. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub first: Option, @@ -58,12 +61,12 @@ pub struct GetVipsRequest { pub after: Option, } -impl GetVipsRequest { +impl<'a> GetVipsRequest<'a> { /// Get channel VIPs in channel - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), - user_id: vec![], + user_id: Cow::Borrowed(&[]), first: None, after: None, } @@ -75,18 +78,10 @@ impl GetVipsRequest { self } - /// Filter response with this ID - pub fn user_id(self, user_id: impl Into) -> Self { - Self { - user_id: vec![user_id.into()], - ..self - } - } - /// Filter response with these IDs - pub fn user_ids(self, user_ids: impl IntoIterator>) -> Self { + pub fn user_ids(self, user_ids: impl Into>) -> Self { Self { - user_id: user_ids.into_iter().map(Into::into).collect(), + user_id: user_ids.into(), ..self } } @@ -107,7 +102,7 @@ pub struct Vip { pub user_login: types::UserName, } -impl Request for GetVipsRequest { +impl Request for GetVipsRequest<'_> { type Response = Vec; const PATH: &'static str = "channels/vips"; @@ -115,11 +110,11 @@ impl Request for GetVipsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelReadVips]; } -impl helix::Paginated for GetVipsRequest { +impl helix::Paginated for GetVipsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor; } } -impl RequestGet for GetVipsRequest {} +impl RequestGet for GetVipsRequest<'_> {} #[cfg(test)] #[test] @@ -159,7 +154,9 @@ fn test_request_all() { #[test] fn test_request_multiple() { use helix::*; - let req = GetVipsRequest::broadcaster_id("123").user_ids(["456", "678"]); + + let ids: &[&types::UserIdRef] = &["456".into(), "678".into()]; + let req = GetVipsRequest::broadcaster_id("123").user_ids(ids); // From twitch docs // FIXME: Example has ... diff --git a/src/helix/endpoints/channels/modify_channel_information.rs b/src/helix/endpoints/channels/modify_channel_information.rs index 9f2f78216d..cce5824504 100644 --- a/src/helix/endpoints/channels/modify_channel_information.rs +++ b/src/helix/endpoints/channels/modify_channel_information.rs @@ -61,15 +61,16 @@ use helix::RequestPatch; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct ModifyChannelInformationRequest { +pub struct ModifyChannelInformationRequest<'a> { /// ID of the channel #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, } -impl ModifyChannelInformationRequest { +impl<'a> ModifyChannelInformationRequest<'a> { /// Modify specified broadcasters channel - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { ModifyChannelInformationRequest { broadcaster_id: broadcaster_id.into(), } @@ -83,22 +84,22 @@ impl ModifyChannelInformationRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct ModifyChannelInformationBody { +pub struct ModifyChannelInformationBody<'a> { /// Current game ID being played on the channel. Use “0” or “” (an empty string) to unset the game. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub game_id: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub game_id: Option<&'a types::CategoryIdRef>, /// Language of the channel #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub broadcaster_language: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub broadcaster_language: Option<&'a str>, /// Title of the stream. Value must not be an empty string. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub title: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub title: Option<&'a str>, } -impl ModifyChannelInformationBody { +impl<'a> ModifyChannelInformationBody<'a> { /// Data to set on the stream. /// /// # Examples @@ -111,25 +112,25 @@ impl ModifyChannelInformationBody { pub fn new() -> Self { Default::default() } /// Current game ID being played on the channel. Use “0” or “” (an empty string) to unset the game. - pub fn game_id(&mut self, game_id: impl Into) -> &mut Self { + pub fn game_id(&mut self, game_id: impl Into<&'a types::CategoryIdRef>) -> &mut Self { self.game_id = Some(game_id.into()); self } /// Language of the channel - pub fn broadcaster_language(&mut self, broadcaster_language: impl Into) -> &mut Self { + pub fn broadcaster_language(&mut self, broadcaster_language: impl Into<&'a str>) -> &mut Self { self.broadcaster_language = Some(broadcaster_language.into()); self } /// Title of the stream. Value must not be an empty string. - pub fn title(&mut self, title: impl Into) -> &mut ModifyChannelInformationBody { + pub fn title(&'a mut self, title: impl Into<&'a str>) -> &'a mut ModifyChannelInformationBody { self.title = Some(title.into()); self } } -impl helix::private::SealedSerialize for ModifyChannelInformationBody {} +impl helix::private::SealedSerialize for ModifyChannelInformationBody<'_> {} /// Return Values for [Modify Channel Information](super::modify_channel_information) /// @@ -141,7 +142,7 @@ pub enum ModifyChannelInformation { Success, } -impl Request for ModifyChannelInformationRequest { +impl Request for ModifyChannelInformationRequest<'_> { type Response = ModifyChannelInformation; const PATH: &'static str = "channels"; @@ -149,8 +150,8 @@ impl Request for ModifyChannelInformationRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::UserEditBroadcast]; } -impl RequestPatch for ModifyChannelInformationRequest { - type Body = ModifyChannelInformationBody; +impl<'a> RequestPatch for ModifyChannelInformationRequest<'a> { + type Body = ModifyChannelInformationBody<'a>; fn parse_inner_response( request: Option, @@ -190,7 +191,7 @@ fn test_request() { let req = ModifyChannelInformationRequest::broadcaster_id("0"); let body = ModifyChannelInformationBody { - title: Some("Hello World!".to_string()), + title: Some("Hello World!".into()), ..Default::default() }; diff --git a/src/helix/endpoints/channels/remove_channel_vip.rs b/src/helix/endpoints/channels/remove_channel_vip.rs index a4e5dcf198..05fe3f973e 100644 --- a/src/helix/endpoints/channels/remove_channel_vip.rs +++ b/src/helix/endpoints/channels/remove_channel_vip.rs @@ -48,20 +48,22 @@ use helix::RequestDelete; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct RemoveChannelVipRequest { +pub struct RemoveChannelVipRequest<'a> { /// The ID of the broadcaster that’s removing VIP status from the user. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of the user to remove as a VIP from the broadcaster’s chat room. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub user_id: types::UserId, + #[serde(borrow)] + pub user_id: &'a types::UserIdRef, } -impl RemoveChannelVipRequest { +impl<'a> RemoveChannelVipRequest<'a> { /// Remove channel VIP pub fn new( - broadcaster_id: impl Into, - user_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + user_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -80,7 +82,7 @@ pub enum RemoveChannelVipResponse { Success, } -impl Request for RemoveChannelVipRequest { +impl Request for RemoveChannelVipRequest<'_> { type Response = RemoveChannelVipResponse; const PATH: &'static str = "channels/vips"; @@ -88,7 +90,7 @@ impl Request for RemoveChannelVipRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManageVips]; } -impl RequestDelete for RemoveChannelVipRequest { +impl RequestDelete for RemoveChannelVipRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, diff --git a/src/helix/endpoints/channels/start_commercial.rs b/src/helix/endpoints/channels/start_commercial.rs index f3ffa55c87..a2a3dc57b2 100644 --- a/src/helix/endpoints/channels/start_commercial.rs +++ b/src/helix/endpoints/channels/start_commercial.rs @@ -48,6 +48,8 @@ //! //! You can also get the [`http::Request`] with [`request.create_request(body, &token, &client_id)`](helix::RequestPost::create_request) //! and parse the [`http::Response`] with [`StartCommercialRequest::parse_response(None, &request.get_uri(), response)`](StartCommercialRequest::parse_response) +use std::marker::PhantomData; + use super::*; use helix::RequestPost; @@ -55,17 +57,16 @@ use helix::RequestPost; /// Query Parameters for [Start Commercial](super::start_commercial) /// /// [`start-commercial`](https://dev.twitch.tv/docs/api/reference#start-commercial) -#[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] +#[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[non_exhaustive] -pub struct StartCommercialRequest {} - -impl StartCommercialRequest { - /// Create a new [`StartCommercialRequest`] - pub fn new() -> Self { StartCommercialRequest {} } +pub struct StartCommercialRequest<'a> { + #[serde(skip)] + _marker: PhantomData<&'a ()>, } -impl Default for StartCommercialRequest { - fn default() -> Self { StartCommercialRequest::new() } +impl StartCommercialRequest<'_> { + /// Create a new [`StartCommercialRequest`] + pub fn new() -> Self { StartCommercialRequest::default() } } /// Body Parameters for [Start Commercial](super::start_commercial) @@ -74,18 +75,19 @@ impl Default for StartCommercialRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct StartCommercialBody { +pub struct StartCommercialBody<'a> { /// ID of the channel requesting a commercial #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Desired length of the commercial in seconds. Valid options are 30, 60, 90, 120, 150, 180. pub length: types::CommercialLength, } -impl StartCommercialBody { +impl<'a> StartCommercialBody<'a> { /// Start a commercial in this broadcasters channel pub fn new( - broadcaster_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, length: impl Into, ) -> Self { Self { @@ -110,7 +112,7 @@ pub struct StartCommercial { pub retry_after: u64, } -impl Request for StartCommercialRequest { +impl Request for StartCommercialRequest<'_> { /// FIXME: Make non-vec type Response = Vec; @@ -119,17 +121,17 @@ impl Request for StartCommercialRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelEditCommercial]; } -impl RequestPost for StartCommercialRequest { - type Body = StartCommercialBody; +impl<'a> RequestPost for StartCommercialRequest<'a> { + type Body = StartCommercialBody<'a>; } -impl helix::private::SealedSerialize for StartCommercialBody {} +impl helix::private::SealedSerialize for StartCommercialBody<'_> {} #[cfg(test)] #[test] fn test_request() { use helix::*; - let req = StartCommercialRequest {}; + let req = StartCommercialRequest::default(); let body = StartCommercialBody::new("1234", types::CommercialLength::Length120); diff --git a/src/helix/endpoints/chat/get_channel_chat_badges.rs b/src/helix/endpoints/chat/get_channel_chat_badges.rs index 6e40f5c17a..660911da24 100644 --- a/src/helix/endpoints/chat/get_channel_chat_badges.rs +++ b/src/helix/endpoints/chat/get_channel_chat_badges.rs @@ -46,15 +46,16 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetChannelChatBadgesRequest { +pub struct GetChannelChatBadgesRequest<'a> { /// The broadcaster whose chat badges are being requested. Provided broadcaster_id must match the user_id in the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, } -impl GetChannelChatBadgesRequest { +impl<'a> GetChannelChatBadgesRequest<'a> { /// Get chat badges for the specified broadcaster. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), } @@ -66,7 +67,7 @@ impl GetChannelChatBadgesRequest { /// [`get-channel-chat-badges`](https://dev.twitch.tv/docs/api/reference#get-channel-chat-badges) pub type GetChannelChatBadgesResponse = BadgeSet; -impl Request for GetChannelChatBadgesRequest { +impl Request for GetChannelChatBadgesRequest<'_> { type Response = Vec; const PATH: &'static str = "chat/badges"; @@ -74,7 +75,7 @@ impl Request for GetChannelChatBadgesRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetChannelChatBadgesRequest {} +impl RequestGet for GetChannelChatBadgesRequest<'_> {} #[cfg(test)] #[test] diff --git a/src/helix/endpoints/chat/get_channel_emotes.rs b/src/helix/endpoints/chat/get_channel_emotes.rs index 8696ac2e47..f0e8e71ede 100644 --- a/src/helix/endpoints/chat/get_channel_emotes.rs +++ b/src/helix/endpoints/chat/get_channel_emotes.rs @@ -46,15 +46,16 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetChannelEmotesRequest { +pub struct GetChannelEmotesRequest<'a> { /// The broadcaster whose emotes are being requested. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, } -impl GetChannelEmotesRequest { +impl<'a> GetChannelEmotesRequest<'a> { /// Get emotes in a specific broadcasters channel. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), } @@ -66,7 +67,7 @@ impl GetChannelEmotesRequest { /// [`get-channel-emotes`](https://dev.twitch.tv/docs/api/reference#get-channel-emotes) pub type GetChannelEmotesResponse = ChannelEmote; -impl Request for GetChannelEmotesRequest { +impl Request for GetChannelEmotesRequest<'_> { type Response = Vec; const PATH: &'static str = "chat/emotes"; @@ -74,7 +75,7 @@ impl Request for GetChannelEmotesRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetChannelEmotesRequest {} +impl RequestGet for GetChannelEmotesRequest<'_> {} #[cfg(test)] #[test] diff --git a/src/helix/endpoints/chat/get_chat_settings.rs b/src/helix/endpoints/chat/get_chat_settings.rs index 786c24f530..31d1cb4b61 100644 --- a/src/helix/endpoints/chat/get_chat_settings.rs +++ b/src/helix/endpoints/chat/get_chat_settings.rs @@ -61,10 +61,11 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetChatSettingsRequest { +pub struct GetChatSettingsRequest<'a> { /// The ID of the broadcaster whose chat settings you want to get. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Required only to access the [`non_moderator_chat_delay`](ChatSettings::non_moderator_chat_delay) /// or [`non_moderator_chat_delay_duration`](ChatSettings::non_moderator_chat_delay_duration) settings. /// If you want to access these settings, you need to provide a valid [`moderator_id`](Self::moderator_id) @@ -77,12 +78,13 @@ pub struct GetChatSettingsRequest { /// If the broadcaster wants to get their own settings (instead of having the moderator do it), /// set this parameter to the broadcaster’s ID, too. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub moderator_id: Option, + #[serde(borrow)] + pub moderator_id: Option<&'a types::UserIdRef>, } -impl GetChatSettingsRequest { +impl<'a> GetChatSettingsRequest<'a> { /// Get chat settings for broadcasters channel - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), moderator_id: None, @@ -93,13 +95,13 @@ impl GetChatSettingsRequest { /// /// Required only to access the [`non_moderator_chat_delay`](ChatSettings::non_moderator_chat_delay) /// or [`non_moderator_chat_delay_duration`](ChatSettings::non_moderator_chat_delay_duration) settings. - pub fn moderator_id(mut self, moderator_id: impl Into) -> Self { + pub fn moderator_id(mut self, moderator_id: impl Into<&'a types::UserIdRef>) -> Self { self.moderator_id = Some(moderator_id.into()); self } } -impl Request for GetChatSettingsRequest { +impl Request for GetChatSettingsRequest<'_> { type Response = ChatSettings; #[cfg(feature = "twitch_oauth2")] @@ -110,7 +112,7 @@ impl Request for GetChatSettingsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetChatSettingsRequest { +impl RequestGet for GetChatSettingsRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, diff --git a/src/helix/endpoints/chat/get_chatters.rs b/src/helix/endpoints/chat/get_chatters.rs index c06b989db9..b630f39119 100644 --- a/src/helix/endpoints/chat/get_chatters.rs +++ b/src/helix/endpoints/chat/get_chatters.rs @@ -52,15 +52,17 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetChattersRequest { +pub struct GetChattersRequest<'a> { /// The ID of the broadcaster whose list of chatters you want to get. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of the moderator or the specified broadcaster that’s requesting the list of chatters. This ID must match the user ID associated with the user access token. /// /// The moderator must have permission to moderate the broadcaster’s chat room. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub moderator_id: types::UserId, + #[serde(borrow)] + pub moderator_id: &'a types::UserIdRef, /// The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 1,000. The default is 100. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub first: Option, @@ -69,15 +71,15 @@ pub struct GetChattersRequest { pub after: Option, } -impl GetChattersRequest { +impl<'a> GetChattersRequest<'a> { /// Get chatters in broadcasters channel /// /// # Notes /// /// The moderator has to be the token owner and can moderate the chat pub fn new( - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + moderator_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -94,7 +96,7 @@ impl GetChattersRequest { } } -impl helix::Paginated for GetChattersRequest { +impl helix::Paginated for GetChattersRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } @@ -109,7 +111,7 @@ pub struct Chatter { pub user_login: types::UserName, } -impl Request for GetChattersRequest { +impl Request for GetChattersRequest<'_> { type Response = Vec; const PATH: &'static str = "chat/chatters"; @@ -117,7 +119,7 @@ impl Request for GetChattersRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetChattersRequest {} +impl RequestGet for GetChattersRequest<'_> {} #[cfg(test)] #[test] diff --git a/src/helix/endpoints/chat/get_emote_sets.rs b/src/helix/endpoints/chat/get_emote_sets.rs index b663ae7f25..4ed6085bb1 100644 --- a/src/helix/endpoints/chat/get_emote_sets.rs +++ b/src/helix/endpoints/chat/get_emote_sets.rs @@ -39,6 +39,7 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; /// Query Parameters for [Get Channel Emotes](super::get_emote_sets) /// @@ -46,27 +47,19 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetEmoteSetsRequest { +pub struct GetEmoteSetsRequest<'a> { // FIXME: twitch doc specifies maximum as 25, but it actually is 10 /// The broadcaster whose emotes are being requested. Minimum: 1. Maximum: 10 #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub emote_set_id: Vec, + #[serde(borrow)] + pub emote_set_id: Cow<'a, [&'a types::EmoteSetIdRef]>, } -impl GetEmoteSetsRequest { - /// Get emotes in this set - pub fn emote_set_id(emote_set_id: impl Into) -> Self { - Self { - emote_set_id: vec![emote_set_id.into()], - } - } - +impl<'a> GetEmoteSetsRequest<'a> { /// Get emotes in these sets - pub fn emote_set_ids( - emote_set_ids: impl IntoIterator>, - ) -> Self { + pub fn emote_set_ids(emote_set_ids: impl Into>) -> Self { Self { - emote_set_id: emote_set_ids.into_iter().map(Into::into).collect(), + emote_set_id: emote_set_ids.into(), } } } @@ -120,7 +113,7 @@ impl Emote { pub fn url(&self) -> types::EmoteUrlBuilder<'_> { EmoteUrlBuilder::new(&self.id) } } -impl Request for GetEmoteSetsRequest { +impl Request for GetEmoteSetsRequest<'_> { type Response = Vec; const PATH: &'static str = "chat/emotes/set"; @@ -128,13 +121,15 @@ impl Request for GetEmoteSetsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetEmoteSetsRequest {} +impl RequestGet for GetEmoteSetsRequest<'_> {} #[cfg(test)] #[test] fn test_request() { use helix::*; - let req = GetEmoteSetsRequest::emote_set_id("301590448"); + + let ids: &[&types::EmoteSetIdRef] = &["301590448".into()]; + let req = GetEmoteSetsRequest::emote_set_ids(ids); // From twitch docs // FIXME: Example has ... and is malformed, uses [] in images diff --git a/src/helix/endpoints/chat/get_user_chat_color.rs b/src/helix/endpoints/chat/get_user_chat_color.rs index da779abb9e..01fa38c773 100644 --- a/src/helix/endpoints/chat/get_user_chat_color.rs +++ b/src/helix/endpoints/chat/get_user_chat_color.rs @@ -39,6 +39,7 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; /// Query Parameters for [Get Chatters](super::get_user_chat_color) /// @@ -46,23 +47,17 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetUserChatColorRequest { +pub struct GetUserChatColorRequest<'a> { /// The ID of the user whose color you want to get. - pub user_id: Vec, + #[serde(borrow)] + pub user_id: Cow<'a, [&'a types::UserIdRef]>, } -impl GetUserChatColorRequest { - /// Get chat color of specified user - pub fn user_id(user_id: impl Into) -> Self { - Self { - user_id: vec![user_id.into()], - } - } - +impl<'a> GetUserChatColorRequest<'a> { /// Get chat colors of specified users - pub fn user_ids(user_ids: impl IntoIterator>) -> Self { + pub fn user_ids(user_ids: impl Into>) -> Self { Self { - user_id: user_ids.into_iter().map(Into::into).collect(), + user_id: user_ids.into(), } } } @@ -90,7 +85,7 @@ pub struct UserChatColor { pub color: Option, } -impl Request for GetUserChatColorRequest { +impl Request for GetUserChatColorRequest<'_> { type Response = Vec; const PATH: &'static str = "chat/color"; @@ -98,13 +93,14 @@ impl Request for GetUserChatColorRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetUserChatColorRequest {} +impl RequestGet for GetUserChatColorRequest<'_> {} #[cfg(test)] #[test] fn test_request() { use helix::*; - let req = GetUserChatColorRequest::user_ids(["11111", "44444"]); + let ids: &[&types::UserIdRef] = &["11111".into(), "44444".into()]; + let req = GetUserChatColorRequest::user_ids(ids); // From twitch docs // FIXME: Example has ... diff --git a/src/helix/endpoints/chat/send_chat_announcement.rs b/src/helix/endpoints/chat/send_chat_announcement.rs index a72c39888b..facb28bdc5 100644 --- a/src/helix/endpoints/chat/send_chat_announcement.rs +++ b/src/helix/endpoints/chat/send_chat_announcement.rs @@ -63,22 +63,24 @@ use helix::RequestPost; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct SendChatAnnouncementRequest { +pub struct SendChatAnnouncementRequest<'a> { /// The ID of the broadcaster that owns the chat room to send the announcement to. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of a user who has permission to moderate the broadcaster’s chat room. /// /// This ID must match the user ID in the OAuth token, which can be a moderator or the broadcaster. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub moderator_id: types::UserId, + #[serde(borrow)] + pub moderator_id: &'a types::UserIdRef, } -impl SendChatAnnouncementRequest { +impl<'a> SendChatAnnouncementRequest<'a> { /// Send announcement in channel as this moderator pub fn new( - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + moderator_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -93,9 +95,10 @@ impl SendChatAnnouncementRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct SendChatAnnouncementBody { +pub struct SendChatAnnouncementBody<'a> { /// The announcement to make in the broadcaster’s chat room. Announcements are limited to a maximum of 500 characters; announcements longer than 500 characters are truncated. - pub message: String, + #[serde(borrow)] + pub message: &'a str, // FIXME: Enumify? /// The color used to highlight the announcement. Possible case-sensitive values are: /// @@ -110,10 +113,10 @@ pub struct SendChatAnnouncementBody { pub color: AnnouncementColor, } -impl SendChatAnnouncementBody { +impl<'a> SendChatAnnouncementBody<'a> { /// Create a new announcement with specified color pub fn new( - message: String, + message: &'a str, color: impl std::convert::TryInto, ) -> Result { Ok(Self { @@ -123,13 +126,13 @@ impl SendChatAnnouncementBody { } } -impl helix::private::SealedSerialize for SendChatAnnouncementBody {} +impl helix::private::SealedSerialize for SendChatAnnouncementBody<'_> {} -impl helix::HelixRequestBody for Vec { +impl<'a> helix::HelixRequestBody for [SendChatAnnouncementBody<'a>] { fn try_to_body(&self) -> Result { #[derive(Serialize)] struct InnerBody<'a> { - data: &'a Vec, + data: &'a [SendChatAnnouncementBody<'a>], } serde_json::to_vec(&InnerBody { data: self }) @@ -149,7 +152,7 @@ pub enum SendChatAnnouncementResponse { Success, } -impl Request for SendChatAnnouncementRequest { +impl Request for SendChatAnnouncementRequest<'_> { // FIXME: this is a single entry type Response = SendChatAnnouncementResponse; @@ -159,8 +162,8 @@ impl Request for SendChatAnnouncementRequest { &[twitch_oauth2::Scope::ModeratorManageAnnouncements]; } -impl RequestPost for SendChatAnnouncementRequest { - type Body = SendChatAnnouncementBody; +impl<'a> RequestPost for SendChatAnnouncementRequest<'a> { + type Body = SendChatAnnouncementBody<'a>; fn parse_inner_response<'d>( request: Option, @@ -195,7 +198,7 @@ fn test_request() { use helix::*; let req = SendChatAnnouncementRequest::new("1234", "5678"); - let body = SendChatAnnouncementBody::new("hello chat!".to_owned(), "purple").unwrap(); + let body = SendChatAnnouncementBody::new("hello chat!", "purple").unwrap(); dbg!(req.create_request(body, "token", "clientid").unwrap()); diff --git a/src/helix/endpoints/chat/update_chat_settings.rs b/src/helix/endpoints/chat/update_chat_settings.rs index 6df7f3b6d3..f7f04163fe 100644 --- a/src/helix/endpoints/chat/update_chat_settings.rs +++ b/src/helix/endpoints/chat/update_chat_settings.rs @@ -67,24 +67,26 @@ use helix::RequestPatch; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct UpdateChatSettingsRequest { +pub struct UpdateChatSettingsRequest<'a> { /// The ID of the broadcaster whose chat settings you want to update. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of a user that has permission to moderate the broadcaster’s chat room. /// This ID must match the user ID associated with the user OAuth token. /// /// If the broadcaster is making the update, also set this parameter to the broadcaster’s ID. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub moderator_id: types::UserId, + #[serde(borrow)] + pub moderator_id: &'a types::UserIdRef, } ///FIXME: The moderator_id parameter is redundant, we should make this a client ext function -impl UpdateChatSettingsRequest { +impl<'a> UpdateChatSettingsRequest<'a> { /// Update the chat settings for the specified broadcaster as the specified moderator pub fn new( - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + moderator_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -175,7 +177,7 @@ impl helix::private::SealedSerialize for UpdateChatSettingsBody {} /// [`update-chat-settings`](https://dev.twitch.tv/docs/api/reference#update-chat-settings) pub type UpdateChatSettingsResponse = ChatSettings; -impl Request for UpdateChatSettingsRequest { +impl Request for UpdateChatSettingsRequest<'_> { type Response = ChatSettings; const PATH: &'static str = "chat/settings"; @@ -184,7 +186,7 @@ impl Request for UpdateChatSettingsRequest { &[twitch_oauth2::Scope::ModeratorManageChatSettings]; } -impl RequestPatch for UpdateChatSettingsRequest { +impl RequestPatch for UpdateChatSettingsRequest<'_> { type Body = UpdateChatSettingsBody; fn parse_inner_response( diff --git a/src/helix/endpoints/chat/update_user_chat_color.rs b/src/helix/endpoints/chat/update_user_chat_color.rs index 3a02535f2b..8b2e12ba35 100644 --- a/src/helix/endpoints/chat/update_user_chat_color.rs +++ b/src/helix/endpoints/chat/update_user_chat_color.rs @@ -49,19 +49,23 @@ use helix::RequestPut; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct UpdateUserChatColorRequest { +pub struct UpdateUserChatColorRequest<'a> { /// The ID of the user whose chat color you want to update. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub user_id: types::UserId, + #[serde(borrow)] + pub user_id: &'a types::UserIdRef, /// The color to use for the user’s name in chat. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] #[serde(borrow = "'static")] pub color: types::NamedUserColor<'static>, } -impl UpdateUserChatColorRequest { +impl<'a> UpdateUserChatColorRequest<'a> { /// Update the users chat color - pub fn new(user_id: impl Into, color: types::NamedUserColor<'static>) -> Self { + pub fn new( + user_id: impl Into<&'a types::UserIdRef>, + color: types::NamedUserColor<'static>, + ) -> Self { Self { user_id: user_id.into(), color, @@ -80,7 +84,7 @@ pub enum UpdateUserChatColorResponse { Success, } -impl Request for UpdateUserChatColorRequest { +impl Request for UpdateUserChatColorRequest<'_> { type Response = UpdateUserChatColorResponse; const PATH: &'static str = "chat/color"; @@ -88,7 +92,7 @@ impl Request for UpdateUserChatColorRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::UserManageChatColor]; } -impl RequestPut for UpdateUserChatColorRequest { +impl RequestPut for UpdateUserChatColorRequest<'_> { type Body = helix::EmptyBody; fn parse_inner_response<'d>( diff --git a/src/helix/endpoints/clips/get_clips.rs b/src/helix/endpoints/clips/get_clips.rs index 3d41d2d55f..92c103b823 100644 --- a/src/helix/endpoints/clips/get_clips.rs +++ b/src/helix/endpoints/clips/get_clips.rs @@ -39,6 +39,7 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; /// Query Parameters for [Get Clips](super::get_clips) /// @@ -46,36 +47,42 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetClipsRequest { +pub struct GetClipsRequest<'a> { /// ID of the broadcaster for whom clips are returned. The number of clips returned is determined by the first query-string parameter (default: 20). Results are ordered by view count. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub broadcaster_id: Option, + #[serde(borrow)] + pub broadcaster_id: Option<&'a types::UserIdRef>, /// ID of the game for which clips are returned. The number of clips returned is determined by the first query-string parameter (default: 20). Results are ordered by view count. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub game_id: Option, + #[serde(borrow)] + pub game_id: Option<&'a types::CategoryIdRef>, // FIXME: add types::ClipId /// ID of the clip being queried. Limit: 100. #[cfg_attr(feature = "typed-builder", builder(default))] - pub id: Vec, + #[serde(borrow)] + pub id: Cow<'a, [&'a types::ClipIdRef]>, // one of above is needed. /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. This applies only to queries specifying broadcaster_id or game_id. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, /// Cursor for backward pagination: tells the server where to start fetching the next set of results, in a multi-page response. This applies only to queries specifying broadcaster_id or game_id. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] - pub before: Option, + #[serde(borrow)] + pub before: Option<&'a helix::CursorRef>, /// Ending date/time for returned clips, in RFC3339 format. (Note that the seconds value is ignored.) If this is specified, started_at also must be specified; otherwise, the time period is ignored. #[cfg_attr(feature = "typed-builder", builder(default))] - pub ended_at: Option, + #[serde(borrow)] + pub ended_at: Option<&'a types::TimestampRef>, /// Maximum number of objects to return. Maximum: 100. Default: 20. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub first: Option, /// Starting date/time for returned clips, in RFC3339 format. (Note that the seconds value is ignored.) If this is specified, ended_at also should be specified; otherwise, the ended_at date/time will be 1 week after the started_at value. #[cfg_attr(feature = "typed-builder", builder(default))] - pub started_at: Option, + #[serde(borrow)] + pub started_at: Option<&'a types::TimestampRef>, } -impl GetClipsRequest { +impl<'a> GetClipsRequest<'a> { /// An empty request /// /// # Notes @@ -85,7 +92,7 @@ impl GetClipsRequest { Self { broadcaster_id: Default::default(), game_id: Default::default(), - id: Default::default(), + id: Cow::Borrowed(&[]), after: Default::default(), before: Default::default(), ended_at: Default::default(), @@ -95,7 +102,7 @@ impl GetClipsRequest { } /// Broadcaster for whom clips are returned. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: Some(broadcaster_id.into()), ..Self::empty() @@ -103,37 +110,29 @@ impl GetClipsRequest { } /// Game for which clips are returned. - pub fn game_id(game_id: impl Into) -> Self { + pub fn game_id(game_id: impl Into<&'a types::CategoryIdRef>) -> Self { Self { game_id: Some(game_id.into()), ..Self::empty() } } - /// ID of clip being queried - pub fn clip_id(clip_id: impl Into) -> Self { - Self { - id: vec![clip_id.into()], - ..Self::empty() - } - } - /// IDs of clips being queried - pub fn clip_ids(clip_ids: impl IntoIterator>) -> Self { + pub fn clip_ids(clip_ids: impl Into>) -> Self { Self { - id: clip_ids.into_iter().map(Into::into).collect(), + id: clip_ids.into(), ..Self::empty() } } /// Ending date/time for the returned clips - pub fn started_at(&mut self, started_at: impl Into) -> &mut Self { + pub fn started_at(&mut self, started_at: impl Into<&'a types::TimestampRef>) -> &mut Self { self.started_at = Some(started_at.into()); self } /// Ending date/time for the returned clips - pub fn ended_at(&mut self, ended_at: impl Into) -> &mut Self { + pub fn ended_at(&mut self, ended_at: impl Into<&'a types::TimestampRef>) -> &mut Self { self.ended_at = Some(ended_at.into()); self } @@ -182,7 +181,7 @@ pub struct Clip { pub vod_offset: Option, } -impl Request for GetClipsRequest { +impl Request for GetClipsRequest<'_> { type Response = Vec; const PATH: &'static str = "clips"; @@ -190,9 +189,9 @@ impl Request for GetClipsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetClipsRequest {} +impl RequestGet for GetClipsRequest<'_> {} -impl helix::Paginated for GetClipsRequest { +impl helix::Paginated for GetClipsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } @@ -200,7 +199,8 @@ impl helix::Paginated for GetClipsRequest { #[test] fn test_request() { use helix::*; - let req = GetClipsRequest::clip_id(String::from("AwkwardHelplessSalamanderSwiftRage")); + + let req = GetClipsRequest::clip_ids(vec!["AwkwardHelplessSalamanderSwiftRage".into()]); // From twitch docs let data = br#" diff --git a/src/helix/endpoints/eventsub/create_eventsub_subscription.rs b/src/helix/endpoints/eventsub/create_eventsub_subscription.rs index 37ccd669b8..f45412e226 100644 --- a/src/helix/endpoints/eventsub/create_eventsub_subscription.rs +++ b/src/helix/endpoints/eventsub/create_eventsub_subscription.rs @@ -53,7 +53,7 @@ pub struct CreateEventSubSubscriptionBody { pub transport: Transport, } -impl helix::HelixRequestBody for CreateEventSubSubscriptionBody { +impl<'a, E: EventSubscription> helix::HelixRequestBody for CreateEventSubSubscriptionBody { fn try_to_body(&self) -> Result { #[derive(PartialEq, Serialize, Debug)] struct IEventSubRequestBody<'a> { @@ -76,8 +76,8 @@ impl helix::HelixRequestBody for CreateEventSubSubscriptio // FIXME: Builder? impl CreateEventSubSubscriptionBody { /// Create a new [`CreateEventSubSubscriptionBody`] - pub fn new(subscription: E, transport: Transport) -> CreateEventSubSubscriptionBody { - CreateEventSubSubscriptionBody { + pub fn new(subscription: E, transport: Transport) -> Self { + Self { subscription, transport, } @@ -194,14 +194,13 @@ fn test_request() { let req: CreateEventSubSubscriptionRequest = CreateEventSubSubscriptionRequest::default(); - let body = CreateEventSubSubscriptionBody::new( - UserUpdateV1::new("1234"), - eventsub::Transport { - method: eventsub::TransportMethod::Webhook, - callback: "example.com".to_string(), - secret: "heyhey13".to_string(), - }, - ); + let sub = UserUpdateV1::new("1234"); + let transport = eventsub::Transport { + method: eventsub::TransportMethod::Webhook, + callback: "example.com".to_string(), + secret: "heyhey13".to_string(), + }; + let body = CreateEventSubSubscriptionBody::new(sub, transport); dbg!(req.create_request(body, "token", "clientid").unwrap()); diff --git a/src/helix/endpoints/eventsub/delete_eventsub_subscription.rs b/src/helix/endpoints/eventsub/delete_eventsub_subscription.rs index 5dec9c4b96..fd2a168f7c 100644 --- a/src/helix/endpoints/eventsub/delete_eventsub_subscription.rs +++ b/src/helix/endpoints/eventsub/delete_eventsub_subscription.rs @@ -9,18 +9,19 @@ use helix::RequestDelete; #[derive(PartialEq, Eq, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct DeleteEventSubSubscriptionRequest { +pub struct DeleteEventSubSubscriptionRequest<'a> { /// The subscription ID for the subscription you want to delete. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub id: types::EventSubId, + #[serde(borrow)] + pub id: &'a types::EventSubIdRef, } -impl DeleteEventSubSubscriptionRequest { +impl<'a> DeleteEventSubSubscriptionRequest<'a> { /// Delete this eventsub subscription. - pub fn id(id: impl Into) -> Self { Self { id: id.into() } } + pub fn id(id: impl Into<&'a types::EventSubIdRef>) -> Self { Self { id: id.into() } } } -impl Request for DeleteEventSubSubscriptionRequest { +impl Request for DeleteEventSubSubscriptionRequest<'_> { type Response = DeleteEventSubSubscription; const PATH: &'static str = "eventsub/subscriptions"; @@ -38,7 +39,7 @@ pub enum DeleteEventSubSubscription { Success, } -impl RequestDelete for DeleteEventSubSubscriptionRequest { +impl RequestDelete for DeleteEventSubSubscriptionRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, diff --git a/src/helix/endpoints/eventsub/get_eventsub_subscriptions.rs b/src/helix/endpoints/eventsub/get_eventsub_subscriptions.rs index 0feb687906..63a187707c 100644 --- a/src/helix/endpoints/eventsub/get_eventsub_subscriptions.rs +++ b/src/helix/endpoints/eventsub/get_eventsub_subscriptions.rs @@ -10,7 +10,7 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetEventSubSubscriptionsRequest { +pub struct GetEventSubSubscriptionsRequest<'a> { /// Include this parameter to filter subscriptions by their status. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub status: Option, @@ -22,7 +22,8 @@ pub struct GetEventSubSubscriptionsRequest { /// The response contains subscriptions where the user ID /// matches a user ID that you specified in the Condition object when you created the subscription. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub user_id: Option, + #[serde(borrow)] + pub user_id: Option<&'a types::UserIdRef>, // FIXME: https://github.com/twitchdev/issues/issues/272 /// Cursor for forward pagination #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] @@ -33,7 +34,7 @@ pub struct GetEventSubSubscriptionsRequest { pub first: Option, } -impl GetEventSubSubscriptionsRequest { +impl GetEventSubSubscriptionsRequest<'_> { /// Get eventsub subscriptions by this status pub fn status(status: impl Into) -> Self { Self { @@ -51,7 +52,7 @@ impl GetEventSubSubscriptionsRequest { } } -impl Request for GetEventSubSubscriptionsRequest { +impl Request for GetEventSubSubscriptionsRequest<'_> { type Response = EventSubSubscriptions; const PATH: &'static str = "eventsub/subscriptions"; @@ -76,7 +77,7 @@ pub struct EventSubSubscriptions { pub subscriptions: Vec, } -impl RequestGet for GetEventSubSubscriptionsRequest { +impl RequestGet for GetEventSubSubscriptionsRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, @@ -122,7 +123,7 @@ impl RequestGet for GetEventSubSubscriptionsRequest { } } -impl helix::Paginated for GetEventSubSubscriptionsRequest { +impl helix::Paginated for GetEventSubSubscriptionsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/games/get_games.rs b/src/helix/endpoints/games/get_games.rs index ccd8d2f66d..0b010d6795 100644 --- a/src/helix/endpoints/games/get_games.rs +++ b/src/helix/endpoints/games/get_games.rs @@ -35,6 +35,7 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; /// Query Parameters for [Get Games](super::get_games) /// @@ -42,44 +43,30 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetGamesRequest { +pub struct GetGamesRequest<'a> { /// Game ID. At most 100 id values can be specified. #[cfg_attr(feature = "typed-builder", builder(default))] - pub id: Vec, + #[serde(borrow)] + pub id: Cow<'a, [&'a types::CategoryIdRef]>, /// Game name. The name must be an exact match. For instance, “Pokemon” will not return a list of Pokemon games; instead, query the specific Pokemon game(s) in which you are interested. At most 100 name values can be specified. #[cfg_attr(feature = "typed-builder", builder(default))] - pub name: Vec, + #[serde(borrow)] + pub name: Cow<'a, [&'a str]>, } -impl GetGamesRequest { - /// Get game with specific exact name match. - pub fn name(name: impl Into) -> Self { - Self { - name: vec![name.into()], - ..Self::empty() - } - } - +impl<'a> GetGamesRequest<'a> { /// Get games with specific exact name match. - pub fn names(names: impl IntoIterator) -> Self { - Self { - name: names.into_iter().collect(), - ..Self::empty() - } - } - - /// Get game with specific exact id match. - pub fn id(id: impl Into) -> Self { + pub fn names(names: impl Into>) -> Self { Self { - id: vec![id.into()], + name: names.into(), ..Self::empty() } } /// Get games with specific exact id match. - pub fn ids(ids: impl IntoIterator>) -> Self { + pub fn ids(ids: impl Into>) -> Self { Self { - id: ids.into_iter().map(Into::into).collect(), + id: ids.into(), ..Self::empty() } } @@ -87,8 +74,8 @@ impl GetGamesRequest { /// Returns an empty [`GetGamesRequest`] fn empty() -> Self { Self { - id: Default::default(), - name: Default::default(), + id: Cow::Borrowed(&[]), + name: Cow::Borrowed(&[]), } } } @@ -98,7 +85,7 @@ impl GetGamesRequest { /// [`get-games`](https://dev.twitch.tv/docs/api/reference#get-games) pub type Game = types::TwitchCategory; -impl Request for GetGamesRequest { +impl Request for GetGamesRequest<'_> { type Response = Vec; const PATH: &'static str = "games"; @@ -106,13 +93,13 @@ impl Request for GetGamesRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetGamesRequest {} +impl RequestGet for GetGamesRequest<'_> {} #[cfg(test)] #[test] fn test_request() { use helix::*; - let req = GetGamesRequest::id("493057"); + let req = GetGamesRequest::ids(vec!["493057".into()]); // From twitch docs let data = br#" diff --git a/src/helix/endpoints/games/get_top_games.rs b/src/helix/endpoints/games/get_top_games.rs index 6d2feb5627..d3bddacfb1 100644 --- a/src/helix/endpoints/games/get_top_games.rs +++ b/src/helix/endpoints/games/get_top_games.rs @@ -45,19 +45,20 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetTopGamesRequest { +pub struct GetTopGamesRequest<'a> { /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub after: Option, /// Cursor for backward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub before: Option, + #[serde(borrow)] + pub before: Option<&'a helix::CursorRef>, /// Maximum number of objects to return. Maximum: 100. Default: 20. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub first: Option, } -impl GetTopGamesRequest { +impl GetTopGamesRequest<'_> { /// Set amount of results returned per page. pub fn first(mut self, first: usize) -> Self { self.first = Some(first); @@ -70,7 +71,7 @@ impl GetTopGamesRequest { /// [`get-top-games`](https://dev.twitch.tv/docs/api/reference#get-top-games) pub type Game = types::TwitchCategory; -impl Request for GetTopGamesRequest { +impl Request for GetTopGamesRequest<'_> { type Response = Vec; const PATH: &'static str = "games/top"; @@ -78,9 +79,9 @@ impl Request for GetTopGamesRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetTopGamesRequest {} +impl RequestGet for GetTopGamesRequest<'_> {} -impl helix::Paginated for GetTopGamesRequest { +impl helix::Paginated for GetTopGamesRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/goals/get_creator_goals.rs b/src/helix/endpoints/goals/get_creator_goals.rs index fc8587a5dc..588d2d5271 100644 --- a/src/helix/endpoints/goals/get_creator_goals.rs +++ b/src/helix/endpoints/goals/get_creator_goals.rs @@ -46,10 +46,11 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetCreatorGoalsRequest { +pub struct GetCreatorGoalsRequest<'a> { /// Must match the User ID in the Bearer token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub cursor: Option, @@ -58,12 +59,13 @@ pub struct GetCreatorGoalsRequest { pub first: Option, /// Retreive a single event by event ID #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub id: Option, + #[serde(borrow)] + pub id: Option<&'a str>, } -impl GetCreatorGoalsRequest { +impl<'a> GetCreatorGoalsRequest<'a> { /// Gets the broadcaster’s list of active goals. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), cursor: Default::default(), @@ -107,7 +109,7 @@ pub struct CreatorGoal { pub created_at: types::Timestamp, } -impl Request for GetCreatorGoalsRequest { +impl Request for GetCreatorGoalsRequest<'_> { type Response = Vec; const PATH: &'static str = "goals"; @@ -115,7 +117,7 @@ impl Request for GetCreatorGoalsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelReadGoals]; } -impl RequestGet for GetCreatorGoalsRequest {} +impl RequestGet for GetCreatorGoalsRequest<'_> {} #[cfg(test)] #[test] diff --git a/src/helix/endpoints/hypetrain/get_hypetrain_events.rs b/src/helix/endpoints/hypetrain/get_hypetrain_events.rs index 7595cc7655..43547cd6ae 100644 --- a/src/helix/endpoints/hypetrain/get_hypetrain_events.rs +++ b/src/helix/endpoints/hypetrain/get_hypetrain_events.rs @@ -47,10 +47,11 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetHypeTrainEventsRequest { +pub struct GetHypeTrainEventsRequest<'a> { /// Must match the User ID in the Bearer token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub cursor: Option, @@ -63,12 +64,13 @@ pub struct GetHypeTrainEventsRequest { note = "this does nothing, see https://discuss.dev.twitch.tv/t/get-hype-train-events-api-endpoint-id-query-parameter-deprecation/37613" )] #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub id: Option, + #[serde(borrow)] + pub id: Option<&'a str>, } -impl GetHypeTrainEventsRequest { +impl<'a> GetHypeTrainEventsRequest<'a> { /// Get hypetrain evens - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), cursor: Default::default(), @@ -134,7 +136,7 @@ pub struct HypeTrainEventData { pub id: types::HypeTrainId, } -impl Request for GetHypeTrainEventsRequest { +impl Request for GetHypeTrainEventsRequest<'_> { type Response = Vec; const PATH: &'static str = "hypetrain/events"; @@ -142,9 +144,9 @@ impl Request for GetHypeTrainEventsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetHypeTrainEventsRequest {} +impl RequestGet for GetHypeTrainEventsRequest<'_> {} -impl helix::Paginated for GetHypeTrainEventsRequest { +impl helix::Paginated for GetHypeTrainEventsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.cursor = cursor } } diff --git a/src/helix/endpoints/moderation/add_blocked_term.rs b/src/helix/endpoints/moderation/add_blocked_term.rs index e2a1314710..0195a55b0c 100644 --- a/src/helix/endpoints/moderation/add_blocked_term.rs +++ b/src/helix/endpoints/moderation/add_blocked_term.rs @@ -59,22 +59,24 @@ use helix::RequestPost; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct AddBlockedTermRequest { +pub struct AddBlockedTermRequest<'a> { /// The ID of the broadcaster that owns the list of blocked terms. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID associated with the user OAuth token. /// /// If the broadcaster wants to add the blocked term (instead of having the moderator do it), set this parameter to the broadcaster’s ID, too. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub moderator_id: types::UserId, + #[serde(borrow)] + pub moderator_id: &'a types::UserIdRef, } -impl AddBlockedTermRequest { +impl<'a> AddBlockedTermRequest<'a> { /// Where to add blocked term pub fn new( - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + moderator_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -89,26 +91,27 @@ impl AddBlockedTermRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct AddBlockedTermBody { +pub struct AddBlockedTermBody<'a> { ///The word or phrase to block from being used in the broadcaster’s chat room. /// /// The term must contain a minimum of 2 characters and may contain up to a maximum of 500 characters. /// Terms can use a wildcard character (*). The wildcard character must appear at the beginning or end of a word, or set of characters. For example, *foo or foo*. - pub text: String, + #[serde(borrow)] + pub text: &'a str, } -impl AddBlockedTermBody { +impl<'a> AddBlockedTermBody<'a> { /// Create a new [`AddBlockedTermBody`] - pub fn new(text: String) -> Self { Self { text } } + pub fn new(text: &'a str) -> Self { Self { text } } } -impl helix::private::SealedSerialize for AddBlockedTermBody {} +impl helix::private::SealedSerialize for AddBlockedTermBody<'_> {} -impl helix::HelixRequestBody for Vec { +impl<'a> helix::HelixRequestBody for [AddBlockedTermBody<'a>] { fn try_to_body(&self) -> Result { #[derive(Serialize)] struct InnerBody<'a> { - data: &'a Vec, + data: &'a [AddBlockedTermBody<'a>], } serde_json::to_vec(&InnerBody { data: self }) @@ -122,7 +125,7 @@ impl helix::HelixRequestBody for Vec { /// [`add-blocked-term`](https://dev.twitch.tv/docs/api/reference#add-blocked-term) pub type AddBlockedTermResponse = BlockedTerm; -impl Request for AddBlockedTermRequest { +impl Request for AddBlockedTermRequest<'_> { // FIXME: this is a single entry type Response = Vec; @@ -132,8 +135,8 @@ impl Request for AddBlockedTermRequest { &[twitch_oauth2::Scope::ModeratorManageBlockedTerms]; } -impl RequestPost for AddBlockedTermRequest { - type Body = AddBlockedTermBody; +impl<'a> RequestPost for AddBlockedTermRequest<'a> { + type Body = AddBlockedTermBody<'a>; } #[cfg(test)] @@ -142,7 +145,7 @@ fn test_request() { use helix::*; let req = AddBlockedTermRequest::new("1234", "5678"); - let body = AddBlockedTermBody::new("A phrase I'm not fond of".to_string()); + let body = AddBlockedTermBody::new("A phrase I'm not fond of"); dbg!(req.create_request(body, "token", "clientid").unwrap()); diff --git a/src/helix/endpoints/moderation/add_channel_moderator.rs b/src/helix/endpoints/moderation/add_channel_moderator.rs index 73563c42fc..660ada22e3 100644 --- a/src/helix/endpoints/moderation/add_channel_moderator.rs +++ b/src/helix/endpoints/moderation/add_channel_moderator.rs @@ -49,20 +49,22 @@ use helix::RequestPost; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct AddChannelModeratorRequest { +pub struct AddChannelModeratorRequest<'a> { /// The ID of the broadcaster that owns the chat room. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of the user to add as a moderator in the broadcaster’s chat room. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub moderator_id: types::UserId, + #[serde(borrow)] + pub moderator_id: &'a types::UserIdRef, } -impl AddChannelModeratorRequest { +impl<'a> AddChannelModeratorRequest<'a> { /// Add moderator on channel pub fn new( - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + moderator_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -82,7 +84,7 @@ pub enum AddChannelModeratorResponse { Success, } -impl Request for AddChannelModeratorRequest { +impl Request for AddChannelModeratorRequest<'_> { type Response = AddChannelModeratorResponse; const PATH: &'static str = "moderation/moderators"; @@ -90,7 +92,7 @@ impl Request for AddChannelModeratorRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManageModerators]; } -impl RequestPost for AddChannelModeratorRequest { +impl RequestPost for AddChannelModeratorRequest<'_> { type Body = helix::EmptyBody; fn parse_inner_response<'d>( diff --git a/src/helix/endpoints/moderation/ban_user.rs b/src/helix/endpoints/moderation/ban_user.rs index 883ee5b28f..16a41c90d7 100644 --- a/src/helix/endpoints/moderation/ban_user.rs +++ b/src/helix/endpoints/moderation/ban_user.rs @@ -59,24 +59,26 @@ use helix::RequestPost; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct BanUserRequest { +pub struct BanUserRequest<'a> { /// The ID of the broadcaster whose chat room the user is being banned from. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of a user that has permission to moderate the broadcaster’s chat room. /// This ID must match the user ID associated with the user OAuth token. /// /// If the broadcaster wants to ban the user (instead of having the moderator do it), /// set this parameter to the broadcaster’s ID, too. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub moderator_id: types::UserId, + #[serde(borrow)] + pub moderator_id: &'a types::UserIdRef, } -impl BanUserRequest { +impl<'a> BanUserRequest<'a> { /// Ban a user on this channel pub fn new( - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + moderator_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -91,7 +93,7 @@ impl BanUserRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct BanUserBody { +pub struct BanUserBody<'a> { /// Duration of the (optional) timeout in seconds. /// /// To ban a user indefinitely, don’t include this field. @@ -104,17 +106,19 @@ pub struct BanUserBody { pub duration: Option, /// The reason the user is being banned or put in a timeout. The text is user defined and limited to a maximum of 500 characters. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub reason: String, + #[serde(borrow)] + pub reason: &'a str, /// The ID of the user to ban or put in a timeout. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub user_id: types::UserId, + #[serde(borrow)] + pub user_id: &'a types::UserIdRef, } -impl BanUserBody { +impl<'a> BanUserBody<'a> { /// Create a new [`BanUserBody`] pub fn new( - user_id: impl Into, - reason: String, + user_id: impl Into<&'a types::UserIdRef>, + reason: &'a str, duration: impl Into>, ) -> Self { Self { @@ -125,11 +129,11 @@ impl BanUserBody { } } -impl helix::HelixRequestBody for BanUserBody { +impl helix::HelixRequestBody for BanUserBody<'_> { fn try_to_body(&self) -> Result { #[derive(Serialize)] struct InnerBody<'a> { - data: &'a BanUserBody, + data: &'a BanUserBody<'a>, } serde_json::to_vec(&InnerBody { data: self }) .map_err(Into::into) @@ -156,7 +160,7 @@ pub struct BanUser { pub user_id: types::UserId, } -impl Request for BanUserRequest { +impl Request for BanUserRequest<'_> { type Response = BanUser; const PATH: &'static str = "moderation/bans"; @@ -165,8 +169,8 @@ impl Request for BanUserRequest { &[twitch_oauth2::Scope::ModeratorManageBannedUsers]; } -impl RequestPost for BanUserRequest { - type Body = BanUserBody; +impl<'a> RequestPost for BanUserRequest<'a> { + type Body = BanUserBody<'a>; fn parse_inner_response( request: Option, @@ -212,7 +216,7 @@ fn test_request() { use helix::*; let req = BanUserRequest::new("1234", "5678"); - let body = BanUserBody::new("9876", "no reason".to_string(), 300); + let body = BanUserBody::new("9876", "no reason", 300); dbg!(req.create_request(body, "token", "clientid").unwrap()); @@ -249,7 +253,7 @@ fn test_request_error() { use helix::*; let req = BanUserRequest::new("1234", "5678"); - let body = BanUserBody::new("9876", "no reason".to_string(), 300); + let body = BanUserBody::new("9876", "no reason", 300); dbg!(req.create_request(body, "token", "clientid").unwrap()); diff --git a/src/helix/endpoints/moderation/check_automod_status.rs b/src/helix/endpoints/moderation/check_automod_status.rs index 50ea62d9d0..ba3898f293 100644 --- a/src/helix/endpoints/moderation/check_automod_status.rs +++ b/src/helix/endpoints/moderation/check_automod_status.rs @@ -58,21 +58,23 @@ use super::*; use helix::RequestPost; + /// Query Parameters for [Check AutoMod Status](super::check_automod_status) /// /// [`check-automod-status`](https://dev.twitch.tv/docs/api/reference#check-automod-status) #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct CheckAutoModStatusRequest { +pub struct CheckAutoModStatusRequest<'a> { /// Must match the User ID in the Bearer token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, } -impl CheckAutoModStatusRequest { +impl<'a> CheckAutoModStatusRequest<'a> { /// Check automod status in this broadcasters channel. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), } @@ -85,26 +87,28 @@ impl CheckAutoModStatusRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct CheckAutoModStatusBody { +pub struct CheckAutoModStatusBody<'a> { /// Developer-generated identifier for mapping messages to results. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub msg_id: types::MsgId, + #[serde(borrow)] + pub msg_id: &'a types::MsgIdRef, /// Message text. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub msg_text: String, + #[serde(borrow)] + pub msg_text: &'a str, /// User ID of the sender. #[deprecated(since = "0.7.0", note = "user_id in automod check is no longer read")] #[cfg_attr( feature = "typed-builder", builder(setter(into, strip_option), default) )] - #[serde(skip_serializing_if = "Option::is_none")] - pub user_id: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub user_id: Option<&'a types::UserIdRef>, } -impl CheckAutoModStatusBody { +impl<'a> CheckAutoModStatusBody<'a> { /// Create a new [`CheckAutoModStatusBody`] - pub fn new(msg_id: impl Into, msg_text: String) -> Self { + pub fn new(msg_id: impl Into<&'a types::MsgIdRef>, msg_text: &'a str) -> Self { Self { msg_id: msg_id.into(), msg_text, @@ -113,11 +117,11 @@ impl CheckAutoModStatusBody { } } -impl helix::HelixRequestBody for Vec { +impl<'a> helix::HelixRequestBody for [CheckAutoModStatusBody<'a>] { fn try_to_body(&self) -> Result { #[derive(Serialize)] struct InnerBody<'a> { - data: &'a Vec, + data: &'a [CheckAutoModStatusBody<'a>], } serde_json::to_vec(&InnerBody { data: self }) @@ -139,7 +143,7 @@ pub struct CheckAutoModStatus { pub is_permitted: bool, } -impl Request for CheckAutoModStatusRequest { +impl Request for CheckAutoModStatusRequest<'_> { type Response = Vec; const PATH: &'static str = "moderation/enforcements/status"; @@ -147,22 +151,28 @@ impl Request for CheckAutoModStatusRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ModerationRead]; } -impl RequestPost for CheckAutoModStatusRequest { - type Body = Vec; +impl<'a> RequestPost for CheckAutoModStatusRequest<'a> { + type Body = &'a [&'a CheckAutoModStatusBody<'a>]; } +impl<'a> helix::private::SealedSerialize for &'a [&'a CheckAutoModStatusBody<'a>] {} + #[cfg(test)] #[test] fn test_request() { use helix::*; let req = CheckAutoModStatusRequest::broadcaster_id("198704263"); - let body = vec![ - CheckAutoModStatusBody::new("123", "hello world".to_string()), - CheckAutoModStatusBody::new("393", "automoded word".to_string()), - ]; - - dbg!(req.create_request(body, "token", "clientid").unwrap()); + dbg!(req + .create_request( + &[ + &CheckAutoModStatusBody::new("123", "hello world"), + &CheckAutoModStatusBody::new("393", "automoded word"), + ], + "token", + "clientid" + ) + .unwrap()); // From twitch docs let data = br#" diff --git a/src/helix/endpoints/moderation/delete_chat_messages.rs b/src/helix/endpoints/moderation/delete_chat_messages.rs index e1cb573fbd..dd345803f4 100644 --- a/src/helix/endpoints/moderation/delete_chat_messages.rs +++ b/src/helix/endpoints/moderation/delete_chat_messages.rs @@ -49,15 +49,17 @@ use helix::RequestDelete; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct DeleteChatMessagesRequest { +pub struct DeleteChatMessagesRequest<'a> { /// The ID of the broadcaster that owns the chat room to remove messages from. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of a user that has permission to moderate the broadcaster’s chat room. /// /// This ID must match the user ID in the OAuth token. If the broadcaster wants to remove messages themselves, set this parameter to the broadcaster’s ID, too. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub moderator_id: types::UserId, + #[serde(borrow)] + pub moderator_id: &'a types::UserIdRef, /// The ID of the message to remove. /// /// The id tag in the PRIVMSG contains the message’s ID (see [PRIVMSG Tags](https://dev.twitch.tv/docs/irc/tags#privmsg-tags)). @@ -70,14 +72,15 @@ pub struct DeleteChatMessagesRequest { /// /// If not specified, the request removes all messages in the broadcaster’s chat room. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub message_id: Option, + #[serde(borrow)] + pub message_id: Option<&'a types::MsgIdRef>, } -impl DeleteChatMessagesRequest { +impl<'a> DeleteChatMessagesRequest<'a> { /// Remove chat message(s) pub fn new( - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + moderator_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -87,7 +90,7 @@ impl DeleteChatMessagesRequest { } /// A specific message to remove - pub fn message_id(mut self, message_id: impl Into) -> Self { + pub fn message_id(mut self, message_id: impl Into<&'a types::MsgIdRef>) -> Self { self.message_id = Some(message_id.into()); self } @@ -103,7 +106,7 @@ pub enum DeleteChatMessagesResponse { Success, } -impl Request for DeleteChatMessagesRequest { +impl Request for DeleteChatMessagesRequest<'_> { type Response = DeleteChatMessagesResponse; #[cfg(feature = "twitch_oauth2")] @@ -114,7 +117,7 @@ impl Request for DeleteChatMessagesRequest { &[twitch_oauth2::Scope::ModeratorManageChatMessages]; } -impl RequestDelete for DeleteChatMessagesRequest { +impl RequestDelete for DeleteChatMessagesRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, diff --git a/src/helix/endpoints/moderation/get_banned_users.rs b/src/helix/endpoints/moderation/get_banned_users.rs index 4f699bfd71..0efa28fd33 100644 --- a/src/helix/endpoints/moderation/get_banned_users.rs +++ b/src/helix/endpoints/moderation/get_banned_users.rs @@ -39,6 +39,7 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; /// Query Parameters for [Get Banned Users](super::get_banned_users) /// @@ -46,47 +47,44 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetBannedUsersRequest { +pub struct GetBannedUsersRequest<'a> { /// Must match the User ID in the Bearer token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Filters the results and only returns a status object for users who are banned in this channel and have a matching user_id. /// Format: Repeated Query Parameter, eg. /moderation/banned?broadcaster_id=1&user_id=2&user_id=3 /// Maximum: 100 #[cfg_attr(feature = "typed-builder", builder(default))] - pub user_id: Vec, + #[serde(borrow)] + pub user_id: Cow<'a, [&'a types::UserIdRef]>, /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, /// Cursor for backward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] - pub before: Option, + #[serde(borrow)] + pub before: Option<&'a helix::CursorRef>, /// Number of values to be returned per page. Limit: 100. Default: 20. #[cfg_attr(feature = "typed-builder", builder(setter(into), default))] pub first: Option, } -impl GetBannedUsersRequest { +impl<'a> GetBannedUsersRequest<'a> { /// Get banned users in a broadcasters channel. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), - user_id: Default::default(), + user_id: Cow::Borrowed(&[]), after: Default::default(), before: Default::default(), first: Default::default(), } } - /// Check if supplied user is banned. - pub fn user(mut self, user_id: impl Into) -> Self { - self.user_id = vec![user_id.into()]; - self - } - /// Check if supplied users are banned. - pub fn users(mut self, user_ids: impl IntoIterator>) -> Self { - self.user_id = user_ids.into_iter().map(Into::into).collect(); + pub fn users(mut self, user_ids: impl Into>) -> Self { + self.user_id = user_ids.into(); self } @@ -124,7 +122,7 @@ pub struct BannedUser { pub moderator_name: types::DisplayName, } -impl Request for GetBannedUsersRequest { +impl Request for GetBannedUsersRequest<'_> { type Response = Vec; const PATH: &'static str = "moderation/banned"; @@ -132,9 +130,9 @@ impl Request for GetBannedUsersRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ModerationRead]; } -impl RequestGet for GetBannedUsersRequest {} +impl RequestGet for GetBannedUsersRequest<'_> {} -impl helix::Paginated for GetBannedUsersRequest { +impl helix::Paginated for GetBannedUsersRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/moderation/get_blocked_terms.rs b/src/helix/endpoints/moderation/get_blocked_terms.rs index 3978212edc..5cf96a7c60 100644 --- a/src/helix/endpoints/moderation/get_blocked_terms.rs +++ b/src/helix/endpoints/moderation/get_blocked_terms.rs @@ -48,14 +48,16 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetBlockedTerms { +pub struct GetBlockedTerms<'a> { /// The ID of the broadcaster whose blocked terms you’re getting. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID associated with the user OAuth token. /// If the broadcaster wants to get their own block terms (instead of having the moderator do it), set this parameter to the broadcaster’s ID, too. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub moderator_id: types::UserId, + #[serde(borrow)] + pub moderator_id: &'a types::UserIdRef, /// The maximum number of blocked terms to return per page in the response. The minimum page size is 1 blocked term per page and the maximum is 100. The default is 20. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub first: Option, @@ -64,11 +66,11 @@ pub struct GetBlockedTerms { pub after: Option, } -impl GetBlockedTerms { +impl<'a> GetBlockedTerms<'a> { /// Get blocked terms in a broadcasters channel as specified moderator pub fn new( - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + moderator_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -90,7 +92,7 @@ impl GetBlockedTerms { /// [`get-blocked-terms`](https://dev.twitch.tv/docs/api/reference#get-blocked-terms) pub type GetBlockedTermsResponse = BlockedTerm; -impl Request for GetBlockedTerms { +impl Request for GetBlockedTerms<'_> { type Response = Vec; const PATH: &'static str = "moderation/blocked_terms"; @@ -99,9 +101,9 @@ impl Request for GetBlockedTerms { &[twitch_oauth2::Scope::ModeratorReadBlockedTerms]; } -impl RequestGet for GetBlockedTerms {} +impl RequestGet for GetBlockedTerms<'_> {} -impl helix::Paginated for GetBlockedTerms { +impl helix::Paginated for GetBlockedTerms<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/moderation/get_moderators.rs b/src/helix/endpoints/moderation/get_moderators.rs index e2f2209048..71b301c44b 100644 --- a/src/helix/endpoints/moderation/get_moderators.rs +++ b/src/helix/endpoints/moderation/get_moderators.rs @@ -38,6 +38,7 @@ //! and parse the [`http::Response`] with [`GetModeratorsRequest::parse_response(None, &request.get_uri(), response)`](GetModeratorsRequest::parse_response) use super::*; use helix::RequestGet; +use std::borrow::Cow; // Format: Repeated Query Parameter, eg. /moderation/banned?broadcaster_id=1&user_id=2&user_id=3 // Maximum: 100 @@ -47,13 +48,15 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetModeratorsRequest { +pub struct GetModeratorsRequest<'a> { /// Must match the User ID in the Bearer token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Filters the results and only returns a status object for users who are moderators in this channel and have a matching user_id. #[cfg_attr(feature = "typed-builder", builder(setter(into), default))] - pub user_id: Vec, + #[serde(borrow)] + pub user_id: Cow<'a, [&'a types::UserIdRef]>, /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, @@ -62,29 +65,20 @@ pub struct GetModeratorsRequest { pub first: Option, } -impl GetModeratorsRequest { +impl<'a> GetModeratorsRequest<'a> { /// Get moderators in a broadcasters channel. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), - user_id: Default::default(), + user_id: Cow::Borrowed(&[]), after: Default::default(), first: Default::default(), } } - /// Check if supplied user is a moderator. - pub fn user_id(mut self, user_id: impl Into) -> Self { - self.user_id = vec![user_id.into()]; - self - } - /// Filter the results for specific users. - pub fn user_ids( - mut self, - user_ids: impl IntoIterator>, - ) -> Self { - self.user_id = user_ids.into_iter().map(Into::into).collect(); + pub fn user_ids(mut self, user_ids: impl Into>) -> Self { + self.user_id = user_ids.into(); self } @@ -110,7 +104,7 @@ pub struct Moderator { pub user_login: types::UserName, } -impl Request for GetModeratorsRequest { +impl Request for GetModeratorsRequest<'_> { type Response = Vec; const PATH: &'static str = "moderation/moderators"; @@ -118,9 +112,9 @@ impl Request for GetModeratorsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ModerationRead]; } -impl RequestGet for GetModeratorsRequest {} +impl RequestGet for GetModeratorsRequest<'_> {} -impl helix::Paginated for GetModeratorsRequest { +impl helix::Paginated for GetModeratorsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/moderation/manage_held_automod_messages.rs b/src/helix/endpoints/moderation/manage_held_automod_messages.rs index d47b1fc477..f2feaf7e0e 100644 --- a/src/helix/endpoints/moderation/manage_held_automod_messages.rs +++ b/src/helix/endpoints/moderation/manage_held_automod_messages.rs @@ -53,23 +53,24 @@ //! You can also get the [`http::Request`] with [`request.create_request(&token, &client_id)`](helix::RequestPost::create_request) //! and parse the [`http::Response`] with [`ManageHeldAutoModMessagesRequest::parse_response(None, &request.get_uri(), response)`](ManageHeldAutoModMessagesRequest::parse_response) +use std::marker::PhantomData; + use super::*; use helix::RequestPost; /// Query Parameters for [Manage Held AutoMod Messages](super::manage_held_automod_messages) /// /// [`manage-held-automod-messages`](https://dev.twitch.tv/docs/api/reference#manage-held-automod-messages) -#[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] +#[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct ManageHeldAutoModMessagesRequest {} - -impl ManageHeldAutoModMessagesRequest { - /// Create a new [`ManageHeldAutoModMessagesRequest`] - pub fn new() -> Self { Self {} } +pub struct ManageHeldAutoModMessagesRequest<'a> { + #[serde(skip)] + _marker: PhantomData<&'a ()>, } -impl Default for ManageHeldAutoModMessagesRequest { - fn default() -> Self { Self::new() } +impl ManageHeldAutoModMessagesRequest<'_> { + /// Create a new [`ManageHeldAutoModMessagesRequest`] + pub fn new() -> Self { Self::default() } } /// Body Parameters for [Manage Held AutoMod Messages](super::manage_held_automod_messages) @@ -78,19 +79,21 @@ impl Default for ManageHeldAutoModMessagesRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct ManageHeldAutoModMessagesBody { +pub struct ManageHeldAutoModMessagesBody<'a> { /// The moderator who is approving or rejecting the held message. Must match the user_id in the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub user_id: types::UserId, + #[serde(borrow)] + pub user_id: &'a types::UserIdRef, /// ID of the message to be allowed or denied. These message IDs are retrieved from IRC or PubSub. Only one message ID can be provided. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub msg_id: types::MsgId, + #[serde(borrow)] + pub msg_id: &'a types::MsgIdRef, /// The action to take for the message. Must be "ALLOW" or "DENY". #[cfg_attr(feature = "typed-builder", builder(setter(into)))] pub action: AutoModAction, } -impl ManageHeldAutoModMessagesBody { +impl<'a> ManageHeldAutoModMessagesBody<'a> { /// Create a new [`ManageHeldAutoModMessagesBody`] /// /// # Examples @@ -101,8 +104,8 @@ impl ManageHeldAutoModMessagesBody { /// let body = ManageHeldAutoModMessagesBody::new("1234", "5678", true); /// ``` pub fn new( - user_id: impl Into, - msg_id: impl Into, + user_id: impl Into<&'a types::UserIdRef>, + msg_id: impl Into<&'a types::MsgIdRef>, action: impl Into, ) -> Self { Self { @@ -114,7 +117,7 @@ impl ManageHeldAutoModMessagesBody { } /// Action to take for a message. -#[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] +#[derive(PartialEq, Eq, Deserialize, Serialize, Copy, Clone, Debug)] #[serde(rename_all = "UPPERCASE")] #[non_exhaustive] pub enum AutoModAction { @@ -133,7 +136,7 @@ impl From for AutoModAction { } } -impl helix::private::SealedSerialize for ManageHeldAutoModMessagesBody {} +impl helix::private::SealedSerialize for ManageHeldAutoModMessagesBody<'_> {} /// Return Values for [Manage Held AutoMod Messages](super::manage_held_automod_messages) /// @@ -146,7 +149,7 @@ pub enum ManageHeldAutoModMessages { Success, } -impl Request for ManageHeldAutoModMessagesRequest { +impl Request for ManageHeldAutoModMessagesRequest<'_> { type Response = ManageHeldAutoModMessages; const PATH: &'static str = "moderation/automod/message"; @@ -154,8 +157,8 @@ impl Request for ManageHeldAutoModMessagesRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ModerationRead]; } -impl RequestPost for ManageHeldAutoModMessagesRequest { - type Body = ManageHeldAutoModMessagesBody; +impl<'a> RequestPost for ManageHeldAutoModMessagesRequest<'a> { + type Body = ManageHeldAutoModMessagesBody<'a>; fn parse_inner_response<'d>( request: Option, diff --git a/src/helix/endpoints/moderation/remove_blocked_term.rs b/src/helix/endpoints/moderation/remove_blocked_term.rs index 452e6016ff..a1dfd34745 100644 --- a/src/helix/endpoints/moderation/remove_blocked_term.rs +++ b/src/helix/endpoints/moderation/remove_blocked_term.rs @@ -49,25 +49,28 @@ use helix::RequestDelete; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct RemoveBlockedTermRequest { +pub struct RemoveBlockedTermRequest<'a> { /// The ID of the broadcaster that owns the list of blocked terms. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID associated with the user OAuth token. /// If the broadcaster wants to delete the blocked term (instead of having the moderator do it), set this parameter to the broadcaster’s ID, too. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub moderator_id: types::UserId, + #[serde(borrow)] + pub moderator_id: &'a types::UserIdRef, /// The ID of the blocked term you want to delete. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub id: types::BlockedTermId, + #[serde(borrow)] + pub id: &'a types::BlockedTermIdRef, } -impl RemoveBlockedTermRequest { +impl<'a> RemoveBlockedTermRequest<'a> { /// Remove blocked term pub fn new( - broadcaster_id: impl Into, - moderator_id: impl Into, - id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + moderator_id: impl Into<&'a types::UserIdRef>, + id: impl Into<&'a types::BlockedTermIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -87,7 +90,7 @@ pub enum RemoveBlockedTerm { Success, } -impl Request for RemoveBlockedTermRequest { +impl Request for RemoveBlockedTermRequest<'_> { type Response = RemoveBlockedTerm; #[cfg(feature = "twitch_oauth2")] @@ -98,7 +101,7 @@ impl Request for RemoveBlockedTermRequest { &[twitch_oauth2::Scope::ModeratorManageBlockedTerms]; } -impl RequestDelete for RemoveBlockedTermRequest { +impl RequestDelete for RemoveBlockedTermRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, diff --git a/src/helix/endpoints/moderation/remove_channel_moderator.rs b/src/helix/endpoints/moderation/remove_channel_moderator.rs index 7a51974fc7..d2056d52eb 100644 --- a/src/helix/endpoints/moderation/remove_channel_moderator.rs +++ b/src/helix/endpoints/moderation/remove_channel_moderator.rs @@ -49,20 +49,22 @@ use helix::RequestDelete; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct RemoveChannelModeratorRequest { +pub struct RemoveChannelModeratorRequest<'a> { /// The ID of the broadcaster that owns the chat room. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of the user to remove as a moderator from the broadcaster’s chat room. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub moderator_id: types::UserId, + #[serde(borrow)] + pub moderator_id: &'a types::UserIdRef, } -impl RemoveChannelModeratorRequest { +impl<'a> RemoveChannelModeratorRequest<'a> { /// Remove moderator pub fn new( - broadcaster_id: impl Into, - moderator_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + moderator_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -82,7 +84,7 @@ pub enum RemoveChannelModeratorResponse { Success, } -impl Request for RemoveChannelModeratorRequest { +impl Request for RemoveChannelModeratorRequest<'_> { type Response = RemoveChannelModeratorResponse; const PATH: &'static str = "moderation/moderators"; @@ -90,7 +92,7 @@ impl Request for RemoveChannelModeratorRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManageModerators]; } -impl RequestDelete for RemoveChannelModeratorRequest { +impl RequestDelete for RemoveChannelModeratorRequest<'_> { fn parse_inner_response<'d>( request: Option, uri: &http::Uri, diff --git a/src/helix/endpoints/moderation/unban_user.rs b/src/helix/endpoints/moderation/unban_user.rs index 76f77bf020..33e7a15a55 100644 --- a/src/helix/endpoints/moderation/unban_user.rs +++ b/src/helix/endpoints/moderation/unban_user.rs @@ -51,24 +51,27 @@ use helix::RequestDelete; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct UnbanUserRequest { +pub struct UnbanUserRequest<'a> { /// The ID of the broadcaster whose chat room the user is banned from chatting in. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID associated with the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub moderator_id: types::UserId, + #[serde(borrow)] + pub moderator_id: &'a types::UserIdRef, /// The ID of the user to remove the ban or timeout from. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub user_id: types::UserId, + #[serde(borrow)] + pub user_id: &'a types::UserIdRef, } -impl UnbanUserRequest { +impl<'a> UnbanUserRequest<'a> { /// Remove the ban or timeout that was placed on the specified user. pub fn new( - broadcaster_id: impl Into, - moderator_id: impl Into, - user_id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + moderator_id: impl Into<&'a types::UserIdRef>, + user_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -88,7 +91,7 @@ pub enum UnbanUserResponse { Success, } -impl Request for UnbanUserRequest { +impl Request for UnbanUserRequest<'_> { type Response = UnbanUserResponse; const PATH: &'static str = "moderation/bans"; @@ -97,7 +100,7 @@ impl Request for UnbanUserRequest { &[twitch_oauth2::Scope::ModeratorManageBannedUsers]; } -impl RequestDelete for UnbanUserRequest { +impl RequestDelete for UnbanUserRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, diff --git a/src/helix/endpoints/points/create_custom_rewards.rs b/src/helix/endpoints/points/create_custom_rewards.rs index 3d343e82ff..647533e1ec 100644 --- a/src/helix/endpoints/points/create_custom_rewards.rs +++ b/src/helix/endpoints/points/create_custom_rewards.rs @@ -63,15 +63,16 @@ use helix::RequestPost; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct CreateCustomRewardRequest { +pub struct CreateCustomRewardRequest<'a> { /// Provided broadcaster_id must match the user_id in the auth token #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, } -impl CreateCustomRewardRequest { +impl<'a> CreateCustomRewardRequest<'a> { /// Channel to create reward on - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), } @@ -84,14 +85,15 @@ impl CreateCustomRewardRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct CreateCustomRewardBody { +pub struct CreateCustomRewardBody<'a> { /// The title of the reward #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub title: String, + #[serde(borrow)] + pub title: &'a str, /// The prompt for the viewer when they are redeeming the reward #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub prompt: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub prompt: Option<&'a str>, /// The cost of the reward pub cost: usize, /// Is the reward currently enabled, if false the reward won’t show up to viewers. Defaults true @@ -100,8 +102,8 @@ pub struct CreateCustomRewardBody { pub is_enabled: Option, /// Custom background color for the reward. Format: Hex with # prefix. Example: #00E5CB. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub background_color: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub background_color: Option<&'a str>, /// Does the user need to enter information when redeeming the reward. Defaults false #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] #[serde(skip_serializing_if = "Option::is_none")] @@ -136,10 +138,10 @@ pub struct CreateCustomRewardBody { pub should_redemptions_skip_request_queue: Option, } -impl CreateCustomRewardBody { +impl<'a> CreateCustomRewardBody<'a> { // FIXME: need to add more here /// Reward to create with title. - pub fn new(title: String, cost: usize) -> Self { + pub fn new(title: &'a str, cost: usize) -> Self { Self { title, prompt: Default::default(), @@ -158,14 +160,14 @@ impl CreateCustomRewardBody { } } -impl helix::private::SealedSerialize for CreateCustomRewardBody {} +impl helix::private::SealedSerialize for CreateCustomRewardBody<'_> {} /// Return Values for [Create Custom Rewards](super::create_custom_rewards) /// /// [`create-custom-rewards`](https://dev.twitch.tv/docs/api/reference#create-custom-rewards) pub type CreateCustomRewardResponse = super::CustomReward; -impl Request for CreateCustomRewardRequest { +impl Request for CreateCustomRewardRequest<'_> { type Response = CreateCustomRewardResponse; const PATH: &'static str = "channel_points/custom_rewards"; @@ -174,8 +176,8 @@ impl Request for CreateCustomRewardRequest { &[twitch_oauth2::Scope::ChannelManageRedemptions]; } -impl RequestPost for CreateCustomRewardRequest { - type Body = CreateCustomRewardBody; +impl<'a> RequestPost for CreateCustomRewardRequest<'a> { + type Body = CreateCustomRewardBody<'a>; fn parse_inner_response( request: Option, @@ -219,7 +221,7 @@ fn test_request() { use helix::*; let req = CreateCustomRewardRequest::broadcaster_id("274637212"); - let body = CreateCustomRewardBody::new("game analysis 1v1".to_owned(), 50000); + let body = CreateCustomRewardBody::new("game analysis 1v1", 50000); dbg!(req.create_request(body, "token", "clientid").unwrap()); diff --git a/src/helix/endpoints/points/delete_custom_reward.rs b/src/helix/endpoints/points/delete_custom_reward.rs index 7a997dbf4b..ada2f8eeb7 100644 --- a/src/helix/endpoints/points/delete_custom_reward.rs +++ b/src/helix/endpoints/points/delete_custom_reward.rs @@ -48,18 +48,23 @@ use helix::RequestDelete; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct DeleteCustomRewardRequest { +pub struct DeleteCustomRewardRequest<'a> { /// Provided broadcaster_id must match the user_id in the auth token #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// ID of the Custom Reward to delete, must match a Custom Reward on broadcaster_id’s channel. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub id: types::RewardId, + #[serde(borrow)] + pub id: &'a types::RewardIdRef, } -impl DeleteCustomRewardRequest { +impl<'a> DeleteCustomRewardRequest<'a> { /// Reward to delete - pub fn new(broadcaster_id: impl Into, id: impl Into) -> Self { + pub fn new( + broadcaster_id: impl Into<&'a types::UserIdRef>, + id: impl Into<&'a types::RewardIdRef>, + ) -> Self { Self { broadcaster_id: broadcaster_id.into(), id: id.into(), @@ -79,7 +84,7 @@ pub enum DeleteCustomReward { Success, } -impl Request for DeleteCustomRewardRequest { +impl Request for DeleteCustomRewardRequest<'_> { type Response = DeleteCustomReward; const PATH: &'static str = "channel_points/custom_rewards"; @@ -88,7 +93,7 @@ impl Request for DeleteCustomRewardRequest { &[twitch_oauth2::Scope::ChannelManageRedemptions]; } -impl RequestDelete for DeleteCustomRewardRequest { +impl RequestDelete for DeleteCustomRewardRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, diff --git a/src/helix/endpoints/points/get_custom_reward.rs b/src/helix/endpoints/points/get_custom_reward.rs index e4466d8a09..bae54c9d2e 100644 --- a/src/helix/endpoints/points/get_custom_reward.rs +++ b/src/helix/endpoints/points/get_custom_reward.rs @@ -42,6 +42,7 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; /// Query Parameters for [Get Custom Reward](super::get_custom_reward) /// @@ -49,37 +50,33 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetCustomRewardRequest { +pub struct GetCustomRewardRequest<'a> { /// Provided broadcaster_id must match the user_id in the auth token #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// When used, this parameter filters the results and only returns reward objects for the Custom Rewards with matching ID. Maximum: 50 #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub id: Vec, + #[serde(borrow)] + pub id: Cow<'a, [&'a types::RewardIdRef]>, /// When set to true, only returns custom rewards that the calling client_id can manage. Defaults false. #[cfg_attr(feature = "typed-builder", builder(default))] pub only_manageable_rewards: Option, } -impl GetCustomRewardRequest { +impl<'a> GetCustomRewardRequest<'a> { /// Rewards on this broadcasters channel - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), - id: Default::default(), + id: Cow::Borrowed(&[]), only_manageable_rewards: Default::default(), } } - /// Get reward with this id - pub fn id(mut self, id: impl Into) -> Self { - self.id = vec![id.into()]; - self - } - /// Get rewards with these ids - pub fn ids(mut self, id: impl IntoIterator>) -> Self { - self.id = id.into_iter().map(Into::into).collect(); + pub fn ids(mut self, id: impl Into>) -> Self { + self.id = id.into(); self } @@ -139,7 +136,7 @@ pub struct CustomReward { pub cooldown_expires_at: Option, } -impl Request for GetCustomRewardRequest { +impl Request for GetCustomRewardRequest<'_> { type Response = Vec; const PATH: &'static str = "channel_points/custom_rewards"; @@ -148,13 +145,13 @@ impl Request for GetCustomRewardRequest { &[twitch_oauth2::scopes::Scope::ChannelReadRedemptions]; } -impl RequestGet for GetCustomRewardRequest {} +impl RequestGet for GetCustomRewardRequest<'_> {} #[cfg(test)] #[test] fn test_request() { use helix::*; - let req = GetCustomRewardRequest::broadcaster_id("274637212".to_string()); + let req = GetCustomRewardRequest::broadcaster_id("274637212"); // From twitch docs let data = br##" diff --git a/src/helix/endpoints/points/get_custom_reward_redemption.rs b/src/helix/endpoints/points/get_custom_reward_redemption.rs index ff15a493c5..1901aa423f 100644 --- a/src/helix/endpoints/points/get_custom_reward_redemption.rs +++ b/src/helix/endpoints/points/get_custom_reward_redemption.rs @@ -51,14 +51,16 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetCustomRewardRedemptionRequest { +pub struct GetCustomRewardRedemptionRequest<'a> { /// Provided broadcaster_id must match the user_id in the auth token #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// When ID is not provided, this parameter returns paginated Custom Reward Redemption objects for redemptions of the Custom Reward with ID reward_id #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub reward_id: Option, + #[serde(borrow)] + pub reward_id: Option<&'a types::RewardIdRef>, /// When id is not provided, this param is required and filters the paginated Custom Reward Redemption objects for redemptions with the matching status. Can be one of UNFULFILLED, FULFILLED or CANCELED #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] @@ -73,9 +75,9 @@ pub struct GetCustomRewardRedemptionRequest { pub first: Option, } -impl GetCustomRewardRedemptionRequest { +impl<'a> GetCustomRewardRedemptionRequest<'a> { /// Reward to fetch - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), reward_id: None, @@ -86,7 +88,7 @@ impl GetCustomRewardRedemptionRequest { } /// Specific reward to query - pub fn reward_id(mut self, reward_id: impl Into) -> Self { + pub fn reward_id(mut self, reward_id: impl Into<&'a types::RewardIdRef>) -> Self { self.reward_id = Some(reward_id.into()); self } @@ -157,7 +159,7 @@ pub struct Reward { pub cost: i64, } -impl Request for GetCustomRewardRedemptionRequest { +impl Request for GetCustomRewardRedemptionRequest<'_> { type Response = Vec; const PATH: &'static str = "channel_points/custom_rewards/redemptions"; @@ -166,9 +168,9 @@ impl Request for GetCustomRewardRedemptionRequest { &[twitch_oauth2::scopes::Scope::ChannelReadRedemptions]; } -impl RequestGet for GetCustomRewardRedemptionRequest {} +impl RequestGet for GetCustomRewardRedemptionRequest<'_> {} -impl helix::Paginated for GetCustomRewardRedemptionRequest { +impl helix::Paginated for GetCustomRewardRedemptionRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/points/mod.rs b/src/helix/endpoints/points/mod.rs index ebad1639bc..2faf987d19 100644 --- a/src/helix/endpoints/points/mod.rs +++ b/src/helix/endpoints/points/mod.rs @@ -50,7 +50,7 @@ pub use update_redemption_status::{ UpdateRedemptionStatusBody, UpdateRedemptionStatusInformation, UpdateRedemptionStatusRequest, }; /// Custom reward redemption statuses: UNFULFILLED, FULFILLED or CANCELED -#[derive(PartialEq, Eq, serde::Serialize, serde::Deserialize, Clone, Debug)] +#[derive(PartialEq, Eq, serde::Serialize, serde::Deserialize, Copy, Clone, Debug)] pub enum CustomRewardRedemptionStatus { /// Unfulfilled reward - the user has claimed it but it is still pending. #[serde(rename = "UNFULFILLED")] diff --git a/src/helix/endpoints/points/update_custom_reward.rs b/src/helix/endpoints/points/update_custom_reward.rs index 241a55428a..81580f0c21 100644 --- a/src/helix/endpoints/points/update_custom_reward.rs +++ b/src/helix/endpoints/points/update_custom_reward.rs @@ -69,18 +69,23 @@ use helix::RequestPatch; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct UpdateCustomRewardRequest { +pub struct UpdateCustomRewardRequest<'a> { /// Provided broadcaster_id must match the user_id in the auth token #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// ID of the Custom Reward to update, must match a Custom Reward on broadcaster_id’s channel. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub id: types::RewardId, + #[serde(borrow)] + pub id: &'a types::RewardIdRef, } -impl UpdateCustomRewardRequest { +impl<'a> UpdateCustomRewardRequest<'a> { /// Update a Custom Reward created on the broadcaster's channel - pub fn new(broadcaster_id: impl Into, id: impl Into) -> Self { + pub fn new( + broadcaster_id: impl Into<&'a types::UserIdRef>, + id: impl Into<&'a types::RewardIdRef>, + ) -> Self { Self { broadcaster_id: broadcaster_id.into(), id: id.into(), @@ -94,23 +99,23 @@ impl UpdateCustomRewardRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct UpdateCustomRewardBody { +pub struct UpdateCustomRewardBody<'a> { /// The title of the reward #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub title: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub title: Option<&'a str>, /// The prompt for the viewer when they are redeeming the reward #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub prompt: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub prompt: Option<&'a str>, /// The cost of the reward #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] #[serde(skip_serializing_if = "Option::is_none")] pub cost: Option, /// Custom background color for the reward. Format: Hex with # prefix. Example: #00E5CB. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub background_color: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub background_color: Option<&'a str>, /// Is the reward currently enabled, if false the reward won’t show up to viewers #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] #[serde(skip_serializing_if = "Option::is_none")] @@ -153,7 +158,7 @@ pub struct UpdateCustomRewardBody { pub should_redemptions_skip_request_queue: Option, } -impl helix::private::SealedSerialize for UpdateCustomRewardBody {} +impl helix::private::SealedSerialize for UpdateCustomRewardBody<'_> {} /// Return Values for [Update CustomReward](super::update_custom_reward) /// @@ -166,7 +171,7 @@ pub enum UpdateCustomReward { Success(CustomReward), } -impl Request for UpdateCustomRewardRequest { +impl Request for UpdateCustomRewardRequest<'_> { type Response = UpdateCustomReward; const PATH: &'static str = "channel_points/custom_rewards"; @@ -175,8 +180,8 @@ impl Request for UpdateCustomRewardRequest { &[twitch_oauth2::Scope::ChannelManageRedemptions]; } -impl RequestPatch for UpdateCustomRewardRequest { - type Body = UpdateCustomRewardBody; +impl<'a> RequestPatch for UpdateCustomRewardRequest<'a> { + type Body = UpdateCustomRewardBody<'a>; fn parse_inner_response( request: Option, diff --git a/src/helix/endpoints/points/update_redemption_status.rs b/src/helix/endpoints/points/update_redemption_status.rs index a787b79c70..dfcbded267 100644 --- a/src/helix/endpoints/points/update_redemption_status.rs +++ b/src/helix/endpoints/points/update_redemption_status.rs @@ -75,26 +75,29 @@ use helix::RequestPatch; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct UpdateRedemptionStatusRequest { +pub struct UpdateRedemptionStatusRequest<'a> { /// Provided broadcaster_id must match the user_id in the auth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// ID of the Custom Reward the redemptions to be updated are for. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub reward_id: types::RewardId, + #[serde(borrow)] + pub reward_id: &'a types::RewardIdRef, /// ID of the Custom Reward Redemption to update, must match a Custom Reward Redemption on broadcaster_id’s channel #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub id: types::RedemptionId, + #[serde(borrow)] + pub id: &'a types::RedemptionIdRef, } -impl UpdateRedemptionStatusRequest { +impl<'a> UpdateRedemptionStatusRequest<'a> { /// Update the status of Custom Reward Redemption object on a channel that are in the UNFULFILLED status. pub fn new( - broadcaster_id: impl Into, - reward_id: impl Into, - id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + reward_id: impl Into<&'a types::RewardIdRef>, + id: impl Into<&'a types::RedemptionIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -132,7 +135,7 @@ pub enum UpdateRedemptionStatusInformation { Success(CustomRewardRedemption), } -impl Request for UpdateRedemptionStatusRequest { +impl Request for UpdateRedemptionStatusRequest<'_> { type Response = UpdateRedemptionStatusInformation; const PATH: &'static str = "channel_points/custom_rewards/redemptions"; @@ -141,7 +144,7 @@ impl Request for UpdateRedemptionStatusRequest { &[twitch_oauth2::scopes::Scope::ChannelManageBroadcast]; } -impl RequestPatch for UpdateRedemptionStatusRequest { +impl RequestPatch for UpdateRedemptionStatusRequest<'_> { type Body = UpdateRedemptionStatusBody; fn parse_inner_response( diff --git a/src/helix/endpoints/polls/create_poll.rs b/src/helix/endpoints/polls/create_poll.rs index 232b3c5290..6a4688fca9 100644 --- a/src/helix/endpoints/polls/create_poll.rs +++ b/src/helix/endpoints/polls/create_poll.rs @@ -63,6 +63,9 @@ //! You can also get the [`http::Request`] with [`request.create_request(&token, &client_id)`](helix::RequestPost::create_request) //! and parse the [`http::Response`] with [`CreatePollRequest::parse_response(None, &request.get_uri(), response)`](CreatePollRequest::parse_response) +use std::borrow::Cow; +use std::marker::PhantomData; + use super::*; use helix::RequestPost; /// Query Parameters for [Create Poll](super::create_poll) @@ -71,11 +74,14 @@ use helix::RequestPost; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct CreatePollRequest {} +pub struct CreatePollRequest<'a> { + #[serde(skip)] + _marker: PhantomData<&'a ()>, +} -impl CreatePollRequest { +impl CreatePollRequest<'_> { /// Create a new [`CreatePollRequest`] - pub fn new() -> Self { Self {} } + pub fn new() -> Self { Self::default() } } /// Body Parameters for [Create Poll](super::create_poll) @@ -84,17 +90,20 @@ impl CreatePollRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct CreatePollBody { +pub struct CreatePollBody<'a> { /// The broadcaster running polls. Provided broadcaster_id must match the user_id in the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Question displayed for the poll. Maximum: 60 characters. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub title: String, + #[serde(borrow)] + pub title: &'a str, /// Total duration for the poll (in seconds). Minimum: 15. Maximum: 1800. pub duration: i64, /// Array of the poll choices. Minimum: 2 choices. Maximum: 5 choices. - pub choices: Vec, + #[serde(borrow)] + pub choices: Cow<'a, [NewPollChoice<'a>]>, /// Indicates if Bits can be used for voting. Default: false #[deprecated(since = "0.7.0", note = "bit options for polls has been removed")] #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] @@ -113,7 +122,7 @@ pub struct CreatePollBody { pub channel_points_per_vote: Option, } -impl CreatePollBody { +impl<'a> CreatePollBody<'a> { /// Set if Channel Points voting is enabled pub fn channel_points_voting_enabled(mut self, enabled: bool) -> Self { self.channel_points_voting_enabled = Some(enabled); @@ -128,16 +137,16 @@ impl CreatePollBody { /// Poll settings pub fn new( - broadcaster_id: impl Into, - title: String, + broadcaster_id: impl Into<&'a types::UserIdRef>, + title: &'a str, duration: i64, - choices: impl IntoIterator>, + choices: impl Into]>>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), title, duration, - choices: choices.into_iter().map(|s| s.into()).collect(), + choices: choices.into(), bits_voting_enabled: Default::default(), bits_per_vote: Default::default(), channel_points_voting_enabled: Default::default(), @@ -146,20 +155,21 @@ impl CreatePollBody { } } -impl helix::private::SealedSerialize for CreatePollBody {} +impl helix::private::SealedSerialize for CreatePollBody<'_> {} /// Choice settings for a poll #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct NewPollChoice { +pub struct NewPollChoice<'a> { /// Text displayed for the choice. Maximum: 25 characters. - pub title: String, + #[serde(borrow)] + pub title: &'a str, } -impl NewPollChoice { +impl<'a> NewPollChoice<'a> { /// Create a new [`NewPollChoice`] - pub fn new(title: impl Into) -> Self { + pub fn new(title: impl Into<&'a str>) -> Self { Self { title: title.into(), } @@ -171,7 +181,7 @@ impl NewPollChoice { /// [`create-poll`](https://dev.twitch.tv/docs/api/reference#create-poll) pub type CreatePollResponse = super::Poll; -impl Request for CreatePollRequest { +impl Request for CreatePollRequest<'_> { type Response = CreatePollResponse; const PATH: &'static str = "polls"; @@ -179,8 +189,8 @@ impl Request for CreatePollRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManagePolls]; } -impl RequestPost for CreatePollRequest { - type Body = CreatePollBody; +impl<'a> RequestPost for CreatePollRequest<'a> { + type Body = CreatePollBody<'a>; fn parse_inner_response( request: Option, @@ -224,14 +234,10 @@ fn test_request() { use helix::*; let req = CreatePollRequest::new(); - let body = CreatePollBody::new( - "141981764", - "Heads or Tails?".to_owned(), - 1800, - [NewPollChoice::new("Heads"), NewPollChoice::new("Tails")], - ) - .channel_points_per_vote(100) - .channel_points_voting_enabled(true); + let choices: &[NewPollChoice] = &[NewPollChoice::new("Heads"), NewPollChoice::new("Tails")]; + let body = CreatePollBody::new("141981764", "Heads or Tails?", 1800, choices) + .channel_points_per_vote(100) + .channel_points_voting_enabled(true); dbg!(req.create_request(body, "token", "clientid").unwrap()); diff --git a/src/helix/endpoints/polls/end_poll.rs b/src/helix/endpoints/polls/end_poll.rs index 31643abf2f..44726ef723 100644 --- a/src/helix/endpoints/polls/end_poll.rs +++ b/src/helix/endpoints/polls/end_poll.rs @@ -54,6 +54,8 @@ //! You can also get the [`http::Request`] with [`request.create_request(&token, &client_id)`](helix::RequestPost::create_request) //! and parse the [`http::Response`] with [`EndPollRequest::parse_response(None, &request.get_uri(), response)`](EndPollRequest::parse_response) +use std::marker::PhantomData; + use crate::helix::{parse_json, HelixRequestPatchError}; use super::*; @@ -65,11 +67,14 @@ pub use types::PollStatus; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct EndPollRequest {} +pub struct EndPollRequest<'a> { + #[serde(skip)] + _marker: PhantomData<&'a ()>, +} -impl EndPollRequest { +impl EndPollRequest<'_> { /// Make a new [`EndPollRequest`] - pub fn new() -> Self { Self {} } + pub fn new() -> Self { Self::default() } } /// Body Parameters for [End Poll](super::end_poll) @@ -78,13 +83,15 @@ impl EndPollRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct EndPollBody { +pub struct EndPollBody<'a> { /// The broadcaster running polls. Provided broadcaster_id must match the user_id in the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// ID of the poll. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub id: types::PollId, + #[serde(borrow)] + pub id: &'a types::PollIdRef, /// The poll status to be set. /// /// Valid values: @@ -93,11 +100,11 @@ pub struct EndPollBody { pub status: PollStatus, } -impl EndPollBody { +impl<'a> EndPollBody<'a> { /// End a poll that is currently active. pub fn new( - broadcaster_id: impl Into, - id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + id: impl Into<&'a types::PollIdRef>, status: PollStatus, ) -> Self { Self { @@ -108,7 +115,7 @@ impl EndPollBody { } } -impl helix::private::SealedSerialize for EndPollBody {} +impl helix::private::SealedSerialize for EndPollBody<'_> {} /// Return Values for [Update CustomReward](super::end_poll) /// @@ -126,7 +133,7 @@ pub enum EndPoll { AuthFailed, } -impl Request for EndPollRequest { +impl Request for EndPollRequest<'_> { type Response = EndPoll; const PATH: &'static str = "polls"; @@ -134,8 +141,8 @@ impl Request for EndPollRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManagePolls]; } -impl RequestPatch for EndPollRequest { - type Body = EndPollBody; +impl<'a> RequestPatch for EndPollRequest<'a> { + type Body = EndPollBody<'a>; fn parse_inner_response( request: Option, diff --git a/src/helix/endpoints/polls/get_polls.rs b/src/helix/endpoints/polls/get_polls.rs index ff9121858b..a481afe82e 100644 --- a/src/helix/endpoints/polls/get_polls.rs +++ b/src/helix/endpoints/polls/get_polls.rs @@ -39,6 +39,7 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; pub use types::{PollChoice, PollStatus}; /// Query Parameters for [Get polls](super::get_polls) @@ -47,13 +48,15 @@ pub use types::{PollChoice, PollStatus}; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetPollsRequest { +pub struct GetPollsRequest<'a> { /// The broadcaster running polls. Provided broadcaster_id must match the user_id in the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// ID of a poll. Filters results to one or more specific polls. Not providing one or more IDs will return the full list of polls for the authenticated channel. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub id: Vec, + #[serde(borrow)] + pub id: Cow<'a, [&'a types::PollIdRef]>, /// Cursor for forward pagination #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub after: Option, @@ -62,9 +65,9 @@ pub struct GetPollsRequest { pub first: Option, } -impl GetPollsRequest { +impl<'a> GetPollsRequest<'a> { /// The broadcaster running polls. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), id: Default::default(), @@ -73,15 +76,9 @@ impl GetPollsRequest { } } - /// ID of a poll to query. - pub fn id(mut self, id: impl Into) -> Self { - self.id = vec![id.into()]; - self - } - /// IDs of the polls to query. - pub fn ids(mut self, id: impl IntoIterator>) -> Self { - self.id = id.into_iter().map(Into::into).collect(); + pub fn ids(mut self, id: impl Into>) -> Self { + self.id = id.into(); self } } @@ -125,7 +122,7 @@ pub struct Poll { pub ended_at: Option, } -impl Request for GetPollsRequest { +impl Request for GetPollsRequest<'_> { type Response = Vec; const PATH: &'static str = "polls"; @@ -133,9 +130,9 @@ impl Request for GetPollsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelReadPolls]; } -impl RequestGet for GetPollsRequest {} +impl RequestGet for GetPollsRequest<'_> {} -impl helix::Paginated for GetPollsRequest { +impl helix::Paginated for GetPollsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor; } } @@ -143,8 +140,8 @@ impl helix::Paginated for GetPollsRequest { #[test] fn test_request() { use helix::*; - let req = - GetPollsRequest::broadcaster_id("141981764").id("ed961efd-8a3f-4cf5-a9d0-e616c590cd2a"); + let req = GetPollsRequest::broadcaster_id("141981764") + .ids(vec!["ed961efd-8a3f-4cf5-a9d0-e616c590cd2a".into()]); // From twitch docs let data = br#" diff --git a/src/helix/endpoints/predictions/create_prediction.rs b/src/helix/endpoints/predictions/create_prediction.rs index 8c616793a7..feb65001d7 100644 --- a/src/helix/endpoints/predictions/create_prediction.rs +++ b/src/helix/endpoints/predictions/create_prediction.rs @@ -61,6 +61,8 @@ //! You can also get the [`http::Request`] with [`request.create_request(&token, &client_id)`](helix::RequestPost::create_request) //! and parse the [`http::Response`] with [`CreatePredictionRequest::parse_response(None, &request.get_uri(), response)`](CreatePredictionRequest::parse_response) +use std::marker::PhantomData; + use super::*; use helix::RequestPost; @@ -70,11 +72,14 @@ use helix::RequestPost; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct CreatePredictionRequest {} +pub struct CreatePredictionRequest<'a> { + #[serde(skip)] + _marker: PhantomData<&'a ()>, +} -impl CreatePredictionRequest { +impl CreatePredictionRequest<'_> { /// Create a new [`CreatePredictionRequest`] - pub fn new() -> Self { Self {} } + pub fn new() -> Self { Self::default() } } /// Body Parameters for [Create Prediction](super::create_prediction) @@ -83,25 +88,27 @@ impl CreatePredictionRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct CreatePredictionBody { +pub struct CreatePredictionBody<'a> { /// The broadcaster running Predictions. Provided broadcaster_id must match the user_id in the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Title for the Prediction. Maximum: 45 characters. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub title: String, + #[serde(borrow)] + pub title: &'a str, /// Array of outcome objects with titles for the Prediction. Array size must be 2. - pub outcomes: (NewPredictionOutcome, NewPredictionOutcome), + pub outcomes: (NewPredictionOutcome<'a>, NewPredictionOutcome<'a>), /// Total duration for the Prediction (in seconds). Minimum: 1. Maximum: 1800. pub prediction_window: i64, } -impl CreatePredictionBody { +impl<'a> CreatePredictionBody<'a> { /// Create a Channel Points Prediction for a specific Twitch channel. pub fn new( - broadcaster_id: impl Into, - title: String, - outcomes: (NewPredictionOutcome, NewPredictionOutcome), + broadcaster_id: impl Into<&'a types::UserIdRef>, + title: &'a str, + outcomes: (NewPredictionOutcome<'a>, NewPredictionOutcome<'a>), prediction_window: i64, ) -> Self { Self { @@ -113,27 +120,28 @@ impl CreatePredictionBody { } } -impl helix::private::SealedSerialize for CreatePredictionBody {} +impl helix::private::SealedSerialize for CreatePredictionBody<'_> {} /// Choice settings for a poll #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct NewPredictionOutcome { +pub struct NewPredictionOutcome<'a> { /// Text displayed for the choice. Maximum: 25 characters. - pub title: String, + #[serde(borrow)] + pub title: &'a str, } -impl NewPredictionOutcome { +impl<'a> NewPredictionOutcome<'a> { /// Create a new [`NewPredictionOutcome`] - pub fn new(title: impl Into) -> Self { + pub fn new(title: impl Into<&'a str>) -> Self { Self { title: title.into(), } } /// Create a two new [`NewPredictionOutcome`]s - pub fn new_tuple(blue: impl Into, pink: impl Into) -> (Self, Self) { + pub fn new_tuple(blue: impl Into<&'a str>, pink: impl Into<&'a str>) -> (Self, Self) { (Self::new(blue), Self::new(pink)) } } @@ -143,7 +151,7 @@ impl NewPredictionOutcome { /// [`create-prediction`](https://dev.twitch.tv/docs/api/reference#create-prediction) pub type CreatePredictionResponse = super::Prediction; -impl Request for CreatePredictionRequest { +impl Request for CreatePredictionRequest<'_> { type Response = CreatePredictionResponse; const PATH: &'static str = "predictions"; @@ -152,8 +160,8 @@ impl Request for CreatePredictionRequest { &[twitch_oauth2::Scope::ChannelManagePredictions]; } -impl RequestPost for CreatePredictionRequest { - type Body = CreatePredictionBody; +impl<'a> RequestPost for CreatePredictionRequest<'a> { + type Body = CreatePredictionBody<'a>; fn parse_inner_response( request: Option, @@ -199,7 +207,7 @@ fn test_request() { let body = CreatePredictionBody::new( "141981764", - "Any leeks in the stream?".to_owned(), + "Any leeks in the stream?", NewPredictionOutcome::new_tuple("Yes, give it time.", "Definitely not."), 120, ); diff --git a/src/helix/endpoints/predictions/end_prediction.rs b/src/helix/endpoints/predictions/end_prediction.rs index 5eed4cb268..05dcc0028e 100644 --- a/src/helix/endpoints/predictions/end_prediction.rs +++ b/src/helix/endpoints/predictions/end_prediction.rs @@ -54,6 +54,8 @@ //! You can also get the [`http::Request`] with [`request.create_request(&token, &client_id)`](helix::RequestPost::create_request) //! and parse the [`http::Response`] with [`EndPredictionRequest::parse_response(None, &request.get_uri(), response)`](EndPredictionRequest::parse_response) +use std::marker::PhantomData; + use crate::helix::{parse_json, HelixRequestPatchError}; use super::*; @@ -64,11 +66,14 @@ use helix::RequestPatch; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct EndPredictionRequest {} +pub struct EndPredictionRequest<'a> { + #[serde(skip)] + _marker: PhantomData<&'a ()>, +} -impl EndPredictionRequest { +impl EndPredictionRequest<'_> { /// Make a new [`EndPredictionRequest`] - pub fn new() -> Self { Self {} } + pub fn new() -> Self { Self::default() } } /// Body Parameters for [End Prediction](super::end_prediction) @@ -77,13 +82,15 @@ impl EndPredictionRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct EndPredictionBody { +pub struct EndPredictionBody<'a> { /// The broadcaster running predictions. Provided broadcaster_id must match the user_id in the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// ID of the prediction. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub id: types::PredictionId, + #[serde(borrow)] + pub id: &'a types::PredictionIdRef, /// The Prediction status to be set. Valid values: /// /// [`RESOLVED`](types::PredictionStatus): A winning outcome has been chosen and the Channel Points have been distributed to the users who predicted the correct outcome. @@ -92,14 +99,15 @@ pub struct EndPredictionBody { pub status: types::PredictionStatus, /// ID of the winning outcome for the Prediction. This parameter is required if status is being set to [`RESOLVED`](types::PredictionStatus). #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub winning_outcome_id: Option, + #[serde(borrow)] + pub winning_outcome_id: Option<&'a types::PredictionIdRef>, } -impl EndPredictionBody { +impl<'a> EndPredictionBody<'a> { /// End given prediction that is currently active. pub fn new( - broadcaster_id: impl Into, - id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + id: impl Into<&'a types::PredictionIdRef>, status: impl Into, ) -> Self { Self { @@ -115,14 +123,14 @@ impl EndPredictionBody { /// This parameter is required if status is being set to [`RESOLVED`](types::PredictionStatus). pub fn winning_outcome_id( mut self, - winning_outcome_id: impl Into, + winning_outcome_id: impl Into<&'a types::PredictionIdRef>, ) -> Self { self.winning_outcome_id = Some(winning_outcome_id.into()); self } } -impl helix::private::SealedSerialize for EndPredictionBody {} +impl helix::private::SealedSerialize for EndPredictionBody<'_> {} /// Return Values for [Update CustomReward](super::end_prediction) /// @@ -140,7 +148,7 @@ pub enum EndPrediction { AuthFailed, } -impl Request for EndPredictionRequest { +impl Request for EndPredictionRequest<'_> { type Response = EndPrediction; const PATH: &'static str = "predictions"; @@ -149,8 +157,8 @@ impl Request for EndPredictionRequest { &[twitch_oauth2::Scope::ChannelManagePredictions]; } -impl RequestPatch for EndPredictionRequest { - type Body = EndPredictionBody; +impl<'a> RequestPatch for EndPredictionRequest<'a> { + type Body = EndPredictionBody<'a>; fn parse_inner_response( request: Option, diff --git a/src/helix/endpoints/predictions/get_predictions.rs b/src/helix/endpoints/predictions/get_predictions.rs index 2a4f0cf485..bc24bbfbc0 100644 --- a/src/helix/endpoints/predictions/get_predictions.rs +++ b/src/helix/endpoints/predictions/get_predictions.rs @@ -39,6 +39,7 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; pub use types::{PredictionOutcome, PredictionOutcomeId, PredictionStatus}; /// Query Parameters for [Get predictions](super::get_predictions) @@ -47,16 +48,18 @@ pub use types::{PredictionOutcome, PredictionOutcomeId, PredictionStatus}; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetPredictionsRequest { +pub struct GetPredictionsRequest<'a> { /// The broadcaster running Predictions. Provided broadcaster_id must match the user_id in the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// ID of a Prediction. Filters results to one or more specific Predictions. /// Not providing one or more IDs will return the full list of Predictions for the authenticated channel. /// /// Maximum: 100 #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub id: Vec, + #[serde(borrow)] + pub id: Cow<'a, [&'a types::PredictionIdRef]>, /// Cursor for forward pagination #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub after: Option, @@ -65,26 +68,20 @@ pub struct GetPredictionsRequest { pub first: Option, } -impl GetPredictionsRequest { +impl<'a> GetPredictionsRequest<'a> { /// Get information about predictions for this broadcasters channel. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), - id: Default::default(), + id: Cow::Borrowed(&[]), after: Default::default(), first: Default::default(), } } - /// ID of a Prediction. - pub fn id(mut self, id: impl Into) -> Self { - self.id = vec![id.into()]; - self - } - /// IDs of a Predictions. - pub fn ids(mut self, ids: impl IntoIterator>) -> Self { - self.id = ids.into_iter().map(Into::into).collect(); + pub fn ids(mut self, ids: impl Into>) -> Self { + self.id = ids.into(); self } } @@ -122,7 +119,7 @@ pub struct Prediction { pub locked_at: Option, } -impl Request for GetPredictionsRequest { +impl Request for GetPredictionsRequest<'_> { type Response = Vec; const PATH: &'static str = "predictions"; @@ -130,9 +127,9 @@ impl Request for GetPredictionsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelReadPredictions]; } -impl RequestGet for GetPredictionsRequest {} +impl RequestGet for GetPredictionsRequest<'_> {} -impl helix::Paginated for GetPredictionsRequest { +impl helix::Paginated for GetPredictionsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor; } } @@ -140,8 +137,9 @@ impl helix::Paginated for GetPredictionsRequest { #[test] fn test_request() { use helix::*; + let req = GetPredictionsRequest::broadcaster_id("55696719") - .id("d6676d5c-c86e-44d2-bfc4-100fb48f0656"); + .ids(vec!["d6676d5c-c86e-44d2-bfc4-100fb48f0656".into()]); // From twitch docs let data = br#" diff --git a/src/helix/endpoints/raids/cancel_a_raid.rs b/src/helix/endpoints/raids/cancel_a_raid.rs index 4e3058cde0..746451fd51 100644 --- a/src/helix/endpoints/raids/cancel_a_raid.rs +++ b/src/helix/endpoints/raids/cancel_a_raid.rs @@ -45,15 +45,16 @@ use helix::RequestDelete; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct CancelARaidRequest { +pub struct CancelARaidRequest<'a> { /// The ID of the broadcaster that sent the raiding party. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, } -impl CancelARaidRequest { +impl<'a> CancelARaidRequest<'a> { /// Cancel a pending raid on this broadcasters channel - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), } @@ -70,7 +71,7 @@ pub enum CancelARaidResponse { Success, } -impl Request for CancelARaidRequest { +impl Request for CancelARaidRequest<'_> { type Response = CancelARaidResponse; #[cfg(feature = "twitch_oauth2")] @@ -80,7 +81,7 @@ impl Request for CancelARaidRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManageRaids]; } -impl RequestDelete for CancelARaidRequest { +impl RequestDelete for CancelARaidRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, diff --git a/src/helix/endpoints/raids/start_a_raid.rs b/src/helix/endpoints/raids/start_a_raid.rs index 742ac79e9a..2743794daa 100644 --- a/src/helix/endpoints/raids/start_a_raid.rs +++ b/src/helix/endpoints/raids/start_a_raid.rs @@ -43,20 +43,22 @@ use helix::RequestPost; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct StartARaidRequest { +pub struct StartARaidRequest<'a> { /// The ID of the broadcaster that’s sending the raiding party. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - from_broadcaster_id: types::UserId, + #[serde(borrow)] + from_broadcaster_id: &'a types::UserIdRef, /// The ID of the broadcaster to raid. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - to_broadcaster_id: types::UserId, + #[serde(borrow)] + to_broadcaster_id: &'a types::UserIdRef, } -impl StartARaidRequest { +impl<'a> StartARaidRequest<'a> { /// Create a new [`StartARaidRequest`] pub fn new( - from_broadcaster_id: impl Into, - to_broadcaster_id: impl Into, + from_broadcaster_id: impl Into<&'a types::UserIdRef>, + to_broadcaster_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { from_broadcaster_id: from_broadcaster_id.into(), @@ -77,7 +79,7 @@ pub struct StartARaidResponse { /// A Boolean value that indicates whether the channel being raided contains mature content. is_mature: bool, } -impl Request for StartARaidRequest { +impl Request for StartARaidRequest<'_> { type Response = StartARaidResponse; const PATH: &'static str = "raids"; @@ -85,7 +87,7 @@ impl Request for StartARaidRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManageRaids]; } -impl RequestPost for StartARaidRequest { +impl RequestPost for StartARaidRequest<'_> { type Body = helix::EmptyBody; fn parse_inner_response( diff --git a/src/helix/endpoints/schedule/create_channel_stream_schedule_segment.rs b/src/helix/endpoints/schedule/create_channel_stream_schedule_segment.rs index ba3f52bead..f41ec81fee 100644 --- a/src/helix/endpoints/schedule/create_channel_stream_schedule_segment.rs +++ b/src/helix/endpoints/schedule/create_channel_stream_schedule_segment.rs @@ -76,15 +76,16 @@ use helix::RequestPost; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct CreateChannelStreamScheduleSegmentRequest { +pub struct CreateChannelStreamScheduleSegmentRequest<'a> { /// User ID of the broadcaster who owns the channel streaming schedule. Provided broadcaster_id must match the user_id in the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, } -impl CreateChannelStreamScheduleSegmentRequest { +impl<'a> CreateChannelStreamScheduleSegmentRequest<'a> { /// Create a single scheduled broadcast or a recurring scheduled broadcast for a channel’s [stream schedule](https://help.twitch.tv/s/article/channel-page-setup#Schedule). - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), } @@ -97,40 +98,42 @@ impl CreateChannelStreamScheduleSegmentRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct CreateChannelStreamScheduleSegmentBody { +pub struct CreateChannelStreamScheduleSegmentBody<'a> { /// Start time for the scheduled broadcast specified in RFC3339 format. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub start_time: types::Timestamp, + #[serde(borrow)] + pub start_time: &'a types::TimestampRef, // FIXME: specific braid? /// The timezone of the application creating the scheduled broadcast using the IANA time zone database format. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub timezone: String, + #[serde(borrow)] + pub timezone: &'a str, /// Indicates if the scheduled broadcast is recurring weekly. pub is_recurring: bool, /// Duration of the scheduled broadcast in minutes from the start_time. Default: 240. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub duration: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub duration: Option<&'a str>, /// Game/Category ID for the scheduled broadcast. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub category_id: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub category_id: Option<&'a types::CategoryIdRef>, /// Title for the scheduled broadcast. Maximum: 140 characters. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub title: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub title: Option<&'a str>, } -impl CreateChannelStreamScheduleSegmentBody { +impl<'a> CreateChannelStreamScheduleSegmentBody<'a> { /// Create a single scheduled broadcast or a recurring scheduled broadcast for a channel’s [stream schedule](https://help.twitch.tv/s/article/channel-page-setup#Schedule). pub fn new( - start_time: impl Into, - timezone: String, + start_time: impl Into<&'a types::TimestampRef>, + timezone: impl Into<&'a str>, is_recurring: bool, ) -> Self { Self { start_time: start_time.into(), - timezone, + timezone: timezone.into(), is_recurring, duration: Default::default(), category_id: Default::default(), @@ -139,14 +142,14 @@ impl CreateChannelStreamScheduleSegmentBody { } } -impl helix::private::SealedSerialize for CreateChannelStreamScheduleSegmentBody {} +impl helix::private::SealedSerialize for CreateChannelStreamScheduleSegmentBody<'_> {} /// Return Values for [Create Channel Stream Schedule Segment](super::create_channel_stream_schedule_segment) /// /// [`create-channel-stream-schedule-segment`](https://dev.twitch.tv/docs/api/reference#create-channel-stream-schedule-segment) pub type CreateChannelStreamScheduleSegmentResponse = ScheduledBroadcasts; -impl Request for CreateChannelStreamScheduleSegmentRequest { +impl Request for CreateChannelStreamScheduleSegmentRequest<'_> { type Response = CreateChannelStreamScheduleSegmentResponse; const PATH: &'static str = "schedule/segment"; @@ -154,8 +157,8 @@ impl Request for CreateChannelStreamScheduleSegmentRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManageSchedule]; } -impl RequestPost for CreateChannelStreamScheduleSegmentRequest { - type Body = CreateChannelStreamScheduleSegmentBody; +impl<'a> RequestPost for CreateChannelStreamScheduleSegmentRequest<'a> { + type Body = CreateChannelStreamScheduleSegmentBody<'a>; } #[cfg(test)] @@ -166,15 +169,12 @@ fn test_request() { use helix::*; let req = CreateChannelStreamScheduleSegmentRequest::broadcaster_id("141981764"); + let ts = types::Timestamp::try_from("2021-07-01T18:00:00Z").unwrap(); let body = CreateChannelStreamScheduleSegmentBody { - duration: Some("60".to_string()), + duration: Some("60"), category_id: Some("509670".into()), - title: Some("TwitchDev Monthly Update // July 1, 2021".to_string()), - ..CreateChannelStreamScheduleSegmentBody::new( - types::Timestamp::try_from("2021-07-01T18:00:00Z").unwrap(), - "America/New_York".to_owned(), - false, - ) + title: Some("TwitchDev Monthly Update // July 1, 2021"), + ..CreateChannelStreamScheduleSegmentBody::new(&*ts, "America/New_York", false) }; dbg!(req.create_request(body, "token", "clientid").unwrap()); diff --git a/src/helix/endpoints/schedule/delete_channel_stream_schedule_segment.rs b/src/helix/endpoints/schedule/delete_channel_stream_schedule_segment.rs index c75224c7fa..1a672786a6 100644 --- a/src/helix/endpoints/schedule/delete_channel_stream_schedule_segment.rs +++ b/src/helix/endpoints/schedule/delete_channel_stream_schedule_segment.rs @@ -50,20 +50,22 @@ use helix::RequestDelete; #[derive(PartialEq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct DeleteChannelStreamScheduleSegmentRequest { +pub struct DeleteChannelStreamScheduleSegmentRequest<'a> { /// User ID of the broadcaster who owns the channel streaming schedule. Provided broadcaster_id must match the user_id in the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of the streaming segment to delete. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub id: types::StreamSegmentId, + #[serde(borrow)] + pub id: &'a types::StreamSegmentIdRef, } -impl DeleteChannelStreamScheduleSegmentRequest { +impl<'a> DeleteChannelStreamScheduleSegmentRequest<'a> { /// Delete a single scheduled broadcast or a recurring scheduled broadcast for a channel’s [stream schedule](https://help.twitch.tv/s/article/channel-page-setup#Schedule). pub fn new( - broadcaster_id: impl Into, - id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + id: impl Into<&'a types::StreamSegmentIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -82,7 +84,7 @@ pub enum DeleteChannelStreamScheduleSegment { Success, } -impl Request for DeleteChannelStreamScheduleSegmentRequest { +impl Request for DeleteChannelStreamScheduleSegmentRequest<'_> { type Response = DeleteChannelStreamScheduleSegment; const PATH: &'static str = "schedule/segment"; @@ -90,7 +92,7 @@ impl Request for DeleteChannelStreamScheduleSegmentRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManageSchedule]; } -impl RequestDelete for DeleteChannelStreamScheduleSegmentRequest { +impl RequestDelete for DeleteChannelStreamScheduleSegmentRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, diff --git a/src/helix/endpoints/schedule/get_channel_stream_schedule.rs b/src/helix/endpoints/schedule/get_channel_stream_schedule.rs index 0ba5f58496..fdf1053e65 100644 --- a/src/helix/endpoints/schedule/get_channel_stream_schedule.rs +++ b/src/helix/endpoints/schedule/get_channel_stream_schedule.rs @@ -47,19 +47,23 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetChannelStreamScheduleRequest { +pub struct GetChannelStreamScheduleRequest<'a> { /// User ID of the broadcaster who owns the channel streaming schedule. Provided broadcaster_id must match the user_id in the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of the stream segment to return. Maximum: 100. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub id: Option, + #[serde(borrow)] + pub id: Option<&'a types::StreamSegmentIdRef>, /// A timestamp in RFC3339 format to start returning stream segments from. If not specified, the current date and time is used. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub start_time: Option, + #[serde(borrow)] + pub start_time: Option<&'a types::TimestampRef>, /// A timezone offset for the requester specified in minutes. This is recommended to ensure stream segments are returned for the correct week. For example, a timezone that is +4 hours from GMT would be “240.” If not specified, “0” is used for GMT. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub utc_offset: Option, + #[serde(borrow)] + pub utc_offset: Option<&'a str>, /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, @@ -68,9 +72,9 @@ pub struct GetChannelStreamScheduleRequest { pub first: Option, } -impl GetChannelStreamScheduleRequest { +impl<'a> GetChannelStreamScheduleRequest<'a> { /// Get a broadcasters schedule - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), id: Default::default(), @@ -82,19 +86,19 @@ impl GetChannelStreamScheduleRequest { } /// Set the id for the request. - pub fn id(mut self, id: impl Into) -> Self { + pub fn id(mut self, id: impl Into<&'a types::StreamSegmentIdRef>) -> Self { self.id = Some(id.into()); self } /// Set the start_time for the request. - pub fn start_time(mut self, start_time: impl Into) -> Self { + pub fn start_time(mut self, start_time: impl Into<&'a types::TimestampRef>) -> Self { self.start_time = Some(start_time.into()); self } /// Set the utc_offset for the request. - pub fn utc_offset(mut self, utc_offset: impl Into) -> Self { + pub fn utc_offset(mut self, utc_offset: impl Into<&'a str>) -> Self { self.utc_offset = Some(utc_offset.into()); self } @@ -111,7 +115,7 @@ impl GetChannelStreamScheduleRequest { /// [`get-channel-stream-schedule`](https://dev.twitch.tv/docs/api/reference#get-channel-stream-schedule) pub type GetChannelStreamScheduleResponse = ScheduledBroadcasts; -impl Request for GetChannelStreamScheduleRequest { +impl Request for GetChannelStreamScheduleRequest<'_> { type Response = ScheduledBroadcasts; const PATH: &'static str = "schedule"; @@ -119,9 +123,9 @@ impl Request for GetChannelStreamScheduleRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetChannelStreamScheduleRequest {} +impl RequestGet for GetChannelStreamScheduleRequest<'_> {} -impl helix::Paginated for GetChannelStreamScheduleRequest { +impl helix::Paginated for GetChannelStreamScheduleRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor; } } diff --git a/src/helix/endpoints/schedule/update_channel_stream_schedule.rs b/src/helix/endpoints/schedule/update_channel_stream_schedule.rs index 994381de6b..4fea71883d 100644 --- a/src/helix/endpoints/schedule/update_channel_stream_schedule.rs +++ b/src/helix/endpoints/schedule/update_channel_stream_schedule.rs @@ -49,27 +49,31 @@ use helix::RequestPatch; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct UpdateChannelStreamScheduleRequest { +pub struct UpdateChannelStreamScheduleRequest<'a> { /// User ID of the broadcaster who owns the channel streaming schedule. Provided broadcaster_id must match the user_id in the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Indicates if Vacation Mode is enabled. Set to true to add a vacation or false to remove vacation from the channel streaming schedule. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub is_vacation_enabled: Option, /// Start time for vacation specified in RFC3339 format. Required if is_vacation_enabled is set to true. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub vacation_start_time: Option, + #[serde(borrow)] + pub vacation_start_time: Option<&'a types::TimestampRef>, /// End time for vacation specified in RFC3339 format. Required if is_vacation_enabled is set to true. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub vacation_end_time: Option, + #[serde(borrow)] + pub vacation_end_time: Option<&'a types::TimestampRef>, /// The timezone for when the vacation is being scheduled using the IANA time zone database format. Required if is_vacation_enabled is set to true. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub timezone: Option, + #[serde(borrow)] + pub timezone: Option<&'a str>, } -impl UpdateChannelStreamScheduleRequest { +impl<'a> UpdateChannelStreamScheduleRequest<'a> { /// Update the settings for a channel’s stream schedule. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), is_vacation_enabled: Default::default(), @@ -91,7 +95,7 @@ pub enum UpdateChannelStreamSchedule { Success, } -impl Request for UpdateChannelStreamScheduleRequest { +impl Request for UpdateChannelStreamScheduleRequest<'_> { type Response = UpdateChannelStreamSchedule; const PATH: &'static str = "schedule/settings"; @@ -99,7 +103,7 @@ impl Request for UpdateChannelStreamScheduleRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManageSchedule]; } -impl RequestPatch for UpdateChannelStreamScheduleRequest { +impl RequestPatch for UpdateChannelStreamScheduleRequest<'_> { type Body = helix::EmptyBody; fn parse_inner_response( @@ -137,13 +141,17 @@ impl RequestPatch for UpdateChannelStreamScheduleRequest { #[cfg(test)] #[test] fn test_request() { + use std::convert::TryFrom; + use helix::*; - use std::convert::TryInto; + + let start = types::Timestamp::try_from("2021-05-16T00:00:00Z").unwrap(); + let end = types::Timestamp::try_from("2021-05-23T00:00:00Z").unwrap(); let req = UpdateChannelStreamScheduleRequest { is_vacation_enabled: Some(true), - vacation_start_time: Some("2021-05-16T00:00:00Z".try_into().unwrap()), - vacation_end_time: Some("2021-05-23T00:00:00Z".try_into().unwrap()), - timezone: Some("America/New_York".to_string()), + vacation_start_time: Some(&start), + vacation_end_time: Some(&end), + timezone: Some("America/New_York"), ..UpdateChannelStreamScheduleRequest::broadcaster_id("141981764") }; diff --git a/src/helix/endpoints/schedule/update_channel_stream_schedule_segment.rs b/src/helix/endpoints/schedule/update_channel_stream_schedule_segment.rs index 6945b22993..15f24138e1 100644 --- a/src/helix/endpoints/schedule/update_channel_stream_schedule_segment.rs +++ b/src/helix/endpoints/schedule/update_channel_stream_schedule_segment.rs @@ -64,20 +64,22 @@ use helix::RequestPatch; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct UpdateChannelStreamScheduleSegmentRequest { +pub struct UpdateChannelStreamScheduleSegmentRequest<'a> { /// User ID of the broadcaster who owns the channel streaming schedule. Provided broadcaster_id must match the user_id in the user OAuth token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// The ID of the streaming segment to update. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub id: types::StreamSegmentId, + #[serde(borrow)] + pub id: &'a types::StreamSegmentIdRef, } -impl UpdateChannelStreamScheduleSegmentRequest { +impl<'a> UpdateChannelStreamScheduleSegmentRequest<'a> { /// Update a single scheduled broadcast or a recurring scheduled broadcast for a channel’s [stream schedule](https://help.twitch.tv/s/article/channel-page-setup#Schedule). pub fn new( - broadcaster_id: impl Into, - id: impl Into, + broadcaster_id: impl Into<&'a types::UserIdRef>, + id: impl Into<&'a types::StreamSegmentIdRef>, ) -> Self { Self { broadcaster_id: broadcaster_id.into(), @@ -92,23 +94,23 @@ impl UpdateChannelStreamScheduleSegmentRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct UpdateChannelStreamScheduleSegmentBody { +pub struct UpdateChannelStreamScheduleSegmentBody<'a> { /// Start time for the scheduled broadcast specified in RFC3339 format. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub start_time: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub start_time: Option<&'a str>, /// Duration of the scheduled broadcast in minutes from the start_time. Default: 240. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub duration: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub duration: Option<&'a str>, /// Game/Category ID for the scheduled broadcast. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub category_id: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub category_id: Option<&'a types::CategoryIdRef>, /// Title for the scheduled broadcast. Maximum: 140 characters. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub title: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub title: Option<&'a str>, /// Indicated if the scheduled broadcast is canceled. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] #[serde(skip_serializing_if = "Option::is_none")] @@ -116,18 +118,18 @@ pub struct UpdateChannelStreamScheduleSegmentBody { // FIXME: Enum? /// The timezone of the application creating the scheduled broadcast using the IANA time zone database format. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - #[serde(skip_serializing_if = "Option::is_none")] - pub timezone: Option, + #[serde(skip_serializing_if = "Option::is_none", borrow)] + pub timezone: Option<&'a str>, } -impl helix::private::SealedSerialize for UpdateChannelStreamScheduleSegmentBody {} +impl helix::private::SealedSerialize for UpdateChannelStreamScheduleSegmentBody<'_> {} /// Return Values for [Update Channel Stream Schedule Segment](super::update_channel_stream_schedule_segment) /// /// [`update-channel-stream-schedule-segment`](https://dev.twitch.tv/docs/api/reference#update-channel-stream-schedule-segment) pub type UpdateChannelStreamScheduleSegmentResponse = ScheduledBroadcasts; -impl Request for UpdateChannelStreamScheduleSegmentRequest { +impl Request for UpdateChannelStreamScheduleSegmentRequest<'_> { type Response = UpdateChannelStreamScheduleSegmentResponse; const PATH: &'static str = "schedule/segment"; @@ -135,8 +137,8 @@ impl Request for UpdateChannelStreamScheduleSegmentRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManageSchedule]; } -impl RequestPatch for UpdateChannelStreamScheduleSegmentRequest { - type Body = UpdateChannelStreamScheduleSegmentBody; +impl<'a> RequestPatch for UpdateChannelStreamScheduleSegmentRequest<'a> { + type Body = UpdateChannelStreamScheduleSegmentBody<'a>; fn parse_inner_response( request: Option, @@ -175,7 +177,7 @@ fn test_request() { "eyJzZWdtZW50SUQiOiJlNGFjYzcyNC0zNzFmLTQwMmMtODFjYS0yM2FkYTc5NzU5ZDQiLCJpc29ZZWFyIjoyMDIxLCJpc29XZWVrIjoyNn0="); let body = UpdateChannelStreamScheduleSegmentBody { - duration: Some("120".to_string()), + duration: Some("120"), ..<_>::default() }; diff --git a/src/helix/endpoints/search/search_categories.rs b/src/helix/endpoints/search/search_categories.rs index 8eb783356b..3e1941d8e6 100644 --- a/src/helix/endpoints/search/search_categories.rs +++ b/src/helix/endpoints/search/search_categories.rs @@ -46,24 +46,26 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct SearchCategoriesRequest { +pub struct SearchCategoriesRequest<'a> { /// URI encoded search query #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub query: String, + #[serde(borrow)] + pub query: &'a str, /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, /// Cursor for backward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] - pub before: Option, + #[serde(borrow)] + pub before: Option<&'a helix::CursorRef>, /// Number of values to be returned per page. Limit: 100. Default: 20. #[cfg_attr(feature = "typed-builder", builder(setter(into), default))] pub first: Option, } -impl SearchCategoriesRequest { +impl<'a> SearchCategoriesRequest<'a> { /// Search categories with the following query. - pub fn query(query: impl Into) -> Self { + pub fn query(query: impl Into<&'a str>) -> Self { Self { query: query.into(), after: None, @@ -84,7 +86,7 @@ impl SearchCategoriesRequest { /// [`search-categories`](https://dev.twitch.tv/docs/api/reference#search-categories) pub type Category = types::TwitchCategory; -impl Request for SearchCategoriesRequest { +impl Request for SearchCategoriesRequest<'_> { type Response = Vec; const PATH: &'static str = "search/categories"; @@ -92,7 +94,7 @@ impl Request for SearchCategoriesRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for SearchCategoriesRequest { +impl RequestGet for SearchCategoriesRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, @@ -121,7 +123,7 @@ impl RequestGet for SearchCategoriesRequest { } } -impl helix::Paginated for SearchCategoriesRequest { +impl helix::Paginated for SearchCategoriesRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/search/search_channels.rs b/src/helix/endpoints/search/search_channels.rs index e313353578..2f453910b4 100644 --- a/src/helix/endpoints/search/search_channels.rs +++ b/src/helix/endpoints/search/search_channels.rs @@ -46,10 +46,11 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct SearchChannelsRequest { +pub struct SearchChannelsRequest<'a> { /// URL encoded search query #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub query: String, + #[serde(borrow)] + pub query: &'a str, /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, @@ -62,9 +63,9 @@ pub struct SearchChannelsRequest { pub live_only: Option, } -impl SearchChannelsRequest { +impl<'a> SearchChannelsRequest<'a> { /// Search channels with the following query. - pub fn query(query: impl Into) -> Self { + pub fn query(query: impl Into<&'a str>) -> Self { Self { query: query.into(), after: None, @@ -122,7 +123,7 @@ pub struct Channel { pub tag_ids: Vec, } -impl Request for SearchChannelsRequest { +impl Request for SearchChannelsRequest<'_> { type Response = Vec; const PATH: &'static str = "search/channels"; @@ -130,9 +131,9 @@ impl Request for SearchChannelsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for SearchChannelsRequest {} +impl RequestGet for SearchChannelsRequest<'_> {} -impl helix::Paginated for SearchChannelsRequest { +impl helix::Paginated for SearchChannelsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/streams/get_followed_streams.rs b/src/helix/endpoints/streams/get_followed_streams.rs index d9df296809..d9f4efc2da 100644 --- a/src/helix/endpoints/streams/get_followed_streams.rs +++ b/src/helix/endpoints/streams/get_followed_streams.rs @@ -46,28 +46,30 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetFollowedStreamsRequest { +pub struct GetFollowedStreamsRequest<'a> { /// Returns streams broadcast by one or more specified user IDs. You can specify up to 100 IDs. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub user_id: types::UserId, + #[serde(borrow)] + pub user_id: &'a types::UserIdRef, /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, /// Cursor for backward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] - pub before: Option, + #[serde(borrow)] + pub before: Option<&'a helix::CursorRef>, /// Maximum number of objects to return. Maximum: 100. Default: 20. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub first: Option, } -impl GetFollowedStreamsRequest { +impl<'a> GetFollowedStreamsRequest<'a> { /// Get a users followed streams. /// /// Requires token with scope [`user:read:follows`](twitch_oauth2::Scope::UserReadFollows). /// /// See also [`HelixClient::get_followed_streams`](crate::helix::HelixClient::get_followed_streams). - pub fn user_id(user_id: impl Into) -> Self { + pub fn user_id(user_id: impl Into<&'a types::UserIdRef>) -> Self { Self { user_id: user_id.into(), after: Default::default(), @@ -88,7 +90,7 @@ impl GetFollowedStreamsRequest { /// [`get-followed-streams`](https://dev.twitch.tv/docs/api/reference#get-followed-streams) pub type GetFollowedStreamsResponse = Stream; -impl Request for GetFollowedStreamsRequest { +impl Request for GetFollowedStreamsRequest<'_> { type Response = Vec; const PATH: &'static str = "streams/followed"; @@ -96,9 +98,9 @@ impl Request for GetFollowedStreamsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::UserReadFollows]; } -impl RequestGet for GetFollowedStreamsRequest {} +impl RequestGet for GetFollowedStreamsRequest<'_> {} -impl helix::Paginated for GetFollowedStreamsRequest { +impl helix::Paginated for GetFollowedStreamsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/streams/get_stream_tags.rs b/src/helix/endpoints/streams/get_stream_tags.rs index 4791079457..f8941a275d 100644 --- a/src/helix/endpoints/streams/get_stream_tags.rs +++ b/src/helix/endpoints/streams/get_stream_tags.rs @@ -46,16 +46,17 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetStreamTagsRequest { +pub struct GetStreamTagsRequest<'a> { // FIXME: twitch docs sucks /// ID of the stream whose tags are going to be fetched #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, } -impl GetStreamTagsRequest { +impl<'a> GetStreamTagsRequest<'a> { /// ID of the stream whose tags are going to be fetched - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), } @@ -67,7 +68,7 @@ impl GetStreamTagsRequest { /// [`get-stream-tags`](https://dev.twitch.tv/docs/api/reference#get-stream-tags) pub type Tag = helix::tags::TwitchTag; -impl Request for GetStreamTagsRequest { +impl Request for GetStreamTagsRequest<'_> { type Response = Vec; const PATH: &'static str = "streams/tags"; @@ -75,7 +76,7 @@ impl Request for GetStreamTagsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetStreamTagsRequest {} +impl RequestGet for GetStreamTagsRequest<'_> {} #[cfg(test)] #[test] diff --git a/src/helix/endpoints/streams/get_streams.rs b/src/helix/endpoints/streams/get_streams.rs index 6773c2979f..98fc3d0191 100644 --- a/src/helix/endpoints/streams/get_streams.rs +++ b/src/helix/endpoints/streams/get_streams.rs @@ -39,66 +39,56 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; /// Query Parameters for [Get Streams](super::get_streams) /// /// [`get-streams`](https://dev.twitch.tv/docs/api/reference#get-streams) -#[derive(PartialEq, Deserialize, Serialize, Clone, Debug, Default)] +#[derive(PartialEq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetStreamsRequest { +pub struct GetStreamsRequest<'a> { /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, /// Cursor for backward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] - pub before: Option, + #[serde(borrow)] + pub before: Option<&'a helix::CursorRef>, /// Maximum number of objects to return. Maximum: 100. Default: 20. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub first: Option, /// Returns streams broadcasting a specified game ID. You can specify up to 10 IDs. #[cfg_attr(feature = "typed-builder", builder(default))] - pub game_id: Vec, + #[serde(borrow)] + pub game_id: Cow<'a, [&'a types::CategoryIdRef]>, /// Stream language. You can specify up to 100 languages. #[cfg_attr(feature = "typed-builder", builder(default))] - pub language: Option, + #[serde(borrow)] + pub language: Option<&'a str>, /// Returns streams broadcast by one or more specified user IDs. You can specify up to 100 IDs. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub user_id: Vec, + #[serde(borrow)] + pub user_id: Cow<'a, [&'a types::UserIdRef]>, /// Returns streams broadcast by one or more specified user login names. You can specify up to 100 names. #[cfg_attr(feature = "typed-builder", builder(default))] - pub user_login: Vec, + #[serde(borrow)] + pub user_login: Cow<'a, [&'a types::UserNameRef]>, } -impl GetStreamsRequest { - /// Return stream for specified user id - pub fn user_id(user_id: impl Into) -> Self { - Self { - user_id: vec![user_id.into()], - ..Self::default() - } - } - +impl<'a> GetStreamsRequest<'a> { /// Return streams for specified user ids - pub fn user_ids(user_ids: impl IntoIterator>) -> Self { + pub fn user_ids(user_ids: impl Into>) -> Self { Self { - user_id: user_ids.into_iter().map(Into::into).collect(), - ..Self::default() - } - } - - /// Return stream for specified user by [nickname](types::UserName) - pub fn user_login(user_login: impl Into) -> Self { - Self { - user_login: vec![user_login.into()], + user_id: user_ids.into(), ..Self::default() } } /// Return streams for specified users by [nickname](types::UserName) - pub fn user_logins(user_logins: impl IntoIterator>) -> Self { + pub fn user_logins(user_logins: impl Into>) -> Self { Self { - user_login: user_logins.into_iter().map(Into::into).collect(), + user_login: user_logins.into(), ..Self::default() } } @@ -110,6 +100,20 @@ impl GetStreamsRequest { } } +impl Default for GetStreamsRequest<'_> { + fn default() -> Self { + Self { + after: None, + before: None, + first: None, + game_id: Cow::Borrowed(&[]), + language: None, + user_id: Cow::Borrowed(&[]), + user_login: Cow::Borrowed(&[]), + } + } +} + /// Return Values for [Get Streams](super::get_streams) /// /// [`get-streams`](https://dev.twitch.tv/docs/api/reference#get-streams) @@ -149,7 +153,7 @@ pub struct Stream { pub viewer_count: usize, } -impl Request for GetStreamsRequest { +impl Request for GetStreamsRequest<'_> { type Response = Vec; const PATH: &'static str = "streams"; @@ -157,9 +161,9 @@ impl Request for GetStreamsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetStreamsRequest {} +impl RequestGet for GetStreamsRequest<'_> {} -impl helix::Paginated for GetStreamsRequest { +impl helix::Paginated for GetStreamsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/streams/replace_stream_tags.rs b/src/helix/endpoints/streams/replace_stream_tags.rs index 66b01ac765..538acd02cb 100644 --- a/src/helix/endpoints/streams/replace_stream_tags.rs +++ b/src/helix/endpoints/streams/replace_stream_tags.rs @@ -60,6 +60,7 @@ //! and parse the [`http::Response`] with [`ReplaceStreamTagsRequest::parse_response(None, &request.get_uri(), response)`](ReplaceStreamTagsRequest::parse_response) use super::*; use helix::RequestPut; +use std::borrow::Cow; /// Query Parameters for [Replace Stream Tags](super::replace_stream_tags) /// @@ -67,15 +68,16 @@ use helix::RequestPut; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct ReplaceStreamTagsRequest { +pub struct ReplaceStreamTagsRequest<'a> { /// ID of the stream for which tags are to be replaced. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, } -impl ReplaceStreamTagsRequest { +impl<'a> ReplaceStreamTagsRequest<'a> { /// ID of the stream for which tags are to be replaced. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), } @@ -92,25 +94,18 @@ impl ReplaceStreamTagsRequest { #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct ReplaceStreamTagsBody { +pub struct ReplaceStreamTagsBody<'a> { /// IDs of tags to be applied to the stream. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub tag_ids: Vec, + #[serde(borrow)] + pub tag_ids: Cow<'a, [&'a types::TagIdRef]>, } -impl ReplaceStreamTagsBody { +impl<'a> ReplaceStreamTagsBody<'a> { /// IDs of tags to be applied to the stream. - pub fn tag_ids(tag_ids: impl IntoIterator>) -> Self { + pub fn tag_ids(tag_ids: impl Into>) -> Self { Self { - tag_ids: tag_ids.into_iter().map(Into::into).collect(), - ..Self::default() - } - } - - /// ID of tag to be applied to the stream. - pub fn tag_id(tag_id: impl Into) -> Self { - Self { - tag_ids: vec![tag_id.into()], + tag_ids: tag_ids.into(), ..Self::default() } } @@ -125,9 +120,9 @@ pub enum ReplaceStreamTags { Success, } -impl helix::private::SealedSerialize for ReplaceStreamTagsBody {} +impl helix::private::SealedSerialize for ReplaceStreamTagsBody<'_> {} -impl Request for ReplaceStreamTagsRequest { +impl Request for ReplaceStreamTagsRequest<'_> { type Response = ReplaceStreamTags; const PATH: &'static str = "streams/tags"; @@ -135,8 +130,8 @@ impl Request for ReplaceStreamTagsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManageBroadcast]; } -impl RequestPut for ReplaceStreamTagsRequest { - type Body = ReplaceStreamTagsBody; +impl<'a> RequestPut for ReplaceStreamTagsRequest<'a> { + type Body = ReplaceStreamTagsBody<'a>; fn parse_inner_response( request: Option, @@ -171,10 +166,11 @@ fn test_request() { use helix::*; let req = ReplaceStreamTagsRequest::broadcaster_id("0"); - let body = ReplaceStreamTagsBody::tag_ids([ - "621fb5bf-5498-4d8f-b4ac-db4d40d401bf", - "79977fb9-f106-4a87-a386-f1b0f99783dd", - ]); + let ids: &[&types::TagIdRef] = &[ + "621fb5bf-5498-4d8f-b4ac-db4d40d401bf".into(), + "79977fb9-f106-4a87-a386-f1b0f99783dd".into(), + ]; + let body = ReplaceStreamTagsBody::tag_ids(ids); dbg!(req.create_request(body, "token", "clientid").unwrap()); // From twitch docs diff --git a/src/helix/endpoints/subscriptions/check_user_subscription.rs b/src/helix/endpoints/subscriptions/check_user_subscription.rs index 591da087ae..8c5fd16376 100644 --- a/src/helix/endpoints/subscriptions/check_user_subscription.rs +++ b/src/helix/endpoints/subscriptions/check_user_subscription.rs @@ -38,6 +38,7 @@ //! and parse the [`http::Response`] with [`CheckUserSubscriptionRequest::parse_response(None, &request.get_uri(), response)`](CheckUserSubscriptionRequest::parse_response) use super::*; use helix::RequestGet; +use std::borrow::Cow; /// Query Parameters for [Check User Subscription](super::check_user_subscription) /// @@ -45,36 +46,29 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct CheckUserSubscriptionRequest { +pub struct CheckUserSubscriptionRequest<'a> { /// User ID of the broadcaster. Must match the User ID in the Bearer token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Unique identifier of account to get subscription status of. Accepts up to 100 values. #[cfg_attr(feature = "typed-builder", builder(default))] - pub user_id: Vec, + #[serde(borrow)] + pub user_id: Cow<'a, [&'a types::UserIdRef]>, } -impl CheckUserSubscriptionRequest { +impl<'a> CheckUserSubscriptionRequest<'a> { /// Checks subscribed users to this specific channel. - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), - user_id: Default::default(), + user_id: Cow::Borrowed(&[]), } } /// Filter the results for specific users. - pub fn user_ids( - mut self, - user_ids: impl IntoIterator>, - ) -> Self { - self.user_id = user_ids.into_iter().map(Into::into).collect(); - self - } - - /// Filter the results for specific user. - pub fn user_id(mut self, user_id: impl Into) -> Self { - self.user_id = vec![user_id.into()]; + pub fn user_ids(mut self, user_ids: impl Into>) -> Self { + self.user_id = user_ids.into(); self } } @@ -102,7 +96,7 @@ pub struct UserSubscription { pub tier: types::SubscriptionTier, } -impl Request for CheckUserSubscriptionRequest { +impl Request for CheckUserSubscriptionRequest<'_> { type Response = UserSubscription; const PATH: &'static str = "subscriptions/user"; @@ -110,7 +104,7 @@ impl Request for CheckUserSubscriptionRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::UserReadSubscriptions]; } -impl RequestGet for CheckUserSubscriptionRequest { +impl RequestGet for CheckUserSubscriptionRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, diff --git a/src/helix/endpoints/subscriptions/get_broadcaster_subscriptions.rs b/src/helix/endpoints/subscriptions/get_broadcaster_subscriptions.rs index 83f5ee3a90..39f26ce21a 100644 --- a/src/helix/endpoints/subscriptions/get_broadcaster_subscriptions.rs +++ b/src/helix/endpoints/subscriptions/get_broadcaster_subscriptions.rs @@ -39,19 +39,22 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; /// Query Parameters for [Get Broadcaster Subscriptions](super::get_broadcaster_subscriptions) /// /// [`get-broadcaster-subscriptions`](https://dev.twitch.tv/docs/api/reference#get-broadcaster-subscriptions) #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetBroadcasterSubscriptionsRequest { +pub struct GetBroadcasterSubscriptionsRequest<'a> { /// User ID of the broadcaster. Must match the User ID in the Bearer token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Unique identifier of account to get subscription status of. Accepts up to 100 values. #[cfg_attr(feature = "typed-builder", builder(default))] - pub user_id: Vec, + #[serde(borrow)] + pub user_id: Cow<'a, [&'a types::UserIdRef]>, /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, @@ -60,23 +63,20 @@ pub struct GetBroadcasterSubscriptionsRequest { pub first: Option, } -impl GetBroadcasterSubscriptionsRequest { +impl<'a> GetBroadcasterSubscriptionsRequest<'a> { /// Get a broadcasters subscribers - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), - user_id: Default::default(), + user_id: Cow::Borrowed(&[]), after: Default::default(), first: Default::default(), } } /// check for specific users in broadcasters subscriptions - pub fn subscriber( - mut self, - user_ids: impl IntoIterator>, - ) -> Self { - self.user_id = user_ids.into_iter().map(Into::into).collect(); + pub fn subscriber(mut self, user_ids: impl Into>) -> Self { + self.user_id = user_ids.into(); self } @@ -132,7 +132,7 @@ pub struct BroadcasterSubscription { pub user_name: types::DisplayName, } -impl Request for GetBroadcasterSubscriptionsRequest { +impl Request for GetBroadcasterSubscriptionsRequest<'_> { type Response = Vec; const PATH: &'static str = "subscriptions"; @@ -141,13 +141,13 @@ impl Request for GetBroadcasterSubscriptionsRequest { &[twitch_oauth2::Scope::ChannelReadSubscriptions]; } -impl RequestGet for GetBroadcasterSubscriptionsRequest {} +impl RequestGet for GetBroadcasterSubscriptionsRequest<'_> {} -impl helix::Paginated for GetBroadcasterSubscriptionsRequest { +impl helix::Paginated for GetBroadcasterSubscriptionsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } -impl helix::Response> { +impl helix::Response, Vec> { /// The current number of subscriber points earned by this broadcaster. pub fn points(&self) -> Result { let points = self.get_other("points")?; diff --git a/src/helix/endpoints/subscriptions/get_broadcaster_subscriptions_events.rs b/src/helix/endpoints/subscriptions/get_broadcaster_subscriptions_events.rs index 3100c4fb4c..6d843ff1a8 100644 --- a/src/helix/endpoints/subscriptions/get_broadcaster_subscriptions_events.rs +++ b/src/helix/endpoints/subscriptions/get_broadcaster_subscriptions_events.rs @@ -46,6 +46,7 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; /// Query Parameters for [Get Broadcaster Subscriptions Events](super::get_broadcaster_subscriptions_events) /// @@ -53,14 +54,16 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetBroadcasterSubscriptionsEventsRequest { +pub struct GetBroadcasterSubscriptionsEventsRequest<'a> { /// Must match the User ID in the Bearer token. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Filters the results and only returns a status object for users who have a subscribe event in this channel and have a matching user_id. /// Maximum: 100 #[cfg_attr(feature = "typed-builder", builder(default))] - pub user_id: Vec, + #[serde(borrow)] + pub user_id: Cow<'a, [&'a types::UserIdRef]>, /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, @@ -69,15 +72,16 @@ pub struct GetBroadcasterSubscriptionsEventsRequest { pub first: Option, /// Retreive a single event by event ID #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub id: Option, + #[serde(borrow)] + pub id: Option<&'a str>, } -impl GetBroadcasterSubscriptionsEventsRequest { +impl<'a> GetBroadcasterSubscriptionsEventsRequest<'a> { /// Get events for this broadcaster - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), - user_id: Default::default(), + user_id: Cow::Borrowed(&[]), after: Default::default(), first: Default::default(), id: Default::default(), @@ -85,17 +89,8 @@ impl GetBroadcasterSubscriptionsEventsRequest { } /// Filter the results for specific users. - pub fn user_ids( - mut self, - user_ids: impl IntoIterator>, - ) -> Self { - self.user_id = user_ids.into_iter().map(Into::into).collect(); - self - } - - /// Filter the results for specific user. - pub fn user_id(mut self, user_id: impl Into) -> Self { - self.user_id = vec![user_id.into()]; + pub fn user_ids(mut self, user_ids: impl Into>) -> Self { + self.user_id = user_ids.into(); self } } @@ -181,7 +176,7 @@ where D: serde::de::Deserializer<'de> { }) } -impl Request for GetBroadcasterSubscriptionsEventsRequest { +impl Request for GetBroadcasterSubscriptionsEventsRequest<'_> { type Response = Vec; const PATH: &'static str = "subscriptions/events"; @@ -190,9 +185,9 @@ impl Request for GetBroadcasterSubscriptionsEventsRequest { &[twitch_oauth2::Scope::ChannelReadSubscriptions]; } -impl RequestGet for GetBroadcasterSubscriptionsEventsRequest {} +impl RequestGet for GetBroadcasterSubscriptionsEventsRequest<'_> {} -impl helix::Paginated for GetBroadcasterSubscriptionsEventsRequest { +impl helix::Paginated for GetBroadcasterSubscriptionsEventsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/tags/get_all_stream_tags.rs b/src/helix/endpoints/tags/get_all_stream_tags.rs index fc7506c5f5..1c53d2d09a 100644 --- a/src/helix/endpoints/tags/get_all_stream_tags.rs +++ b/src/helix/endpoints/tags/get_all_stream_tags.rs @@ -38,14 +38,15 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; /// Query Parameters for [Get All Stream Tags](super::get_all_stream_tags) /// /// [`get-all-stream-tags`](https://dev.twitch.tv/docs/api/reference#get-all-stream-tags) -#[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] +#[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetAllStreamTagsRequest { +pub struct GetAllStreamTagsRequest<'a> { /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, @@ -54,20 +55,25 @@ pub struct GetAllStreamTagsRequest { pub first: Option, /// ID of a tag. Multiple IDs can be specified. If provided, only the specified tag(s) is(are) returned. Maximum of 100. #[cfg_attr(feature = "typed-builder", builder(default))] - pub tag_id: Vec, + #[serde(borrow)] + pub tag_id: Cow<'a, [&'a types::TagIdRef]>, } -impl GetAllStreamTagsRequest { +impl<'a> GetAllStreamTagsRequest<'a> { /// Filter the results for specific tag. - pub fn tag_ids(mut self, tag_ids: impl IntoIterator>) -> Self { - self.tag_id = tag_ids.into_iter().map(Into::into).collect(); + pub fn tag_ids(mut self, tag_ids: impl Into>) -> Self { + self.tag_id = tag_ids.into(); self } +} - /// Filter the results for specific tag. - pub fn tag_id(mut self, tag_id: impl Into) -> Self { - self.tag_id = vec![tag_id.into()]; - self +impl Default for GetAllStreamTagsRequest<'_> { + fn default() -> Self { + Self { + after: None, + first: None, + tag_id: Cow::Borrowed(&[]), + } } } @@ -76,7 +82,7 @@ impl GetAllStreamTagsRequest { /// [`get-all-stream-tags`](https://dev.twitch.tv/docs/api/reference#get-all-stream-tags) pub type Tag = helix::tags::TwitchTag; -impl Request for GetAllStreamTagsRequest { +impl Request for GetAllStreamTagsRequest<'_> { type Response = Vec; const PATH: &'static str = "tags/streams"; @@ -84,9 +90,9 @@ impl Request for GetAllStreamTagsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetAllStreamTagsRequest {} +impl RequestGet for GetAllStreamTagsRequest<'_> {} -impl helix::Paginated for GetAllStreamTagsRequest { +impl helix::Paginated for GetAllStreamTagsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/teams/get_channel_teams.rs b/src/helix/endpoints/teams/get_channel_teams.rs index 7d0dfad9de..94cc1ead0b 100644 --- a/src/helix/endpoints/teams/get_channel_teams.rs +++ b/src/helix/endpoints/teams/get_channel_teams.rs @@ -44,15 +44,16 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetChannelTeamsRequest { +pub struct GetChannelTeamsRequest<'a> { /// Team ID. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, } -impl GetChannelTeamsRequest { +impl<'a> GetChannelTeamsRequest<'a> { /// Get the team of this specific broadcaster - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), } @@ -77,7 +78,7 @@ pub struct BroadcasterTeam { pub team: TeamInformation, } -impl Request for GetChannelTeamsRequest { +impl Request for GetChannelTeamsRequest<'_> { type Response = Vec; #[cfg(feature = "twitch_oauth2")] @@ -87,7 +88,7 @@ impl Request for GetChannelTeamsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetChannelTeamsRequest {} +impl RequestGet for GetChannelTeamsRequest<'_> {} #[cfg(test)] #[test] diff --git a/src/helix/endpoints/teams/get_teams.rs b/src/helix/endpoints/teams/get_teams.rs index 4d68bc523d..683ae2e110 100644 --- a/src/helix/endpoints/teams/get_teams.rs +++ b/src/helix/endpoints/teams/get_teams.rs @@ -44,18 +44,20 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetTeamsRequest { +pub struct GetTeamsRequest<'a> { /// Team ID. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub id: Option, + #[serde(borrow)] + pub id: Option<&'a types::TeamIdRef>, /// Team name. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub name: Option, + #[serde(borrow)] + pub name: Option<&'a str>, } -impl GetTeamsRequest { +impl<'a> GetTeamsRequest<'a> { /// Get team with this [`TeamId`](types::TeamId) - pub fn id(id: impl Into) -> Self { + pub fn id(id: impl Into<&'a types::TeamIdRef>) -> Self { Self { id: Some(id.into()), name: None, @@ -63,7 +65,7 @@ impl GetTeamsRequest { } /// Get team with this name - pub fn name(name: String) -> Self { + pub fn name(name: &'a str) -> Self { Self { id: None, name: Some(name), @@ -85,7 +87,7 @@ pub struct Team { pub team: TeamInformation, } -impl Request for GetTeamsRequest { +impl Request for GetTeamsRequest<'_> { type Response = Vec; #[cfg(feature = "twitch_oauth2")] @@ -95,7 +97,7 @@ impl Request for GetTeamsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetTeamsRequest {} +impl RequestGet for GetTeamsRequest<'_> {} #[cfg(test)] #[test] diff --git a/src/helix/endpoints/users/block_user.rs b/src/helix/endpoints/users/block_user.rs index 289678fc42..88de0bb3c5 100644 --- a/src/helix/endpoints/users/block_user.rs +++ b/src/helix/endpoints/users/block_user.rs @@ -52,10 +52,11 @@ use helix::RequestPut; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct BlockUserRequest { +pub struct BlockUserRequest<'a> { /// User ID of the follower #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub target_user_id: types::UserId, + #[serde(borrow)] + pub target_user_id: &'a types::UserIdRef, /// Source context for blocking the user. Valid values: "chat", "whisper". #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub source_context: Option, @@ -64,9 +65,9 @@ pub struct BlockUserRequest { pub reason: Option, } -impl BlockUserRequest { +impl<'a> BlockUserRequest<'a> { /// Block a user - pub fn block_user(target_user_id: impl Into) -> Self { + pub fn block_user(target_user_id: impl Into<&'a types::UserIdRef>) -> Self { Self { target_user_id: target_user_id.into(), source_context: None, @@ -88,7 +89,7 @@ impl BlockUserRequest { } /// Source context for blocking the user. -#[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] +#[derive(PartialEq, Eq, Deserialize, Serialize, Copy, Clone, Debug)] #[serde(rename_all = "lowercase")] #[non_exhaustive] pub enum SourceContext { @@ -99,7 +100,7 @@ pub enum SourceContext { } /// Reason for blocking the user. -#[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] +#[derive(PartialEq, Eq, Deserialize, Serialize, Copy, Clone, Debug)] #[serde(rename_all = "lowercase")] #[non_exhaustive] pub enum Reason { @@ -121,7 +122,7 @@ pub enum BlockUser { Success, } -impl Request for BlockUserRequest { +impl Request for BlockUserRequest<'_> { type Response = BlockUser; #[cfg(feature = "twitch_oauth2")] @@ -131,7 +132,7 @@ impl Request for BlockUserRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::UserManageBlockedUsers]; } -impl RequestPut for BlockUserRequest { +impl RequestPut for BlockUserRequest<'_> { type Body = helix::EmptyBody; fn parse_inner_response( diff --git a/src/helix/endpoints/users/get_user_block_list.rs b/src/helix/endpoints/users/get_user_block_list.rs index 52f227d655..dbb73f70e9 100644 --- a/src/helix/endpoints/users/get_user_block_list.rs +++ b/src/helix/endpoints/users/get_user_block_list.rs @@ -44,10 +44,11 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetUserBlockListRequest { +pub struct GetUserBlockListRequest<'a> { /// User ID for a Twitch user. #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub broadcaster_id: types::UserId, + #[serde(borrow)] + pub broadcaster_id: &'a types::UserIdRef, /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, @@ -56,9 +57,9 @@ pub struct GetUserBlockListRequest { pub first: Option, } -impl GetUserBlockListRequest { +impl<'a> GetUserBlockListRequest<'a> { /// Get a specified user’s block list - pub fn broadcaster_id(broadcaster_id: impl Into) -> Self { + pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self { Self { broadcaster_id: broadcaster_id.into(), after: Default::default(), @@ -82,7 +83,7 @@ pub struct UserBlock { pub display_name: types::DisplayName, } -impl Request for GetUserBlockListRequest { +impl Request for GetUserBlockListRequest<'_> { type Response = Vec; #[cfg(feature = "twitch_oauth2")] @@ -93,9 +94,9 @@ impl Request for GetUserBlockListRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetUserBlockListRequest {} +impl RequestGet for GetUserBlockListRequest<'_> {} -impl helix::Paginated for GetUserBlockListRequest { +impl helix::Paginated for GetUserBlockListRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/users/get_users.rs b/src/helix/endpoints/users/get_users.rs index 77f540f843..eaebc5f351 100644 --- a/src/helix/endpoints/users/get_users.rs +++ b/src/helix/endpoints/users/get_users.rs @@ -39,6 +39,7 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; /// Query Parameters for [Get Users](super::get_users) /// @@ -46,50 +47,36 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetUsersRequest { +pub struct GetUsersRequest<'a> { /// User ID. Multiple user IDs can be specified. Limit: 100. #[cfg_attr(feature = "typed-builder", builder(default))] - pub id: Vec, + #[serde(borrow)] + pub id: Cow<'a, [&'a types::UserIdRef]>, /// User login name. Multiple login names can be specified. Limit: 100. #[cfg_attr(feature = "typed-builder", builder(default))] - pub login: Vec, + #[serde(borrow)] + pub login: Cow<'a, [&'a types::UserNameRef]>, } -impl GetUsersRequest { - /// Get a single user by their [`UserName`](types::UserName) - pub fn login(login: impl Into) -> Self { - Self { - id: Vec::default(), - login: vec![login.into()], - } - } - +impl<'a> GetUsersRequest<'a> { /// Get multiple user by their [`UserName`](types::UserName) /// /// ```rust /// use twitch_api::helix::users::get_users::GetUsersRequest; /// GetUsersRequest::logins(["twitch", "justintv"]); /// ``` - pub fn logins(login: impl IntoIterator>) -> Self { + pub fn logins(login: impl Into>) -> Self { Self { - id: Vec::default(), - login: login.into_iter().map(Into::into).collect(), - } - } - - /// Get a user by their [`UserId`](types::UserId) - pub fn id(id: impl Into) -> Self { - Self { - id: vec![id.into()], - login: Vec::default(), + id: Cow::Borrowed(&[]), + login: login.into(), } } /// Get multiple user by their [`UserId`](types::UserId) - pub fn ids(ids: impl IntoIterator>) -> Self { + pub fn ids(ids: impl Into>) -> Self { Self { - id: ids.into_iter().map(Into::into).collect(), - login: Vec::default(), + id: ids.into(), + login: Cow::Borrowed(&[]), } } @@ -100,8 +87,8 @@ impl GetUsersRequest { /// This is not a valid request, it needs to be filled out with other fields. pub fn new() -> Self { Self { - id: Vec::default(), - login: Vec::default(), + id: Cow::Borrowed(&[]), + login: Cow::Borrowed(&[]), } } } @@ -143,7 +130,7 @@ pub struct User { pub view_count: usize, } -impl Request for GetUsersRequest { +impl Request for GetUsersRequest<'_> { type Response = Vec; #[cfg(feature = "twitch_oauth2")] @@ -153,13 +140,15 @@ impl Request for GetUsersRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetUsersRequest {} +impl RequestGet for GetUsersRequest<'_> {} #[cfg(test)] #[test] fn test_request() { use helix::*; - let req = GetUsersRequest::id("44322889"); + + let ids: &[&types::UserIdRef] = &["44322889".into()]; + let req = GetUsersRequest::ids(ids); // From twitch docs // FIXME: This is not valid anymore. Twitch.... diff --git a/src/helix/endpoints/users/get_users_follows.rs b/src/helix/endpoints/users/get_users_follows.rs index 5b4106ca5e..9945415780 100644 --- a/src/helix/endpoints/users/get_users_follows.rs +++ b/src/helix/endpoints/users/get_users_follows.rs @@ -43,7 +43,7 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetUsersFollowsRequest { +pub struct GetUsersFollowsRequest<'a> { /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, @@ -52,15 +52,17 @@ pub struct GetUsersFollowsRequest { pub first: Option, /// User ID. The request returns information about users who are being followed by the from_id user. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub from_id: Option, + #[serde(borrow)] + pub from_id: Option<&'a types::UserIdRef>, /// User ID. The request returns information about users who are following the to_id user. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub to_id: Option, + #[serde(borrow)] + pub to_id: Option<&'a types::UserIdRef>, } -impl GetUsersFollowsRequest { +impl<'a> GetUsersFollowsRequest<'a> { /// Get the broadcasters that `from_id` is following - pub fn following(from_id: impl Into) -> Self { + pub fn following(from_id: impl Into<&'a types::UserIdRef>) -> Self { Self { from_id: Some(from_id.into()), ..Self::empty() @@ -68,7 +70,7 @@ impl GetUsersFollowsRequest { } /// Get the followers of `to_id` - pub fn followers(to_id: impl Into) -> Self { + pub fn followers(to_id: impl Into<&'a types::UserIdRef>) -> Self { Self { to_id: Some(to_id.into()), ..Self::empty() @@ -77,8 +79,8 @@ impl GetUsersFollowsRequest { /// Check if user follows a specific broadcaster pub fn follows( - user_id: impl Into, - broadcaster_id: impl Into, + user_id: impl Into<&'a types::UserIdRef>, + broadcaster_id: impl Into<&'a types::UserIdRef>, ) -> Self { Self { from_id: Some(user_id.into()), @@ -141,7 +143,7 @@ pub struct FollowRelationship { pub to_login: types::UserName, } -impl Request for GetUsersFollowsRequest { +impl Request for GetUsersFollowsRequest<'_> { type Response = UsersFollows; #[cfg(feature = "twitch_oauth2")] @@ -151,7 +153,7 @@ impl Request for GetUsersFollowsRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[]; } -impl RequestGet for GetUsersFollowsRequest { +impl RequestGet for GetUsersFollowsRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, @@ -190,7 +192,7 @@ impl RequestGet for GetUsersFollowsRequest { } } -impl helix::Paginated for GetUsersFollowsRequest { +impl helix::Paginated for GetUsersFollowsRequest<'_> { fn set_pagination(&mut self, cursor: Option) { self.after = cursor } } diff --git a/src/helix/endpoints/users/unblock_user.rs b/src/helix/endpoints/users/unblock_user.rs index b8800688d0..bb806fd10d 100644 --- a/src/helix/endpoints/users/unblock_user.rs +++ b/src/helix/endpoints/users/unblock_user.rs @@ -45,15 +45,16 @@ use helix::RequestDelete; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct UnblockUserRequest { +pub struct UnblockUserRequest<'a> { /// User ID of the follower #[cfg_attr(feature = "typed-builder", builder(setter(into)))] - pub target_user_id: types::UserId, + #[serde(borrow)] + pub target_user_id: &'a types::UserIdRef, } -impl UnblockUserRequest { +impl<'a> UnblockUserRequest<'a> { /// Create a new unblock request - pub fn unblock_user(target_user_id: impl Into) -> Self { + pub fn unblock_user(target_user_id: impl Into<&'a types::UserIdRef>) -> Self { Self { target_user_id: target_user_id.into(), } @@ -70,7 +71,7 @@ pub enum UnblockUser { Success, } -impl Request for UnblockUserRequest { +impl Request for UnblockUserRequest<'_> { type Response = UnblockUser; #[cfg(feature = "twitch_oauth2")] @@ -80,7 +81,7 @@ impl Request for UnblockUserRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::UserManageBlockedUsers]; } -impl RequestDelete for UnblockUserRequest { +impl RequestDelete for UnblockUserRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, diff --git a/src/helix/endpoints/videos/delete_videos.rs b/src/helix/endpoints/videos/delete_videos.rs index c6afeae1d6..e606b8e9a8 100644 --- a/src/helix/endpoints/videos/delete_videos.rs +++ b/src/helix/endpoints/videos/delete_videos.rs @@ -39,6 +39,7 @@ use super::*; use helix::RequestDelete; +use std::borrow::Cow; // FIXME: One of id, user_id or game_id needs to be specified. typed_builder should have enums. id can not be used with other params /// Query Parameters for [Delete Videos](super::delete_videos) @@ -47,26 +48,16 @@ use helix::RequestDelete; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct DeleteVideosRequest { +pub struct DeleteVideosRequest<'a> { /// ID of the video(s) to be deleted. Limit: 5. #[cfg_attr(feature = "typed-builder", builder(default))] - pub id: Vec, + #[serde(borrow)] + pub id: Cow<'a, [&'a types::VideoIdRef]>, } -impl DeleteVideosRequest { - /// ID of the video to be deleted - pub fn id(id: impl Into) -> Self { - Self { - id: vec![id.into()], - } - } - +impl<'a> DeleteVideosRequest<'a> { /// ID of the videos to be deleted - pub fn ids(ids: impl IntoIterator>) -> Self { - Self { - id: ids.into_iter().map(Into::into).collect(), - } - } + pub fn ids(ids: impl Into>) -> Self { Self { id: ids.into() } } } // FIXME: Should return VideoIds /// Return Values for [Delete Videos](super::delete_videos) @@ -79,7 +70,7 @@ pub enum DeleteVideo { Success, } -impl Request for DeleteVideosRequest { +impl Request for DeleteVideosRequest<'_> { type Response = DeleteVideo; const PATH: &'static str = "videos"; @@ -87,7 +78,7 @@ impl Request for DeleteVideosRequest { const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelManageVideos]; } -impl RequestDelete for DeleteVideosRequest { +impl RequestDelete for DeleteVideosRequest<'_> { fn parse_inner_response( request: Option, uri: &http::Uri, @@ -119,7 +110,7 @@ impl RequestDelete for DeleteVideosRequest { #[test] fn test_request() { use helix::*; - let req = DeleteVideosRequest::id("234482848"); + let req = DeleteVideosRequest::ids(vec!["234482848".into()]); // From twitch docs let data = br#""#.to_vec(); diff --git a/src/helix/endpoints/videos/get_videos.rs b/src/helix/endpoints/videos/get_videos.rs index 61f3d7bcf0..fdb87b8ef6 100644 --- a/src/helix/endpoints/videos/get_videos.rs +++ b/src/helix/endpoints/videos/get_videos.rs @@ -39,6 +39,7 @@ use super::*; use helix::RequestGet; +use std::borrow::Cow; // FIXME: One of id, user_id or game_id needs to be specified. typed_builder should have enums. id can not be used with other params /// Query Parameters for [Get Videos](super::get_videos) @@ -47,28 +48,33 @@ use helix::RequestGet; #[derive(PartialEq, Eq, Deserialize, Serialize, Clone, Debug, Default)] #[cfg_attr(feature = "typed-builder", derive(typed_builder::TypedBuilder))] #[non_exhaustive] -pub struct GetVideosRequest { +pub struct GetVideosRequest<'a> { /// ID of the video being queried. Limit: 100. If this is specified, you cannot use any of the optional query parameters below. #[cfg_attr(feature = "typed-builder", builder(default))] - pub id: Vec, + #[serde(borrow)] + pub id: Cow<'a, [&'a types::VideoIdRef]>, /// ID of the user who owns the video. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub user_id: Option, + #[serde(borrow)] + pub user_id: Option<&'a types::UserIdRef>, /// ID of the game the video is of. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub game_id: Option, + #[serde(borrow)] + pub game_id: Option<&'a types::CategoryIdRef>, /// Cursor for forward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] pub after: Option, /// Cursor for backward pagination: tells the server where to start fetching the next set of results, in a multi-page response. The cursor value specified here is from the pagination response field of a prior query. #[cfg_attr(feature = "typed-builder", builder(default))] - pub before: Option, + #[serde(borrow)] + pub before: Option<&'a helix::CursorRef>, /// Number of values to be returned when getting videos by user or game ID. Limit: 100. Default: 20. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub first: Option, /// Language of the video being queried. Limit: 1. #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] - pub language: Option, + #[serde(borrow)] + pub language: Option<&'a str>, /// Period during which the video was created. Valid values: "all", "day", "week", "month". Default: "all". #[cfg_attr(feature = "typed-builder", builder(default, setter(into)))] pub period: Option, @@ -81,25 +87,17 @@ pub struct GetVideosRequest { pub type_: Option, } -impl GetVideosRequest { - /// ID of the video being queried. - pub fn id(id: impl Into) -> Self { - Self { - id: vec![id.into()], - ..Self::default() - } - } - +impl<'a> GetVideosRequest<'a> { /// IDs of the videos being queried. - pub fn ids(ids: impl IntoIterator>) -> Self { + pub fn ids(ids: impl Into>) -> Self { Self { - id: ids.into_iter().map(Into::into).collect(), + id: ids.into(), ..Self::default() } } /// ID of the user who owns the video. - pub fn user_id(user_id: impl Into) -> Self { + pub fn user_id(user_id: impl Into<&'a types::UserIdRef>) -> Self { Self { user_id: Some(user_id.into()), ..Self::default() @@ -107,7 +105,7 @@ impl GetVideosRequest { } /// ID of the game the video is of. - pub fn game_id(game_id: impl Into) -> Self { + pub fn game_id(game_id: impl Into<&'a types::CategoryIdRef>) -> Self { Self { game_id: Some(game_id.into()), ..Self::default() @@ -171,7 +169,7 @@ pub struct MutedSegment { pub offset: i64, } -impl Request for GetVideosRequest { +impl Request for GetVideosRequest<'_> { type Response = Vec