1extern crate self as enum_tree;
2
3pub use enum_tree_derive::{DeepVariants, EnumFrom, IntoAncestors};
4
5pub trait DeepVariants: Sized + 'static
31{
32 const DEEP_VARIANTS: &'static [Self];
34}
35
36pub trait DeepCount
43{
44 const DEEP_COUNT: usize;
46}
47impl<T: DeepVariants> DeepCount for T
48{
49 const DEEP_COUNT: usize = Self::DEEP_VARIANTS.len();
50}
51
52#[cfg(test)]
53mod tests
54{
55 use enum_tree_derive::DeepVariants;
56
57 use super::*;
58
59 #[derive(DeepVariants, PartialEq, Eq, Debug)]
60 enum EmptyEnum {}
61
62 #[derive(DeepVariants, PartialEq, Eq, Debug)]
63 enum UnitEnum2
64 {
65 A,
66 B,
67 }
68
69 #[derive(DeepVariants, PartialEq, Eq, Debug)]
70 enum UnitEnum3
71 {
72 A,
73 B,
74 C,
75 }
76
77 #[derive(DeepVariants, PartialEq, Eq, Debug)]
78 enum UnitEnum5
79 {
80 A,
81 B,
82 C,
83 D,
84 E,
85 }
86
87 #[derive(DeepVariants, PartialEq, Eq, Debug)]
88 enum SingletonEnum
89 {
90 Empty(EmptyEnum),
91 Var2(UnitEnum2),
92 Var3(UnitEnum3),
93 Var5(UnitEnum5),
94 }
95
96 #[derive(DeepVariants, PartialEq, Eq, Debug)]
104 enum MixedEnum
105 {
106 UnitA,
107 Empty(EmptyEnum),
108 Var2(UnitEnum2),
109 UnitB,
110 Tuple(SingletonEnum),
111 Var5(UnitEnum5),
112 UnitC,
113 }
114
115 #[test]
116 fn empty_enum()
117 {
118 assert_eq!(EmptyEnum::DEEP_VARIANTS, &[]);
119 assert_eq!(EmptyEnum::DEEP_COUNT, 0);
120 }
121
122 #[test]
123 fn unit_enum()
124 {
125 assert_eq!(UnitEnum3::DEEP_COUNT, 3);
126 }
127
128 #[test]
129 #[expect(
130 clippy::identity_op,
131 reason = "showing the sum decomposition aids readability"
132 )]
133 fn singleton_variants()
134 {
135 assert_eq!(SingletonEnum::DEEP_COUNT, 0 + 2 + 3 + 5);
136 }
137
138 #[test]
139 #[expect(
140 clippy::identity_op,
141 reason = "showing the sum decomposition aids readability"
142 )]
143 fn mixed_variants()
144 {
145 assert_eq!(
146 MixedEnum::DEEP_COUNT,
147 1 + 0 + 2 + 1 + SingletonEnum::DEEP_COUNT + 5 + 1
148 );
149
150 let desired = &[
151 MixedEnum::UnitA,
152 MixedEnum::Var2(UnitEnum2::A),
153 MixedEnum::Var2(UnitEnum2::B),
154 MixedEnum::UnitB,
155 MixedEnum::Tuple(SingletonEnum::Var2(UnitEnum2::A)),
156 MixedEnum::Tuple(SingletonEnum::Var2(UnitEnum2::B)),
157 MixedEnum::Tuple(SingletonEnum::Var3(UnitEnum3::A)),
158 MixedEnum::Tuple(SingletonEnum::Var3(UnitEnum3::B)),
159 MixedEnum::Tuple(SingletonEnum::Var3(UnitEnum3::C)),
160 MixedEnum::Tuple(SingletonEnum::Var5(UnitEnum5::A)),
161 MixedEnum::Tuple(SingletonEnum::Var5(UnitEnum5::B)),
162 MixedEnum::Tuple(SingletonEnum::Var5(UnitEnum5::C)),
163 MixedEnum::Tuple(SingletonEnum::Var5(UnitEnum5::D)),
164 MixedEnum::Tuple(SingletonEnum::Var5(UnitEnum5::E)),
165 MixedEnum::Var5(UnitEnum5::A),
166 MixedEnum::Var5(UnitEnum5::B),
167 MixedEnum::Var5(UnitEnum5::C),
168 MixedEnum::Var5(UnitEnum5::D),
169 MixedEnum::Var5(UnitEnum5::E),
170 MixedEnum::UnitC,
171 ];
172 assert_eq!(MixedEnum::DEEP_VARIANTS, desired);
173 }
174
175 #[derive(DeepVariants, PartialEq, Eq, Debug)]
176 #[expect(
177 dead_code,
178 reason = "variants exist solely to exercise the skip attribute"
179 )]
180 enum SkippedUnitEnum
181 {
182 A,
183 #[enum_tree(skip)]
184 B,
185 C,
186 }
187
188 #[derive(DeepVariants, PartialEq, Eq, Debug)]
189 #[expect(
190 dead_code,
191 reason = "variants exist solely to exercise the skip attribute"
192 )]
193 enum SkippedSingletonEnum
194 {
195 Unit,
196 Nested(UnitEnum3),
197 #[enum_tree(skip)]
198 Skipped(UnitEnum5),
199 }
200
201 #[test]
202 fn skip_unit_variant()
203 {
204 assert_eq!(SkippedUnitEnum::DEEP_COUNT, 2);
205 assert_eq!(
206 SkippedUnitEnum::DEEP_VARIANTS,
207 &[SkippedUnitEnum::A, SkippedUnitEnum::C]
208 );
209 }
210
211 #[test]
212 fn skip_singleton_variant()
213 {
214 assert_eq!(SkippedSingletonEnum::DEEP_COUNT, 1 + 3);
215 assert_eq!(
216 SkippedSingletonEnum::DEEP_VARIANTS,
217 &[
218 SkippedSingletonEnum::Unit,
219 SkippedSingletonEnum::Nested(UnitEnum3::A),
220 SkippedSingletonEnum::Nested(UnitEnum3::B),
221 SkippedSingletonEnum::Nested(UnitEnum3::C),
222 ]
223 );
224 }
225}
226
227#[cfg(test)]
228mod enum_from_tests
229{
230 use enum_tree_derive::EnumFrom;
231
232 #[derive(EnumFrom, PartialEq, Eq, Debug)]
233 enum TupleSingleton
234 {
235 #[expect(dead_code, reason = "exercising the EnumFrom derive on a unit variant")]
236 Unit,
237 Int(#[enum_from(from)] i32),
238 Str(#[enum_from(from)] String),
239 }
240
241 #[test]
242 fn tuple_singleton_from()
243 {
244 let a: TupleSingleton = 7_i32.into();
245 assert_eq!(a, TupleSingleton::Int(7));
246 let b: TupleSingleton = String::from("hi").into();
247 assert_eq!(b, TupleSingleton::Str("hi".to_owned()));
248 }
249
250 #[derive(PartialEq, Eq, Debug)]
251 struct Wrapper(i32);
252
253 fn wrap(n: i32) -> Wrapper
254 {
255 Wrapper(n)
256 }
257
258 #[derive(EnumFrom, PartialEq, Eq, Debug)]
259 enum ViaFunc
260 {
261 Wrapped(#[enum_from(from = i32, via = wrap)] Wrapper),
262 }
263
264 #[test]
265 fn via_func()
266 {
267 let v: ViaFunc = 5_i32.into();
268 assert_eq!(v, ViaFunc::Wrapped(Wrapper(5)));
269 }
270
271 #[derive(EnumFrom, PartialEq, Eq, Debug)]
272 enum ViaClosure
273 {
274 Doubled(#[enum_from(from = i32, via = |x| x * 2)] i32),
275 }
276
277 #[test]
278 fn via_closure()
279 {
280 let v: ViaClosure = 4_i32.into();
281 assert_eq!(v, ViaClosure::Doubled(8));
282 }
283
284 #[derive(PartialEq, Eq, Debug, Default)]
285 struct HasDefault
286 {
287 inner: i32,
288 }
289
290 fn make_has_default() -> HasDefault
291 {
292 HasDefault { inner: 42 }
293 }
294
295 #[derive(PartialEq, Eq, Debug)]
296 struct Singleton; #[derive(EnumFrom, PartialEq, Eq, Debug)]
299 enum MultiField
300 {
301 Named
302 {
303 #[enum_from(from)]
304 #[enum_from(default = || 4_i64)]
305 src: i64,
306
307 #[enum_from(default)]
308 a: HasDefault,
309
310 #[enum_from(default = make_has_default)]
311 b: HasDefault,
312
313 #[enum_from(from, default = "make_has_default")]
314 c: HasDefault,
315
316 #[enum_from(default = HasDefault { inner: 9 })]
317 d: HasDefault,
318
319 e: Singleton,
320 },
321 Unnamed(
322 #[enum_from(from)] i32,
323 #[enum_from(default)] HasDefault,
324 #[enum_from(default = HasDefault { inner: 11 })] HasDefault,
325 ),
326 }
327
328 #[test]
329 fn multi_field_named()
330 {
331 let v: MultiField = 1_i64.into();
332 assert_eq!(
333 v,
334 MultiField::Named {
335 src: 1,
336 a: HasDefault::default(),
337 b: HasDefault { inner: 42 },
338 c: HasDefault { inner: 42 },
339 d: HasDefault { inner: 9 },
340 e: Singleton,
341 }
342 );
343 let w: MultiField = 6_i32.into();
344 assert_eq!(
345 w,
346 MultiField::Unnamed(6, HasDefault::default(), HasDefault { inner: 11 })
347 );
348
349 let x: MultiField = HasDefault { inner: 22 }.into();
350 assert_eq!(
351 x,
352 MultiField::Named {
353 src: 4,
354 a: HasDefault::default(),
355 b: HasDefault { inner: 42 },
356 c: HasDefault { inner: 22 },
357 d: HasDefault { inner: 9 },
358 e: Singleton,
359 }
360 );
361 }
362
363 #[derive(EnumFrom, PartialEq, Eq, Debug)]
366 enum MultiFieldUnnamed
367 {
368 Unnamed(
369 #[enum_from(from)] i64,
370 #[enum_from(default)] HasDefault,
371 #[enum_from(default = HasDefault { inner: 11 })] HasDefault,
372 ),
373 }
374
375 #[test]
376 fn multi_field_unnamed()
377 {
378 let v: MultiFieldUnnamed = 3_i64.into();
379 assert_eq!(
380 v,
381 MultiFieldUnnamed::Unnamed(3, HasDefault::default(), HasDefault { inner: 11 },)
382 );
383 }
384
385 #[derive(EnumFrom, PartialEq, Eq, Debug)]
386 enum MultipleFromSameVariant
387 {
388 Both(#[enum_from(from)] i32, #[enum_from(from)] String),
389 }
390
391 #[test]
392 fn multiple_from_same_variant()
393 {
394 let a: MultipleFromSameVariant = 5_i32.into();
395 assert_eq!(a, MultipleFromSameVariant::Both(5, String::default()));
396
397 let b: MultipleFromSameVariant = "x".to_owned().into();
398 assert_eq!(
399 b,
400 MultipleFromSameVariant::Both(i32::default(), "x".to_owned())
401 );
402 }
403}