samp_codegen/lib.rs
1//! Proc macros for the `rust-samp` toolkit.
2//!
3//! - `#[native]` — generates the `extern "C"` FFI wrapper for a Rust function,
4//! parsing arguments via [`AmxCell`] and handling the return value.
5//! - `initialize_plugin!` — generates the entry points required by the server
6//! (`Supports`/`Load`/`Unload`/`AmxLoad`/`AmxUnload`/`ProcessTick` on SA-MP
7//! and `ComponentEntryPoint` + vtable on Open Multiplayer), as well as native registration.
8//! - `#[derive(SampPlugin)]` — shortcut for an empty `impl SampPlugin for T {}`.
9//!
10//! This crate only compiles when loaded by `samp` via reexport — it has no
11//! runtime API of its own.
12//!
13//! [`AmxCell`]: samp::cell::AmxCell
14
15#![recursion_limit = "128"]
16
17use proc_macro::TokenStream;
18
19mod event;
20mod native;
21mod plugin;
22
23/// Prefix applied to the name of the `extern "C"` wrapper function generated by `#[native]`.
24/// Avoids collision with any function name declared by the developer.
25pub(crate) const NATIVE_PREFIX: &str = "__samp_native_";
26
27/// Prefix applied to the name of the native registration block in `initialize_plugin!`.
28pub(crate) const REG_PREFIX: &str = "__samp_reg_";
29
30/// Prefix applied to the handler wrapper generated by `#[event]`.
31pub(crate) const EVENT_PREFIX: &str = "__samp_event_";
32
33/// Prefix applied to the event registration block consumed by `initialize_plugin!`.
34pub(crate) const EVENT_REG_PREFIX: &str = "__samp_event_reg_";
35
36/// Generates the `extern "C"` wrapper that reads the AMX argument table, parses
37/// it into the Rust types declared in the signature and invokes the marked method.
38#[proc_macro_attribute]
39pub fn native(args: TokenStream, input: TokenStream) -> TokenStream {
40 native::create_native(args, input)
41}
42
43/// Generates the handler wrapper that observes a Pawn callback
44/// (`OnPlayerConnect`, `OnPlayerSpawn`, …). Parses the callback arguments into
45/// the Rust types declared in the signature and invokes the marked method when
46/// the callback runs in the gamemode's AMX. Register the handlers via
47/// `initialize_plugin!(events: [...])`.
48#[proc_macro_attribute]
49pub fn event(args: TokenStream, input: TokenStream) -> TokenStream {
50 event::create_event(args, input)
51}
52
53/// Generates the entry points required by the server (SA-MP + Open Multiplayer), the Rust
54/// `IComponent` vtable and the registration of the plugin's native list.
55#[proc_macro]
56pub fn initialize_plugin(input: TokenStream) -> TokenStream {
57 plugin::create_plugin(input)
58}
59
60/// Generates `impl SampPlugin for T {}` with all methods using the default behavior
61/// (empty). Use for structs that do not need to customize any lifecycle callback —
62/// write the `impl SampPlugin` manually when some method needs custom logic.
63///
64/// ```rust,ignore
65/// use samp::prelude::*;
66///
67/// #[derive(SampPlugin)]
68/// struct SimplePlugin { counter: u32 }
69///
70/// // With logic in on_load → do not use the derive
71/// struct AdvancedPlugin;
72/// impl SampPlugin for AdvancedPlugin {
73/// fn on_load(&mut self) { println!("plugin loaded"); }
74/// }
75/// ```
76#[proc_macro_derive(SampPlugin)]
77pub fn derive_samp_plugin(input: TokenStream) -> TokenStream {
78 plugin::derive_samp_plugin(input)
79}