From 296d241a72da7f38226ad243b5a2e9e0020a0cc5 Mon Sep 17 00:00:00 2001 From: Brian Misiak Date: Mon, 22 Jul 2024 12:28:03 -0700 Subject: [PATCH] fix lifetimes --- Cargo.lock | 84 ++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 3 +- src/amx_arguments.rs | 71 ++++++++++++++++++++++--------------- src/lib.rs | 9 ++--- src/scheduling.rs | 9 +++-- src/timer.rs | 12 +++---- 6 files changed, 140 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 003f8ce..6027fa9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + [[package]] name = "bitflags" version = "1.0.4" @@ -20,6 +26,12 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6150896f7f231d85fb8b13d5ef6974bbfae83cd857a0f5bd5ec5c856da32f5b" +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "fern" version = "0.6.2" @@ -41,6 +53,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "log" version = "0.4.6" @@ -50,6 +71,31 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ouroboros" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "944fa20996a25aded6b4795c6d63f10014a7a83f8be9828a11860b08c5fc4a67" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39b0deead1528fd0e5947a8546a9642a9777c25f6e1e26f34c97b204bbb465bd" +dependencies = [ + "heck", + "itertools", + "proc-macro2 1.0.78", + "proc-macro2-diagnostics", + "quote 1.0.35", + "syn 2.0.50", +] + [[package]] name = "proc-macro2" version = "0.4.30" @@ -68,6 +114,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2 1.0.78", + "quote 1.0.35", + "syn 2.0.50", + "version_check", + "yansi", +] + [[package]] name = "quote" version = "0.6.12" @@ -89,7 +148,7 @@ dependencies = [ [[package]] name = "samp" version = "0.1.3" -source = "git+https://github.com/bmisiak/samp-sdk.git?rev=41e94ed94ee83667ff1055590d4ec6e3c290371b#41e94ed94ee83667ff1055590d4ec6e3c290371b" +source = "git+https://github.com/bmisiak/samp-sdk.git?rev=90285d9da04950a1af1f2dfcbb661b5619e8b487#90285d9da04950a1af1f2dfcbb661b5619e8b487" dependencies = [ "fern", "samp-codegen", @@ -99,7 +158,7 @@ dependencies = [ [[package]] name = "samp-codegen" version = "0.1.2" -source = "git+https://github.com/bmisiak/samp-sdk.git?rev=41e94ed94ee83667ff1055590d4ec6e3c290371b#41e94ed94ee83667ff1055590d4ec6e3c290371b" +source = "git+https://github.com/bmisiak/samp-sdk.git?rev=90285d9da04950a1af1f2dfcbb661b5619e8b487#90285d9da04950a1af1f2dfcbb661b5619e8b487" dependencies = [ "proc-macro2 0.4.30", "quote 0.6.12", @@ -114,6 +173,7 @@ dependencies = [ "fern", "fnv", "log", + "ouroboros", "samp", "slab", "snafu", @@ -122,7 +182,7 @@ dependencies = [ [[package]] name = "samp-sdk" version = "0.9.2" -source = "git+https://github.com/bmisiak/samp-sdk.git?rev=41e94ed94ee83667ff1055590d4ec6e3c290371b#41e94ed94ee83667ff1055590d4ec6e3c290371b" +source = "git+https://github.com/bmisiak/samp-sdk.git?rev=90285d9da04950a1af1f2dfcbb661b5619e8b487#90285d9da04950a1af1f2dfcbb661b5619e8b487" dependencies = [ "bitflags", ] @@ -154,6 +214,12 @@ dependencies = [ "syn 2.0.50", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" version = "0.15.34" @@ -187,3 +253,15 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/Cargo.toml b/Cargo.toml index 3ee6d7e..da2d2c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 diff --git a/src/amx_arguments.rs b/src/amx_arguments.rs index 726dccc..d7c7986 100644 --- a/src/amx_arguments.rs +++ b/src/amx_arguments.rs @@ -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)] @@ -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`). @@ -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 { self.amx.exec(self.callback_idx) } -} +}*/ #[derive(Debug, Clone)] pub(crate) struct VariadicAmxArguments { @@ -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, 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 { + + 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()) } } diff --git a/src/lib.rs b/src/lib.rs index 269f327..9865ff5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; @@ -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 { @@ -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}"); } } diff --git a/src/scheduling.rs b/src/scheduling.rs index c6195b8..6753adb 100644 --- a/src/scheduling.rs +++ b/src/scheduling.rs @@ -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, }; @@ -96,7 +98,7 @@ pub(crate) fn remove_timers(predicate: impl Fn(&Timer) -> bool) { #[inline] pub(crate) fn reschedule_next_due_and_then( now: Instant, - timer_manipulator: impl Fn(&Timer) -> T, + timer_manipulator: impl FnOnce(&Timer) -> T, ) -> Option { STATE.with_borrow_mut(|State { timers, queue }| { let Some(scheduled @ &Schedule { key, .. }) = queue.last() else { @@ -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), } } diff --git a/src/timer.rs b/src/timer.rs index a0eab86..08a8cc5 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,7 +1,7 @@ use crate::amx_arguments::{StackedCallback, VariadicAmxArguments}; use samp::{ - amx::{self, Amx, AmxIdent}, + amx::{self, Amx}, consts::AmxExecIdx, error::AmxError, }; @@ -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, 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 { self.passed_arguments - .push_onto_amx_stack(amx, self.amx_callback_index) + .push_onto_amx_stack(self.amx.clone(), self.amx_callback_index) } }