credo 0.8.0

A framework for trust-free distributed cryptographic claims and secret management
Documentation
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())
    }
}