Skip to main content

cordis_core/
service.rs

1use std::{
2    any::TypeId,
3    marker::PhantomData,
4    sync::{Arc, Weak},
5};
6
7use crate::{Result, runtime::Runtime};
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10pub(crate) struct ServiceId {
11    pub key: TypeId,
12    pub isolation: u64,
13}
14
15impl ServiceId {
16    pub fn root(key: TypeId) -> Self {
17        Self { key, isolation: 0 }
18    }
19}
20
21/// Typed service key. The associated value may be unsized, including a trait
22/// object such as `dyn Database`.
23pub trait ServiceKey: Send + Sync + 'static {
24    type Value: ?Sized + Send + Sync + 'static;
25    const NAME: &'static str;
26}
27
28#[derive(Clone, Copy, Debug, PartialEq, Eq)]
29pub struct ServiceDeclaration {
30    pub(crate) key: TypeId,
31    pub name: &'static str,
32}
33
34impl ServiceDeclaration {
35    pub fn of<K: ServiceKey>() -> Self {
36        Self {
37            key: TypeId::of::<K>(),
38            name: K::NAME,
39        }
40    }
41}
42
43#[derive(Clone, Copy, Debug, PartialEq, Eq)]
44pub struct Dependency {
45    pub(crate) key: TypeId,
46    pub name: &'static str,
47    pub required: bool,
48}
49
50impl Dependency {
51    pub fn required<K: ServiceKey>() -> Self {
52        Self {
53            key: TypeId::of::<K>(),
54            name: K::NAME,
55            required: true,
56        }
57    }
58
59    pub fn optional<K: ServiceKey>() -> Self {
60        Self {
61            key: TypeId::of::<K>(),
62            name: K::NAME,
63            required: false,
64        }
65    }
66}
67
68/// Non-owning service control handle. Dropping it does not unregister the
69/// service; ownership remains with the activation scope.
70pub struct ServiceHandle<K: ServiceKey> {
71    pub(crate) runtime: Weak<Runtime>,
72    pub(crate) id: ServiceId,
73    pub(crate) owner: u64,
74    pub(crate) token: u64,
75    pub(crate) _key: PhantomData<fn() -> K>,
76}
77
78impl<K: ServiceKey> ServiceHandle<K> {
79    pub fn replace(&self, value: Arc<K::Value>) -> Result<u64> {
80        let runtime = self.runtime.upgrade().ok_or(crate::Error::PluginDisposed)?;
81        runtime.replace_service::<K>(self.id, self.owner, self.token, value)
82    }
83
84    pub fn touch(&self) -> Result<u64> {
85        let runtime = self.runtime.upgrade().ok_or(crate::Error::PluginDisposed)?;
86        runtime.touch_service::<K>(self.id, self.owner, self.token)
87    }
88
89    /// Unregisters early. Safe to call repeatedly.
90    pub fn remove(&self) -> bool {
91        self.runtime
92            .upgrade()
93            .is_some_and(|runtime| runtime.remove_service(self.id, self.owner, self.token))
94    }
95}
96
97pub(crate) struct ServiceEntry {
98    pub value: Box<dyn std::any::Any + Send + Sync>,
99    pub owner: u64,
100    pub token: u64,
101    pub generation: u64,
102    pub name: &'static str,
103    pub active: bool,
104}
105
106pub(crate) fn boxed_service<K: ServiceKey>(
107    value: Arc<K::Value>,
108) -> Box<dyn std::any::Any + Send + Sync> {
109    Box::new(value)
110}