1use crate::registry::RegistryApi;
2use anymap::{any::Any, Map};
3use lazy_static::lazy_static;
4use std::{ffi::c_void, sync::RwLock};
5
6pub trait Api: Copy + Clone + Send + Sync + 'static {
7 type CType;
8 const NAME: &'static [u8];
9
10 fn new(api: *mut c_void) -> Self;
11}
12
13pub trait ApiWithCtx: Api {
14 type Ctx;
15 type ApiInstance: Copy + Clone;
16
17 fn wrap(self, ctx: *const Self::Ctx) -> Self::ApiInstance;
18}
19
20pub trait ApiWithCtxMut: ApiWithCtx {
21 type ApiInstanceMut: Copy + Clone;
22
23 fn wrap_mut(self, ctx: *mut Self::Ctx) -> Self::ApiInstanceMut;
24}
25
26lazy_static! {
27 static ref REGISTERED_APIS: RwLock<Map<dyn Any + Send + Sync>> = RwLock::new(Map::new());
28}
29
30#[inline]
31#[allow(clippy::missing_safety_doc)]
32pub unsafe fn register<A: Api>(reg: &mut RegistryApi) {
33 REGISTERED_APIS
34 .write()
35 .unwrap()
36 .insert(A::new(reg.get(A::NAME)));
37}
38
39#[inline]
40pub fn get<A: Api>() -> A {
41 *REGISTERED_APIS.read().unwrap().get::<A>().unwrap()
42}
43
44#[inline]
45pub fn with_ctx<A: ApiWithCtx>(ctx: *const A::Ctx) -> A::ApiInstance {
46 assert!(!ctx.is_null());
47 REGISTERED_APIS
48 .read()
49 .unwrap()
50 .get::<A>()
51 .unwrap()
52 .wrap(ctx)
53}
54
55#[inline]
56pub fn with_ctx_mut<A: ApiWithCtxMut>(ctx: *mut A::Ctx) -> A::ApiInstanceMut {
57 assert!(!ctx.is_null());
58 REGISTERED_APIS
59 .read()
60 .unwrap()
61 .get::<A>()
62 .unwrap()
63 .wrap_mut(ctx)
64}