mysql_handler_macros/lib.rs
1// Copyright (C) 2026 ren-yamanashi
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU General Public License, version 2.0,
5// as published by the Free Software Foundation.
6//
7// This program is designed to work with certain software (including
8// but not limited to OpenSSL) that is licensed under separate terms,
9// as designated in a particular file or component or in included license
10// documentation. The authors of this program hereby grant you an additional
11// permission to link the program and your derivative works with the
12// separately licensed software that they have either included with
13// the program or referenced in the documentation.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program; if not, see <https://www.gnu.org/licenses/>.
22
23//! Procedural macros for `mysql-handler` engine cdylibs.
24//!
25//! The single macro this crate exposes, [`plugin`], generates the
26//! three `#[unsafe(no_mangle)] pub static` items mysqld dlsyms at
27//! `INSTALL PLUGIN` time, plus the panic-safe init wrapper that
28//! registers the engine factory.
29
30// `pub(crate)` on internal items is required for `unreachable_pub`;
31// the resulting `redundant_pub_crate` lint is a false positive here.
32#![allow(clippy::redundant_pub_crate)]
33
34mod args;
35mod expand;
36
37use proc_macro::TokenStream;
38use syn::{ItemStruct, parse_macro_input};
39
40use crate::args::PluginArgs;
41
42/// Attribute macro that turns a `Default`-constructible engine struct
43/// into a loadable MySQL plugin.
44///
45/// # Arguments
46///
47/// - `name`: plugin name (string literal, ASCII, ≤ 64 bytes, no NUL).
48/// SQL identifies the engine by this name in `INSTALL PLUGIN <name>`.
49/// - `description`: human-readable description (string literal).
50/// - `version`: plugin version, any const expression evaluating to
51/// `c_uint` (commonly `env!("CARGO_PKG_VERSION")` parsed elsewhere
52/// or a literal like `0x0001`).
53/// - `license`: any const expression of type
54/// `mysql_handler::license::License`. The discriminant is folded
55/// into the static initialiser at compile time.
56/// - `author`: author or organisation name (string literal).
57/// - `handlerton` (optional): path to a `Default`-constructible
58/// handlerton struct (typically a unit struct) implementing
59/// `mysql_handler::hton::Handlerton`. When supplied the generated
60/// `rust__plugin_init` additionally registers the handlerton so
61/// engine-level callbacks (transactions, savepoints, discovery)
62/// route through it. Omit when the engine only needs the per-handler
63/// surface.
64///
65/// # Example
66///
67/// ```ignore
68/// use mysql_handler::prelude::*;
69///
70/// #[plugin(
71/// name = "my_engine",
72/// description = "Custom storage engine",
73/// version = 0x0001,
74/// license = License::Gpl,
75/// author = "me",
76/// )]
77/// #[derive(Default)]
78/// pub struct MyEngine;
79///
80/// impl mysql_handler::engine::StorageEngine for MyEngine {}
81/// ```
82#[proc_macro_attribute]
83pub fn plugin(args: TokenStream, item: TokenStream) -> TokenStream {
84 let args = parse_macro_input!(args as PluginArgs);
85 let target = parse_macro_input!(item as ItemStruct);
86 expand::plugin(&args, &target)
87 .unwrap_or_else(syn::Error::into_compile_error)
88 .into()
89}