| // Copyright 2026 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| //! A utility for test environments. |
| //! |
| //! This module exposes the [`NormalizedRangeCheckingIterator`] to assist in constructing a |
| //! validated iterator over collections of ranges used for testing. |
| |
| /// An iterator which verifies that the underlying `iter` is a [`NormalizedRangeIterator`]. |
| pub struct NormalizedRangeCheckingIterator<I> { |
| iter: I, |
| prev: Option<crate::Range>, |
| } |
| |
| impl<I> NormalizedRangeCheckingIterator<I> |
| where |
| I: Iterator<Item = crate::Range>, |
| { |
| pub fn new(ranges: impl IntoIterator<IntoIter = I>) -> Self { |
| Self { iter: ranges.into_iter(), prev: None } |
| } |
| } |
| |
| impl<I> Iterator for NormalizedRangeCheckingIterator<I> |
| where |
| I: Iterator<Item = crate::Range>, |
| { |
| type Item = crate::Range; |
| |
| fn next(&mut self) -> Option<crate::Range> { |
| let cur = self.iter.next()?; |
| if let Some(prev) = self.prev { |
| assert!(prev.end() < cur.addr() || (prev.end() == cur.addr() && prev.ty() != cur.ty())); |
| } |
| self.prev = Some(cur); |
| Some(cur) |
| } |
| } |
| |
| // Safety: `NormalizedRangeCheckingIterator` will panic if it violates the normalized invariant. |
| unsafe impl<I> crate::NormalizedRangeIterator for NormalizedRangeCheckingIterator<I> where |
| I: Iterator<Item = crate::Range> |
| { |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| |
| // Panic when the underlying iterator has two adjacent ranges of the same type. |
| #[test] |
| #[should_panic] |
| fn normalized_range_checking_iterator_test_maximally_contiguous() { |
| let mut ranges = NormalizedRangeCheckingIterator::new([ |
| crate::Range::new(0, 0x1000, crate::Type::FreeRam), |
| crate::Range::new(0x1000, 0x1000, crate::Type::FreeRam), |
| ]); |
| |
| ranges.next(); |
| ranges.next(); |
| } |
| |
| // Panic when underlying iterator is not lexicographically sorted. |
| #[test] |
| #[should_panic] |
| fn normalized_range_checking_iterator_test_lexicographically_sorted() { |
| let mut ranges = NormalizedRangeCheckingIterator::new([ |
| crate::Range::new(0x5000, 0x1000, crate::Type::FreeRam), |
| crate::Range::new(0, 0x1000, crate::Type::FreeRam), |
| ]); |
| |
| ranges.next(); |
| ranges.next(); |
| } |
| |
| // Panic when underlying iterator has overlapping ranges. |
| #[test] |
| #[should_panic] |
| fn normalized_range_checking_iterator_test_non_overlapping() { |
| let mut ranges = NormalizedRangeCheckingIterator::new([ |
| crate::Range::new(0, 0x1000, crate::Type::FreeRam), |
| crate::Range::new(0, 0x1000, crate::Type::FreeRam), |
| ]); |
| |
| ranges.next(); |
| ranges.next(); |
| } |
| } |