rust-samp follows Rust's Result convention for error reporting, with
a single error type for every AMX VM failure.
pub type AmxResult<T> = Result<T, AmxError>;Most SDK methods return AmxResult<T>. A native can return either
AmxResult<T> (or any Result<T, E: Display>) — in which case the
generated wrapper logs the Err and returns 0 — or a bare T that
implements AmxCell.
#[native(name = "Divide")]
fn divide(&mut self, _amx: &Amx, a: i32, b: i32) -> AmxResult<i32> {
if b == 0 {
return Err(AmxError::Divide); // division by zero
}
Ok(a / b)
}AmxError mirrors the codes defined by the AMX C header. Built via
AmxError::from(code) from any i32; unknown values become
AmxError::Unknown instead of panicking.
| Variant | Code | Display |
|---|---|---|
Exit |
1 | Forced exit |
Assert |
2 | Assertion failed |
StackError |
3 | Stack / heap collision |
Bounds |
4 | Index out of bounds |
MemoryAccess |
5 | Invalid memory access |
InvalidInstruction |
6 | Invalid instruction |
StackLow |
7 | Stack underflow |
HeapLow |
8 | Heap underflow |
Callback |
9 | No callback or invalid callback |
Native |
10 | Native function failed |
Divide |
11 | Divide by zero |
Sleep |
12 | Go into sleepmode |
InvalidState |
13 | No implementation for this state, no fall-back |
Memory |
16 | Out of memory |
Format |
17 | Invalid file format |
Version |
18 | File is for a newer version of AMX |
NotFound |
19 | Function not found |
Index |
20 | Invalid index parameter (bad entry point) |
Debug |
21 | Debugger cannot run |
Init |
22 | AMX not initialize |
UserData |
23 | Unable to set user data field |
InitJit |
24 | Cannot initialize the JIT |
Params |
25 | Parameter error |
Domain |
26 | Domain error, expression result does not fit in range |
General |
27 | General error (unknown or unspecific error) |
Overlay |
28 | Overlays are unsupported (JIT) or uninitialized |
Unknown |
— | Unknown error |
AmxError implements std::error::Error, so it composes with ?,
anyhow, eyre, and friends.
#[native(name = "CallCallback")]
fn call_callback(&mut self, amx: &Amx) -> AmxResult<bool> {
let index = amx.find_public("OnMyCallback")?;
let result = amx.exec(index)?;
Ok(result > 0)
}let err = AmxError::from(19); // AmxError::NotFound
let code = AmxError::NotFound as i32; // 19Every variant has a stable, English message that maps 1:1 to the original C header strings:
let err = AmxError::NotFound;
println!("{err}"); // "Function not found"Sometimes it is more convenient to return a status code from the native than to log an error:
#[native(name = "TryConnect")]
fn try_connect(&mut self, _amx: &Amx, address: &AmxString) -> i32 {
match self.connect(&**address) {
Ok(_) => 1,
Err(_) => -1,
}
}When several outcomes share the same native, a small enum + AmxCell
keeps the call sites readable:
#[derive(Clone, Copy)]
enum Status {
Ok,
NotFound,
Error,
}
impl AmxCell<'_> for Status {
fn as_cell(&self) -> i32 {
match self {
Status::Ok => 1,
Status::NotFound => 0,
Status::Error => -1,
}
}
}
#[native(name = "DoSomething")]
fn do_something(&mut self, _amx: &Amx) -> Status {
Status::Ok
}