Skip to main content

nautilus_plugin/
macros.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
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// -------------------------------------------------------------------------------------------------
15
16//! Declarative macros for plug-in metadata export.
17
18/// Defines a plug-in's static metadata manifest and emits the
19/// `nautilus_plugin_init` entry symbol.
20///
21/// Use this exactly once per plug-in cdylib, at module scope.
22///
23/// # Required fields
24///
25/// - `name`: short machine-readable plug-in name.
26/// - `version`: plug-in version string (usually `env!("CARGO_PKG_VERSION")`).
27///
28/// # Optional fields
29///
30/// - `vendor`: free-form vendor/author string (default `""`).
31#[macro_export]
32macro_rules! nautilus_plugin {
33    (
34        $(name: $name:expr,)?
35        $(vendor: $vendor:expr,)?
36        $(version: $version:expr,)?
37    ) => {
38        $crate::__nautilus_plugin_impl! {
39            @parse
40            name = ($($name)?),
41            vendor = ($($vendor)?),
42            version = ($($version)?),
43        }
44    };
45}
46
47/// Internal expansion of [`nautilus_plugin!`]. Not part of the public API.
48#[doc(hidden)]
49#[macro_export]
50macro_rules! __nautilus_plugin_impl {
51    (
52        @parse
53        name = (),
54        $($rest:tt)*
55    ) => {
56        ::core::compile_error!("`nautilus_plugin!` requires a `name` field");
57    };
58    (
59        @parse
60        name = ($name:expr),
61        vendor = ($($vendor:expr)?),
62        version = (),
63    ) => {
64        ::core::compile_error!("`nautilus_plugin!` requires a `version` field");
65    };
66    (
67        @parse
68        name = ($name:expr),
69        vendor = ($($vendor:expr)?),
70        version = ($version:expr),
71    ) => {
72        const _: () = {
73            static MANIFEST: ::std::sync::LazyLock<$crate::manifest::PluginManifest> =
74                ::std::sync::LazyLock::new(|| $crate::manifest::PluginManifest {
75                    abi_version: $crate::NAUTILUS_PLUGIN_ABI_VERSION,
76                    plugin_name: $crate::boundary::BorrowedStr::from_str($name),
77                    plugin_vendor: $crate::boundary::BorrowedStr::from_str(
78                        $crate::__nautilus_plugin_impl!(@opt $($vendor)?),
79                    ),
80                    plugin_version: $crate::boundary::BorrowedStr::from_str($version),
81                    build_id: $crate::manifest::PluginBuildId::current(),
82                });
83
84            #[unsafe(no_mangle)]
85            pub unsafe extern "C" fn nautilus_plugin_init(
86                host: *const $crate::host::HostVTable,
87            ) -> *const $crate::manifest::PluginManifest {
88                let result = ::std::panic::catch_unwind(|| {
89                    if host.is_null() {
90                        return ::core::ptr::null::<$crate::manifest::PluginManifest>();
91                    }
92                    &*MANIFEST as *const _
93                });
94
95                match result {
96                    Ok(ptr) => ptr,
97                    Err(payload) => {
98                        $crate::panic::drop_payload(payload);
99                        ::core::ptr::null()
100                    }
101                }
102            }
103        };
104    };
105
106    (@opt) => { "" };
107    (@opt $vendor:expr) => { $vendor };
108}