Skip to main content

confium_macros/
lib.rs

1//! Proc-macros for Confium plugin authors.
2//!
3//! Two macros reduce the per-plugin boilerplate that would otherwise be
4//! hand-rolled `extern "C"` symbols plus the plugin lifecycle hooks:
5//!
6//! - [`macro@plugin_interface`] on an `impl Trait for Type` block emits
7//!   the `cfmp_<iface>_*` FFI entry-point symbols from the trait methods.
8//! - [`macro@export`] emits the plugin lifecycle symbols
9//!   (`cfmp_interface_version`, `cfmp_initialize`, `cfmp_finalize`,
10//!   `cfmp_query_interfaces`) plus the optional `cfmp_metadata` symbol
11//!   when paired with [`macro@plugin_metadata`].
12//!
13//! ## Supported interfaces
14//!
15//! The `#[plugin_interface]` macro recognizes the wire protocol for all
16//! Confium crypto interfaces at version 0: `hash`, `cipher`, `aead`,
17//! `kdf`, `rng`, `signature`, `kem`, and `keyfmt`. Each interface emits
18//! its canonical `cfmp_<iface>_*` symbol set, dispatching through the
19//! corresponding trait in `confium_api::plugin`.
20//!
21//! Interfaces with complex parameter lists (`signature`, `kem`,
22//! `keyfmt`) automatically get `#[allow(clippy::too_many_arguments)]`
23//! on the affected symbols, since the parameter count is fixed by the
24//! C ABI.
25//!
26//! Interface auto-discovery: every `#[plugin_interface]` attribute
27//! registers its `(name, version)` pair at link time via `inventory`.
28//! The `#[export]` macro iterates these registrations at runtime to
29//! populate `cfmp_query_interfaces`, so plugin authors do not need to
30//! repeat the interface list in `#[export]`.
31//!
32//! See `TODO.roadmap/03-plugin-contract.md` for the wire contract and
33//! `crates/confium-api/src/` for the shared types the macros consume.
34
35mod export;
36mod interface;
37mod metadata;
38mod util;
39
40use proc_macro::TokenStream;
41
42/// Attribute macro that emits the `cfmp_<iface>_*` FFI entry-point
43/// symbols for the wire protocol named by `name = "..."`.
44///
45/// Supported interfaces (all at version 0): `hash`, `cipher`, `aead`,
46/// `kdf`, `rng`, `signature`, `kem`, `keyfmt`. Each dispatches through
47/// the corresponding trait in `confium_api::plugin`.
48///
49/// Place this attribute on an `impl Trait for Type` block. Example for
50/// the hash interface:
51///
52/// ```ignore
53/// # use confium_api::plugin_interface;
54/// # use confium_api::HashPlugin;
55/// # struct MyHash;
56/// #[plugin_interface(name = "hash", version = 0)]
57/// impl HashPlugin for MyHash {
58///     // ... methods ...
59/// }
60/// ```
61///
62/// The cipher interface advertises under the wire name `symmetric`
63/// (matching the loader-side `CipherKind`); all other interfaces use
64/// the same name for both the attribute and the wire protocol.
65#[proc_macro_attribute]
66pub fn plugin_interface(attr: TokenStream, item: TokenStream) -> TokenStream {
67    interface::plugin_interface_impl(attr.into(), item.into())
68        .unwrap_or_else(|e| e.to_compile_error())
69        .into()
70}
71
72/// Attribute used together with [`macro@export`] to attach static
73/// registry metadata to the plugin. The strings are leaked at plugin
74/// load time and exposed through the generated `cfmp_metadata` symbol.
75///
76/// Example:
77///
78/// ```ignore
79/// # use confium_macros::{export, plugin_metadata};
80/// #[plugin_metadata(
81///     name = "mock-hash",
82///     version = "0.1.0",
83///     vendor = "confium",
84///     license = "BSD-2-Clause",
85/// )]
86/// #[export]
87/// struct Plugin;
88/// ```
89#[proc_macro_attribute]
90pub fn plugin_metadata(attr: TokenStream, item: TokenStream) -> TokenStream {
91    metadata::plugin_metadata_impl(attr.into(), item.into())
92        .unwrap_or_else(|e| e.to_compile_error())
93        .into()
94}
95
96/// Emits the plugin lifecycle symbols:
97///
98/// - `cfmp_interface_version` → returns `0` (current plugin contract).
99/// - `cfmp_initialize` / `cfmp_finalize` → no-op success.
100/// - `cfmp_query_interfaces` → packed `name\0version\0` byte stream
101///   enumerating the interfaces registered by `#[plugin_interface]` in
102///   this crate.
103/// - `cfmp_metadata` → present only when `#[plugin_metadata]` is used
104///   on the same item.
105///
106/// Place it on any item in the crate root of your plugin's `cdylib`:
107///
108/// ```ignore
109/// # use confium_macros::export;
110/// #[export]
111/// struct Plugin;
112/// ```
113#[proc_macro_attribute]
114pub fn export(attr: TokenStream, item: TokenStream) -> TokenStream {
115    export::export_impl(attr.into(), item.into())
116        .unwrap_or_else(|e| e.to_compile_error())
117        .into()
118}