Repository: cberner/redb
Pull request #502 (2023-01-22 18:40:14)

Relax requirements on argument lifetimes to range() and drain()


Patch:
diff --git a/src/table.rs b/src/table.rs
index 4faf580..409d48d 100644
--- a/src/table.rs
+++ b/src/table.rs
@@ -70,14 +70,14 @@ impl<'db, 'txn, K: RedbKey + ?Sized + 'txn, V: RedbValue + ?Sized + 'txn> Table<
     }
 
     /// Removes the specified range and returns the removed entries in an iterator
-    pub fn drain<'a, KR>(
+    pub fn drain<'a: 'b, 'b, KR>(
         &'a mut self,
-        range: impl RangeBounds<KR> + Clone + 'a,
+        range: impl RangeBounds<KR> + Clone + 'b,
     ) -> Result<Drain<'a, K, V>>
     where
         K: 'a,
         // TODO: we should not require Clone here
-        KR: Borrow<K::SelfType<'a>> + ?Sized + Clone + 'a,
+        KR: Borrow<K::SelfType<'b>> + ?Sized + Clone + 'b,
     {
         // Safety: No other references to this table can exist.
         // Tables can only be opened mutably in one location (see Error::TableAlreadyOpen),
@@ -147,10 +147,13 @@ impl<'db, 'txn, K: RedbKey + ?Sized, V: RedbValue + ?Sized> ReadableTable<K, V>
         self.tree.get(key.borrow())
     }
 
-    fn range<'a, KR>(&'a self, range: impl RangeBounds<KR> + 'a) -> Result<RangeIter<'a, K, V>>
+    fn range<'a: 'b, 'b, KR>(
+        &'a self,
+        range: impl RangeBounds<KR> + 'b,
+    ) -> Result<RangeIter<'a, K, V>>
     where
         K: 'a,
-        KR: Borrow<K::SelfType<'a>> + ?Sized + 'a,
+        KR: Borrow<K::SelfType<'b>> + ?Sized + 'b,
     {
         self.tree.range(range).map(RangeIter::new)
     }
@@ -208,10 +211,13 @@ pub trait ReadableTable<K: RedbKey + ?Sized, V: RedbValue + ?Sized> {
     /// # Ok(())
     /// # }
     /// ```
-    fn range<'a, KR>(&'a self, range: impl RangeBounds<KR> + 'a) -> Result<RangeIter<'a, K, V>>
+    fn range<'a: 'b, 'b, KR>(
+        &'a self,
+        range: impl RangeBounds<KR> + 'b,
+    ) -> Result<RangeIter<'a, K, V>>
     where
         K: 'a,
-        KR: Borrow<K::SelfType<'a>> + ?Sized + 'a;
+        KR: Borrow<K::SelfType<'b>> + ?Sized + 'b;
 
     /// Returns the number of entries in the table
     fn len(&self) -> Result<usize>;
@@ -252,10 +258,13 @@ impl<'txn, K: RedbKey + ?Sized, V: RedbValue + ?Sized> ReadableTable<K, V>
         self.tree.get(key.borrow())
     }
 
-    fn range<'a, KR>(&'a self, range: impl RangeBounds<KR> + 'a) -> Result<RangeIter<'a, K, V>>
+    fn range<'a: 'b, 'b, KR>(
+        &'a self,
+        range: impl RangeBounds<KR> + 'b,
+    ) -> Result<RangeIter<'a, K, V>>
     where
         K: 'a,
-        KR: Borrow<K::SelfType<'a>> + ?Sized + 'a,
+        KR: Borrow<K::SelfType<'b>> + ?Sized + 'b,
     {
         self.tree.range(range).map(RangeIter::new)
     }
diff --git a/src/tree_store/btree.rs b/src/tree_store/btree.rs
index 786dcc8..549b495 100644
--- a/src/tree_store/btree.rs
+++ b/src/tree_store/btree.rs
@@ -169,7 +169,10 @@ impl<'a, K: RedbKey + ?Sized + 'a, V: RedbValue + ?Sized + 'a> BtreeMut<'a, K, V
     >(
         &'a0 self,
         range: T,
-    ) -> Result<BtreeRangeIter<K, V>> {
+    ) -> Result<BtreeRangeIter<'a, K, V>>
+    where
+        'a: 'a0,
+    {
         self.read_tree().range(range)
     }
 
@@ -182,7 +185,10 @@ impl<'a, K: RedbKey + ?Sized + 'a, V: RedbValue + ?Sized + 'a> BtreeMut<'a, K, V
     >(
         &'a0 mut self,
         range: T,
-    ) -> Result<BtreeDrain<K, V>> {
+    ) -> Result<BtreeDrain<'a, K, V>>
+    where
+        'a: 'a0,
+    {
         let iter = self.range(range.clone())?;
         let return_iter = self.range(range)?;
         let mut free_on_drop = vec![];


Test patch:
diff --git a/tests/basic_tests.rs b/tests/basic_tests.rs
index b059348..36dd08f 100644
--- a/tests/basic_tests.rs
+++ b/tests/basic_tests.rs
@@ -937,6 +937,56 @@ fn array_type() {
     assert!(iter.next().is_none());
 }
 
+#[test]
+fn range_lifetime() {
+    let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
+    let db = Database::create(tmpfile.path()).unwrap();
+
+    let definition: TableDefinition<&str, &str> = TableDefinition::new("x");
+
+    let write_txn = db.begin_write().unwrap();
+    {
+        let mut table = write_txn.open_table(definition).unwrap();
+        table.insert("hello", "world").unwrap();
+    }
+    write_txn.commit().unwrap();
+
+    let read_txn = db.begin_read().unwrap();
+    let table = read_txn.open_table(definition).unwrap();
+
+    let mut iter = {
+        let start = "hello".to_string();
+        table.range::<&str>(start.as_str()..).unwrap()
+    };
+    assert_eq!(iter.next().unwrap().1.value(), "world");
+    assert!(iter.next().is_none());
+}
+
+#[test]
+fn drain_lifetime() {
+    let tmpfile: NamedTempFile = NamedTempFile::new().unwrap();
+    let db = Database::create(tmpfile.path()).unwrap();
+
+    let definition: TableDefinition<&str, &str> = TableDefinition::new("x");
+
+    let write_txn = db.begin_write().unwrap();
+    {
+        let mut table = write_txn.open_table(definition).unwrap();
+        table.insert("hello", "world").unwrap();
+    }
+    write_txn.commit().unwrap();
+
+    let txn = db.begin_write().unwrap();
+    let mut table = txn.open_table(definition).unwrap();
+
+    let mut iter = {
+        let start = "hello".to_string();
+        table.drain::<&str>(start.as_str()..).unwrap()
+    };
+    assert_eq!(iter.next().unwrap().1.value(), "world");
+    assert!(iter.next().is_none());
+}
+
 #[test]
 fn custom_ordering() {
     #[derive(Debug)]