I'm struggling to express my code in a way to please the borrow-checker.
I have a function create_task
which creates a future of some database operations. There's a stream of values where each element needs to be inserted to a database within a transaction. The problem is sharing the transaction between multiple closures as it has also mutably borrowed the connection object.
#![feature(conservative_impl_trait)]
extern crate futures;
extern crate rusqlite;
use futures::prelude::*;
use futures::{future, stream};
use rusqlite::Connection;
fn main() {
let task = create_task();
task.wait().unwrap();
}
fn create_task() -> impl Future<Item = (), Error = ()> {
let mut conn = Connection::open("temp.db").unwrap();
conn.execute("CREATE TABLE IF NOT EXISTS temp (val INTEGER)", &[]).unwrap();
// tx takes a mut ref to conn!
let tx = conn.transaction().unwrap();
stream::iter_ok::<_, ()>(vec![1, 2, 3])
.for_each(|val| {
// tx borrowed here!
tx.execute("INSERT INTO temp (val) VALUES (?1)", &[&val]).unwrap();
future::ok(())
})
.map(|_| {
// tx moved/consumed here!
tx.commit().unwrap();
})
}
There are multiple issues with the code:
conn
does not live long enough. It needs to be also moved to the closures. Perhaps as anRc<Connection>
because of two closures?conn
can't be simply shared as anRc
because of mutability requirements. PerhapsRc<RefCell<Connection>>
is a more suitable type?- the borrow-checker does not know that the borrow to
tx
ends after the firstfor_each
closure, therefore it cannot be moved to the secondmap
closure. Once again, moving it asRc<Transaction>
to both closures might be reasonable?
I've been fiddling around with those ideas and know that the desired lifetimes are possible and make sense, but have not been able to express my code to the compiler in a correct way.