use std::{hash::Hash, pin::Pin, sync::Arc};
use crate::Scope;
pub trait User: Send + Sync + 'static {
type Scope: Scope;
type Id: Clone + Eq + Hash + Send + Sync + 'static;
type Credentials;
fn id(&self) -> Self::Id;
fn scope(&self) -> Self::Scope;
}
pub trait Backend: Send + Sync + 'static {
type User: User;
type Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>;
type Get: Future<Output = Result<Option<Self::User>, Self::Error>> + Send + 'static;
type Authenticate: Future<Output = Result<Option<Self::User>, Self::Error>> + Send + 'static;
fn get(&self, id: <Self::User as User>::Id) -> Self::Get;
fn authenticate(&self, credentials: <Self::User as User>::Credentials) -> Self::Authenticate;
}
pub struct ErasedBackend<User>(Arc<dyn DynBackend<User = User>>);
impl<User> ErasedBackend<User> {
#[inline]
pub(crate) fn new<D>(backend: D) -> Self
where
D: Backend<User = User> + 'static,
{
Self(Arc::new(backend))
}
}
impl<User> Clone for ErasedBackend<User> {
#[inline]
fn clone(&self) -> Self {
Self(Arc::clone(&self.0))
}
}
impl<User> Backend for ErasedBackend<User>
where
User: self::User,
{
type User = User;
type Error = BoxError;
type Get = BoxFuture<Result<Option<Self::User>, BoxError>>;
type Authenticate = BoxFuture<Result<Option<Self::User>, BoxError>>;
#[inline]
fn get(&self, id: User::Id) -> Self::Get {
self.0.get(id)
}
#[inline]
fn authenticate(&self, credentials: User::Credentials) -> Self::Authenticate {
self.0.authenticate(credentials)
}
}
type BoxFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
trait DynBackend: Send + Sync + 'static {
type User: User;
fn get(&self, id: <Self::User as User>::Id) -> BoxFuture<Result<Option<Self::User>, BoxError>>;
fn authenticate(
&self,
credentials: <Self::User as User>::Credentials,
) -> BoxFuture<Result<Option<Self::User>, BoxError>>;
}
impl<T> DynBackend for T
where
T: Backend,
{
type User = T::User;
#[inline]
fn get(&self, id: <Self::User as User>::Id) -> BoxFuture<Result<Option<Self::User>, BoxError>> {
let fut = self.get(id);
Box::pin(async move { fut.await.map_err(Into::into) })
}
#[inline]
fn authenticate(
&self,
credentials: <Self::User as User>::Credentials,
) -> BoxFuture<Result<Option<Self::User>, BoxError>> {
let fut = self.authenticate(credentials);
Box::pin(async move { fut.await.map_err(Into::into) })
}
}