crates/kernel/ents-testutil/src/counting.rs
counting.rshistorycomment on this file
| 1 | //! An object-read counter, for asserting incremental-evaluation bounds. |
| 2 | |
| 3 | use std::cell::Cell; |
| 4 | |
| 5 | use gix_object::Find; |
| 6 | use gix_object::find; |
| 7 | |
| 8 | /// Wraps any [`Find`] and counts `try_find` calls, so a test can assert |
| 9 | /// that an "incremental" code path really is bounded — for example, that |
| 10 | /// evaluating a query entry set after a one-commit advance does not |
| 11 | /// re-walk a three-hundred-commit history (`query.incremental`). |
| 12 | /// |
| 13 | /// # Examples |
| 14 | /// |
| 15 | /// ``` |
| 16 | /// use ents_testutil::{CountingFind, ObjectStore, empty_tree}; |
| 17 | /// use gix_object::Find as _; |
| 18 | /// |
| 19 | /// let objects = ObjectStore::default(); |
| 20 | /// let tree = empty_tree(&objects); |
| 21 | /// |
| 22 | /// let counting = CountingFind::new(&objects); |
| 23 | /// let mut buf = Vec::new(); |
| 24 | /// counting.try_find(&tree, &mut buf).expect("readable"); |
| 25 | /// assert_eq!(counting.reads(), 1); |
| 26 | /// |
| 27 | /// counting.reset(); |
| 28 | /// assert_eq!(counting.reads(), 0); |
| 29 | /// ``` |
| 30 | #[derive(Debug)] |
| 31 | pub struct CountingFind<'a, F: Find> { |
| 32 | inner: &'a F, |
| 33 | reads: Cell<usize>, |
| 34 | } |
| 35 | |
| 36 | impl<'a, F: Find> CountingFind<'a, F> { |
| 37 | /// Wrap `inner`, starting the counter at zero. |
| 38 | #[must_use] |
| 39 | pub fn new(inner: &'a F) -> Self { |
| 40 | Self { |
| 41 | inner, |
| 42 | reads: Cell::new(0), |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | /// How many `try_find` calls have happened since the last |
| 47 | /// [`CountingFind::reset`]. |
| 48 | #[must_use] |
| 49 | pub fn reads(&self) -> usize { |
| 50 | self.reads.get() |
| 51 | } |
| 52 | |
| 53 | /// Zero the counter — typically after warming caches, so an assertion |
| 54 | /// covers only the increment under test. |
| 55 | pub fn reset(&self) { |
| 56 | self.reads.set(0); |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | impl<F: Find> Find for CountingFind<'_, F> { |
| 61 | fn try_find<'b>( |
| 62 | &self, |
| 63 | id: &gix_hash::oid, |
| 64 | buffer: &'b mut Vec<u8>, |
| 65 | ) -> Result<Option<gix_object::Data<'b>>, find::Error> { |
| 66 | self.reads.set(self.reads.get().saturating_add(1)); |
| 67 | self.inner.try_find(id, buffer) |
| 68 | } |
| 69 | } |