microde_application/
relationship.rs1use std::any::TypeId;
2use std::marker::PhantomData;
3use std::sync::Arc;
4use std::sync::atomic::{AtomicU64, Ordering};
5
6static NEXT_PORT_ID: AtomicU64 = AtomicU64::new(0);
7static NEXT_SLOT_ID: AtomicU64 = AtomicU64::new(0);
8
9pub struct Port<T: ?Sized> {
11 id: u64,
12 description: String,
13 contract: PhantomData<fn() -> T>,
14 module_type: Option<(TypeId, &'static str)>,
15}
16
17impl<T: ?Sized> Port<T> {
18 pub fn new(description: impl Into<String>) -> Self {
19 Self {
20 id: NEXT_PORT_ID.fetch_add(1, Ordering::Relaxed),
21 description: description.into(),
22 contract: PhantomData,
23 module_type: None,
24 }
25 }
26
27 pub fn description(&self) -> &str {
28 &self.description
29 }
30
31 pub fn for_module<Module: crate::MicrodeModule + 'static>(
32 description: impl Into<String>,
33 ) -> Self {
34 Self {
35 id: NEXT_PORT_ID.fetch_add(1, Ordering::Relaxed),
36 description: description.into(),
37 contract: PhantomData,
38 module_type: Some((TypeId::of::<Module>(), std::any::type_name::<Module>())),
39 }
40 }
41}
42
43impl<T: ?Sized> Clone for Port<T> {
44 fn clone(&self) -> Self {
45 Self {
46 id: self.id,
47 description: self.description.clone(),
48 contract: PhantomData,
49 module_type: self.module_type,
50 }
51 }
52}
53
54struct Relationship<T: ?Sized> {
55 slot_id: u64,
56 name: String,
57 port: Port<T>,
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub enum RelationshipKind {
62 Dependency,
63 Reference,
64}
65
66#[derive(Debug, Clone, PartialEq, Eq)]
67pub struct RelationshipDescriptor {
68 pub(crate) slot_id: u64,
69 pub(crate) name: String,
70 pub(crate) port_id: u64,
71 pub(crate) port_description: String,
72 pub(crate) kind: RelationshipKind,
73 pub(crate) module_type: Option<(TypeId, &'static str)>,
74}
75
76pub trait RelationshipSlot {
77 fn descriptor(&self) -> RelationshipDescriptor;
78}
79
80impl<T: ?Sized> Relationship<T> {
81 fn new(name: impl Into<String>, port: Port<T>) -> Self {
82 Self {
83 slot_id: NEXT_SLOT_ID.fetch_add(1, Ordering::Relaxed),
84 name: name.into(),
85 port,
86 }
87 }
88}
89
90macro_rules! relationship_handle {
91 ($name:ident, $kind:expr) => {
92 pub struct $name<T: ?Sized>(Relationship<T>);
93
94 impl<T: ?Sized> Clone for $name<T> {
95 fn clone(&self) -> Self {
96 Self(Relationship {
97 slot_id: self.0.slot_id,
98 name: self.0.name.clone(),
99 port: self.0.port.clone(),
100 })
101 }
102 }
103
104 impl<T: ?Sized> $name<T> {
105 pub fn new(name: impl Into<String>, port: Port<T>) -> Self {
106 Self(Relationship::new(name, port))
107 }
108
109 pub fn name(&self) -> &str {
110 &self.0.name
111 }
112
113 pub fn port(&self) -> &Port<T> {
114 &self.0.port
115 }
116
117 pub(crate) fn slot_id(&self) -> u64 {
118 self.0.slot_id
119 }
120 }
121
122 impl<T: ?Sized> RelationshipSlot for $name<T> {
123 fn descriptor(&self) -> RelationshipDescriptor {
124 RelationshipDescriptor {
125 slot_id: self.0.slot_id,
126 name: self.0.name.clone(),
127 port_id: self.0.port.id,
128 port_description: self.0.port.description.clone(),
129 kind: $kind,
130 module_type: self.0.port.module_type,
131 }
132 }
133 }
134 };
135}
136
137relationship_handle!(Dependency, RelationshipKind::Dependency);
138relationship_handle!(Reference, RelationshipKind::Reference);
139
140#[derive(Clone)]
141pub struct Provider {
142 pub(crate) port_id: u64,
143 resolver: Arc<
144 dyn Fn() -> Result<Arc<dyn std::any::Any + Send + Sync>, crate::MicrodeError> + Send + Sync,
145 >,
146}
147
148impl Provider {
149 pub fn new<T: Send + Sync + 'static>(port: Port<T>, value: T) -> Self {
150 let value: Arc<dyn std::any::Any + Send + Sync> = Arc::new(value);
151 Self {
152 port_id: port.id,
153 resolver: Arc::new(move || Ok(value.clone())),
154 }
155 }
156
157 pub fn try_new<T, Factory>(port: Port<T>, factory: Factory) -> Self
158 where
159 T: Send + Sync + 'static,
160 Factory: Fn() -> Result<T, crate::MicrodeError> + Send + Sync + 'static,
161 {
162 Self {
163 port_id: port.id,
164 resolver: Arc::new(move || {
165 factory().map(|value| Arc::new(value) as Arc<dyn std::any::Any + Send + Sync>)
166 }),
167 }
168 }
169
170 pub(crate) fn resolve(
171 &self,
172 ) -> Result<Arc<dyn std::any::Any + Send + Sync>, crate::MicrodeError> {
173 (self.resolver)()
174 }
175}