pub trait Provider {
// Required methods
fn metadata(&self) -> Metadata;
fn data(&self) -> Result<BTreeMap<Profile, BTreeMap<String, Value>>, Error>;
// Provided method
fn profile(&self) -> Option<Profile> { ... }
}
Expand description
Trait implemented by configuration source providers.
For an overview of built-in providers, see the top-level docs.
§Overview
A Provider
reads from a source to provide configuration data for
Figment
s (Provider::data()
). A Provider
also provides Metadata
to identify the source of its configuration data (Provider::metadata()
).
A provider may also optionally set a Profile
for the Figment
it is
merged (but not joined) into by implementing Provider::profile()
.
§Nesting
A Provider
meant to be consumed externally should allow for optional
nesting when sensible. The general pattern
is to allow a Profile
to be specified. If one is not, read the
configuration data as a Map<Profile, Dict>
, thus using the top-level keys
as profiles. If one is specified, read the data as Dict
and
Profile::collect()
into the specified profile.
§Example
Implementing a Provider
requires implementing methods that provide both of
these pieces of data. The first, Provider::metadata()
identifies the
provider’s configuration sources, if any, and allows the provider to
customize how paths to keys are interpolated. The second,
Provider::data()
, actually reads the configuration and returns the data.
As an example, consider a provider that reads configuration from a
networked store at some Url
. A Provider
implementation for such a
provider may resemble the following:
use figment::{Provider, Metadata, Profile, Error, value::{Map, Dict}};
/// A provider that fetches its data from a given URL.
struct NetProvider {
/// The profile to emit data to if nesting is disabled.
profile: Option<Profile>,
/// The url to fetch data from.
url: Url
};
impl Provider for NetProvider {
/// Returns metadata with kind `Network`, custom source `self.url`,
/// and interpolator that returns a URL of `url/a/b/c` for key `a.b.c`.
fn metadata(&self) -> Metadata {
let url = self.url.clone();
Metadata::named("Network")
.source(self.url.as_str())
.interpolater(move |profile, keys| match profile.is_custom() {
true => format!("{}/{}/{}", url, profile, keys.join("/")),
false => format!("{}/{}", url, keys.join("/")),
})
}
/// Fetches the data from `self.url`. Note that `Dict`, `Map`, and
/// `Profile` are `Deserialize`, so we can deserialized to them.
fn data(&self) -> Result<Map<Profile, Dict>, Error> {
fn fetch<'a, T: Deserialize<'a>>(url: &Url) -> Result<T, Error> {
/* fetch from the network, deserialize into `T` */
}
match &self.profile {
// Don't nest: `fetch` into a `Dict`.
Some(profile) => Ok(profile.collect(fetch(&self.url)?)),
// Nest: `fetch` into a `Map<Profile, Dict>`.
None => fetch(&self.url),
}
}
}
Required Methods§
Provided Methods§
Implementations on Foreign Types§
Source§impl<K, V> Provider for (K, V)
impl<K, V> Provider for (K, V)
This is exactly equivalent to Serialized::global(K, V)
.