1use failure::bail;
2use failure::format_err;
3use failure::Error;
4use std::convert::TryFrom;
5use std::ops::Deref;
6
7pub trait AtCollection<T>
8where
9 Self: Sized,
10{
11 fn as_slice(&self) -> &[T];
12
13 fn as_vec(self) -> Vec<T>;
14
15 fn into_iter(self) -> std::vec::IntoIter<T> {
16 self.as_vec().into_iter()
17 }
18
19 fn iter(&self) -> std::slice::Iter<T> {
20 self.as_slice().iter()
21 }
22}
23
24macro_rules! atleast {
25 ($name:ident, $n:literal, $($cons:ident),*) => {
26
27 #[derive(Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
28 pub struct $name<T> {
29 raw: Vec<T>,
30 }
31
32 impl<T> $name<T> {
33 pub fn new(
34 $($cons: T),*
35 ) -> $name<T> {
36 $name::new_and($($cons),*, Vec::new())
37 }
38
39 pub fn new_and($($cons: T),*, mut v: Vec<T>) -> $name<T> {
40 let mut raw = vec![$($cons),*];
41 raw.append(&mut v);
42 $name { raw }
43 }
44 }
45
46 impl<T> AtCollection<T> for $name<T> {
47 fn as_slice(&self) -> &[T] {
48 self.raw.as_slice()
49 }
50
51 fn as_vec(self) -> Vec<T> {
52 self.raw
53 }
54 }
55 impl<T> Deref for $name<T> {
56 type Target = [T];
57
58 fn deref(&self) -> &Self::Target {
59 &self.as_slice()
60 }
61 }
62
63 impl<T> TryFrom<Vec<T>> for $name<T> {
64 type Error = Error;
65
66 fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
67 if value.len() < $n {
68 bail!("{} requires at least {} values", stringify!($name), stringify!($n))
69 } else {
70 Ok($name { raw: value })
71 }
72 }
73 }
74
75 };
76}
77
78atleast! {AtLeastOne, 1, a}
79atleast! {AtLeastTwo, 2, a, b}
80atleast! {AtLeastThree, 3, a, b, c}
81atleast! {AtLeastFour, 4, a, b, c, d}
82
83impl<T> AtLeastOne<T> {
84 pub fn one(&self) -> Result<&T, Error> {
85 match self.raw.len() {
86 1 => Ok(&self.raw[0]),
87 _ => Err(format_err!("AtLeastOne has more than one element")),
88 }
89 }
90
91 pub fn to_one(&self) -> &T {
92 self.one().unwrap()
93 }
94}
95
96#[macro_export]
97macro_rules! atl1 {
98 ($($cons:expr),*) => {
99 AtLeastOne::try_from(vec![$($cons),*])
100 }
101}
102
103#[macro_export]
104macro_rules! atl2 {
105 ($($cons:expr),*) => {
106 $crate::AtLeastTwo::try_from(vec![$($cons),*])
107 }
108}
109
110#[macro_export]
111macro_rules! atl3 {
112 ($($cons:expr),*) => {
113 AtLeastThree::try_from(vec![$($cons),*])
114 }
115}
116
117#[macro_export]
118macro_rules! atl4 {
119 ($($cons:expr),*) => {
120 AtLeastFour::try_from(vec![$($cons),*])
121 }
122}
123
124pub struct AtMostOne<T> {
125 raw: Vec<T>,
126}
127
128impl<T> AtMostOne<T> {
129 pub fn new(a: T) -> AtMostOne<T> {
130 let raw = vec![a];
131 AtMostOne { raw }
132 }
133}
134
135impl<T> AtCollection<T> for AtMostOne<T> {
136 fn as_slice(&self) -> &[T] {
137 self.raw.as_slice()
138 }
139
140 fn as_vec(self) -> Vec<T> {
141 self.raw
142 }
143}
144
145pub struct AtMostTwo<T> {
146 raw: Vec<T>,
147}
148
149impl<T> AtMostTwo<T> {
150 pub fn new(a: T) -> AtMostTwo<T> {
151 let raw = vec![a];
152 AtMostTwo { raw }
153 }
154}
155
156impl<T> AtCollection<T> for AtMostTwo<T> {
157 fn as_slice(&self) -> &[T] {
158 self.raw.as_slice()
159 }
160
161 fn as_vec(self) -> Vec<T> {
162 self.raw
163 }
164}
165
166pub struct AtMostThree<T> {
167 raw: Vec<T>,
168}
169
170impl<T> AtMostThree<T> {
171 pub fn new(a: T) -> AtMostThree<T> {
172 let raw = vec![a];
173 AtMostThree { raw }
174 }
175}
176
177impl<T> AtCollection<T> for AtMostThree<T> {
178 fn as_slice(&self) -> &[T] {
179 self.raw.as_slice()
180 }
181
182 fn as_vec(self) -> Vec<T> {
183 self.raw
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn iter() {
193 let alt = AtLeastTwo::new(1, 2);
194
195 let mut i = alt.iter();
196 assert_eq!(i.next(), Some(&1));
197 assert_eq!(i.next(), Some(&2));
198 }
199
200 #[test]
201 fn into_iter() {
202 let alt = AtLeastTwo::new(1, 2);
203
204 let mut i = alt.into_iter();
205 assert_eq!(i.next(), Some(1));
206 assert_eq!(i.next(), Some(2));
207 }
208
209 #[test]
210 fn for_iter() {
211 let alt = AtLeastOne::new(1);
212
213 for i in alt.into_iter() {
214 assert_eq!(i, 1);
215 }
216 }
217
218 #[test]
219 fn length() {
220 let alt = AtLeastTwo::new(1, 2);
221
222 assert_eq!(alt.len(), 2);
223 }
224
225 #[test]
226 fn try_from() {
227 assert!(AtLeastThree::try_from(vec![1, 2, 3]).is_ok());
228 assert!(AtLeastThree::try_from(vec![1, 2]).is_err());
229
230 assert!(AtLeastTwo::try_from(vec![1, 2, 3]).is_ok());
231 assert!(AtLeastTwo::try_from(vec![1]).is_err());
232 }
233
234 #[test]
235 fn at_least_one_macro() {
236 let atl1 = atl1![1].unwrap();
237 assert_eq!(1, atl1.len());
238
239 let atl1 = atl1![1, 2, 3].unwrap();
240 assert_eq!(3, atl1.len());
241 }
242
243 #[test]
244 fn at_least_two_macro() {
245 let atl2 = atl2![1];
246 assert!(atl2.is_err());
247 }
248
249 #[test]
250 fn at_least_two_expr() {
251 let atl2 = atl2![1 + 2, 3 + 4];
252 assert_eq!(atl2.unwrap().len(), 2);
253 }
254
255 #[test]
256 fn to_one() {
257 let ato1 = atl1![1].unwrap();
258 let ato2 = atl1![1, 2].unwrap();
259
260 assert!(ato1.one().is_ok());
261 assert!(ato2.one().is_err());
262
263 assert_eq!(ato1.to_one(), &1);
264 }
265}