Hi everyone,
I've been trying to figure out an error all day. I've tried many different approaches, but I just can't seem to fix it.
Here's my code:
use mysql_async::prelude::{Query, WithParams};
use mysql_async::Conn;
use mysql_async::Result;
pub struct MySQLLock {
name: String,
conn: Conn,
}
impl MySQLLock {
pub fn new(name: &str, conn: Conn) -> Self {
MySQLLock { name: name.to_string(), conn }
}
pub async fn try_lock<'a, F, Fut, R>(&'a mut self, func: F) -> Result<R>
where
F: FnOnce(bool, &'a mut Conn) -> Fut,
Fut: Future<Output = Result<R>>,
{
// create lock in DB
let locked: bool = "SELECT GET_LOCK(?,?)"
.with((&self.name, 10))
.first(&mut self.conn)
.await?
.unwrap_or(false);
// exec func
let result = func(locked, &mut self.conn).await?;
// release lock in DB
if locked {
"SELECT RELEASE_LOCK(?)"
.with((&self.name,))
.ignore(&mut self.conn)
.await?;
}
//
Ok(result)
}
}
#[cfg(test)]
mod tests {
use super::*;
use mysql_async::Error;
use mysql_async::prelude::Queryable;
#[tokio::test]
async fn test_lock() {
let conn = Conn::from_url("mysql://root:@localhost:3306")
.await
.unwrap();
let mut lock = MySQLLock::new("lock_name", conn);
let _ = lock.try_lock(|locked, conn| async move {
if !locked {
return Err(Error::Other("Can't create lock".into()));
}
let one: u32 = conn.query_first("SELECT 1").await?.unwrap();
let two: u32 = conn.query_first("SELECT 2").await?.unwrap();
Ok((one, two))
})
.await
.unwrap();
}
}
And here's the error:
error[E0499]: cannot borrow `self.conn` as mutable more than once at a time
|
15 | pub async fn try_lock<'a, F, Fut, R>(&'a mut self, func: F) -> Result<R>
| -- lifetime `'a` defined here
...
27 | let result = func(locked, &mut self.conn).await?;
| ----------------------------
| | |
| | first mutable borrow occurs here
| argument requires that `self.conn` is borrowed for `'a`
...
32 | .ignore(&mut self.conn)
| ^^^^^^^^^^^^^^ second mutable borrow occurs here
If I remove lifetime 'a
here F: FnOnce(bool, &'a mut Conn) -> Fut
, I get a other error, which I also can't figure out
error: lifetime may not live long enough
|
52 | let _ = lock.try_lock(|locked, conn| async move {
| ________________________________________-----_^
| | | |
| | | return type of closure `{async block@pool_core/src/lock.rs:52:46: 52:56}` contains a lifetime `'2`
| | has type `&'1 mut mysql_async::Conn`
53 | | if !locked {
54 | | return Err(Error::Other("Can't create lock".into()));
... |
58 | | Ok((one, two))
59 | | })
| |_________^ returning this value requires that `'1` must outlive `'2`
I think I understand the errors, but I have no idea how to actually fix them.
Perhaps my structure/logic/thinking is wrong, and this should be approached differently in Rust?