Skip to main content

samp_sdk/
exports.rs

1//! Typed access to the `amx_*` functions exported by the server.
2//!
3//! The server exposes `amx_Exports` (passed in `Load()`) as a flat table of
4//! pointers, indexed by the values of [`Exports`]. Each function has a
5//! zero-sized marker type (generated by `impl_export!`) that carries the
6//! corresponding offset in [`Export::OFFSET`] and the function type in [`Export::Output`].
7//!
8//! Typical usage: `Exec::from_table(fn_table)` returns the typed pointer.
9//! Resolving on demand avoids storing all 44 pointers in [`crate::amx::Amx`].
10
11use crate::raw::functions;
12
13macro_rules! impl_export {
14    ($name:ident) => {
15        pub struct $name;
16
17        impl Export for $name {
18            type Output = functions::$name;
19            const OFFSET: isize = Exports::$name as isize;
20
21            #[inline(always)]
22            fn from_table(fn_table: usize) -> Self::Output {
23                assert!(fn_table != 0, "from_table() received null fn_table");
24                let table = fn_table as *const usize;
25
26                unsafe {
27                    let ptr = table.offset(Self::OFFSET);
28                    assert!(
29                        ptr.read() != 0,
30                        "from_table() function at offset {} is null",
31                        Self::OFFSET
32                    );
33                    ptr.cast::<Self::Output>().read()
34                }
35            }
36        }
37    };
38}
39
40/// Retrieves a typed pointer from the `amx_Exports` table.
41pub trait Export {
42    /// Type of the exported function — alias declared in [`crate::raw::functions`].
43    type Output;
44
45    /// Offset of this function in the table. Values correspond 1:1 to [`Exports`].
46    const OFFSET: isize;
47
48    /// Reads the pointer at offset `OFFSET` of the `fn_table` table.
49    ///
50    /// # Panics
51    /// In debug mode, panics if `fn_table` is null or if the read pointer is
52    /// null (indicates a non-conforming server or a corrupted table).
53    fn from_table(fn_table: usize) -> Self::Output;
54}
55
56impl_export!(Align16);
57impl_export!(Align32);
58impl_export!(Allot);
59impl_export!(Callback);
60impl_export!(Cleanup);
61impl_export!(Clone);
62impl_export!(Exec);
63impl_export!(FindNative);
64impl_export!(FindPublic);
65impl_export!(FindPubVar);
66impl_export!(FindTagId);
67impl_export!(Flags);
68impl_export!(GetAddr);
69impl_export!(GetNative);
70impl_export!(GetPublic);
71impl_export!(GetPubVar);
72impl_export!(GetString);
73impl_export!(GetTag);
74impl_export!(GetUserData);
75impl_export!(Init);
76impl_export!(InitJIT);
77impl_export!(MemInfo);
78impl_export!(NameLength);
79impl_export!(NativeInfo);
80impl_export!(NumNatives);
81impl_export!(NumPublics);
82impl_export!(NumPubVars);
83impl_export!(NumTags);
84impl_export!(Push);
85impl_export!(PushArray);
86impl_export!(PushString);
87impl_export!(RaiseError);
88impl_export!(Register);
89impl_export!(Release);
90impl_export!(SetCallback);
91impl_export!(SetDebugHook);
92impl_export!(SetString);
93impl_export!(SetUserData);
94impl_export!(StrLen);
95impl_export!(UTF8Check);
96impl_export!(UTF8Get);
97impl_export!(UTF8Len);
98impl_export!(UTF8Put);
99
100// Open Multiplayer only — see the note on [`Exports`].
101impl_export!(PushStringLen);
102impl_export!(SetStringLen);
103impl_export!(Swap16);
104impl_export!(Swap32);
105impl_export!(Swap64);
106impl_export!(GetNativeByIndex);
107impl_export!(MakeAddr);
108impl_export!(StrSize);
109
110/// Indices of the `amx_*` functions in the server's `amx_Exports` table.
111///
112/// The order is fixed by the SA-MP ABI — do not reorder.
113///
114/// Entries `[0..=43]` exist on both servers. Entries `[44..=51]` exist **only**
115/// in the 52-slot table open.mp's Pawn component returns from
116/// `getAmxFunctions()`; the SA-MP table ends at `[43]`, so resolving one of
117/// them against a SA-MP table reads past its end. The `samp` crate exposes
118/// them through `AmxOmpExt`, which checks the running mode first.
119#[derive(Debug, Clone, Copy, PartialEq)]
120pub enum Exports {
121    Align16 = 0,
122    Align32 = 1,
123    Align64 = 2,
124    Allot = 3,
125    Callback = 4,
126    Cleanup = 5,
127    Clone = 6,
128    Exec = 7,
129    FindNative = 8,
130    FindPublic = 9,
131    FindPubVar = 10,
132    FindTagId = 11,
133    Flags = 12,
134    GetAddr = 13,
135    GetNative = 14,
136    GetPublic = 15,
137    GetPubVar = 16,
138    GetString = 17,
139    GetTag = 18,
140    GetUserData = 19,
141    Init = 20,
142    InitJIT = 21,
143    MemInfo = 22,
144    NameLength = 23,
145    NativeInfo = 24,
146    NumNatives = 25,
147    NumPublics = 26,
148    NumPubVars = 27,
149    NumTags = 28,
150    Push = 29,
151    PushArray = 30,
152    PushString = 31,
153    RaiseError = 32,
154    Register = 33,
155    Release = 34,
156    SetCallback = 35,
157    SetDebugHook = 36,
158    SetString = 37,
159    SetUserData = 38,
160    StrLen = 39,
161    UTF8Check = 40,
162    UTF8Get = 41,
163    UTF8Len = 42,
164    UTF8Put = 43,
165    // --- Open Multiplayer only ---
166    PushStringLen = 44,
167    SetStringLen = 45,
168    Swap16 = 46,
169    Swap32 = 47,
170    Swap64 = 48,
171    GetNativeByIndex = 49,
172    MakeAddr = 50,
173    StrSize = 51,
174}
175
176impl From<Exports> for isize {
177    fn from(exports: Exports) -> isize {
178        exports as isize
179    }
180}