Skip to main content

fidius_macro/
lib.rs

1// Copyright 2026 Colliery, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15mod impl_macro;
16mod interface;
17mod ir;
18
19use proc_macro::TokenStream;
20use syn::{parse_macro_input, ItemImpl, ItemTrait};
21
22use impl_macro::PluginImplAttrs;
23use ir::InterfaceAttrs;
24
25/// Define a plugin interface from a trait.
26///
27/// Generates a `#[repr(C)]` vtable struct, interface hash constant,
28/// capability bit constants, and a descriptor builder function.
29///
30/// # Example
31///
32/// ```ignore
33/// #[plugin_interface(version = 1, buffer = PluginAllocated)]
34/// pub trait Greeter: Send + Sync {
35///     fn greet(&self, name: String) -> String;
36///
37///     #[optional(since = 2)]
38///     fn greet_fancy(&self, name: String) -> String;
39/// }
40/// ```
41#[proc_macro_attribute]
42pub fn plugin_interface(attr: TokenStream, item: TokenStream) -> TokenStream {
43    let attrs = parse_macro_input!(attr as InterfaceAttrs);
44    let item_trait = parse_macro_input!(item as ItemTrait);
45
46    match ir::parse_interface(attrs, &item_trait) {
47        Ok(ir) => match interface::generate_interface(&ir) {
48            Ok(tokens) => tokens.into(),
49            Err(err) => err.to_compile_error().into(),
50        },
51        Err(err) => err.to_compile_error().into(),
52    }
53}
54
55/// Implement a plugin interface for a concrete type.
56///
57/// Generates extern "C" FFI shims, a static vtable, a plugin descriptor,
58/// and a plugin registry.
59///
60/// # Example
61///
62/// ```ignore
63/// pub struct MyGreeter;
64///
65/// #[plugin_impl(Greeter)]
66/// impl Greeter for MyGreeter {
67///     fn greet(&self, name: String) -> String {
68///         format!("Hello, {name}!")
69///     }
70/// }
71/// ```
72#[proc_macro_attribute]
73pub fn plugin_impl(attr: TokenStream, item: TokenStream) -> TokenStream {
74    let attrs = parse_macro_input!(attr as PluginImplAttrs);
75    let item_impl = parse_macro_input!(item as ItemImpl);
76
77    match impl_macro::generate_plugin_impl(&attrs, &item_impl) {
78        Ok(tokens) => tokens.into(),
79        Err(err) => err.to_compile_error().into(),
80    }
81}