Skip to content

Commit

Permalink
Merge #303
Browse files Browse the repository at this point in the history
303: fix lifetimes issues r=Emilgardis a=Emilgardis

resolves #236 

Co-authored-by: Emil Gardström <emil.gardstrom@gmail.com>
  • Loading branch information
bors[bot] and Emilgardis authored Dec 19, 2022
2 parents cf4c7df + 10806bf commit 6517559
Show file tree
Hide file tree
Showing 17 changed files with 179 additions and 175 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- `typed-builder` is now optional and not enabled by default, enable feature `typed-builder` to use the `::builder()` methods
- Client ext methods that take a `IntoIterator<Item = T>` now takes a `IntoIterator<Item = impl Into<T>>`
- `Get Channel Information` can now take multiple ids
- Simplified lifetimes for `Client`. Fixes an issue where &'1 Thing<'static> where: Thing<'static> would wrongly lower '1 to be specific. See <https://github.com/twitch-rs/twitch_api/issues/236>

### Changes

Expand Down
20 changes: 15 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "twitch_api"
version = "0.7.0-rc.2"
version = "0.7.0-rc.3"
authors = ["Emil Gardström <emil.gardstrom@gmail.com>"]
edition = "2018"
repository = "https://github.com/twitch-rs/twitch_api"
Expand All @@ -27,8 +27,8 @@ members = ["xtask", "examples/*"]
exclude = ["twitch_types", "twitch_oauth2"]

[workspace.dependencies]
twitch_api = { version = "0.7.0-rc.2", path = "." }
twitch_oauth2 = { version = "0.9.2", path = "twitch_oauth2/" }
twitch_api = { version = "0.7.0-rc.3", path = "." }
twitch_oauth2 = { version = "0.10.0", path = "twitch_oauth2/" }

