1use crate::{LinkedBinding, Module, ModuleManifest};
2use platform_core::{AppContext, Migration};
3use std::any::{Any, TypeId};
4use std::sync::Arc;
5
6#[derive(Clone)]
7pub struct HostContribution {
8 type_id: TypeId,
9 value: Arc<dyn Any + Send + Sync>,
10}
11
12impl std::fmt::Debug for HostContribution {
13 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14 formatter
15 .debug_struct("HostContribution")
16 .field("type_id", &self.type_id)
17 .finish_non_exhaustive()
18 }
19}
20
21impl HostContribution {
22 pub fn typed<T>(value: T) -> Self
23 where
24 T: Send + Sync + 'static,
25 {
26 Self {
27 type_id: TypeId::of::<T>(),
28 value: Arc::new(value),
29 }
30 }
31
32 pub fn get<T>(&self) -> Option<&T>
33 where
34 T: Send + Sync + 'static,
35 {
36 (self.type_id == TypeId::of::<T>())
37 .then(|| self.value.downcast_ref::<T>())
38 .flatten()
39 }
40}
41
42#[derive(Debug, Clone)]
43pub struct HostLinkedModule {
44 pub module_name: &'static str,
45 pub manifest: fn() -> ModuleManifest,
46 pub load: Option<fn(&AppContext) -> Module>,
47 pub http_binding: Option<fn() -> LinkedBinding>,
48 pub migrations: &'static [Migration],
49 contributions: Vec<HostContribution>,
50}
51
52impl HostLinkedModule {
53 #[must_use]
54 pub fn manifest_only(
55 module_name: &'static str,
56 manifest: fn() -> ModuleManifest,
57 migrations: &'static [Migration],
58 ) -> Self {
59 Self {
60 module_name,
61 manifest,
62 load: None,
63 http_binding: None,
64 migrations,
65 contributions: Vec::new(),
66 }
67 }
68
69 #[must_use]
70 pub fn linked(
71 module_name: &'static str,
72 manifest: fn() -> ModuleManifest,
73 load: fn(&AppContext) -> Module,
74 migrations: &'static [Migration],
75 ) -> Self {
76 Self {
77 module_name,
78 manifest,
79 load: Some(load),
80 http_binding: None,
81 migrations,
82 contributions: Vec::new(),
83 }
84 }
85
86 #[must_use]
87 pub fn with_http_binding(mut self, http_binding: fn() -> LinkedBinding) -> Self {
88 self.http_binding = Some(http_binding);
89 self
90 }
91
92 #[must_use]
93 pub fn with_contribution<T>(mut self, contribution: T) -> Self
94 where
95 T: Send + Sync + 'static,
96 {
97 self.contributions
98 .push(HostContribution::typed(contribution));
99 self
100 }
101
102 pub fn contributions<T>(&self) -> impl Iterator<Item = &T>
103 where
104 T: Send + Sync + 'static,
105 {
106 self.contributions
107 .iter()
108 .filter_map(HostContribution::get::<T>)
109 }
110}