Skip to main content

microde_application/
relationship.rs

1use 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
9/// Nominal runtime identity for a provider contract.
10pub 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}