Skip to content

Commit

Permalink
fix lifetimes
Browse files Browse the repository at this point in the history
  • Loading branch information
bmisiak committed Jul 22, 2024
1 parent dc1e82b commit 296d241
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 48 deletions.
84 changes: 81 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ publish = false
crate-type = ["cdylib"]

[dependencies]
samp = { git = "https://github.com/bmisiak/samp-sdk.git", rev = "41e94ed94ee83667ff1055590d4ec6e3c290371b" }
samp = { git = "https://github.com/bmisiak/samp-sdk.git", rev = "90285d9da04950a1af1f2dfcbb661b5619e8b487" }
slab = "0.4.2"
log = "0.4.6"
fern = { version = "0.6", features = [] }
fnv = "1.0.7"
snafu = "0.8.0"
durr = "2"
ouroboros = "0.18.4"

[profile.release]
lto = true
71 changes: 43 additions & 28 deletions src/amx_arguments.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use samp::{
amx::Amx, args::Args, cell::UnsizedBuffer, consts::AmxExecIdx, error::AmxError,
amx::{Allocator, Amx},
args::Args,
cell::UnsizedBuffer,
consts::AmxExecIdx,
error::AmxError,
prelude::AmxString,
};
use snafu::{ensure, OptionExt, ResultExt};
use std::{convert::TryInto, num::TryFromIntError};
use std::{convert::TryInto, num::TryFromIntError, pin::Pin};

