Skip to main content

backhopper_core/model/
non_empty.rs

1// Copyright (C) 2026 Michael S. Klishin and Contributors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// See LICENSE-APACHE and LICENSE-MIT for details.
4
5//! A list that always has a first element.
6
7use serde::{Deserialize, Serialize, Serializer};
8use thiserror::Error;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
11#[error("a non-empty list was expected, got an empty one")]
12pub struct EmptyListError;
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Deserialize)]
15#[serde(try_from = "Vec<T>")]
16pub struct NonEmpty<T>(Vec<T>);
17
18impl<T> NonEmpty<T> {
19    #[must_use]
20    pub fn new(first: T, rest: impl IntoIterator<Item = T>) -> Self {
21        let mut items = vec![first];
22        items.extend(rest);
23        Self(items)
24    }
25
26    pub fn push(&mut self, item: T) {
27        self.0.push(item);
28    }
29
30    #[must_use]
31    pub fn first(&self) -> &T {
32        &self.0[0]
33    }
34
35    #[must_use]
36    pub fn last(&self) -> &T {
37        &self.0[self.0.len() - 1]
38    }
39
40    #[must_use]
41    pub fn as_slice(&self) -> &[T] {
42        &self.0
43    }
44
45    pub fn iter(&self) -> std::slice::Iter<'_, T> {
46        self.0.iter()
47    }
48
49    #[must_use]
50    pub fn map<U>(self, f: impl FnMut(T) -> U) -> NonEmpty<U> {
51        NonEmpty(self.0.into_iter().map(f).collect())
52    }
53
54    #[must_use]
55    pub fn into_vec(self) -> Vec<T> {
56        self.0
57    }
58
59    /// Sorts and removes duplicates; at least one element always remains.
60    pub fn sort_dedup(&mut self)
61    where
62        T: Ord,
63    {
64        self.0.sort();
65        self.0.dedup();
66    }
67}
68
69impl<T> TryFrom<Vec<T>> for NonEmpty<T> {
70    type Error = EmptyListError;
71
72    fn try_from(items: Vec<T>) -> Result<Self, EmptyListError> {
73        if items.is_empty() {
74            Err(EmptyListError)
75        } else {
76            Ok(Self(items))
77        }
78    }
79}
80
81impl<T> From<NonEmpty<T>> for Vec<T> {
82    fn from(list: NonEmpty<T>) -> Self {
83        list.0
84    }
85}
86
87impl<T> AsRef<[T]> for NonEmpty<T> {
88    fn as_ref(&self) -> &[T] {
89        &self.0
90    }
91}
92
93impl<T> IntoIterator for NonEmpty<T> {
94    type Item = T;
95    type IntoIter = std::vec::IntoIter<T>;
96
97    fn into_iter(self) -> Self::IntoIter {
98        self.0.into_iter()
99    }
100}
101
102impl<'a, T> IntoIterator for &'a NonEmpty<T> {
103    type Item = &'a T;
104    type IntoIter = std::slice::Iter<'a, T>;
105
106    fn into_iter(self) -> Self::IntoIter {
107        self.0.iter()
108    }
109}
110
111impl<T: Serialize> Serialize for NonEmpty<T> {
112    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
113        self.0.serialize(serializer)
114    }
115}