Skip to main content

cliquenet/util/
nonempty.rs

1use std::{collections::BTreeMap, iter::once};
2
3/// Small helper to ensure some container type is not empty.
4#[derive(Debug)]
5pub(crate) struct NonEmpty<T: Container>(T::Element, T);
6
7pub(crate) trait Container {
8    type Element;
9}
10
11impl<A> Container for Vec<A> {
12    type Element = A;
13}
14
15impl<K: Ord, V> Container for BTreeMap<K, V> {
16    type Element = (K, V);
17}
18
19impl<A> NonEmpty<Vec<A>> {
20    pub(crate) fn new<I>(fst: A, rest: I) -> Self
21    where
22        I: IntoIterator<Item = A>,
23    {
24        Self(fst, rest.into_iter().collect())
25    }
26
27    pub(crate) fn assert_non_empty_vec<I>(it: I) -> Self
28    where
29        I: IntoIterator<Item = A>,
30    {
31        let mut it = it.into_iter();
32        let fst = it.next().expect("non empty vector");
33        Self(fst, it.collect())
34    }
35
36    pub(crate) fn last(&self) -> &A {
37        self.1.as_slice().last().unwrap_or(&self.0)
38    }
39
40    pub(crate) fn get(&self, i: usize) -> Option<&A> {
41        match i {
42            0 => Some(&self.0),
43            _ => self.1.get(i - 1),
44        }
45    }
46
47    pub(crate) fn iter(&self) -> impl Iterator<Item = &A> {
48        once(&self.0).chain(self.1.as_slice().iter())
49    }
50}
51
52impl<K: Ord, V> NonEmpty<BTreeMap<K, V>> {
53    pub(crate) fn assert_non_empty_map<I>(it: I) -> Self
54    where
55        I: IntoIterator<Item = (K, V)>,
56    {
57        let mut m = BTreeMap::from_iter(it);
58        let fst = m.pop_first().expect("non empty map");
59        Self(fst, m)
60    }
61
62    pub(crate) fn first(&self) -> (&K, &V) {
63        (&self.0.0, &self.0.1)
64    }
65
66    pub(crate) fn last(&self) -> (&K, &V) {
67        self.1.last_key_value().unwrap_or((&self.0.0, &self.0.1))
68    }
69
70    pub(crate) fn get(&self, k: &K) -> Option<&V> {
71        (&self.0.0 == k)
72            .then_some(&self.0.1)
73            .or_else(|| self.1.get(k))
74    }
75
76    pub(crate) fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
77        once((&self.0.0, &self.0.1)).chain(self.1.iter())
78    }
79}