/// These are the types of arguments the plugin supports for passing on to the callback.
#[derive(Debug, Clone)]
Expand All @@ -15,13 +19,16 @@ pub enum PassedArgument {

/// A callback which MUST be executed.
/// Its args are already on the AMX stack.
#[must_use]
pub(crate) struct StackedCallback<'amx> {
pub amx: &'amx Amx,
#[ouroboros::self_referencing]
pub(crate) struct StackedCallback {
pub amx: Amx,
#[borrows(amx)]
#[covariant]
pub allocator: Allocator<'this>,
pub callback_idx: AmxExecIdx,
}

impl<'amx> StackedCallback<'amx> {
/*
impl StackedCallback {
/// ### SAFETY:
/// The `amx.exec()` here might call one of our natives
/// such as `SetPreciseTimer` (`PreciseTimers::create`).
Expand All @@ -30,10 +37,11 @@ impl<'amx> StackedCallback<'amx> {
/// To avoid aliasing, there MUST NOT be any
/// active references to them when this is called.
#[inline]
#[must_use]
pub unsafe fn execute(self) -> Result<i32, AmxError> {
self.amx.exec(self.callback_idx)
}
}
}*/

#[derive(Debug, Clone)]
pub(crate) struct VariadicAmxArguments {
Expand Down Expand Up @@ -116,29 +124,36 @@ impl VariadicAmxArguments {
}

/// Push the arguments onto the AMX stack, in first-in-last-out order, i.e. reversed
pub fn push_onto_amx_stack<'amx>(
pub fn push_onto_amx_stack<'cb, 'amx: 'cb>(
&self,
amx: &'amx Amx,
amx: Amx,
callback_idx: AmxExecIdx,
) -> Result<StackedCallback<'amx>, AmxError> {
let allocator = amx.allocator();
for param in self.inner.iter().rev() {
match param {
PassedArgument::PrimitiveCell(cell_value) => {
amx.push(cell_value)?;
}
PassedArgument::Str(bytes) => {
let buffer = allocator.allot_buffer(bytes.len() + 1)?;
let amx_str = unsafe { AmxString::new(buffer, bytes) };
amx.push(amx_str)?;
}
PassedArgument::Array(array_cells) => {
let amx_buffer = allocator.allot_array(array_cells.as_slice())?;
amx.push(array_cells.len())?;
amx.push(amx_buffer)?;
) -> Result<StackedCallback, AmxError> {

Ok(StackedCallbackBuilder {
amx: amx.clone(),
callback_idx,
allocator_builder: |amx| {
let allocator = amx.allocator();
for param in self.inner.iter().rev() {
match param {
PassedArgument::PrimitiveCell(cell_value) => {
amx.push(cell_value).unwrap();
}
PassedArgument::Str(bytes) => {
let buffer = allocator.allot_buffer(bytes.len() + 1).unwrap();
let amx_str = unsafe { AmxString::new(buffer, bytes) };
amx.push(amx_str).unwrap();
}
PassedArgument::Array(array_cells) => {
let amx_buffer = allocator.allot_array(array_cells.as_slice()).unwrap();
amx.push(array_cells.len()).unwrap();
amx.push(amx_buffer).unwrap();
}
}
}
allocator
}
}
Ok(StackedCallback { amx, callback_idx })
}.build())
}
}
9 changes: 5 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ use samp::amx::Amx;
use samp::cell::AmxString;
use samp::error::{AmxError, AmxResult};
use samp::plugin::SampPlugin;
use scheduling::{reschedule_timer, reschedule_next_due_and_then};
use scheduling::{reschedule_next_due_and_then, reschedule_timer};

use std::convert::TryFrom;
use std::time::{Duration, Instant};
use timer::Timer;
mod amx_arguments;
mod schedule;
Expand Down Expand Up @@ -45,7 +44,7 @@ impl PreciseTimers {

let timer = Timer {
passed_arguments,
amx_identifier: amx.amx().as_ptr().into(),
amx: amx.clone(),
amx_callback_index: amx.find_public(&callback_name.to_string())?,
};
let key = insert_and_schedule_timer(timer, |key| Schedule {
Expand Down Expand Up @@ -125,7 +124,9 @@ impl SampPlugin for PreciseTimers {
match callback {
Ok(stacked_callback) => {
// SAFETY: We are not holding any references to scheduling stores.
if let Err(exec_err) = unsafe { stacked_callback.execute() } {
if let Err(exec_err) = stacked_callback
.with_amx(|amx| amx.exec(*stacked_callback.borrow_callback_idx()))
{
error!("Error while executing timer: {exec_err}");
}
}
Expand Down
9 changes: 4 additions & 5 deletions src/scheduling.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::{cell::RefCell, time::Instant};

use fnv::FnvHashSet;
use samp::error::AmxError;
use slab::Slab;
use snafu::{ensure, OptionExt, Snafu};

use crate::{
amx_arguments::StackedCallback,
schedule::{Repeat, Schedule},
timer::Timer,
};
Expand Down Expand Up @@ -96,7 +98,7 @@ pub(crate) fn remove_timers(predicate: impl Fn(&Timer) -> bool) {
#[inline]
pub(crate) fn reschedule_next_due_and_then<T>(
now: Instant,
timer_manipulator: impl Fn(&Timer) -> T,
timer_manipulator: impl FnOnce(&Timer) -> T,
) -> Option<T> {
STATE.with_borrow_mut(|State { timers, queue }| {
let Some(scheduled @ &Schedule { key, .. }) = queue.last() else {
Expand Down Expand Up @@ -134,22 +136,19 @@ mod test {
use std::ptr::null_mut;

use durr::{now, Durr};
use samp::raw::types::AMX;

use crate::schedule::Repeat::{DontRepeat, Every};
use crate::scheduling::{State, STATE};
use crate::Timer;
use crate::{amx_arguments::VariadicAmxArguments, scheduling::reschedule_next_due_and_then};
use std::time::Instant;

use super::{insert_and_schedule_timer, Schedule};

fn empty_timer() -> Timer {
let amx_pointer: *mut AMX = null_mut();
Timer {
passed_arguments: VariadicAmxArguments::empty(),
amx_callback_index: samp::consts::AmxExecIdx::Continue,
amx_identifier: amx_pointer.into(),
amx: samp::amx::Amx::new(null_mut(), 0),
}
}

Expand Down
12 changes: 5 additions & 7 deletions src/timer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::amx_arguments::{StackedCallback, VariadicAmxArguments};

use samp::{
amx::{self, Amx, AmxIdent},
amx::{self, Amx},
consts::AmxExecIdx,
error::AmxError,
};
Expand All @@ -10,19 +10,17 @@ use samp::{
#[derive(Debug, Clone)]
pub(crate) struct Timer {
pub passed_arguments: VariadicAmxArguments,
pub amx_identifier: AmxIdent,
pub amx: Amx,
pub amx_callback_index: AmxExecIdx,
}

impl Timer {
pub fn was_scheduled_by_amx(&self, amx: &amx::Amx) -> bool {
self.amx_identifier == AmxIdent::from(amx.amx().as_ptr())
self.amx.amx() == amx.amx()
}

pub fn stack_callback_on_amx<'amx>(&self) -> Result<StackedCallback<'amx>, AmxError> {
// amx::get returns an invalid amx lifetime
let amx: &'amx Amx = amx::get(self.amx_identifier).ok_or(AmxError::NotFound)?;
pub fn stack_callback_on_amx(&self) -> Result<StackedCallback, AmxError> {
self.passed_arguments
.push_onto_amx_stack(amx, self.amx_callback_index)
.push_onto_amx_stack(self.amx.clone(), self.amx_callback_index)
}
}

0 comments on commit 296d241

Please sign in to comment.