Skip to main content

ps_range/
lib.rs

1//! Generalized range abstractions.
2//!
3//! This crate provides three capability traits, alongside the concrete range
4//! types that implement them:
5//!
6//! - [`RangeStart`] describes a range with a defined inclusive lower bound;
7//!   it is the shared base of the two extension traits.
8//! - [`RangeExt`] describes a range bounded on both ends, exposing its upper
9//!   bound in both the inclusive and the exclusive form.
10//! - [`PartialRangeExt`] describes a range that may be unbounded above or
11//!   empty, exposing its upper bound losslessly through [`RangeEnd`] along
12//!   with clamping and intersection operations.
13//! - [`Range`] is a concrete bounded range whose end is either inclusive or
14//!   exclusive, as recorded by [`RangeEnd`].
15//! - [`PartialRange`] is a concrete possibly-unbounded range that also
16//!   implements [`Iterator`].
17//!
18//! Each trait is implemented for the standard library range types, for
19//! shared and mutable references, and for the concrete types above, wherever
20//! the type's shape supports it. [`RangeStart`] and [`PartialRangeExt`] are
21//! also implemented for [`Option`], with [`None`] as the empty range, so a
22//! possibly-absent range remains usable as a range. The traits' method names
23//! are disjoint, so all three can share scope.
24//!
25//! Operations interpret `Idx` as a discrete domain in which `x + one` is the
26//! successor of `x`. A bound is converted between its inclusive and
27//! exclusive forms only where the converted bound is provably representable:
28//! clamping compares bounds through [`RangeEnd`] or against window ends that
29//! are themselves representable, so an inclusive end at the maximum index
30//! value is handled faithfully, without saturation or widening.
31//!
32//! # Examples
33//!
34//! ```
35//! use ps_range::{PartialRange, PartialRangeExt, RangeExt};
36//!
37//! // Clamp a slice request to a buffer's length.
38//! let buffer = [0u8; 10];
39//! let requested = 4usize..;
40//!
41//! assert_eq!(requested.clamp_right_exclusive(buffer.len()), 4..10);
42//! assert_eq!(buffer[requested.clamp_right_exclusive(buffer.len())].len(), 6);
43//!
44//! // Clamping requires only minimal trait bounds on the index type.
45//! assert_eq!((..8).clamp_right(6usize), 0..6);
46//!
47//! // Iteration eventually leaves every range exhausted.
48//! let mut range = PartialRange::from(254u8..);
49//!
50//! assert_eq!(range.by_ref().collect::<Vec<_>>(), vec![254, 255]);
51//! assert_eq!(range, PartialRange::Exhausted);
52//! ```
53#![warn(missing_docs)]
54
55mod partial_range;
56mod partial_range_ext;
57mod range;
58mod range_ext;
59mod start;
60
61pub use partial_range::PartialRange;
62pub use partial_range_ext::PartialRangeExt;
63pub use range::{Range, RangeEnd};
64pub use range_ext::RangeExt;
65pub use start::RangeStart;