#[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::ALL.iter().copied().find(|cap| cap.token() == token) } pub fn served(fostering: bool) -> impl IntoIterator { 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 ); } }