use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;
use std::sync::{Arc, OnceLock, RwLock};
use crate::core::Model;
pub mod admin;
pub mod auth;
pub mod m2m;
pub mod migrate;
pub mod request;
pub mod setting;
pub type ReceiverFuture = Pin<Box<dyn Future<Output = ()> + Send + 'static>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ReceiverId(u64);
#[derive(Debug, Clone, Copy)]
pub struct PostSaveContext {
pub created: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum SignalKind {
PreSave,
PostSave,
PreDelete,
PostDelete,
}
type ReceiverEntry = (ReceiverId, Box<dyn Any + Send + Sync>);
type Bag = Vec<ReceiverEntry>;
fn registry() -> &'static RwLock<HashMap<(TypeId, SignalKind), Bag>> {
static REG: OnceLock<RwLock<HashMap<(TypeId, SignalKind), Bag>>> = OnceLock::new();
REG.get_or_init(|| RwLock::new(HashMap::new()))
}
fn next_id() -> ReceiverId {
use std::sync::atomic::{AtomicU64, Ordering};
static COUNTER: AtomicU64 = AtomicU64::new(1);
ReceiverId(COUNTER.fetch_add(1, Ordering::Relaxed))
}
fn insert_receiver<R: Any + Send + Sync>(key: (TypeId, SignalKind), receiver: R) -> ReceiverId {
let id = next_id();
let mut reg = registry().write().unwrap_or_else(|e| e.into_inner());
reg.entry(key).or_default().push((id, Box::new(receiver)));
id
}
fn remove_receiver(key: (TypeId, SignalKind), id: ReceiverId) -> bool {
let mut reg = registry().write().unwrap_or_else(|e| e.into_inner());
let Some(bag) = reg.get_mut(&key) else {
return false;
};
let before = bag.len();
bag.retain(|(rid, _)| *rid != id);
bag.len() != before
}
fn snapshot<R: Any + Send + Sync + Clone>(key: (TypeId, SignalKind)) -> Vec<R> {
let reg = registry().read().unwrap_or_else(|e| e.into_inner());
let Some(bag) = reg.get(&key) else {
return Vec::new();
};
bag.iter()
.filter_map(|(_, b)| b.downcast_ref::<R>().cloned())
.collect()
}
type SimpleReceiver<T> = Arc<dyn Fn(Arc<T>) -> ReceiverFuture + Send + Sync>;
type PostSaveReceiver<T> = Arc<dyn Fn(Arc<T>, PostSaveContext) -> ReceiverFuture + Send + Sync>;
pub fn connect_pre_save<T, F, Fut>(receiver: F) -> ReceiverId
where
T: Model + Clone + 'static,
F: Fn(Arc<T>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let boxed: SimpleReceiver<T> = Arc::new(move |instance| Box::pin(receiver(instance)));
insert_receiver((TypeId::of::<T>(), SignalKind::PreSave), boxed)
}
pub fn disconnect_pre_save<T: Model + 'static>(id: ReceiverId) -> bool {
remove_receiver((TypeId::of::<T>(), SignalKind::PreSave), id)
}
pub async fn send_pre_save<T: Model + Clone + 'static>(instance: &T) {
if signals_suppressed() {
return;
}
let receivers: Vec<SimpleReceiver<T>> =
snapshot::<SimpleReceiver<T>>((TypeId::of::<T>(), SignalKind::PreSave));
let arc = Arc::new(instance.clone());
for r in receivers {
r(arc.clone()).await;
}
}
pub fn connect_post_save<T, F, Fut>(receiver: F) -> ReceiverId
where
T: Model + Clone + 'static,
F: Fn(Arc<T>, PostSaveContext) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let boxed: PostSaveReceiver<T> =
Arc::new(move |instance, ctx| Box::pin(receiver(instance, ctx)));
insert_receiver((TypeId::of::<T>(), SignalKind::PostSave), boxed)
}
pub fn disconnect_post_save<T: Model + 'static>(id: ReceiverId) -> bool {
remove_receiver((TypeId::of::<T>(), SignalKind::PostSave), id)
}
pub async fn send_post_save<T: Model + Clone + 'static>(instance: &T, ctx: PostSaveContext) {
if signals_suppressed() {
return;
}
let receivers: Vec<PostSaveReceiver<T>> =
snapshot::<PostSaveReceiver<T>>((TypeId::of::<T>(), SignalKind::PostSave));
let arc = Arc::new(instance.clone());
for r in receivers {
r(arc.clone(), ctx).await;
}
}
pub fn connect_pre_delete<T, F, Fut>(receiver: F) -> ReceiverId
where
T: Model + Clone + 'static,
F: Fn(Arc<T>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let boxed: SimpleReceiver<T> = Arc::new(move |instance| Box::pin(receiver(instance)));
insert_receiver((TypeId::of::<T>(), SignalKind::PreDelete), boxed)
}
pub fn disconnect_pre_delete<T: Model + 'static>(id: ReceiverId) -> bool {
remove_receiver((TypeId::of::<T>(), SignalKind::PreDelete), id)
}
pub async fn send_pre_delete<T: Model + Clone + 'static>(instance: &T) {
if signals_suppressed() {
return;
}
let receivers: Vec<SimpleReceiver<T>> =
snapshot::<SimpleReceiver<T>>((TypeId::of::<T>(), SignalKind::PreDelete));
let arc = Arc::new(instance.clone());
for r in receivers {
r(arc.clone()).await;
}
}
pub fn connect_post_delete<T, F, Fut>(receiver: F) -> ReceiverId
where
T: Model + Clone + 'static,
F: Fn(Arc<T>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = ()> + Send + 'static,
{
let boxed: SimpleReceiver<T> = Arc::new(move |instance| Box::pin(receiver(instance)));
insert_receiver((TypeId::of::<T>(), SignalKind::PostDelete), boxed)
}
pub fn disconnect_post_delete<T: Model + 'static>(id: ReceiverId) -> bool {
remove_receiver((TypeId::of::<T>(), SignalKind::PostDelete), id)
}
pub async fn send_post_delete<T: Model + Clone + 'static>(instance: &T) {
if signals_suppressed() {
return;
}
let receivers: Vec<SimpleReceiver<T>> =
snapshot::<SimpleReceiver<T>>((TypeId::of::<T>(), SignalKind::PostDelete));
let arc = Arc::new(instance.clone());
for r in receivers {
r(arc.clone()).await;
}
}
pub fn clear_all() {
registry()
.write()
.unwrap_or_else(|e| e.into_inner())
.clear();
}
pub fn receiver_count<T: Model + 'static>() -> usize {
let reg = registry().read().unwrap_or_else(|e| e.into_inner());
let id = TypeId::of::<T>();
[
SignalKind::PreSave,
SignalKind::PostSave,
SignalKind::PreDelete,
SignalKind::PostDelete,
]
.iter()
.map(|kind| reg.get(&(id, *kind)).map_or(0, Vec::len))
.sum()
}
tokio::task_local! {
static SUPPRESS_SIGNALS: bool;
}
fn signals_suppressed() -> bool {
SUPPRESS_SIGNALS.try_with(|v| *v).unwrap_or(false)
}
pub async fn without_signals<F, R>(fut: F) -> R
where
F: std::future::Future<Output = R>,
{
SUPPRESS_SIGNALS.scope(true, fut).await
}
pub async fn save_quietly<F, R>(fut: F) -> R
where
F: std::future::Future<Output = R>,
{
without_signals(fut).await
}
pub async fn delete_quietly<F, R>(fut: F) -> R
where
F: std::future::Future<Output = R>,
{
without_signals(fut).await
}
#[derive(Debug, Clone)]
pub struct ObserverHandle {
pub pre_save: ReceiverId,
pub post_save: ReceiverId,
pub pre_delete: ReceiverId,
pub post_delete: ReceiverId,
}
pub trait Observer<T: Model + Clone + 'static>: Send + Sync + 'static {
fn pre_save(&self, _instance: Arc<T>) -> ReceiverFuture {
Box::pin(async {})
}
fn post_save(&self, _instance: Arc<T>, _ctx: PostSaveContext) -> ReceiverFuture {
Box::pin(async {})
}
fn pre_delete(&self, _instance: Arc<T>) -> ReceiverFuture {
Box::pin(async {})
}
fn post_delete(&self, _instance: Arc<T>) -> ReceiverFuture {
Box::pin(async {})
}
}
pub fn observe<T, O>(obs: O) -> ObserverHandle
where
T: Model + Clone + 'static,
O: Observer<T>,
{
let obs = Arc::new(obs);
let o1 = Arc::clone(&obs);
let o2 = Arc::clone(&obs);
let o3 = Arc::clone(&obs);
let o4 = Arc::clone(&obs);
ObserverHandle {
pre_save: connect_pre_save::<T, _, _>(move |i| {
let o = Arc::clone(&o1);
async move { o.pre_save(i).await }
}),
post_save: connect_post_save::<T, _, _>(move |i, ctx| {
let o = Arc::clone(&o2);
async move { o.post_save(i, ctx).await }
}),
pre_delete: connect_pre_delete::<T, _, _>(move |i| {
let o = Arc::clone(&o3);
async move { o.pre_delete(i).await }
}),
post_delete: connect_post_delete::<T, _, _>(move |i| {
let o = Arc::clone(&o4);
async move { o.post_delete(i).await }
}),
}
}
pub fn disconnect_observer<T: Model + 'static>(handle: &ObserverHandle) -> usize {
[
disconnect_pre_save::<T>(handle.pre_save),
disconnect_post_save::<T>(handle.post_save),
disconnect_pre_delete::<T>(handle.pre_delete),
disconnect_post_delete::<T>(handle.post_delete),
]
.into_iter()
.filter(|r| *r)
.count()
}