pub enum Scope {
None,
User(String),
Tenant(String),
}Expand description
The subject of a flag check.
Three kinds, because three are what applications actually roll out to:
- a user, by whatever identifier they log in with;
- a tenant, when a feature is bought or enabled per customer rather than per person;
- nobody in particular (
Scope::none), for a switch that is on or off for the whole installation.
The identifier is a String and not a generic parameter on purpose. A flag
store has to write it down, an operator has to type it into a console, and a
percentage rollout has to hash it — all three want text, and a type
parameter here would spread through every signature in the crate to buy
nothing.
use rustlavel_flags::Scope;
assert_eq!(Scope::user("ada").id(), "ada");
assert_eq!(Scope::user_id(41).id(), "41");
assert_eq!(Scope::tenant("acme").key(), "tenant:acme");
assert_eq!(Scope::none().id(), "");Variants§
None
Everybody. Built with Scope::none.
User(String)
One logged-in user, by their authentication identifier.
Tenant(String)
One tenant, team, organisation — whatever the application calls it.
Implementations§
Source§impl Scope
impl Scope
Sourcepub fn none() -> Self
pub fn none() -> Self
The global scope: a flag that is simply on or off, for everyone.
Named none rather than global because of how it reads at the call
site — flags.active("maintenance", &Scope::none()) says “there is
nobody in particular here”, which is the fact the caller has.
Sourcepub fn user_id(id: i64) -> Self
pub fn user_id(id: i64) -> Self
One user, by a numeric primary key — the common case in an application
whose users table is keyed by bigint.
Sourcepub fn id(&self) -> &str
pub fn id(&self) -> &str
The identifier, or "" for Scope::none.
The empty string is deliberate: a resolver that does not care which kind
of scope it was given can read scope.id() unconditionally, and a
global check falls through whatever test it applies rather than
panicking or matching some sentinel value.
Sourcepub fn id_as<T: FromStr>(&self) -> Option<T>
pub fn id_as<T: FromStr>(&self) -> Option<T>
The identifier parsed into a type: scope.id_as::<i64>().
None when the scope is global, or when the identifier is not that
type — a resolver keyed on a numeric user id gets one answer for both,
which is right, because it cannot serve either.
Sourcepub fn kind(&self) -> &'static str
pub fn kind(&self) -> &'static str
"global", "user" or "tenant" — for logs and for the store key.
Sourcepub fn key(&self) -> String
pub fn key(&self) -> String
The string a FlagStore writes an override under.
The kind is part of the key, so a user called acme and a tenant called
acme are two different subjects and cannot inherit each other’s
overrides. An identifier containing a colon is left alone rather than
escaped — the prefix already separates the namespaces, and the only way
two keys can still collide is if one subject’s identifier is literally
another kind’s prefix plus another subject’s identifier, which is a
collision between two identifiers the application itself issued.