[dependencies]
thiserror = "1.0.37"
Expand All @@ -37,7 +37,7 @@ http = "0.2.8"
typed-builder = { version = "0.11.0", optional = true }
url = "2.3.1"
once_cell = "1.16.0"
twitch_oauth2 = { version = "0.9.2", optional = true, path = "twitch_oauth2/" }
twitch_oauth2 = { version = "0.10.0", optional = true, path = "twitch_oauth2/" }
serde = { version = "1.0.148", features = ["derive"] }
serde_path_to_error = { version = "0.1.8", optional = true }
async-trait = { version = "0.1.59", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion examples/eventsub_websocket/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fn install_tracing() {

#[tracing::instrument(skip(client, token))]
pub async fn make_token<'a>(
client: &'a impl twitch_oauth2::client::Client<'a>,
client: &'a impl twitch_oauth2::client::Client,
token: impl Into<twitch_oauth2::AccessToken>,
) -> Result<UserToken, eyre::Report> {
UserToken::from_existing(client, token.into(), None, None)
Expand Down
12 changes: 12 additions & 0 deletions examples/twitch_oauth2-integration/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "twitch_oauth2-integration"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
twitch_api = { workspace = true, features = ["reqwest", "helix"] }
twitch_oauth2 = { workspace = true }
reqwest = { version = "0.11.13" }
tokio = { version = "1.23.0", features = ["macros"] }
25 changes: 25 additions & 0 deletions examples/twitch_oauth2-integration/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use twitch_api::{twitch_oauth2::*, *};

pub async fn get_auth_token_request(
client: &TwitchClient<'_, reqwest::Client>,
) -> Result<AppAccessToken, ()> {
let client_id = ClientId::from("aaa");
let client_secret = ClientSecret::from("aaaa");

let token =
AppAccessToken::get_app_access_token(client, client_id, client_secret, Scope::all())
.await
.unwrap();

Ok(token)
}

pub fn tokio() {
let client: TwitchClient<'static, reqwest::Client> = TwitchClient::new();

tokio::spawn({
async move {
get_auth_token_request(&client).await.unwrap();
}
});
}
65 changes: 24 additions & 41 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@
//! }
//! pub type ClientError = std::io::Error;
//! }
//! impl<'a> twitch_api::HttpClient<'a> for foo::Client {
//! impl twitch_api::HttpClient for foo::Client {
//! type Error = foo::ClientError;
//!
//! fn req(&'a self, request: Request) -> BoxedFuture<'a, Result<Response, Self::Error>> {
//! fn req(&self, request: Request) -> BoxedFuture<'_, Result<Response, Self::Error>> {
//! Box::pin(async move {
//! Ok(self
//! .call(
Expand Down Expand Up @@ -166,14 +166,11 @@ where Buffer: Into<hyper::body::Body>
}

/// A client that can do requests
pub trait Client<'a>: Send + Sync + 'a {
pub trait Client: Send + Sync {
/// Error returned by the client
type Error: Error + Send + Sync + 'static;
/// Send a request
fn req(
&'a self,
request: Request,
) -> BoxedFuture<'a, Result<Response, <Self as Client>::Error>>;
fn req(&self, request: Request) -> BoxedFuture<'_, Result<Response, <Self as Client>::Error>>;
}

/// A specific client default for setting some sane defaults for API calls and oauth2 usage
Expand All @@ -200,47 +197,33 @@ pub trait ClientDefault<'a>: Clone + Sized {
fn default_client_with_name(product: Option<http::HeaderValue>) -> Result<Self, Self::Error>;
}

// This makes errors very muddy, preferably we'd actually use rustc_on_unimplemented, but that is highly not recommended (and doesn't work 100% for me at least)
// impl<'a, F, R, E> Client<'a> for F
// where
// F: Fn(Req) -> R + Send + Sync + 'a,
// R: Future<Output = Result<Response, E>> + Send + Sync + 'a,
// E: Error + Send + Sync + 'static,
// {
// type Error = E;
//
// fn req(&'a self, request: Req) -> BoxedFuture<'a, Result<Response, Self::Error>> {
// Box::pin((self)(request))
// }
// }

#[derive(Debug, Default, thiserror::Error, Clone)]
/// A client that will never work, used to trick documentation tests
#[error("this client does not do anything, only used for documentation test that only checks")]
pub struct DummyHttpClient;

impl<'a> Client<'a> for DummyHttpClient {
impl Client for DummyHttpClient {
type Error = DummyHttpClient;

fn req(&'a self, _: Request) -> BoxedFuture<'a, Result<Response, Self::Error>> {
fn req(&self, _: Request) -> BoxedFuture<'_, Result<Response, Self::Error>> {
Box::pin(async { Err(DummyHttpClient) })
}
}

impl<'a> Client<'a> for twitch_oauth2::client::DummyClient {
impl Client for twitch_oauth2::client::DummyClient {
type Error = twitch_oauth2::client::DummyClient;

fn req(&'a self, _: Request) -> BoxedFuture<'a, Result<Response, Self::Error>> {
fn req(&self, _: Request) -> BoxedFuture<'_, Result<Response, Self::Error>> {
Box::pin(async { Err(twitch_oauth2::client::DummyClient) })
}
}

impl<'a, C> Client<'a> for std::sync::Arc<C>
where C: Client<'a>
impl<C> Client for std::sync::Arc<C>
where C: Client
{
type Error = <C as Client<'a>>::Error;
type Error = <C as Client>::Error;

fn req(&'a self, req: Request) -> BoxedFuture<'a, Result<Response, Self::Error>> {
fn req(&self, req: Request) -> BoxedFuture<'_, Result<Response, Self::Error>> {
self.as_ref().req(req)
}
}
Expand All @@ -267,14 +250,14 @@ pub enum CompatError<E> {
}

#[cfg(feature = "helix")]
impl<'a, C: Client<'a> + Sync> twitch_oauth2::client::Client<'a> for crate::HelixClient<'a, C> {
type Error = CompatError<<C as Client<'a>>::Error>;
impl<'c, C: Client + Sync> twitch_oauth2::client::Client for crate::HelixClient<'c, C> {
type Error = CompatError<<C as Client>::Error>;

fn req(
&'a self,
&self,
request: http::Request<Vec<u8>>,
) -> BoxedFuture<
'a,
'_,
Result<http::Response<Vec<u8>>, <Self as twitch_oauth2::client::Client>::Error>,
> {
let client = self.get_client();
Expand All @@ -297,14 +280,14 @@ impl<'a, C: Client<'a> + Sync> twitch_oauth2::client::Client<'a> for crate::Heli
}

#[cfg(feature = "tmi")]
impl<'a, C: Client<'a> + Sync> twitch_oauth2::client::Client<'a> for crate::TmiClient<'a, C> {
type Error = CompatError<<C as Client<'a>>::Error>;
impl<'c, C: Client + Sync> twitch_oauth2::client::Client for crate::TmiClient<'c, C> {
type Error = CompatError<<C as Client>::Error>;

fn req(
&'a self,
&self,
request: http::Request<Vec<u8>>,
) -> BoxedFuture<
'a,
'_,
Result<http::Response<Vec<u8>>, <Self as twitch_oauth2::client::Client>::Error>,
> {
let client = self.get_client();
Expand All @@ -327,14 +310,14 @@ impl<'a, C: Client<'a> + Sync> twitch_oauth2::client::Client<'a> for crate::TmiC
}

#[cfg(any(feature = "tmi", feature = "helix"))]
impl<'a, C: Client<'a> + Sync> twitch_oauth2::client::Client<'a> for crate::TwitchClient<'a, C> {
type Error = CompatError<<C as Client<'a>>::Error>;
impl<'c, C: Client + Sync> twitch_oauth2::client::Client for crate::TwitchClient<'c, C> {
type Error = CompatError<<C as Client>::Error>;

fn req(
&'a self,
&self,
request: http::Request<Vec<u8>>,
) -> BoxedFuture<
'a,
'_,
Result<http::Response<Vec<u8>>, <Self as twitch_oauth2::client::Client>::Error>,
> {
let client = self.get_client();
Expand Down
4 changes: 2 additions & 2 deletions src/client/reqwest_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use super::*;
use reqwest::Client as ReqwestClient;

#[cfg_attr(nightly, doc(cfg(feature = "reqwest")))] // FIXME: This doc_cfg does nothing
impl<'a> Client<'a> for ReqwestClient {
impl Client for ReqwestClient {
type Error = reqwest::Error;

fn req(&'a self, request: Request) -> BoxedFuture<'static, Result<Response, Self::Error>> {
fn req(&self, request: Request) -> BoxedFuture<'static, Result<Response, Self::Error>> {
// Reqwest plays really nice here and has a try_from on `http::Request` -> `reqwest::Request`
use std::convert::TryFrom;
let req = match reqwest::Request::try_from(request) {
Expand Down
4 changes: 2 additions & 2 deletions src/client/surf_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ pub enum SurfError {
use surf::Client as SurfClient;

#[cfg_attr(nightly, doc(cfg(feature = "surf")))] // FIXME: This doc_cfg does nothing
impl<'a> Client<'a> for SurfClient {
impl Client for SurfClient {
type Error = SurfError;

fn req(&'a self, request: Request) -> BoxedFuture<'static, Result<Response, Self::Error>> {
fn req(&self, request: Request) -> BoxedFuture<'static, Result<Response, Self::Error>> {
// First we translate the `http::Request` method and uri into types that surf understands.

let method: surf::http::Method = request.method().clone().into();
Expand Down
4 changes: 2 additions & 2 deletions src/client/ureq_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ pub enum UreqError {
}

#[cfg_attr(nightly, doc(cfg(feature = "ureq")))] // FIXME: This doc_cfg does nothing
impl<'a> Client<'a> for UreqAgent {
impl Client for UreqAgent {
type Error = UreqError;

fn req(&'a self, request: Request) -> BoxedFuture<'static, Result<Response, Self::Error>> {
fn req(&self, request: Request) -> BoxedFuture<'static, Result<Response, Self::Error>> {
use std::io::Read;

let method = request.method().to_string();
Expand Down
16 changes: 8 additions & 8 deletions src/helix/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub(crate) mod client_ext;
mod custom;

#[cfg(feature = "client")]
impl<C: crate::HttpClient<'static> + crate::client::ClientDefault<'static>> Default
impl<C: crate::HttpClient + crate::client::ClientDefault<'static>> Default
for HelixClient<'static, C>
{
fn default() -> Self { Self::new() }
Expand Down Expand Up @@ -64,13 +64,13 @@ impl<C: crate::HttpClient<'static> + crate::client::ClientDefault<'static>> Defa
#[derive(Clone)]
#[cfg(all(feature = "client", feature = "helix"))] // this is needed due to a bug?
pub struct HelixClient<'a, C>
where C: crate::HttpClient<'a> {
where C: crate::HttpClient + 'a {
pub(crate) client: C,
pub(crate) _pd: std::marker::PhantomData<&'a ()>, // TODO: Implement rate limiter...
}

#[cfg(feature = "client")]
impl<'a, C: crate::HttpClient<'a>> HelixClient<'a, C> {
impl<'a, C: crate::HttpClient> HelixClient<'a, C> {
/// Create a new client with an existing client
pub fn with_client(client: C) -> HelixClient<'a, C> {
HelixClient {
Expand Down Expand Up @@ -117,7 +117,7 @@ impl<'a, C: crate::HttpClient<'a>> HelixClient<'a, C> {
&'a self,
request: R,
token: &T,
) -> Result<Response<R, D>, ClientRequestError<<C as crate::HttpClient<'a>>::Error>>
) -> Result<Response<R, D>, ClientRequestError<<C as crate::HttpClient>::Error>>
where
R: Request<Response = D> + Request + RequestGet,
D: serde::de::DeserializeOwned + PartialEq,
Expand All @@ -142,7 +142,7 @@ impl<'a, C: crate::HttpClient<'a>> HelixClient<'a, C> {
request: R,
body: B,
token: &T,
) -> Result<Response<R, D>, ClientRequestError<<C as crate::HttpClient<'a>>::Error>>
) -> Result<Response<R, D>, ClientRequestError<<C as crate::HttpClient>::Error>>
where
R: Request<Response = D> + Request + RequestPost<Body = B>,
B: HelixRequestBody,
Expand All @@ -168,7 +168,7 @@ impl<'a, C: crate::HttpClient<'a>> HelixClient<'a, C> {
request: R,
body: B,
token: &T,
) -> Result<Response<R, D>, ClientRequestError<<C as crate::HttpClient<'a>>::Error>>
) -> Result<Response<R, D>, ClientRequestError<<C as crate::HttpClient>::Error>>
where
R: Request<Response = D> + Request + RequestPatch<Body = B>,
B: HelixRequestBody,
Expand All @@ -193,7 +193,7 @@ impl<'a, C: crate::HttpClient<'a>> HelixClient<'a, C> {
&'a self,
request: R,
token: &T,
) -> Result<Response<R, D>, ClientRequestError<<C as crate::HttpClient<'a>>::Error>>
) -> Result<Response<R, D>, ClientRequestError<<C as crate::HttpClient>::Error>>
where
R: Request<Response = D> + Request + RequestDelete,
D: serde::de::DeserializeOwned + PartialEq,
Expand All @@ -217,7 +217,7 @@ impl<'a, C: crate::HttpClient<'a>> HelixClient<'a, C> {
request: R,
body: B,
token: &T,
) -> Result<Response<R, D>, ClientRequestError<<C as crate::HttpClient<'a>>::Error>>
) -> Result<Response<R, D>, ClientRequestError<<C as crate::HttpClient>::Error>>
where
R: Request<Response = D> + Request + RequestPut<Body = B>,
B: HelixRequestBody,
Expand Down
Loading

0 comments on commit 6517559

Please sign in to comment.