aws_config/meta/mod.rs
1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6//! Meta-providers that augment existing providers with new behavior
7
8use std::borrow::Cow;
9use std::error::Error;
10use std::fmt;
11
12pub mod credentials;
13pub mod region;
14pub mod token;
15
16/// A single provider's outcome in a chain, capturing the provider name and its error.
17#[derive(Debug)]
18pub struct ProviderAttempt<E> {
19 name: Cow<'static, str>,
20 error: E,
21}
22
23impl<E> ProviderAttempt<E> {
24 pub(crate) fn new(name: Cow<'static, str>, error: E) -> Self {
25 Self { name, error }
26 }
27
28 /// The name of the provider that was attempted.
29 pub fn name(&self) -> &str {
30 &self.name
31 }
32
33 /// The error returned by this provider.
34 pub fn error(&self) -> &E {
35 &self.error
36 }
37}
38
39/// Error returned when all providers in a chain are exhausted without producing credentials or tokens.
40///
41/// Contains per-provider errors for programmatic inspection via [`ProviderChainError::attempts`].
42///
43/// To access from a `CredentialsError` or `TokenError`, downcast the error source:
44/// ```ignore
45/// use aws_config::meta::ProviderChainError;
46/// use aws_credential_types::provider::error::CredentialsError;
47/// use std::error::Error;
48///
49/// if let Some(chain_err) = err.source()
50/// .and_then(|s| s.downcast_ref::<ProviderChainError<CredentialsError>>())
51/// {
52/// for attempt in chain_err.attempts() {
53/// println!("{}: {}", attempt.name(), attempt.error());
54/// }
55/// }
56/// ```
57#[derive(Debug)]
58pub struct ProviderChainError<E: Error> {
59 attempts: Vec<ProviderAttempt<E>>,
60}
61
62impl<E: Error> ProviderChainError<E> {
63 pub(crate) fn new(attempts: Vec<ProviderAttempt<E>>) -> Self {
64 Self { attempts }
65 }
66
67 /// Returns the per-provider errors in chain order.
68 pub fn attempts(&self) -> &[ProviderAttempt<E>] {
69 &self.attempts
70 }
71}
72
73impl<E: Error> fmt::Display for ProviderChainError<E> {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 if self.attempts.is_empty() {
76 return write!(f, "no providers were configured in the chain");
77 }
78 write!(f, "no credentials found in chain. Attempted:")?;
79 for attempt in &self.attempts {
80 write!(f, "\n {}: {}", attempt.name, attempt.error)?;
81 let mut source = attempt.error.source();
82 while let Some(cause) = source {
83 write!(f, ": {cause}")?;
84 source = cause.source();
85 }
86 }
87 Ok(())
88 }
89}
90
91impl<E: Error + 'static> Error for ProviderChainError<E> {}