use std::{
cell::RefCell,
collections::{hash_map::DefaultHasher, HashMap},
hash::{Hash, Hasher},
pin::Pin,
rc::Rc,
};
use futures::{future, Future, FutureExt};
use crate::{Credential, ScopeID};
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
pub struct CredentialSourceHash(u64);
impl CredentialSourceHash {
pub fn from_hashable<H: Hash>(hashable: H) -> Self {
let mut s = DefaultHasher::new();
hashable.hash(&mut s);
CredentialSourceHash(s.finish())
}
}
pub trait CredentialSource {
fn add_credential<'a>(
&'a self,
scope_id: ScopeID,
credential: Credential,
) -> Pin<Box<dyn Future<Output = ()> + 'a>>;
fn credentials_for<'a>(
&'a self,
scope_id: &'a ScopeID,
) -> Pin<Box<dyn Future<Output = Vec<Credential>> + 'a>>;
fn id_hash(&self) -> CredentialSourceHash;
fn clone_ref(&self) -> Box<dyn CredentialSource>;
}
#[derive(Clone)]
pub struct SimpleCredentialSource {
id: u64,
credentials: Rc<RefCell<HashMap<ScopeID, Vec<Credential>>>>,
}
impl SimpleCredentialSource {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
id: rand::random(),
credentials: Rc::new(RefCell::new(HashMap::new())),
}
}
}
impl CredentialSource for SimpleCredentialSource {
fn add_credential<'a>(
&'a self,
scope_id: ScopeID,
credential: Credential,
) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
self.credentials
.borrow_mut()
.entry(scope_id)
.or_insert_with(Vec::new)
.push(credential);
future::ready(()).boxed_local()
}
fn credentials_for<'a>(
&'a self,
scope_id: &'a ScopeID,
) -> Pin<Box<dyn Future<Output = Vec<Credential>> + 'a>> {
future::ready(
self.credentials
.borrow()
.get(scope_id)
.cloned()
.unwrap_or_default(),
)
.boxed_local()
}
fn id_hash(&self) -> CredentialSourceHash {
CredentialSourceHash(self.id)
}
fn clone_ref(&self) -> Box<dyn CredentialSource> {
Box::new(self.clone())
}
}