crew_rs/
credential_source.rs

1use std::{
2    cell::RefCell,
3    collections::{hash_map::DefaultHasher, HashMap},
4    hash::{Hash, Hasher},
5    pin::Pin,
6    rc::Rc,
7};
8
9use futures::{future, Future, FutureExt};
10
11use crate::crew::CrewID;
12use crate::member::MemberCredential;
13
14#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
15pub struct CredentialSourceHash(u64);
16
17impl CredentialSourceHash {
18    pub fn from_hashable<H: Hash>(hashable: H) -> Self {
19        let mut s = DefaultHasher::new();
20        hashable.hash(&mut s);
21        CredentialSourceHash(s.finish())
22    }
23}
24
25pub trait CredentialSource {
26    fn add_credential<'a>(
27        &'a self,
28        crew_id: CrewID,
29        credential: MemberCredential,
30    ) -> Pin<Box<dyn Future<Output = ()> + 'a>>;
31
32    fn current_credentials_for<'a>(&'a self, crew_id: &'a CrewID) -> Vec<MemberCredential>;
33
34    fn id_hash(&self) -> CredentialSourceHash;
35
36    fn clone_ref(&self) -> Box<dyn CredentialSource>;
37
38    fn current_state(&self) -> HashMap<CrewID, Vec<MemberCredential>>;
39}
40
41#[derive(Clone)]
42pub struct SimpleCredentialSource {
43    id: u64,
44    credentials: Rc<RefCell<HashMap<CrewID, Vec<MemberCredential>>>>,
45}
46
47impl SimpleCredentialSource {
48    #[allow(clippy::new_without_default)]
49    pub fn new() -> Self {
50        Self {
51            id: rand::random(),
52            credentials: Rc::new(RefCell::new(HashMap::new())),
53        }
54    }
55}
56
57impl CredentialSource for SimpleCredentialSource {
58    fn add_credential<'a>(
59        &'a self,
60        crew_id: CrewID,
61        credential: MemberCredential,
62    ) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
63        self.credentials
64            .borrow_mut()
65            .entry(crew_id)
66            .or_insert_with(Vec::new)
67            .push(credential);
68        future::ready(()).boxed_local()
69    }
70
71    fn current_credentials_for<'a>(&'a self, crew_id: &'a CrewID) -> Vec<MemberCredential> {
72        self.credentials
73            .borrow()
74            .get(crew_id)
75            .cloned()
76            .unwrap_or_default()
77    }
78
79    fn id_hash(&self) -> CredentialSourceHash {
80        CredentialSourceHash(self.id)
81    }
82
83    fn clone_ref(&self) -> Box<dyn CredentialSource> {
84        Box::new(self.clone())
85    }
86
87    fn current_state(&self) -> HashMap<CrewID, Vec<MemberCredential>> {
88        self.credentials.borrow().clone()
89    }
90}
91
92impl CredentialSource for Box<dyn CredentialSource> {
93    fn add_credential<'a>(
94        &'a self,
95        crew_id: CrewID,
96        credential: MemberCredential,
97    ) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
98        (**self).add_credential(crew_id, credential)
99    }
100
101    fn current_credentials_for<'a>(&'a self, crew_id: &'a CrewID) -> Vec<MemberCredential> {
102        (**self).current_credentials_for(crew_id)
103    }
104
105    fn id_hash(&self) -> CredentialSourceHash {
106        (**self).id_hash()
107    }
108
109    fn clone_ref(&self) -> Box<dyn CredentialSource> {
110        (**self).clone_ref()
111    }
112
113    fn current_state(&self) -> HashMap<CrewID, Vec<MemberCredential>> {
114        (**self).current_state()
115    }
116}