use std::{
any::TypeId,
marker::PhantomData,
sync::{Arc, Weak},
};
use crate::{Result, runtime::Runtime};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub(crate) struct ServiceId {
pub key: TypeId,
pub isolation: u64,
}
impl ServiceId {
pub fn root(key: TypeId) -> Self {
Self { key, isolation: 0 }
}
}
pub trait ServiceKey: Send + Sync + 'static {
type Value: ?Sized + Send + Sync + 'static;
const NAME: &'static str;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ServiceDeclaration {
pub(crate) key: TypeId,
pub name: &'static str,
}
impl ServiceDeclaration {
pub fn of<K: ServiceKey>() -> Self {
Self {
key: TypeId::of::<K>(),
name: K::NAME,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Dependency {
pub(crate) key: TypeId,
pub name: &'static str,
pub required: bool,
}
impl Dependency {
pub fn required<K: ServiceKey>() -> Self {
Self {
key: TypeId::of::<K>(),
name: K::NAME,
required: true,
}
}
pub fn optional<K: ServiceKey>() -> Self {
Self {
key: TypeId::of::<K>(),
name: K::NAME,
required: false,
}
}
}
pub struct ServiceHandle<K: ServiceKey> {
pub(crate) runtime: Weak<Runtime>,
pub(crate) id: ServiceId,
pub(crate) owner: u64,
pub(crate) token: u64,
pub(crate) _key: PhantomData<fn() -> K>,
}
impl<K: ServiceKey> ServiceHandle<K> {
pub fn replace(&self, value: Arc<K::Value>) -> Result<u64> {
let runtime = self.runtime.upgrade().ok_or(crate::Error::PluginDisposed)?;
runtime.replace_service::<K>(self.id, self.owner, self.token, value)
}
pub fn touch(&self) -> Result<u64> {
let runtime = self.runtime.upgrade().ok_or(crate::Error::PluginDisposed)?;
runtime.touch_service::<K>(self.id, self.owner, self.token)
}
pub fn remove(&self) -> bool {
self.runtime
.upgrade()
.is_some_and(|runtime| runtime.remove_service(self.id, self.owner, self.token))
}
}
pub(crate) struct ServiceEntry {
pub value: Box<dyn std::any::Any + Send + Sync>,
pub owner: u64,
pub token: u64,
pub generation: u64,
pub name: &'static str,
pub active: bool,
}
pub(crate) fn boxed_service<K: ServiceKey>(
value: Arc<K::Value>,
) -> Box<dyn std::any::Any + Send + Sync> {
Box::new(value)
}