zenoh_flow_derive/
lib.rs

1//
2// Copyright (c) 2021 - 2024 ZettaScale Technology
3//
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8//
9// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10//
11// Contributors:
12//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>
13//
14
15//! This crate exposes three procedural macros (one for each type of node) to facilitate exposing the symbols required
16//! by Zenoh-Flow in order to dynamically load nodes.
17
18use proc_macro::TokenStream;
19use quote::quote;
20use syn::{parse_macro_input, DeriveInput};
21
22/// Expose the symbols Zenoh-Flow needs to instantiate and start a Source.
23///
24/// In addition to exposing a specific symbol that will not be mangled by the compiler, this macro records the version
25/// of the rust compiler used as well as the version of Zenoh-Flow. These additional information are here to (try) limit
26/// possible surprises due to the lack of stable ABI in Rust.
27///
28/// ## Example
29///
30/// ```
31/// # use async_trait::async_trait;
32/// # use zenoh_flow_nodes::prelude::*;
33/// #[export_source]
34/// pub struct MySource {
35///     // Your logic goes here.
36/// }
37/// # #[async_trait]
38/// # impl Source for MySource{
39/// #   async fn new(
40/// #       context: Context,
41/// #       configuration: Configuration,
42/// #       outputs: Outputs,
43/// #   ) -> Result<Self> {
44/// #         todo!()
45/// #     }
46/// # }
47///
48/// # #[async_trait]
49/// # impl Node for MySource {
50/// #     async fn iteration(&self) -> Result<()> {
51/// #         todo!()
52/// #     }
53/// # }
54/// ```
55#[proc_macro_attribute]
56pub fn export_source(_: TokenStream, input: TokenStream) -> TokenStream {
57    let ast = parse_macro_input!(input as DeriveInput);
58    let ident = &ast.ident;
59
60    let gen = quote! {
61
62        #ast
63
64        #[doc(hidden)]
65        #[no_mangle]
66        pub static _zf_export_source: zenoh_flow_nodes::NodeDeclaration<
67            zenoh_flow_nodes::SourceFn,
68        > = zenoh_flow_nodes::NodeDeclaration::<
69            zenoh_flow_nodes::SourceFn,
70        > {
71            rustc_version: zenoh_flow_nodes::RUSTC_VERSION,
72            core_version: zenoh_flow_nodes::CORE_VERSION,
73            constructor: |context: zenoh_flow_nodes::prelude::Context,
74            configuration: zenoh_flow_nodes::prelude::Configuration,
75            outputs: zenoh_flow_nodes::prelude::Outputs| {
76                std::boxed::Box::pin(async {
77                    let node = <#ident>::new(context, configuration, outputs).await?;
78                    Ok(std::sync::Arc::new(node) as std::sync::Arc<dyn zenoh_flow_nodes::prelude::Node>)
79                })
80            },
81        };
82    };
83    gen.into()
84}
85
86/// Expose the symbols Zenoh-Flow needs to instantiate and start a Sink.
87///
88/// In addition to exposing a specific symbol that will not be mangled by the compiler, this macro records the version
89/// of the rust compiler used as well as the version of Zenoh-Flow. These additional information are here to (try) limit
90/// possible surprises due to the lack of stable ABI in Rust.
91///
92/// ## Example
93///
94/// ```
95/// # use async_trait::async_trait;
96/// # use zenoh_flow_nodes::prelude::*;
97/// #[export_sink]
98/// pub struct MySink {
99///     // Your logic goes here.
100/// }
101/// # #[async_trait]
102/// # impl Sink for MySink {
103/// #   async fn new(
104/// #       context: Context,
105/// #       configuration: Configuration,
106/// #       inputs: Inputs,
107/// #   ) -> Result<Self> {
108/// #         todo!()
109/// #     }
110/// # }
111///
112/// # #[async_trait]
113/// # impl Node for MySink {
114/// #     async fn iteration(&self) -> Result<()> {
115/// #         todo!()
116/// #     }
117/// # }
118/// ```
119#[proc_macro_attribute]
120pub fn export_sink(_: TokenStream, input: TokenStream) -> TokenStream {
121    let ast = parse_macro_input!(input as DeriveInput);
122    let ident = &ast.ident;
123
124    let sink = quote! {#ast};
125
126    let constructor = quote! {
127
128        #[doc(hidden)]
129        #[no_mangle]
130        pub static _zf_export_sink: zenoh_flow_nodes::NodeDeclaration<
131            zenoh_flow_nodes::SinkFn,
132        > = zenoh_flow_nodes::NodeDeclaration::<
133            zenoh_flow_nodes::SinkFn,
134        > {
135            rustc_version: zenoh_flow_nodes::RUSTC_VERSION,
136            core_version: zenoh_flow_nodes::CORE_VERSION,
137            constructor: |context: zenoh_flow_nodes::prelude::Context,
138                          configuration: zenoh_flow_nodes::prelude::Configuration,
139                          mut inputs: zenoh_flow_nodes::prelude::Inputs| {
140                std::boxed::Box::pin(async {
141                    let node = <#ident>::new(context, configuration, inputs).await?;
142                    Ok(std::sync::Arc::new(node) as std::sync::Arc<dyn zenoh_flow_nodes::prelude::Node>)
143                })
144            },
145        };
146    };
147
148    let gen = quote! {
149        #sink
150        #constructor
151
152    };
153    gen.into()
154}
155
156/// Expose the symbols Zenoh-Flow needs to instantiate and start a Operator.
157///
158/// In addition to exposing a specific symbol that will not be mangled by the compiler, this macro records the version
159/// of the rust compiler used as well as the version of Zenoh-Flow. These additional information are here to (try) limit
160/// possible surprises due to the lack of stable ABI in Rust.
161///
162/// ## Example
163///
164/// ```
165/// # use async_trait::async_trait;
166/// # use zenoh_flow_nodes::prelude::*;
167/// #[export_operator]
168/// pub struct MyOperator {
169///     // Your logic code goes here.
170/// }
171/// # #[async_trait]
172/// # impl Operator for MyOperator {
173/// #     async fn new(
174/// #         context: Context,
175/// #         configuration: Configuration,
176/// #         inputs: Inputs,
177/// #         outputs: Outputs,
178/// #     ) -> Result<Self>
179/// #     where
180/// #     Self: Sized {
181/// #         todo!()
182/// #     }
183/// # }
184///
185/// # #[async_trait]
186/// # impl Node for MyOperator {
187/// #     async fn iteration(&self) -> Result<()> {
188/// #         todo!()
189/// #     }
190/// # }
191/// ```
192#[proc_macro_attribute]
193pub fn export_operator(_: TokenStream, input: TokenStream) -> TokenStream {
194    let ast = parse_macro_input!(input as DeriveInput);
195    let ident = &ast.ident;
196
197    let gen = quote! {
198
199        #ast
200
201        #[doc(hidden)]
202        #[no_mangle]
203        pub static _zf_export_operator: zenoh_flow_nodes::NodeDeclaration<
204        zenoh_flow_nodes::OperatorFn,
205        > = zenoh_flow_nodes::NodeDeclaration::<
206        zenoh_flow_nodes::OperatorFn,
207        > {
208            rustc_version: zenoh_flow_nodes::RUSTC_VERSION,
209            core_version: zenoh_flow_nodes::CORE_VERSION,
210            constructor: |context: zenoh_flow_nodes::prelude::Context,
211                          configuration: zenoh_flow_nodes::prelude::Configuration,
212                          mut inputs: zenoh_flow_nodes::prelude::Inputs,
213                          mut outputs: zenoh_flow_nodes::prelude::Outputs| {
214                std::boxed::Box::pin(async {
215                    let node = <#ident>::new(context, configuration, inputs, outputs).await?;
216                    Ok(std::sync::Arc::new(node) as std::sync::Arc<dyn zenoh_flow_nodes::prelude::Node>)
217                })
218            },
219        };
220    };
221    gen.into()
222}