1use std::io::Error;
2use std::pin::Pin;
3
4use bytes::{Bytes, BytesMut};
5use dfir_lang::graph::DfirGraph;
6use futures::{Sink, Stream};
7use serde::Serialize;
8use serde::de::DeserializeOwned;
9use stageleft::QuotedWithContext;
10
11use crate::compile::builder::ExternalPortId;
12use crate::location::dynamic::LocationId;
13use crate::location::member_id::TaglessMemberId;
14use crate::location::{LocationKey, MembershipEvent, NetworkHint};
15
16pub trait Deploy<'a> {
17 type Meta: Default;
18 type InstantiateEnv;
19
20 type Process: Node<Meta = Self::Meta, InstantiateEnv = Self::InstantiateEnv> + Clone;
21 type Cluster: Node<Meta = Self::Meta, InstantiateEnv = Self::InstantiateEnv> + Clone;
22 type External: Node<Meta = Self::Meta, InstantiateEnv = Self::InstantiateEnv>
23 + RegisterPort<'a, Self>;
24
25 const SUPPORTS_EXTERNAL_SERIALIZATION: bool = false;
29
30 #[expect(clippy::too_many_arguments, reason = "networking codegen")]
40 fn o2o_sink_source(
41 env: &mut Self::InstantiateEnv,
42 p1: &Self::Process,
43 p1_port: &<Self::Process as Node>::Port,
44 p2: &Self::Process,
45 p2_port: &<Self::Process as Node>::Port,
46 name: Option<&str>,
47 networking_info: &crate::networking::NetworkingInfo,
48 external_types: Option<(&syn::Type, &syn::Type)>,
49 ) -> (syn::Expr, syn::Expr);
50
51 fn o2o_connect(
56 p1: &Self::Process,
57 p1_port: &<Self::Process as Node>::Port,
58 p2: &Self::Process,
59 p2_port: &<Self::Process as Node>::Port,
60 ) -> Box<dyn FnOnce()>;
61
62 #[expect(clippy::too_many_arguments, reason = "networking codegen")]
74 fn o2m_sink_source(
75 env: &mut Self::InstantiateEnv,
76 p1: &Self::Process,
77 p1_port: &<Self::Process as Node>::Port,
78 c2: &Self::Cluster,
79 c2_port: &<Self::Cluster as Node>::Port,
80 name: Option<&str>,
81 networking_info: &crate::networking::NetworkingInfo,
82 external_types: Option<(&syn::Type, &syn::Type)>,
83 ) -> (syn::Expr, syn::Expr);
84
85 fn o2m_connect(
90 p1: &Self::Process,
91 p1_port: &<Self::Process as Node>::Port,
92 c2: &Self::Cluster,
93 c2_port: &<Self::Cluster as Node>::Port,
94 ) -> Box<dyn FnOnce()>;
95
96 #[expect(clippy::too_many_arguments, reason = "networking codegen")]
108 fn m2o_sink_source(
109 env: &mut Self::InstantiateEnv,
110 c1: &Self::Cluster,
111 c1_port: &<Self::Cluster as Node>::Port,
112 p2: &Self::Process,
113 p2_port: &<Self::Process as Node>::Port,
114 name: Option<&str>,
115 networking_info: &crate::networking::NetworkingInfo,
116 external_types: Option<(&syn::Type, &syn::Type)>,
117 ) -> (syn::Expr, syn::Expr);
118
119 fn m2o_connect(
124 c1: &Self::Cluster,
125 c1_port: &<Self::Cluster as Node>::Port,
126 p2: &Self::Process,
127 p2_port: &<Self::Process as Node>::Port,
128 ) -> Box<dyn FnOnce()>;
129
130 #[expect(clippy::too_many_arguments, reason = "networking codegen")]
142 fn m2m_sink_source(
143 env: &mut Self::InstantiateEnv,
144 c1: &Self::Cluster,
145 c1_port: &<Self::Cluster as Node>::Port,
146 c2: &Self::Cluster,
147 c2_port: &<Self::Cluster as Node>::Port,
148 name: Option<&str>,
149 networking_info: &crate::networking::NetworkingInfo,
150 external_types: Option<(&syn::Type, &syn::Type)>,
151 ) -> (syn::Expr, syn::Expr);
152
153 fn m2m_connect(
158 c1: &Self::Cluster,
159 c1_port: &<Self::Cluster as Node>::Port,
160 c2: &Self::Cluster,
161 c2_port: &<Self::Cluster as Node>::Port,
162 ) -> Box<dyn FnOnce()>;
163
164 fn e2o_many_source(
165 extra_stmts: &mut Vec<syn::Stmt>,
166 p2: &Self::Process,
167 p2_port: &<Self::Process as Node>::Port,
168 codec_type: &syn::Type,
169 shared_handle: String,
170 ) -> syn::Expr;
171 fn e2o_many_sink(shared_handle: String) -> syn::Expr;
172
173 fn e2o_source(
174 extra_stmts: &mut Vec<syn::Stmt>,
175 p1: &Self::External,
176 p1_port: &<Self::External as Node>::Port,
177 p2: &Self::Process,
178 p2_port: &<Self::Process as Node>::Port,
179 codec_type: &syn::Type,
180 shared_handle: String,
181 ) -> syn::Expr;
182 fn e2o_connect(
183 p1: &Self::External,
184 p1_port: &<Self::External as Node>::Port,
185 p2: &Self::Process,
186 p2_port: &<Self::Process as Node>::Port,
187 many: bool,
188 server_hint: NetworkHint,
189 ) -> Box<dyn FnOnce()>;
190
191 fn o2e_sink(
192 p1: &Self::Process,
193 p1_port: &<Self::Process as Node>::Port,
194 p2: &Self::External,
195 p2_port: &<Self::External as Node>::Port,
196 shared_handle: String,
197 ) -> syn::Expr;
198
199 fn e2m_source(
200 extra_stmts: &mut Vec<syn::Stmt>,
201 p1: &Self::External,
202 p1_port: &<Self::External as Node>::Port,
203 c2: &Self::Cluster,
204 c2_port: &<Self::Cluster as Node>::Port,
205 codec_type: &syn::Type,
206 shared_handle: String,
207 ) -> syn::Expr {
208 let _ = (
209 extra_stmts,
210 p1,
211 p1_port,
212 c2,
213 c2_port,
214 codec_type,
215 shared_handle,
216 );
217 todo!("e2m_source is not yet supported for this deploy backend")
218 }
219
220 fn e2m_connect(
221 p1: &Self::External,
222 p1_port: &<Self::External as Node>::Port,
223 c2: &Self::Cluster,
224 c2_port: &<Self::Cluster as Node>::Port,
225 server_hint: NetworkHint,
226 ) -> Box<dyn FnOnce()> {
227 let _ = (p1, p1_port, c2, c2_port, server_hint);
228 todo!("e2m_connect is not yet supported for this deploy backend")
229 }
230
231 fn m2e_sink(
232 c1: &Self::Cluster,
233 c1_port: &<Self::Cluster as Node>::Port,
234 p2: &Self::External,
235 p2_port: &<Self::External as Node>::Port,
236 shared_handle: String,
237 ) -> syn::Expr {
238 let _ = (c1, c1_port, p2, p2_port, shared_handle);
239 todo!("m2e_sink is not yet supported for this deploy backend")
240 }
241
242 fn cluster_ids(
243 of_cluster: LocationKey,
244 ) -> impl QuotedWithContext<'a, &'a [TaglessMemberId], ()> + Clone + 'a;
245
246 fn cluster_self_id() -> impl QuotedWithContext<'a, TaglessMemberId, ()> + Clone + 'a;
247
248 fn cluster_membership_stream(
249 env: &mut Self::InstantiateEnv,
250 at_location: &LocationId,
251 location_id: &LocationId,
252 ) -> impl QuotedWithContext<'a, Box<dyn Stream<Item = (TaglessMemberId, MembershipEvent)> + Unpin>, ()>;
253
254 fn register_embedded_stream_input(
259 _env: &mut Self::InstantiateEnv,
260 _location_key: LocationKey,
261 _ident: &syn::Ident,
262 _element_type: &syn::Type,
263 ) {
264 panic!("register_embedded_stream_input is only supported by EmbeddedDeploy");
265 }
266
267 fn register_embedded_singleton_input(
272 _env: &mut Self::InstantiateEnv,
273 _location_key: LocationKey,
274 _ident: &syn::Ident,
275 _element_type: &syn::Type,
276 ) {
277 panic!("register_embedded_singleton_input is only supported by EmbeddedDeploy");
278 }
279
280 fn register_embedded_output(
285 _env: &mut Self::InstantiateEnv,
286 _location_key: LocationKey,
287 _ident: &syn::Ident,
288 _element_type: &syn::Type,
289 ) {
290 panic!("register_embedded_output is only supported by EmbeddedDeploy");
291 }
292}
293
294pub trait ProcessSpec<'a, D>
295where
296 D: Deploy<'a> + ?Sized,
297{
298 fn build(self, location_key: LocationKey, name_hint: &str) -> D::Process;
299}
300
301pub trait IntoProcessSpec<'a, D>
302where
303 D: Deploy<'a> + ?Sized,
304{
305 type ProcessSpec: ProcessSpec<'a, D>;
306 fn into_process_spec(self) -> Self::ProcessSpec;
307}
308
309impl<'a, D, T> IntoProcessSpec<'a, D> for T
310where
311 D: Deploy<'a> + ?Sized,
312 T: ProcessSpec<'a, D>,
313{
314 type ProcessSpec = T;
315 fn into_process_spec(self) -> Self::ProcessSpec {
316 self
317 }
318}
319
320pub trait ClusterSpec<'a, D>
321where
322 D: Deploy<'a> + ?Sized,
323{
324 fn build(self, location_key: LocationKey, name_hint: &str) -> D::Cluster;
325}
326
327pub trait ExternalSpec<'a, D>
328where
329 D: Deploy<'a> + ?Sized,
330{
331 fn build(self, location_key: LocationKey, name_hint: &str) -> D::External;
332}
333
334pub trait Node {
335 type Port: Clone;
342 type Meta: Default;
343 type InstantiateEnv;
344
345 fn next_port(&self) -> Self::Port;
347
348 fn update_meta(&self, meta: &Self::Meta);
349
350 fn instantiate(
351 &self,
352 env: &mut Self::InstantiateEnv,
353 meta: &mut Self::Meta,
354 graph: DfirGraph,
355 extra_stmts: &[syn::Stmt],
356 sidecars: &[syn::Expr],
357 );
358}
359
360pub type DynSourceSink<Out, In, InErr> = (
361 Pin<Box<dyn Stream<Item = Out>>>,
362 Pin<Box<dyn Sink<In, Error = InErr>>>,
363);
364
365pub trait RegisterPort<'a, D>: Node + Clone
366where
367 D: Deploy<'a> + ?Sized,
368{
369 fn register(&self, external_port_id: ExternalPortId, port: Self::Port);
370
371 fn as_bytes_bidi(
372 &self,
373 external_port_id: ExternalPortId,
374 ) -> impl Future<Output = DynSourceSink<Result<BytesMut, Error>, Bytes, Error>> + 'a;
375
376 fn as_bincode_bidi<InT, OutT>(
377 &self,
378 external_port_id: ExternalPortId,
379 ) -> impl Future<Output = DynSourceSink<OutT, InT, Error>> + 'a
380 where
381 InT: Serialize + 'static,
382 OutT: DeserializeOwned + 'static;
383
384 fn as_bincode_sink<T>(
385 &self,
386 external_port_id: ExternalPortId,
387 ) -> impl Future<Output = Pin<Box<dyn Sink<T, Error = Error>>>> + 'a
388 where
389 T: Serialize + 'static;
390
391 fn as_bincode_source<T>(
392 &self,
393 external_port_id: ExternalPortId,
394 ) -> impl Future<Output = Pin<Box<dyn Stream<Item = T>>>> + 'a
395 where
396 T: DeserializeOwned + 'static;
397}