Expand description
Closed-set settings — Setting and setting_enum!.
A driver name is not a string. It is one of a handful of values the code
actually knows how to build, and every other string is a mistake. Spelling
it as a String moves that mistake from the compiler to production:
CACHE_DRIVER=redys # boots fine, caches in-process, foreversetting_enum! declares the closed set once and derives everything that
follows from it — the wire spelling, Display, FromStr, serde, and a
parse error that lists what was expected:
use rainier_support::{setting_enum, Setting};
setting_enum! {
/// Where cached values live.
pub enum CacheDriver: "cache driver" {
/// This process only.
#[default]
Memory = "memory",
/// One Redis server.
Redis = "redis",
/// A sharded Redis Cluster.
RedisCluster = "redis-cluster",
}
}
assert_eq!(CacheDriver::parse("redis-cluster").unwrap(), CacheDriver::RedisCluster);
assert_eq!(CacheDriver::default(), CacheDriver::Memory);
let err = CacheDriver::parse("redys").unwrap_err();
assert_eq!(
err.message(),
"`redys` is not a valid cache driver; expected one of `memory`, `redis`, `redis-cluster`",
);§Why parsing fails rather than falling back
A default is for a value nobody set. It is not for a value somebody set
wrong — silently substituting one there means the deployment that typed
redys runs on an in-process cache, and the first symptom is a rate limiter
that lets through N × its limit across N instances.
Failing at boot puts the error where the mistake was made, with the list of valid values in the message.
§Every setting has a default
setting_enum! always derives Default, so exactly one variant must
carry #[default] and the macro will not compile otherwise. That is
deliberate: a setting with no default is a setting that has to be named in
every environment, and if that is genuinely what you want, it belongs in
Env::require rather than here.
Traits§
- Setting
- A setting whose values are a closed set of wire spellings.