zenoh_macros/
lib.rs

1//
2// Copyright (c) 2023 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//! ⚠️ WARNING ⚠️
16//!
17//! This crate is intended for Zenoh's internal use.
18//!
19//! [Click here for Zenoh's documentation](https://docs.rs/zenoh/latest/zenoh)
20use proc_macro::TokenStream;
21use quote::{quote, ToTokens};
22use syn::{parse_macro_input, parse_quote, Attribute, Error, Item, ItemImpl, LitStr, TraitItem};
23use zenoh_keyexpr::{
24    format::{
25        macro_support::{self, SegmentBuilder},
26        KeFormat,
27    },
28    key_expr::keyexpr,
29};
30
31const RUSTC_VERSION: &str = include_str!(concat!(env!("OUT_DIR"), "/version.rs"));
32
33#[proc_macro]
34pub fn rustc_version_release(_tokens: TokenStream) -> TokenStream {
35    let release = RUSTC_VERSION
36        .split('\n')
37        .filter_map(|l| {
38            let line = l.trim();
39            if line.is_empty() {
40                None
41            } else {
42                Some(line)
43            }
44        })
45        .find_map(|l| l.strip_prefix("release: "))
46        .unwrap();
47    let commit = RUSTC_VERSION
48        .split('\n')
49        .filter_map(|l| {
50            let line = l.trim();
51            if line.is_empty() {
52                None
53            } else {
54                Some(line)
55            }
56        })
57        .find_map(|l| l.strip_prefix("commit-hash: "))
58        .unwrap();
59    (quote! {(#release, #commit)}).into()
60}
61
62/// An enumeration of items which can be annotated with `#[zenoh_macros::unstable_doc]`, #[zenoh_macros::unstable]`, `#[zenoh_macros::internal]`
63#[allow(clippy::large_enum_variant)]
64enum AnnotableItem {
65    /// Wrapper around [`syn::Item`].
66    Item(Item),
67    /// Wrapper around [`syn::TraitItem`].
68    TraitItem(TraitItem),
69}
70
71macro_rules! parse_annotable_item {
72    ($tokens:ident) => {{
73        let item: Item = parse_macro_input!($tokens as Item);
74
75        if matches!(item, Item::Verbatim(_)) {
76            let tokens = TokenStream::from(item.to_token_stream());
77            let trait_item: TraitItem = parse_macro_input!(tokens as TraitItem);
78
79            if matches!(trait_item, TraitItem::Verbatim(_)) {
80                Err(Error::new_spanned(
81                    trait_item,
82                    "the `unstable` proc-macro attribute only supports items and trait items",
83                ))
84            } else {
85                Ok(AnnotableItem::TraitItem(trait_item))
86            }
87        } else {
88            Ok(AnnotableItem::Item(item))
89        }
90    }};
91}
92
93impl AnnotableItem {
94    /// Mutably borrows the attribute list of this item.
95    fn attributes_mut(&mut self) -> Result<&mut Vec<Attribute>, Error> {
96        match self {
97            AnnotableItem::Item(item) => match item {
98                Item::Const(item) => Ok(&mut item.attrs),
99                Item::Enum(item) => Ok(&mut item.attrs),
100                Item::ExternCrate(item) => Ok(&mut item.attrs),
101                Item::Fn(item) => Ok(&mut item.attrs),
102                Item::ForeignMod(item) => Ok(&mut item.attrs),
103                Item::Impl(item) => Ok(&mut item.attrs),
104                Item::Macro(item) => Ok(&mut item.attrs),
105                Item::Mod(item) => Ok(&mut item.attrs),
106                Item::Static(item) => Ok(&mut item.attrs),
107                Item::Struct(item) => Ok(&mut item.attrs),
108                Item::Trait(item) => Ok(&mut item.attrs),
109                Item::TraitAlias(item) => Ok(&mut item.attrs),
110                Item::Type(item) => Ok(&mut item.attrs),
111                Item::Union(item) => Ok(&mut item.attrs),
112                Item::Use(item) => Ok(&mut item.attrs),
113                other => Err(Error::new_spanned(
114                    other,
115                    "item is not supported by the `unstable` or `internal` proc-macro attribute",
116                )),
117            },
118            AnnotableItem::TraitItem(trait_item) => match trait_item {
119                TraitItem::Const(trait_item) => Ok(&mut trait_item.attrs),
120                TraitItem::Fn(trait_item) => Ok(&mut trait_item.attrs),
121                TraitItem::Type(trait_item) => Ok(&mut trait_item.attrs),
122                TraitItem::Macro(trait_item) => Ok(&mut trait_item.attrs),
123                other => Err(Error::new_spanned(
124                    other,
125                    "item is not supported by the `unstable` or `internal` proc-macro attribute",
126                )),
127            },
128        }
129    }
130
131    /// Converts this item to a `proc_macro2::TokenStream`.
132    fn to_token_stream(&self) -> proc_macro2::TokenStream {
133        match self {
134            AnnotableItem::Item(item) => item.to_token_stream(),
135            AnnotableItem::TraitItem(trait_item) => trait_item.to_token_stream(),
136        }
137    }
138}
139
140#[proc_macro_attribute]
141/// Adds only piece of documentation about the item being unstable but no unstable attribute itself.
142/// This is useful when the whole crate is supposed to be used in unstable mode only, it makes sense
143/// to mention it in documentation for the crate items, but not to add `#[cfg(feature = "unstable")]` to every item.
144pub fn unstable_doc(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
145    let mut item = match parse_annotable_item!(tokens) {
146        Ok(item) => item,
147        Err(err) => return err.into_compile_error().into(),
148    };
149
150    let attrs = match item.attributes_mut() {
151        Ok(attrs) => attrs,
152        Err(err) => return err.into_compile_error().into(),
153    };
154
155    if attrs.iter().any(is_doc_attribute) {
156        let mut pushed = false;
157        let oldattrs = std::mem::take(attrs);
158        for attr in oldattrs {
159            if is_doc_attribute(&attr) && !pushed {
160                attrs.push(attr);
161                // See: https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html#adding-a-warning-block
162                let message = "<div class=\"warning\">This API has been marked as <strong>unstable</strong>: it works as advertised, but it may be changed in a future release.</div>";
163                let note: Attribute = parse_quote!(#[doc = #message]);
164                attrs.push(note);
165                pushed = true;
166            } else {
167                attrs.push(attr);
168            }
169        }
170    }
171
172    TokenStream::from(item.to_token_stream())
173}
174
175#[proc_macro_attribute]
176/// Adds a `#[cfg(feature = "unstable")]` attribute to the item and appends piece of documentation about the item being unstable.
177pub fn unstable(attr: TokenStream, tokens: TokenStream) -> TokenStream {
178    let tokens = unstable_doc(attr, tokens);
179    let mut item = match parse_annotable_item!(tokens) {
180        Ok(item) => item,
181        Err(err) => return err.into_compile_error().into(),
182    };
183
184    let attrs = match item.attributes_mut() {
185        Ok(attrs) => attrs,
186        Err(err) => return err.into_compile_error().into(),
187    };
188
189    let feature_gate: Attribute = parse_quote!(#[cfg(feature = "unstable")]);
190    attrs.push(feature_gate);
191
192    TokenStream::from(item.to_token_stream())
193}
194
195// FIXME(fuzzypixelz): refactor `unstable` macro to accept arguments
196#[proc_macro_attribute]
197pub fn internal_config(args: TokenStream, tokens: TokenStream) -> TokenStream {
198    let tokens = unstable_doc(args, tokens);
199    let mut item = match parse_annotable_item!(tokens) {
200        Ok(item) => item,
201        Err(err) => return err.into_compile_error().into(),
202    };
203
204    let attrs = match item.attributes_mut() {
205        Ok(attrs) => attrs,
206        Err(err) => return err.into_compile_error().into(),
207    };
208
209    let feature_gate: Attribute = parse_quote!(#[cfg(feature = "internal_config")]);
210    let hide_doc: Attribute = parse_quote!(#[doc(hidden)]);
211    attrs.push(feature_gate);
212    attrs.push(hide_doc);
213
214    TokenStream::from(item.to_token_stream())
215}
216
217#[proc_macro_attribute]
218/// Adds a `#[cfg(feature = "internal")]` and `#[doc(hidden)]` attributes to the item.
219pub fn internal(_attr: TokenStream, tokens: TokenStream) -> TokenStream {
220    let mut item = match parse_annotable_item!(tokens) {
221        Ok(item) => item,
222        Err(err) => return err.into_compile_error().into(),
223    };
224
225    let attrs = match item.attributes_mut() {
226        Ok(attrs) => attrs,
227        Err(err) => return err.into_compile_error().into(),
228    };
229
230    let feature_gate: Attribute = parse_quote!(#[cfg(feature = "internal")]);
231    let hide_doc: Attribute = parse_quote!(#[doc(hidden)]);
232    attrs.push(feature_gate);
233    attrs.push(hide_doc);
234
235    TokenStream::from(item.to_token_stream())
236}
237
238/// Returns `true` if the attribute is a `#[doc = "..."]` attribute.
239fn is_doc_attribute(attr: &Attribute) -> bool {
240    attr.path()
241        .get_ident()
242        .is_some_and(|ident| &ident.to_string() == "doc")
243}
244
245fn keformat_support(source: &str) -> proc_macro2::TokenStream {
246    let format = match KeFormat::new(&source) {
247        Ok(format) => format,
248        Err(e) => panic!("{}", e),
249    };
250    let specs = unsafe { macro_support::specs(&format) };
251    let len = specs.len();
252    let setters = specs.iter().map(|spec| {
253        let id = &source[spec.spec_start..(spec.spec_start + spec.id_end as usize)];
254        let set_id = quote::format_ident!("{}", id);
255        quote! {
256            pub fn #set_id <S: ::core::fmt::Display>(&mut self, value: S) -> Result<&mut Self, ::zenoh::key_expr::format::FormatSetError> {
257                match self.0.set(#id, value) {
258                    Ok(_) => Ok(self),
259                    Err(e) => Err(e)
260                }
261            }
262        }
263    });
264    let getters = specs.iter().map(|spec| {
265        let source = &source[spec.spec_start..spec.spec_end];
266        let id = &source[..(spec.id_end as usize)];
267        let get_id = quote::format_ident!("{}", id);
268        let pattern = unsafe {
269            keyexpr::from_str_unchecked(if spec.pattern_end != u16::MAX {
270                &source[(spec.id_end as usize + 1)..(spec.spec_start + spec.pattern_end as usize)]
271            } else {
272                &source[(spec.id_end as usize + 1)..]
273            })
274        };
275        let doc = format!("Get the parsed value for `{id}`.\n\nThis value is guaranteed to be a valid key expression intersecting with `{pattern}`");
276        if pattern.as_bytes() == b"**" {
277            quote! {
278                #[doc = #doc]
279                /// Since the pattern is `**`, this may return `None` if the pattern didn't consume any chunks.
280                pub fn #get_id (&self) -> Option<& ::zenoh::key_expr::keyexpr> {
281                    unsafe {
282                        let s =self._0.get(#id).unwrap_unchecked();
283                        (!s.is_empty()).then(|| ::zenoh::key_expr::keyexpr::from_str_unchecked(s))
284                    }
285                }
286            }
287        } else {
288            quote! {
289                #[doc = #doc]
290                pub fn #get_id (&self) -> &::zenoh::key_expr::keyexpr {
291                    unsafe {::zenoh::key_expr::keyexpr::from_str_unchecked(self._0.get(#id).unwrap_unchecked())}
292                }
293            }
294        }
295    });
296    let segments = specs.iter().map(|spec| {
297        let SegmentBuilder {
298            segment_start,
299            prefix_end,
300            spec_start,
301            id_end,
302            pattern_end,
303            spec_end,
304            segment_end,
305        } = spec;
306        quote! {
307            ::zenoh::key_expr::format::macro_support::SegmentBuilder {
308                segment_start: #segment_start,
309                prefix_end: #prefix_end,
310                spec_start: #spec_start,
311                id_end: #id_end,
312                pattern_end: #pattern_end,
313                spec_end: #spec_end,
314                segment_end: #segment_end,
315            },
316        }
317    });
318
319    let format_doc = format!("The `{source}` format, as a zero-sized-type.");
320    let formatter_doc = format!("And instance of a formatter for `{source}`.");
321
322    quote! {
323            use ::zenoh::Result as ZResult;
324            const FORMAT_INNER: ::zenoh::key_expr::format::KeFormat<'static, [::zenoh::key_expr::format::Segment<'static>; #len]> = unsafe {
325                ::zenoh::key_expr::format::macro_support::const_new(#source, [#(#segments)*])
326            };
327            #[doc = #format_doc]
328            #[derive(Copy, Clone, Hash)]
329            pub struct Format;
330
331            #[doc = #formatter_doc]
332            #[derive(Clone)]
333            pub struct Formatter(::zenoh::key_expr::format::KeFormatter<'static, [::zenoh::key_expr::format::Segment<'static>; #len]>);
334            impl ::core::fmt::Debug for Format {
335                fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
336                    ::core::fmt::Debug::fmt(&FORMAT_INNER, f)
337                }
338            }
339            impl ::core::fmt::Debug for Formatter {
340                fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
341                    ::core::fmt::Debug::fmt(&self.0, f)
342                }
343            }
344            impl ::core::fmt::Display for Format {
345                fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
346                    ::core::fmt::Display::fmt(&FORMAT_INNER, f)
347                }
348            }
349            impl ::core::ops::Deref for Format {
350                type Target = ::zenoh::key_expr::format::KeFormat<'static, [::zenoh::key_expr::format::Segment<'static>; #len]>;
351                fn deref(&self) -> &Self::Target {&FORMAT_INNER}
352            }
353            impl ::core::ops::Deref for Formatter {
354                type Target = ::zenoh::key_expr::format::KeFormatter<'static, [::zenoh::key_expr::format::Segment<'static>; #len]>;
355                fn deref(&self) -> &Self::Target {&self.0}
356            }
357            impl ::core::ops::DerefMut for Formatter {
358                fn deref_mut(&mut self) -> &mut Self::Target {&mut self.0}
359            }
360            impl Formatter {
361                #(#setters)*
362            }
363            pub struct Parsed<'s>{_0: ::zenoh::key_expr::format::Parsed<'s, [::zenoh::key_expr::format::Segment<'s>; #len]>}
364            impl<'s> ::core::ops::Deref for Parsed<'s> {
365                type Target = ::zenoh::key_expr::format::Parsed<'s, [::zenoh::key_expr::format::Segment<'s>; #len]>;
366                fn deref(&self) -> &Self::Target {&self._0}
367            }
368            impl Parsed<'_> {
369                #(#getters)*
370            }
371            impl Format {
372                pub fn formatter() -> Formatter {
373                    Formatter(Format.formatter())
374                }
375                pub fn parse<'s>(target: &'s ::zenoh::key_expr::keyexpr) -> ZResult<Parsed<'s>> {
376                    Ok(Parsed{_0: Format.parse(target)?})
377                }
378                pub fn into_inner(self) -> ::zenoh::key_expr::format::KeFormat<'static, [::zenoh::key_expr::format::Segment<'static>; #len]> {
379                    FORMAT_INNER
380                }
381            }
382            pub fn formatter() -> Formatter {
383                Format::formatter()
384            }
385            pub fn parse<'s>(target: &'s ::zenoh::key_expr::keyexpr) -> ZResult<Parsed<'s>> {
386                Format::parse(target)
387            }
388    }
389}
390
391struct FormatDeclaration {
392    vis: syn::Visibility,
393    name: syn::Ident,
394    lit: syn::LitStr,
395}
396impl syn::parse::Parse for FormatDeclaration {
397    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
398        let vis = input.parse()?;
399        let name = input.parse()?;
400        let _: syn::Token!(:) = input.parse()?;
401        let lit = input.parse()?;
402        Ok(FormatDeclaration { vis, name, lit })
403    }
404}
405struct FormatDeclarations(syn::punctuated::Punctuated<FormatDeclaration, syn::Token!(,)>);
406impl syn::parse::Parse for FormatDeclarations {
407    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
408        Ok(Self(input.parse_terminated(
409            FormatDeclaration::parse,
410            syn::Token![,],
411        )?))
412    }
413}
414
415/// Create format modules from a format specification.
416///
417/// `kedefine!($($vis $ident: $lit),*)` will validate each `$lit` to be a valid KeFormat, and declare a module called `$ident` with `$vis` visibility at its call-site for each format.
418///  The modules contain the following elements:
419/// - `Format`, a zero-sized type that represents your format.
420/// - `formatter()`, a function that constructs a `Formatter` specialized for your format:
421///     - for every spec in your format, `Formatter` will have a method named after the spec's `id` that lets you set a value for that field of your format. These methods will return `Result<&mut Formatter, FormatError>`.
422/// - `parse(target: &keyexpr) -> ZResult<Parsed<'_>>` will parse the provided key expression according to your format. Just like `KeFormat::parse`, parsing is lazy: each field will match the smallest subsection of your `target` that is included in its pattern.
423///     - like `Formatter`, `Parsed` will have a method named after each spec's `id` that returns `&keyexpr`; except for specs whose pattern was `**`, these will return an `Option<&keyexpr>`, where `None` signifies that the pattern was matched by an empty list of chunks.
424#[proc_macro]
425pub fn kedefine(tokens: TokenStream) -> TokenStream {
426    let declarations: FormatDeclarations = syn::parse(tokens).unwrap();
427    let content = declarations.0.into_iter().map(|FormatDeclaration { vis, name, lit }|
428    {
429    let source = lit.value();
430    let docstring = format!(
431        r"The module associated with the `{source}` format, it contains:
432- `Format`, a zero-sized type that represents your format.
433- `formatter()`, a function that constructs a `Formatter` specialized for your format:
434    - for every spec in your format, `Formatter` will have a method named after the spec's `id` that lets you set a value for that field of your format. These methods will return `Result<&mut Formatter, FormatError>`.
435- `parse(target: &keyexpr) -> ZResult<Parsed<'_>>` will parse the provided key expression according to your format. Just like `KeFormat::parse`, parsing is lazy: each field will match the smallest subsection of your `target` that is included in its pattern.
436    - like `Formatter`, `Parsed` will have a method named after each spec's `id` that returns `&keyexpr`; except for specs whose pattern was `**`, these will return an `Option<&keyexpr>`, where `None` signifies that the pattern was matched by an empty list of chunks."
437    );
438    let support = keformat_support(&source);
439    quote! {
440        #[doc = #docstring]
441        #vis mod #name{
442            #support
443        }
444    }});
445    quote!(#(#content)*).into()
446}
447
448struct FormatUsage {
449    id: syn::Expr,
450    assigns: Vec<(syn::Expr, syn::Expr)>,
451}
452impl syn::parse::Parse for FormatUsage {
453    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
454        let id = input.parse()?;
455        let mut assigns = Vec::new();
456        if !input.is_empty() {
457            input.parse::<syn::Token!(,)>()?;
458        }
459        assigns.extend(
460            input
461                .parse_terminated(syn::Expr::parse, syn::Token![,])?
462                .into_iter()
463                .map(|a| match a {
464                    syn::Expr::Assign(a) => (*a.left, *a.right),
465                    a => (a.clone(), a),
466                }),
467        );
468        Ok(FormatUsage { id, assigns })
469    }
470}
471
472/// Write a set of values into a `Formatter`, stopping as soon as a value doesn't fit the specification for its field.
473/// Contrary to `keformat` doesn't build the Formatter into a Key Expression.
474///
475/// `kewrite!($formatter, $($ident [= $expr]),*)` will attempt to write `$expr` into their respective `$ident` fields for `$formatter`.
476/// `$formatter` must be an expression that dereferences to `&mut Formatter`.
477/// `$expr` must resolve to a value that implements `core::fmt::Display`.
478/// `$expr` defaults to `$ident` if omitted.
479///
480/// This macro always results in an expression that resolves to `Result<&mut Formatter, FormatSetError>`.
481#[proc_macro]
482pub fn kewrite(tokens: TokenStream) -> TokenStream {
483    let FormatUsage { id, assigns } = syn::parse(tokens).unwrap();
484    let mut sets = None;
485    for (l, r) in assigns.iter().rev() {
486        if let Some(set) = sets {
487            sets = Some(quote!(.#l(#r).and_then(|x| x #set)));
488        } else {
489            sets = Some(quote!(.#l(#r)));
490        }
491    }
492    quote!(#id #sets).into()
493}
494
495/// Write a set of values into a `Formatter` and then builds it into an `OwnedKeyExpr`, stopping as soon as a value doesn't fit the specification for its field.
496///
497/// `keformat!($formatter, $($ident [= $expr]),*)` will attempt to write `$expr` into their respective `$ident` fields for `$formatter`.
498/// `$formatter` must be an expression that dereferences to `&mut Formatter`.
499/// `$expr` must resolve to a value that implements `core::fmt::Display`.
500/// `$expr` defaults to `$ident` if omitted.
501///
502/// This macro always results in an expression that resolves to `ZResult<OwnedKeyExpr>`, and leaves `$formatter` in its written state.
503#[proc_macro]
504pub fn keformat(tokens: TokenStream) -> TokenStream {
505    let formatted: proc_macro2::TokenStream = kewrite(tokens).into();
506    quote!(match #formatted {
507        Ok(ok) => ok.build(),
508        Err(e) => Err(e.into()),
509    })
510    .into()
511}
512
513/// Equivalent to [`keyexpr::new`](zenoh_keyexpr::keyexpr::new), but the check is run at compile-time and will throw a compile error in case of failure.
514#[proc_macro]
515pub fn ke(tokens: TokenStream) -> TokenStream {
516    let value: LitStr = syn::parse(tokens).unwrap();
517    let ke = value.value();
518    match zenoh_keyexpr::keyexpr::new(&ke) {
519        Ok(_) => quote!(unsafe { zenoh::key_expr::keyexpr::from_str_unchecked(#ke)}).into(),
520        Err(e) => panic!("{}", e),
521    }
522}
523
524/// Equivalent to [`nonwild_keyexpr::new`](zenoh_keyexpr::nonwild_keyexpr::new), but the check is run at compile-time and will throw a compile error in case of failure.
525#[proc_macro]
526pub fn nonwild_ke(tokens: TokenStream) -> TokenStream {
527    let value: LitStr = syn::parse(tokens).unwrap();
528    let ke = value.value();
529    match zenoh_keyexpr::nonwild_keyexpr::new(&ke) {
530        Ok(_) => quote!(unsafe { zenoh::key_expr::nonwild_keyexpr::from_str_unchecked(#ke)}).into(),
531        Err(e) => panic!("{}", e),
532    }
533}
534
535mod zenoh_runtime_derive;
536use syn::DeriveInput;
537use zenoh_runtime_derive::{derive_generic_runtime_param, derive_register_param};
538
539/// Make the underlying struct `Param` be generic over any `T` satisfying a generated `trait DefaultParam { fn param() -> Param; }`
540/// ```rust,ignore
541/// #[derive(GenericRuntimeParam)]
542/// struct Param {
543///    ...
544/// }
545/// ```
546#[proc_macro_derive(GenericRuntimeParam)]
547pub fn generic_runtime_param(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
548    let input: DeriveInput = syn::parse_macro_input!(input);
549    derive_generic_runtime_param(input)
550        .unwrap_or_else(syn::Error::into_compile_error)
551        .into()
552}
553
554/// Register the input `Enum` with the struct `Param` specified in the param attribute
555/// ```rust,ignore
556/// #[derive(RegisterParam)]
557/// #[param(Param)]
558/// enum Enum {
559///    ...
560/// }
561/// ```
562#[proc_macro_derive(RegisterParam, attributes(alias, param))]
563pub fn register_param(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
564    let input: DeriveInput = syn::parse_macro_input!(input);
565    derive_register_param(input)
566        .unwrap_or_else(syn::Error::into_compile_error)
567        .into()
568}
569
570/// Macro `#[internal_trait]` should precede
571/// `impl Trait for Struct { ... }`
572///
573/// This macro wraps the implementations of "internal" tratis.
574///
575/// These traits are used to group set of functions which should be implemented
576/// together and with the same prototype. E.g. `QoSBuilderTrait` provides set of
577/// setters (`congestion_control`, `priority`, `express`) and we should not
578/// forget to implement all these setters for each entity which supports
579/// QoS functionality.
580///
581/// The traits mechanism is a good way to group functions. But additional traits
582/// adds extra burden to end user who have to import it every time.
583///
584/// The macro `internal_trait` solves this problem by adding
585/// methods with same names as in trait to structure implementation itself,
586/// making them available to user without additional trait import.
587///
588#[proc_macro_attribute]
589pub fn internal_trait(_attr: TokenStream, item: TokenStream) -> TokenStream {
590    let input = parse_macro_input!(item as ItemImpl);
591    let trait_path = &input.trait_.as_ref().unwrap().1;
592    let struct_path = &input.self_ty;
593    let generics = &input.generics;
594    // let struct_lifetime = get_type_path_lifetime(struct_path);
595
596    let mut struct_methods = quote! {};
597    for item_fn in input.items.iter() {
598        if let syn::ImplItem::Fn(method) = item_fn {
599            let method_name = &method.sig.ident;
600            let method_generic_params = &method.sig.generics.params;
601            let method_generic_params = if method_generic_params.is_empty() {
602                quote! {}
603            } else {
604                quote! {<#method_generic_params>}
605            };
606            let method_args = &method.sig.inputs;
607            let method_output = &method.sig.output;
608            let where_clause = &method.sig.generics.where_clause;
609            let mut method_call_args = quote! {};
610            for arg in method_args.iter() {
611                match arg {
612                    syn::FnArg::Receiver(_) => {
613                        method_call_args.extend(quote! { self, });
614                    }
615                    syn::FnArg::Typed(pat_type) => {
616                        let pat = &pat_type.pat;
617                        method_call_args.extend(quote! { #pat, });
618                    }
619                }
620            }
621            let mut attributes = quote! {};
622            for attr in &method.attrs {
623                attributes.extend(quote! {
624                    #attr
625                });
626            }
627            // call corresponding trait method from struct method
628            struct_methods.extend(quote! {
629                #attributes
630                pub fn #method_name #method_generic_params (#method_args) #method_output #where_clause {
631                    <#struct_path as #trait_path>::#method_name(#method_call_args)
632                }
633            });
634        }
635    }
636    let struct_methods_output = quote! {
637        impl #generics #struct_path {
638            #struct_methods
639        }
640    };
641    (quote! {
642        #input
643        #struct_methods_output
644    })
645    .into()
646}