Access self in a event handler closure function

Hello. I am trying to develop a Matrix bot, and it uses event handler pattern to determine what must be done for a certain event. The library provides Client, which does basic actions like sending message to a room, and I am making a wrapper class that does more specialised actions (such as detecting if a message is a bot command). I am trying to pass self to this closure function so it can access functions I've made for the wrapper class, but I have no idea how to pass this whilst satisfying the lifetime check.

pub struct MatrixBot{
	client: Client,
	path: PathBuf,
	config: Arc<Mutex<BotConfig>> //BotConfig is just a simple struct that contains config, as the name suggests
}

impl MatrixBot{
	pub async fn new(path: PathBuf) -> MatrixBot { //Constructor
		let client = loader::restore_login(&path).await;
		let config = Arc::new(Mutex::new(loader::restore_config(&path)));
		return MatrixBot{
			client,
			path,
			config
		};
	}

	pub async fn initialise(&self) -> () { //Actually starts the bot
		let response = self.client.sync_once(SyncSettings::default()).await.expect("Syncing failed.");
		self.client.add_event_handler(|event: OriginalSyncRoomMessageEvent, room: Room| async {
			let debug = self.config.lock().expect("Cannot obtain lock due to poisioning.").debug; //Error occurs here
			self.send_debug("Received message.");

		});
    	let settings = SyncSettings::default().token(response.next_batch);
    	self.client.sync(settings).await.expect("Syncing failed.");
	}

	pub async fn send_debug(&self, message: &str) {...}
}

This is the following message:

error[E0521]: borrowed data escapes outside of associated function
  --> src/matrix_bot/matrix_bot.rs:91:3
   |
89 |       pub async fn initialise(&self) -> () {
   |                               -----
   |                               |
   |                               `self` is a reference that is only valid in the associated function body
   |                               let's call the lifetime of this reference `'1`
90 |           let response = self.client.sync_once(SyncSettings::default()).await.expect("Syncing failed.");
91 | /         self.client.add_event_handler(|event: OriginalSyncRoomMessageEvent, room: Room| async {
92 | |             let debug = self.config.lock().expect("Cannot obtain lock due to poisioning.").debug;
93 | |             
94 | |         });
   | |          ^
   | |          |
   | |__________`self` escapes the associated function body here
   |            argument requires that `'1` must outlive `'static`

I assumed that if designed like this, self.client and anything associated with it would never outlive self itself, but it seems that is not the case. How would I be able to access self in this particular situation?

You seem to be only wanting to access self.config in the async { … } block passed to add_event_handler which presumably expects a 'static future. You can solve the problem of the async block saving (and thus potentially accessing later) the local &self reference by creating a clone of self.config in advance, and then moveing that clone into the async block.

let config = Arc::clone(&self.config);
self.client.add_event_handler(move |event: OriginalSyncRoomMessageEvent, room: Room| async move {
    let debug = config.lock().expect("Cannot obtain lock due to poisioning.").debug;
});
2 Likes

Sorry, I forgot to mention another thing I was trying to achieve: calling methods associated with self. In other words, is it possible to call methods like self.send_debug() within that closure? I have updated the OP to demonstrate what I am trying to do.
Regardless, thanks for the pointer for reading the config. I can think of a workaround now.

You won't be able to keep access to &self. That & there means you get only a temporary permission to touch it until the end of the method call, and absolutely no longer, under any circumstances.

The handler may be potentially called after initialise call ends, so it's a violation of the method's contract. The borrow checker doesn't analyze things deeply or precisely, so it won't make any exceptions for the fact that self.client belongs to self and you expect to destroy it before self is destroyed. From the interface perspective visible to the borrow checker, add_event_handler forbids all temporary references, period (that's what 'static bound means).

You could make it initialize(self: Arc<Self>) which gives you a reference that you can keep for as long as you need, and you can then move it to be owned by the handler closure.

Generally, there has to be either Arc or some other copy involved. You can't use temporary references in contexts that aren't strictly statically guaranteed to be just as temporary.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.