blob: f6f934d5fcd0f46045253eaf2cb1a8efa38c17e0 [file] [log] [blame]
// Copyright 2020 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.
use std::{
io::{Read, Seek},
ops::Range,
};
pub trait ReadAndSeek: Read + Seek {}
impl<T> ReadAndSeek for T where T: Read + Seek {}
pub trait RangeOps<T> {
/// Returns `true` if a slice of self is contained in the |other|.
fn overlaps(&self, other: &Self) -> bool;
/// Returns `true` if `start` of one equals `end` of the other.
/// ```
/// let a: Range<u64> = 1..10;
/// let b. Range<u64> = 10..14;
/// assert!(a.is_adjacent(&b));
/// ```
fn is_adjacent(&self, other: &Self) -> bool;
/// Returns `true` if all of `other` is contained within `self`.
/// ```
/// let a: Range<u64> = 1..10;
/// let b. Range<u64> = 2..4;
/// assert!(a.contains_range(&b));
/// assert!(!b.contains_range(&a));
/// ```
fn contains_range(&self, other: &Self) -> bool;
fn is_valid(&self) -> bool;
fn length(&self) -> T;
}
impl<T: Copy + std::cmp::Ord + std::ops::Sub<Output = T>> RangeOps<T> for Range<T> {
fn overlaps(&self, other: &Self) -> bool {
std::cmp::max(self.start, other.start) < std::cmp::min(self.end, other.end)
}
fn is_adjacent(&self, other: &Self) -> bool {
let min_end = std::cmp::min(self.end, other.end);
let max_start = std::cmp::max(self.start, other.start);
min_end == max_start
}
fn contains_range(&self, other: &Self) -> bool {
if self.start >= self.end || other.start >= other.end {
return false;
}
self.start <= other.start && self.end >= other.end
}
fn is_valid(&self) -> bool {
self.start < self.end
}
fn length(&self) -> T {
assert!(self.start < self.end);
self.end - self.start
}
}
#[cfg(test)]
pub(crate) fn get_overlapping_ranges() -> (Range<u64>, Range<u64>) {
(1..5, 4..8)
}
#[cfg(test)]
pub(crate) fn get_containing_ranges() -> (Range<u64>, Range<u64>) {
(1..5, 2..4)
}
#[cfg(test)]
pub(crate) fn get_adjacent_ranges() -> (Range<u64>, Range<u64>) {
(1..5, 5..8)
}
#[cfg(test)]
pub(crate) fn get_non_overlapping_ranges() -> (Range<u64>, Range<u64>) {
(1..5, 6..8)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_range_overlaps() {
let (r1, r2) = get_overlapping_ranges();
assert!(r1.overlaps(&r2));
assert!(r2.overlaps(&r1));
// Overlaps with itself.
assert!(r1.overlaps(&r1));
// Range completely contains the other.
let (r3, r4) = get_containing_ranges();
assert!(r4.overlaps(&r3));
assert!(r3.overlaps(&r4));
}
#[test]
fn test_range_do_not_overlaps() {
// Adjacent ranges
let (r1, r2) = get_adjacent_ranges();
assert!(!r1.overlaps(&r2));
assert!(!r2.overlaps(&r1));
// Non-overlapping
let (r3, r4) = get_non_overlapping_ranges();
assert!(!r4.overlaps(&r3));
assert!(!r3.overlaps(&r4));
}
#[test]
fn test_range_is_adjacent() {
// Adjacent ranges
let (r1, r2) = get_adjacent_ranges();
assert!(r1.is_adjacent(&r2));
assert!(r2.is_adjacent(&r1));
// Non-overlapping
let (r3, r4) = get_non_overlapping_ranges();
assert!(!r4.is_adjacent(&r3));
assert!(!r3.is_adjacent(&r4));
// Overlapping
let (r5, r6) = get_overlapping_ranges();
assert!(!r5.is_adjacent(&r6));
assert!(!r6.is_adjacent(&r5));
assert!(!r5.is_adjacent(&r5));
// Range completely contains the other.
let (r7, r8) = get_containing_ranges();
assert!(!r7.is_adjacent(&r8));
assert!(!r8.is_adjacent(&r7));
}
#[test]
fn test_range_contains_range() {
// r1 has r2
let (r1, r2) = get_containing_ranges();
// One doesn't contains itself.
assert!(r1.contains_range(&r1));
assert!(r1.contains_range(&r2));
// But doesn't have r1.
assert!(!r2.contains_range(&r1));
// Overlapping
let (r3, r4) = get_overlapping_ranges();
assert!(!r3.contains_range(&r4));
assert!(!r4.contains_range(&r3));
// Non-overlapping
let (r5, r6) = get_non_overlapping_ranges();
assert!(!r5.contains_range(&r6));
assert!(!r6.contains_range(&r5));
// Adjacent ranges
let (r7, r8) = get_adjacent_ranges();
assert!(!r7.contains_range(&r8));
assert!(!r8.contains_range(&r7));
}
#[test]
fn test_range_is_valid() {
let r1: Range<u64> = 1..8;
assert!(r1.is_valid());
let r2: Range<u64> = 1..2;
assert!(r2.is_valid());
let r3: Range<u64> = 0..0;
assert!(!r3.is_valid());
let r4: Range<u64> = 1..1;
assert!(!r4.is_valid());
let r5: Range<u64> = 5..2;
assert!(!r5.is_valid());
}
#[test]
fn test_range_length() {
let r1: Range<u64> = 1..8;
assert_eq!(r1.length(), 7);
let r2: Range<u64> = 1..2;
assert_eq!(r2.length(), 1);
}
#[should_panic]
#[test]
fn test_invalid_range_length() {
// Invalid range length
let r1: Range<u64> = 8..1;
r1.length();
}
}