Repository: cberner/redb
Pull request #659 (2023-08-18 13:28:47)

fix(insert sig lifetime): key and value should have different lifetimes
also add `generic_signature_lifetimes` test for it

---

For the latest version, the `write_key_generic` function won't compile:

```rust
error[E0597]: `buf` does not live long enough
  --> src/main.rs:27:31
   |
20 |         key: K::SelfType<'_>,
   |         --- has type `<K as RedbValue>::SelfType<'1>`
...
23 |         let buf = [1, 2, 3];
   |             --- binding `buf` declared here
...
27 |             table.insert(key, buf.as_slice()).unwrap();
   |             ------------------^^^^^^^^^^^^^^-
   |             |                 |
   |             |                 borrowed value does not live long enough
   |             argument requires that `buf` is borrowed for `'1`
...
30 |     }
   |     - `buf` dropped here while still borrowed
```


Patch:
diff --git a/src/multimap_table.rs b/src/multimap_table.rs
index aef779f..8a69e02 100644
--- a/src/multimap_table.rs
+++ b/src/multimap_table.rs
@@ -585,15 +585,11 @@ impl<'db, 'txn, K: RedbKey + 'static, V: RedbKey + 'static> MultimapTable<'db, '
     /// Add the given value to the mapping of the key
     ///
     /// Returns `true` if the key-value pair was present
-    pub fn insert<'a>(
+    pub fn insert<'k, 'v>(
         &mut self,
-        key: impl Borrow<K::SelfType<'a>>,
-        value: impl Borrow<V::SelfType<'a>>,
-    ) -> Result<bool>
-    where
-        K: 'a,
-        V: 'a,
-    {
+        key: impl Borrow<K::SelfType<'k>>,
+        value: impl Borrow<V::SelfType<'v>>,
+    ) -> Result<bool> {
         let value_bytes = V::as_bytes(value.borrow());
         let value_bytes_ref = value_bytes.as_ref();
         if value_bytes_ref.len() > MAX_VALUE_LENGTH {
diff --git a/src/table.rs b/src/table.rs
index d4b0572..6b2453d 100644
--- a/src/table.rs
+++ b/src/table.rs
@@ -105,15 +105,11 @@ impl<'db, 'txn, K: RedbKey + 'static, V: RedbValue + 'static> Table<'db, 'txn, K
     /// Insert mapping of the given key to the given value
     ///
     /// Returns the old value, if the key was present in the table
-    pub fn insert<'a>(
+    pub fn insert<'k, 'v>(
         &mut self,
-        key: impl Borrow<K::SelfType<'a>>,
-        value: impl Borrow<V::SelfType<'a>>,
-    ) -> Result<Option<AccessGuard<V>>>
-    where
-        K: 'a,
-        V: 'a,
-    {
+        key: impl Borrow<K::SelfType<'k>>,
+        value: impl Borrow<V::SelfType<'v>>,
+    ) -> Result<Option<AccessGuard<V>>> {
         let value_len = V::as_bytes(value.borrow()).as_ref().len();
         if value_len > MAX_VALUE_LENGTH {
             return Err(StorageError::ValueTooLarge(value_len));


Test patch:
diff --git a/tests/basic_tests.rs b/tests/basic_tests.rs
index c617366..01bd75a 100644
--- a/tests/basic_tests.rs
+++ b/tests/basic_tests.rs
@@ -1403,3 +1403,44 @@ fn signature_lifetimes() {
     }
     write_txn.commit().unwrap();
 }
+
+#[test]
+fn generic_signature_lifetimes() {
+    fn write_key_generic<K: RedbKey>(
+        table: TableDefinition<K, &[u8]>,
+        key: K::SelfType<'_>,
+        db: &Database,
+    ) {
+        let buf = [1, 2, 3];
+        let write_txn = db.begin_write().unwrap();
+        {
+            let mut table = write_txn.open_table(table).unwrap();
+            table.insert(key, buf.as_slice()).unwrap();
+        }
+        write_txn.commit().unwrap();
+    }
+
+    fn read_key_generic<K: RedbKey>(
+        table: TableDefinition<K, &[u8]>,
+        key: K::SelfType<'_>,
+        db: &Database,
+    ) {
+        let buf = [1, 2, 3];
+        let read_txn = db.begin_read().unwrap();
+        let table = read_txn.open_table(table).unwrap();
+        assert_eq!(table.get(key).unwrap().unwrap().value(), buf);
+    }
+
+    let tmpfile = create_tempfile();
+    let db = &Database::create(tmpfile.path()).unwrap();
+    {
+        let (table, key) = (TableDefinition::<&str, _>::new("&str"), "key");
+        write_key_generic(table, key, db);
+        read_key_generic(table, key, db);
+    }
+    {
+        let (table, key) = (TableDefinition::<(), _>::new("()"), ());
+        write_key_generic(table, key, db);
+        read_key_generic(table, key, db);
+    }
+}