Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Use (mostly) References in Requests #280

Merged
merged 8 commits into from
Oct 30, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 129 additions & 102 deletions src/helix/client/client_ext.rs

Large diffs are not rendered by default.

23 changes: 13 additions & 10 deletions src/helix/endpoints/bits/get_bits_leaderboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<i32>,
Expand All @@ -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<String>,
#[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<types::Timestamp>,
#[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<types::UserId>,
#[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 {
Expand All @@ -76,23 +79,23 @@ 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
}
}

/// Get leaderboard starting at this timestamp
pub fn started_at(self, started_at: impl Into<types::Timestamp>) -> Self {
pub fn started_at(self, started_at: impl Into<&'a types::TimestampRef>) -> Self {
Self {
started_at: Some(started_at.into()),
..self
}
}

/// Get leaderboard where this user is included (if they are on the leaderboard)
pub fn user_id(self, user_id: impl Into<types::UserId>) -> Self {
pub fn user_id(self, user_id: impl Into<&'a types::UserIdRef>) -> Self {
Self {
user_id: Some(user_id.into()),
..self
Expand Down Expand Up @@ -146,15 +149,15 @@ 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";
#[cfg(feature = "twitch_oauth2")]
const SCOPE: &'static [twitch_oauth2::Scope] = &[];
}

impl RequestGet for GetBitsLeaderboardRequest {
impl RequestGet for GetBitsLeaderboardRequest<'_> {
fn parse_inner_response(
request: Option<Self>,
uri: &http::Uri,
Expand Down
13 changes: 7 additions & 6 deletions src/helix/endpoints/bits/get_cheermotes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<types::UserId>,
#[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<types::UserId>) -> Self {
pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self {
Self {
broadcaster_id: Some(broadcaster_id.into()),
}
Expand Down Expand Up @@ -176,15 +177,15 @@ pub struct CheermoteImageArray {
#[serde(transparent)]
pub struct Level(pub String);

impl Request for GetCheermotesRequest {
impl Request for GetCheermotesRequest<'_> {
type Response = Vec<Cheermote>;

const PATH: &'static str = "bits/cheermotes";
#[cfg(feature = "twitch_oauth2")]
const SCOPE: &'static [twitch_oauth2::Scope] = &[];
}

impl RequestGet for GetCheermotesRequest {}
impl RequestGet for GetCheermotesRequest<'_> {}

#[cfg(test)]
#[test]
Expand Down
18 changes: 10 additions & 8 deletions src/helix/endpoints/channels/add_channel_vip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<types::UserId>,
user_id: impl Into<types::UserId>,
broadcaster_id: impl Into<&'a types::UserIdRef>,
user_id: impl Into<&'a types::UserIdRef>,
) -> Self {
Self {
broadcaster_id: broadcaster_id.into(),
Expand All @@ -74,15 +76,15 @@ pub enum AddChannelVipResponse {
Success,
}

impl Request for AddChannelVipRequest {
impl Request for AddChannelVipRequest<'_> {
type Response = AddChannelVipResponse;

const PATH: &'static str = "channels/vips";
#[cfg(feature = "twitch_oauth2")]
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(
Expand Down
15 changes: 8 additions & 7 deletions src/helix/endpoints/channels/get_channel_editors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<types::UserId>) -> Self {
pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self {
Self {
broadcaster_id: broadcaster_id.into(),
}
Expand All @@ -73,21 +74,21 @@ pub struct Editor {
pub created_at: types::Timestamp,
}

impl Request for GetChannelEditorsRequest {
impl Request for GetChannelEditorsRequest<'_> {
type Response = Vec<Editor>;

const PATH: &'static str = "channels/editors";
#[cfg(feature = "twitch_oauth2")]
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#"
Expand Down
15 changes: 8 additions & 7 deletions src/helix/endpoints/channels/get_channel_information.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<types::UserId>) -> Self {
pub fn broadcaster_id(broadcaster_id: impl Into<&'a types::UserIdRef>) -> Self {
Self {
broadcaster_id: broadcaster_id.into(),
}
Expand Down Expand Up @@ -87,15 +88,15 @@ pub struct ChannelInformation {
pub delay: i64,
}

impl Request for GetChannelInformationRequest {
impl Request for GetChannelInformationRequest<'_> {
type Response = Option<ChannelInformation>;

const PATH: &'static str = "channels";
#[cfg(feature = "twitch_oauth2")]
const SCOPE: &'static [twitch_oauth2::Scope] = &[];
}

impl RequestGet for GetChannelInformationRequest {
impl RequestGet for GetChannelInformationRequest<'_> {
fn parse_inner_response(
request: Option<Self>,
uri: &http::Uri,
Expand Down Expand Up @@ -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#"
Expand Down
37 changes: 17 additions & 20 deletions src/helix/endpoints/channels/get_vips.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,23 @@
//! 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)
///
/// [`get-vips`](https://dev.twitch.tv/docs/api/reference#get-vips)
#[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<types::UserId>,
#[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<usize>,
Expand All @@ -58,12 +61,12 @@ pub struct GetVipsRequest {
pub after: Option<helix::Cursor>,
}

impl GetVipsRequest {
impl<'a> GetVipsRequest<'a> {
/// Get channel VIPs in channel
pub fn broadcaster_id(broadcaster_id: impl Into<types::UserId>) -> 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,
}
Expand All @@ -75,18 +78,10 @@ impl GetVipsRequest {
self
}

/// Filter response with this ID
pub fn user_id(self, user_id: impl Into<types::UserId>) -> Self {
Self {
user_id: vec![user_id.into()],
..self
}
}

Comment on lines -78 to -85
Copy link
Member

Choose a reason for hiding this comment

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

removing this and others is a bit sad, but there is no good way to keep it.

If we could store a impl IntoIter<Item=impl Into<Cow<'_, Ref>> wherever we have multiples and have serde properly serialize (and deserialize I guess), that'd be nice.

/// Filter response with these IDs
pub fn user_ids(self, user_ids: impl IntoIterator<Item = impl Into<types::UserId>>) -> Self {
pub fn user_ids(self, user_ids: impl Into<Cow<'a, [&'a types::UserIdRef]>>) -> Self {
Self {
user_id: user_ids.into_iter().map(Into::into).collect(),
user_id: user_ids.into(),
..self
}
}
Expand All @@ -107,19 +102,19 @@ pub struct Vip {
pub user_login: types::UserName,
}

impl Request for GetVipsRequest {
impl Request for GetVipsRequest<'_> {
type Response = Vec<Vip>;

const PATH: &'static str = "channels/vips";
#[cfg(feature = "twitch_oauth2")]
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<helix::Cursor>) { self.after = cursor; }
}

impl RequestGet for GetVipsRequest {}
impl RequestGet for GetVipsRequest<'_> {}

#[cfg(test)]
#[test]
Expand Down Expand Up @@ -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 ...
Expand Down
Loading