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