#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum Capability {
Tangled1,
KnotAcl,
RepoDidInput,
KeepCommit,
AtprotoFirehose,
RepoTokenMint,
SocialWrites,
Foster,
}
impl Capability {
const ALL: &'static [Capability] = &[
Capability::Tangled1,
Capability::KnotAcl,
Capability::RepoDidInput,
Capability::KeepCommit,
Capability::AtprotoFirehose,
Capability::RepoTokenMint,
Capability::SocialWrites,
Capability::Foster,
];
pub const SERVED: &'static [Capability] = &[
Capability::Tangled1,
Capability::KnotAcl,
Capability::RepoDidInput,
Capability::AtprotoFirehose,
Capability::RepoTokenMint,
Capability::SocialWrites,
];
pub const fn token(self) -> &'static str {
match self {
Capability::Tangled1 => "tangled1.0",
Capability::KnotAcl => "knot-acl",
Capability::RepoDidInput => "repo-did-input",
Capability::KeepCommit => "knot-keepcommit",
Capability::AtprotoFirehose => "atproto-firehose",
Capability::RepoTokenMint => "knot-repo-token-mint",
Capability::SocialWrites => "knot-social-writes",
Capability::Foster => "knot-foster",
}
}
pub fn parse(token: &str) -> Option<Self> {
Self::ALL.iter().copied().find(|cap| cap.token() == token)
}
pub fn served(fostering: bool) -> impl IntoIterator<Item = Capability> {
Self::SERVED
.iter()
.copied()
.chain(fostering.then_some(Capability::Foster))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_capability_parses_back_from_its_token() {
Capability::ALL.iter().copied().for_each(|cap| {
assert_eq!(Capability::parse(cap.token()), Some(cap), "{cap:?}");
});
}
#[test]
fn tokens_are_distinct() {
let tokens: Vec<&str> = Capability::ALL.iter().map(|cap| cap.token()).collect();
let mut unique = tokens.clone();
unique.sort_unstable();
unique.dedup();
assert_eq!(unique.len(), tokens.len(), "two variants share a token");
}
#[test]
fn unknown_tokens_are_rejected() {
["", "knot_acl", "KNOT-ACL", "atproto-firehose "]
.iter()
.for_each(|token| assert_eq!(Capability::parse(token), None, "{token:?}"));
}
#[test]
fn served_capabilities_are_real_capabilities() {
Capability::SERVED.iter().copied().for_each(|cap| {
assert!(Capability::ALL.contains(&cap), "{cap:?} is not in ALL");
});
}
#[test]
fn served_without_fostering_is_the_static_list() {
assert!(
Capability::served(false)
.into_iter()
.eq(Capability::SERVED.iter().copied())
);
}
#[test]
fn served_with_fostering_appends_exactly_foster() {
let served: Vec<_> = Capability::served(true).into_iter().collect();
assert_eq!(served.len(), Capability::SERVED.len() + 1);
assert!(
served[..Capability::SERVED.len()]
.iter()
.eq(Capability::SERVED.iter())
);
assert_eq!(
*served.last().expect("one more than SERVED"),
Capability::Foster
);
}
}