Calling Pawn from Rust — exec_public!¶
Pawn public functions can be called from the plugin. The
exec_public! macro (defined in samp-sdk/src/macros.rs, re-exported
as samp::exec_public) handles the boilerplate: it pushes arguments
in the correct order, allocates AMX
heap memory for owned Rust values, executes the function, and frees
everything when the call returns.
No arguments¶
The macro expands to the equivalent of
amx.find_public("OnMyCallback").and_then(|idx| amx.exec(idx)) and
returns AmxResult<i32> — the Pawn return value (or the propagated
AmxError).
With AmxCell arguments¶
Anything that implements AmxCell is pushed directly. The macro
pushes arguments in reverse order automatically — write them in the
same order as the Pawn signature:
Pawn side:
The same form works for Ref<T>, Buffer, UnsizedBuffer, and any
custom type implementing AmxCell.
With Rust strings — expr => string¶
A Rust &str (or anything that derefs to &str) is copied into the
AMX heap before the call. Use the => string modifier:
The temporary heap allocation is tied to an Allocator created
internally and is reclaimed when the call returns.
With Rust slices — expr => array¶
&[T] where T: AmxCell + AmxPrimitive is copied into a contiguous
AMX buffer:
Mixing argument forms¶
The three forms (expr, expr => string, expr => array) can appear
in any combination:
let public_name = pub_name.to_string();
let owned_msg = String::from("another hello");
let table = vec![10_i32, 20, 30];
exec_public!(
amx,
&public_name,
string, // an existing AmxString argument
"literal" => string, // Rust &str → AMX string
&owned_msg => string, // Rust &String → AMX string
&table => array, // Rust slice → AMX array
reference, // Ref<T> argument
);
The order is the same Pawn sees on the stack — first positional argument first.
Manual equivalent¶
For full control, drop the macro:
let allocator = amx.allocator();
let idx = amx.find_public("OnMessage")?;
let msg = allocator.allot_string("Hello, Pawn!")?;
amx.push(msg)?; // pushed first → last argument in Pawn
amx.push(123_i32)?; // pushed second → first argument in Pawn
let result = amx.exec(idx)?;
allocator releases every AMX heap allocation when it goes out of
scope — there is no need to free memory explicitly.
Return value¶
exec_public! returns AmxResult<i32>:
Ok(value)— the Pawnreturnvalue (cell-encoded; cast withf32::from_bitsif the Pawn function returnsFloat:).Err(AmxError::NotFound)—find_publicdid not locate the function.- Other
AmxErrorvariants are forwarded fromamx_Execdirectly (stack overflow, divide by zero, native failure, …).
See Error handling for the full list.
Calling another plugin's native — call_native¶
exec_public! runs a public function of the script. To invoke a
native registered by another plugin (Streamer, MySQL, sscanf, …) in
the same AMX, use Amx::call_native:
// CreateDynamicObject(modelid, Float:x, Float:y, Float:z, ...)
let params = [
19_300, // modelid
0.0_f32.to_bits() as i32, // x (Float: cells are the f32 bits)
0.0_f32.to_bits() as i32, // y
3.5_f32.to_bits() as i32, // z
];
let object_id = amx.call_native("CreateDynamicObject", ¶ms)?;
call_native resolves the host function pointer through amx_FindNative
plus the natives table in the AMX_HEADER, builds the params block in
the AMX convention ([argc * sizeof(cell), arg0, arg1, …]), and surfaces
VM-side errors set by the native back through amx.error.
Arguments are raw cells (i32): pass integers directly and Float:
values as their IEEE-754 bits (x.to_bits() as i32). It returns
AmxResult<i32> — AmxError::NotFound when the native is not registered,
AmxError::Index when the resolved index is out of range, and any VM
error forwarded from the native call.
Note
Reference/array arguments must be allocated in the AMX heap first
(see the manual equivalent above) and passed by
their cell address; call_native does not marshal Rust slices for
you the way exec_public! does.