systemprompt_database/scope/registry.rs
1//! Inventory-based registration for [`ConnectionScopeProvider`]s.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use std::sync::OnceLock;
7
8use super::provider::SharedScopeProvider;
9
10/// One inventory submission per [`crate::register_scope_provider!`] call.
11#[derive(Debug, Clone, Copy)]
12pub struct ScopeProviderRegistration {
13 pub factory: fn() -> SharedScopeProvider,
14}
15
16inventory::collect!(ScopeProviderRegistration);
17
18/// Construct every registered provider, in collection order.
19#[must_use]
20pub fn discover_scope_providers() -> Vec<SharedScopeProvider> {
21 inventory::iter::<ScopeProviderRegistration>()
22 .map(|reg| (reg.factory)())
23 .collect()
24}
25
26/// The process-wide provider list, constructed once on first use. An empty
27/// slice (no extension registered) keeps every scoped-transaction call a
28/// plain `pool.begin()`.
29#[must_use]
30pub fn scope_providers() -> &'static [SharedScopeProvider] {
31 static PROVIDERS: OnceLock<Vec<SharedScopeProvider>> = OnceLock::new();
32 PROVIDERS.get_or_init(discover_scope_providers)
33}
34
35/// Register a [`super::ConnectionScopeProvider`] factory at static-init time.
36///
37/// Wire alongside `register_extension!` in the extension's `extension.rs`:
38///
39/// ```ignore
40/// systemprompt_database::register_scope_provider!(|| {
41/// std::sync::Arc::new(OrgScopeProvider)
42/// as systemprompt_database::scope::SharedScopeProvider
43/// });
44/// ```
45#[macro_export]
46macro_rules! register_scope_provider {
47 ($factory:expr) => {
48 ::inventory::submit! {
49 $crate::scope::ScopeProviderRegistration {
50 factory: $factory,
51 }
52 }
53 };
54}