use crate::provider::{future, token::ProvideToken};
use std::fmt::{self, Debug, Formatter};
use std::future::Future;
use std::marker::PhantomData;
#[derive(Copy, Clone)]
pub struct ProvideTokenFn<'c, T> {
f: T,
phantom: PhantomData<&'c T>,
}
impl<T> Debug for ProvideTokenFn<'_, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "ProvideTokenFn")
}
}
impl<'c, T, F> ProvideToken for ProvideTokenFn<'c, T>
where
T: Fn() -> F + Send + Sync + 'c,
F: Future<Output = crate::provider::token::Result> + Send + 'static,
{
fn provide_token<'a>(&'a self) -> future::ProvideToken<'a>
where
Self: 'a,
{
future::ProvideToken::new((self.f)())
}
}
pub fn provide_token_fn<'c, T, F>(f: T) -> ProvideTokenFn<'c, T>
where
T: Fn() -> F + Send + Sync + 'c,
F: Future<Output = crate::provider::token::Result> + Send + 'static,
{
ProvideTokenFn {
f,
phantom: Default::default(),
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::Token;
use async_trait::async_trait;
use std::fmt::{Debug, Formatter};
fn assert_send_sync<T: Send + Sync>() {}
#[test]
fn creds_are_send_sync() {
assert_send_sync::<Token>()
}
#[async_trait]
trait AnotherTrait: Send + Sync {
async fn token(&self) -> Token;
}
struct AnotherTraitWrapper<T> {
inner: T,
}
impl<T> Debug for AnotherTraitWrapper<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "wrapper")
}
}
impl<T: AnotherTrait> ProvideToken for AnotherTraitWrapper<T> {
fn provide_token<'a>(&'a self) -> future::ProvideToken<'a>
where
Self: 'a,
{
future::ProvideToken::new(async move { Ok(self.inner.token().await) })
}
}
#[tokio::test]
async fn provide_token_fn_closure_can_borrow() {
fn check_is_str_ref(_input: &str) {}
async fn test_async_provider(input: String) -> crate::provider::token::Result {
Ok(Token::new(input, None))
}
let things_to_borrow = vec!["one".to_string(), "two".to_string()];
let mut providers = Vec::new();
for thing in &things_to_borrow {
let provider = provide_token_fn(move || {
check_is_str_ref(thing);
test_async_provider(thing.into())
});
providers.push(provider);
}
let (two, one) = (providers.pop().unwrap(), providers.pop().unwrap());
assert_eq!("one", one.provide_token().await.unwrap().token());
assert_eq!("two", two.provide_token().await.unwrap().token());
}
}