1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
//! Workaround to parse input of natives functions.
use crate::amx::Amx;
use crate::cell::AmxCell;

/// A wrapper of a list of arguments of a native function.
pub struct Args<'a> {
    amx: &'a Amx,
    args: *const i32,
    offset: usize,
}

impl<'a> Args<'a> {
    /// Creates a list from [`Amx`] and arguments.
    ///
    /// # Example
    /// ```
    /// use samp_sdk::args::Args;
    /// use samp_sdk::amx::Amx;
    /// use samp_sdk::cell::AmxString;
    /// # use samp_sdk::raw::types::AMX;
    ///
    /// // native: RawNative(const say_that[]);
    /// extern "C" fn raw_native(amx: *mut AMX, args: *mut i32) -> i32 {
    ///     # let amx_exports = 0;
    ///     // let amx_exports = ...;
    ///     let amx = Amx::new(amx, amx_exports);
    ///     let mut args = Args::new(&amx, args);
    ///
    ///     let say_what = match args.next::<AmxString>() {
    ///         Some(string) => string.to_string(),
    ///         None => {
    ///             println!("RawNative error: no argument");
    ///             return 0;
    ///         }
    ///     };
    ///
    ///     println!("RawNative: {}", say_what);
    ///
    ///     return 1;
    /// }
    /// ```
    ///
    /// [`Amx`]: ../amx/struct.Amx.html
    pub fn new(amx: &'a Amx, args: *const i32) -> Args<'a> {
        Args {
            amx,
            args,
            offset: 0,
        }
    }

    /// Return the next argument in the list (like an iterator).
    ///
    /// When there is no arguments left returns `None`.
    pub fn next<T: AmxCell<'a> + 'a>(&mut self) -> Option<T> {
        let result = self.get(self.offset);
        self.offset += 1;

        result
    }

    /// Get an argument by position, if there is no argument in given location, returns `None`.
    ///
    /// # Example
    /// ```
    /// use samp_sdk::args::Args;
    /// use samp_sdk::amx::Amx;
    /// use samp_sdk::cell::Ref;
    /// # use samp_sdk::raw::types::AMX;
    ///
    /// // native: NativeFn(player_id, &Float:health, &Float:armor);
    /// extern "C" fn raw_native(amx: *mut AMX, args: *mut i32) -> i32 {
    ///     # let amx_exports = 0;
    ///     // let amx_exports = ...;
    ///     let amx = Amx::new(amx, amx_exports);
    ///     let args = Args::new(&amx, args);
    ///
    ///     // change only armor
    ///     args.get::<Ref<f32>>(2)
    ///         .map(|mut armor| *armor = 255.0);
    ///
    ///     return 1;
    /// }
    /// ```
    pub fn get<T: AmxCell<'a> + 'a>(&self, offset: usize) -> Option<T> {
        if offset > self.count() {
            return None;
        }

        unsafe { T::from_raw(self.amx, self.args.add(offset + 1).read()).ok() }
    }

    /// Reset a read offset for [`next()`] method.
    ///
    /// [`next()`]: #method.next
    pub fn reset(&mut self) {
        self.offset = 0;
    }

    /// Get count of arguments in the list.
    pub fn count(&self) -> usize {
        unsafe { (self.args.read() / 4) as usize }
    }
}