I am using the rustqlite library for a SQLite database (playground)
use std::ops::Deref;
pub struct Connection {
}
impl Connection {
pub fn transaction(&mut self) -> Transaction {
Transaction::new(self)
}
}
pub struct Transaction<'conn> {
conn: &'conn Connection
}
impl Transaction<'_> {
pub fn new(conn: &mut Connection) -> Transaction {
Transaction{ conn }
}
pub fn commit(mut self) -> Result<(), ()> {
Ok(())
}
}
impl Deref for Transaction<'_> {
type Target = Connection;
#[inline]
fn deref(&self) -> &Connection {
self.conn
}
}
With this implementation, the Transaction
object will take the ownership of the Connection
object. At the same time, it also implements the Deref
trait so we can call all methods from the Transaction
struct as from the Connection
struct.
The implementation detail is here
From my application code, I want to have a single object that can be represented by either Transaction
or Connection
. This is necessary because the logic has a flag to decide to use transaction or not. There is a cast to treat the Transaction
object as the Connection
object:
let conn = create_connection(); // Connection
let tx = conn.transaction(); // Transaction
let conn: &Transaction = &tx; // cast back to Connection type from the Transaction type
However, I don't know how to arrange this code from the application POV with the condition. Here is my pseudocode:
pub fn execute(is_tx: bool) {
// conn will have Connection type
let conn = match is_tx {
true => &create_connection(),
false => {
let x = create_connection().transaction();
let t: &Connection = &x;
t
}
};
// do other things with conn object
}
pub fn create_connection() -> Connection {
Connection{}
}
However, there will be an error
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:36:21
|
36 | let x = create_connection().transaction();
| ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
37 | let t: &Connection = &x;
| -- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
error[E0597]: `x` does not live long enough
--> src/lib.rs:37:34
|
37 | let t: &Connection = &x;
| ^^ borrowed value does not live long enough
38 | t
| - borrow later used here
39 | }
| - `x` dropped here while still borrowed
I understand the error, but I've tried a couple of workarounds without success, mostly because the Transaction
struct takes ownership of the Connection
struct. How can I fix this?