ahtml/
more_vec.rs

1use std::ops::RangeBounds;
2
3fn usize_range_len<R>(range: &R, end_excl: usize) -> usize
4where
5    R: RangeBounds<usize>,
6{
7    let start = match range.start_bound() {
8        std::ops::Bound::Included(a) => *a,
9        std::ops::Bound::Excluded(_) => unreachable!(
10            "right? a..=b but there's no a=..b; \
11             could one construct this programmatically, though?"
12        ),
13        std::ops::Bound::Unbounded => 0,
14    };
15    match range.end_bound() {
16        std::ops::Bound::Included(e_incl) => {
17            // (e_incl - start) + 1,
18            e_incl
19                .checked_sub(start)
20                .expect("end must be >= start")
21                .checked_add(1)
22                .expect("range end must be < usize::max()")
23        }
24        std::ops::Bound::Excluded(e_excl) => {
25            // e_excl - start,
26            e_excl.checked_sub(start).expect("end must be >= start")
27        }
28        std::ops::Bound::Unbounded => {
29            // end_excl - start,
30            end_excl.checked_sub(start).expect("end must be >= start")
31        }
32    }
33}
34
35#[cfg(test)]
36fn identity<T>(v: T) -> T {
37    v
38}
39
40#[cfg(test)]
41#[test]
42fn t_usize_range_len() {
43    assert_eq!(usize_range_len(&identity(1..4), 10), 3);
44    assert_eq!(usize_range_len(&identity(1..=4), 10), 4);
45    assert_eq!(usize_range_len(&identity(1..), 10), 9);
46    assert_eq!(usize_range_len(&identity(..), 10), 10);
47    assert_eq!(usize_range_len(&identity(..4), 10), 4);
48    assert_eq!(usize_range_len(&identity(..=4), 10), 5);
49    assert_eq!(usize_range_len(&identity(4..4), 10), 0);
50    assert_eq!(usize_range_len(&identity(4..=4), 10), 1);
51    // should it catch that? just let later on
52    assert_eq!(usize_range_len(&identity(..4), 2), 4);
53}
54#[test]
55#[should_panic]
56fn t_usize_range_len_invalid_start() {
57    usize_range_len(&identity(5..4), 2);
58}
59#[test]
60#[should_panic]
61fn t_usize_range_len_invalid_start_2() {
62    usize_range_len(&identity(5..=4), 2);
63}
64#[test]
65#[should_panic]
66fn t_usize_range_len_invalid_start_indirect() {
67    usize_range_len(&identity(5..), 2);
68}
69
70pub trait MoreVec<T> {
71    /// See docs on `push_within_capacity` in std, which is nightly-only
72    fn push_within_capacity_(&mut self, value: T) -> Result<(), T>;
73
74    /// Like `extend_from_within` but fails if the extension cannot be
75    /// done within capacity.
76    fn extend_from_within_within_capacity<R>(&mut self, src: R) -> Result<(), ()>
77    where
78        R: RangeBounds<usize>,
79        T: Clone;
80}
81
82impl<T> MoreVec<T> for Vec<T> {
83    fn push_within_capacity_(&mut self, value: T) -> Result<(), T> {
84        if self.len() < self.capacity() {
85            self.push(value);
86            Ok(())
87        } else {
88            Err(value)
89        }
90    }
91
92    fn extend_from_within_within_capacity<R>(&mut self, src: R) -> Result<(), ()>
93    where
94        R: RangeBounds<usize>,
95        T: Clone,
96    {
97        let len = self.len();
98        let additional_len = usize_range_len(&src, len);
99        let newlen = len + additional_len;
100        if newlen > self.capacity() {
101            return Err(());
102        }
103        self.extend_from_within(src);
104        Ok(())
105    }
106}
107
108#[cfg(test)]
109#[test]
110fn t_within_capacity() {
111    let mut v = Vec::with_capacity(5);
112    v.push_within_capacity_(9).unwrap();
113    v.push_within_capacity_(7).unwrap();
114    v.push_within_capacity_(1).unwrap();
115
116    assert!(v.extend_from_within_within_capacity(0..3).is_err());
117    assert!(v.extend_from_within_within_capacity(1..3).is_ok());
118    assert_eq!(v.as_slice(), &[9, 7, 1, 7, 1]);
119}