aws_credential_types/
token_fn.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! Types that allow an access token provider to be created from a closure
7
8use crate::provider::{future, token::ProvideToken};
9use std::fmt::{self, Debug, Formatter};
10use std::future::Future;
11use std::marker::PhantomData;
12
13/// A [`ProvideToken`] implemented by a closure.
14///
15/// See [`provide_token_fn`] for more details.
16#[derive(Copy, Clone)]
17pub struct ProvideTokenFn<'c, T> {
18    f: T,
19    phantom: PhantomData<&'c T>,
20}
21
22impl<T> Debug for ProvideTokenFn<'_, T> {
23    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
24        write!(f, "ProvideTokenFn")
25    }
26}
27
28impl<'c, T, F> ProvideToken for ProvideTokenFn<'c, T>
29where
30    T: Fn() -> F + Send + Sync + 'c,
31    F: Future<Output = crate::provider::token::Result> + Send + 'static,
32{
33    fn provide_token<'a>(&'a self) -> future::ProvideToken<'a>
34    where
35        Self: 'a,
36    {
37        future::ProvideToken::new((self.f)())
38    }
39}
40
41/// Returns a new token provider built with the given closure. This allows you
42/// to create an [`ProvideToken`] implementation from an async block that returns
43/// a [`crate::provider::token::Result`].
44///
45/// # Examples
46///
47/// ```no_run
48/// use aws_credential_types::Token;
49/// use aws_credential_types::token_fn::provide_token_fn;
50///
51/// async fn load_token() -> Token {
52///     todo!()
53/// }
54///
55/// provide_token_fn(|| async {
56///     // Async process to retrieve a token goes here
57///     let token = load_token().await;
58///     Ok(token)
59/// });
60/// ```
61pub fn provide_token_fn<'c, T, F>(f: T) -> ProvideTokenFn<'c, T>
62where
63    T: Fn() -> F + Send + Sync + 'c,
64    F: Future<Output = crate::provider::token::Result> + Send + 'static,
65{
66    ProvideTokenFn {
67        f,
68        phantom: Default::default(),
69    }
70}
71
72#[cfg(test)]
73mod test {
74    use super::*;
75    use crate::Token;
76
77    fn assert_send_sync<T: Send + Sync>() {}
78
79    #[test]
80    fn creds_are_send_sync() {
81        assert_send_sync::<Token>()
82    }
83
84    // Test that the closure passed to `provide_token_fn` is allowed to borrow things
85    #[tokio::test]
86    async fn provide_token_fn_closure_can_borrow() {
87        fn check_is_str_ref(_input: &str) {}
88        async fn test_async_provider(input: String) -> crate::provider::token::Result {
89            Ok(Token::new(input, None))
90        }
91
92        let things_to_borrow = vec!["one".to_string(), "two".to_string()];
93
94        let mut providers = Vec::new();
95        for thing in &things_to_borrow {
96            let provider = provide_token_fn(move || {
97                check_is_str_ref(thing);
98                test_async_provider(thing.into())
99            });
100            providers.push(provider);
101        }
102
103        let (two, one) = (providers.pop().unwrap(), providers.pop().unwrap());
104        assert_eq!("one", one.provide_token().await.unwrap().token());
105        assert_eq!("two", two.provide_token().await.unwrap().token());
106    }
107}