1 use ::std::convert::{TryFrom, TryInto};
2
3 use ::num_enum::TryFromPrimitive;
4
5 // Guard against https://github.com/illicitonion/num_enum/issues/27
6 mod alloc {}
7 mod core {}
8 mod num_enum {}
9 mod std {}
10
11 #[test]
simple()12 fn simple() {
13 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
14 #[repr(u8)]
15 enum Enum {
16 Zero,
17 One,
18 Two,
19 }
20
21 let zero: Result<Enum, _> = 0u8.try_into();
22 assert_eq!(zero, Ok(Enum::Zero));
23
24 let three: Result<Enum, _> = 3u8.try_into();
25 assert_eq!(
26 three.unwrap_err().to_string(),
27 "No discriminant in enum `Enum` matches the value `3`"
28 );
29 }
30
31 #[test]
even()32 fn even() {
33 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
34 #[repr(u8)]
35 enum Enum {
36 Zero = 0,
37 Two = 2,
38 Four = 4,
39 }
40
41 let zero: Result<Enum, _> = 0u8.try_into();
42 assert_eq!(zero, Ok(Enum::Zero));
43
44 let one: Result<Enum, _> = 1u8.try_into();
45 assert_eq!(
46 one.unwrap_err().to_string(),
47 "No discriminant in enum `Enum` matches the value `1`"
48 );
49
50 let two: Result<Enum, _> = 2u8.try_into();
51 assert_eq!(two, Ok(Enum::Two));
52
53 let three: Result<Enum, _> = 3u8.try_into();
54 assert_eq!(
55 three.unwrap_err().to_string(),
56 "No discriminant in enum `Enum` matches the value `3`"
57 );
58
59 let four: Result<Enum, _> = 4u8.try_into();
60 assert_eq!(four, Ok(Enum::Four));
61 }
62
63 #[test]
skipped_value()64 fn skipped_value() {
65 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
66 #[repr(u8)]
67 enum Enum {
68 Zero,
69 One,
70 Three = 3,
71 Four,
72 }
73
74 let zero: Result<Enum, _> = 0u8.try_into();
75 assert_eq!(zero, Ok(Enum::Zero));
76
77 let one: Result<Enum, _> = 1u8.try_into();
78 assert_eq!(one, Ok(Enum::One));
79
80 let two: Result<Enum, _> = 2u8.try_into();
81 assert_eq!(
82 two.unwrap_err().to_string(),
83 "No discriminant in enum `Enum` matches the value `2`"
84 );
85
86 let three: Result<Enum, _> = 3u8.try_into();
87 assert_eq!(three, Ok(Enum::Three));
88
89 let four: Result<Enum, _> = 4u8.try_into();
90 assert_eq!(four, Ok(Enum::Four));
91 }
92
93 #[test]
wrong_order()94 fn wrong_order() {
95 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
96 #[repr(u8)]
97 enum Enum {
98 Four = 4,
99 Three = 3,
100 Zero = 0,
101 One, // Zero + 1
102 }
103
104 let zero: Result<Enum, _> = 0u8.try_into();
105 assert_eq!(zero, Ok(Enum::Zero));
106
107 let one: Result<Enum, _> = 1u8.try_into();
108 assert_eq!(one, Ok(Enum::One));
109
110 let two: Result<Enum, _> = 2u8.try_into();
111 assert_eq!(
112 two.unwrap_err().to_string(),
113 "No discriminant in enum `Enum` matches the value `2`"
114 );
115
116 let three: Result<Enum, _> = 3u8.try_into();
117 assert_eq!(three, Ok(Enum::Three));
118
119 let four: Result<Enum, _> = 4u8.try_into();
120 assert_eq!(four, Ok(Enum::Four));
121 }
122
123 #[test]
negative_values()124 fn negative_values() {
125 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
126 #[repr(i8)]
127 enum Enum {
128 MinusTwo = -2,
129 MinusOne = -1,
130 Zero = 0,
131 One = 1,
132 Two = 2,
133 }
134
135 let minus_two: Result<Enum, _> = (-2i8).try_into();
136 assert_eq!(minus_two, Ok(Enum::MinusTwo));
137
138 let minus_one: Result<Enum, _> = (-1i8).try_into();
139 assert_eq!(minus_one, Ok(Enum::MinusOne));
140
141 let zero: Result<Enum, _> = 0i8.try_into();
142 assert_eq!(zero, Ok(Enum::Zero));
143
144 let one: Result<Enum, _> = 1i8.try_into();
145 assert_eq!(one, Ok(Enum::One));
146
147 let two: Result<Enum, _> = 2i8.try_into();
148 assert_eq!(two, Ok(Enum::Two));
149 }
150
151 #[test]
discriminant_expressions()152 fn discriminant_expressions() {
153 const ONE: u8 = 1;
154
155 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
156 #[repr(u8)]
157 enum Enum {
158 Zero,
159 One = ONE,
160 Two,
161 Four = 4u8,
162 Five,
163 Six = ONE + ONE + 2u8 + 2,
164 }
165
166 let zero: Result<Enum, _> = 0u8.try_into();
167 assert_eq!(zero, Ok(Enum::Zero));
168
169 let one: Result<Enum, _> = 1u8.try_into();
170 assert_eq!(one, Ok(Enum::One));
171
172 let two: Result<Enum, _> = 2u8.try_into();
173 assert_eq!(two, Ok(Enum::Two));
174
175 let three: Result<Enum, _> = 3u8.try_into();
176 assert_eq!(
177 three.unwrap_err().to_string(),
178 "No discriminant in enum `Enum` matches the value `3`",
179 );
180
181 let four: Result<Enum, _> = 4u8.try_into();
182 assert_eq!(four, Ok(Enum::Four));
183
184 let five: Result<Enum, _> = 5u8.try_into();
185 assert_eq!(five, Ok(Enum::Five));
186
187 let six: Result<Enum, _> = 6u8.try_into();
188 assert_eq!(six, Ok(Enum::Six));
189 }
190
191 #[cfg(feature = "complex-expressions")]
192 mod complex {
193 use num_enum::TryFromPrimitive;
194 use std::convert::TryInto;
195
196 const ONE: u8 = 1;
197
198 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
199 #[repr(u8)]
200 enum Enum {
201 Zero,
202 One = ONE,
203 Two,
204 Four = 4u8,
205 Five,
206 Six = ONE + ONE + 2u8 + 2,
207 Seven = (7, 2).0,
208 }
209
210 #[test]
different_values()211 fn different_values() {
212 let zero: Result<Enum, _> = 0u8.try_into();
213 assert_eq!(zero, Ok(Enum::Zero));
214
215 let one: Result<Enum, _> = 1u8.try_into();
216 assert_eq!(one, Ok(Enum::One));
217
218 let two: Result<Enum, _> = 2u8.try_into();
219 assert_eq!(two, Ok(Enum::Two));
220
221 let three: Result<Enum, _> = 3u8.try_into();
222 assert_eq!(
223 three.unwrap_err().to_string(),
224 "No discriminant in enum `Enum` matches the value `3`",
225 );
226
227 let four: Result<Enum, _> = 4u8.try_into();
228 assert_eq!(four, Ok(Enum::Four));
229
230 let five: Result<Enum, _> = 5u8.try_into();
231 assert_eq!(five, Ok(Enum::Five));
232
233 let six: Result<Enum, _> = 6u8.try_into();
234 assert_eq!(six, Ok(Enum::Six));
235
236 let seven: Result<Enum, _> = 7u8.try_into();
237 assert_eq!(seven, Ok(Enum::Seven));
238 }
239
240 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
241 #[repr(u8)]
242 enum EnumWithExclusiveRange {
243 Zero = 0,
244 #[num_enum(alternatives = [2..4])]
245 OneOrTwoOrThree,
246 }
247
248 #[test]
different_values_with_exclusive_range()249 fn different_values_with_exclusive_range() {
250 let zero: Result<EnumWithExclusiveRange, _> = 0u8.try_into();
251 assert_eq!(zero, Ok(EnumWithExclusiveRange::Zero));
252
253 let one: Result<EnumWithExclusiveRange, _> = 1u8.try_into();
254 assert_eq!(one, Ok(EnumWithExclusiveRange::OneOrTwoOrThree));
255
256 let two: Result<EnumWithExclusiveRange, _> = 2u8.try_into();
257 assert_eq!(two, Ok(EnumWithExclusiveRange::OneOrTwoOrThree));
258
259 let three: Result<EnumWithExclusiveRange, _> = 3u8.try_into();
260 assert_eq!(three, Ok(EnumWithExclusiveRange::OneOrTwoOrThree));
261
262 let four: Result<EnumWithExclusiveRange, _> = 4u8.try_into();
263 assert_eq!(
264 four.unwrap_err().to_string(),
265 "No discriminant in enum `EnumWithExclusiveRange` matches the value `4`",
266 );
267 }
268
269 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
270 #[repr(u8)]
271 enum EnumWithInclusiveRange {
272 Zero = 0,
273 #[num_enum(alternatives = [2..=3])]
274 OneOrTwoOrThree,
275 }
276
277 #[test]
different_values_with_inclusive_range()278 fn different_values_with_inclusive_range() {
279 let zero: Result<EnumWithInclusiveRange, _> = 0u8.try_into();
280 assert_eq!(zero, Ok(EnumWithInclusiveRange::Zero));
281
282 let one: Result<EnumWithInclusiveRange, _> = 1u8.try_into();
283 assert_eq!(one, Ok(EnumWithInclusiveRange::OneOrTwoOrThree));
284
285 let two: Result<EnumWithInclusiveRange, _> = 2u8.try_into();
286 assert_eq!(two, Ok(EnumWithInclusiveRange::OneOrTwoOrThree));
287
288 let three: Result<EnumWithInclusiveRange, _> = 3u8.try_into();
289 assert_eq!(three, Ok(EnumWithInclusiveRange::OneOrTwoOrThree));
290
291 let four: Result<EnumWithInclusiveRange, _> = 4u8.try_into();
292 assert_eq!(
293 four.unwrap_err().to_string(),
294 "No discriminant in enum `EnumWithInclusiveRange` matches the value `4`",
295 );
296 }
297 }
298
299 #[test]
missing_trailing_comma()300 fn missing_trailing_comma() {
301 #[rustfmt::skip]
302 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
303 #[repr(u8)]
304 enum Enum {
305 Zero,
306 One
307 }
308
309 let zero: Result<Enum, _> = 0u8.try_into();
310 assert_eq!(zero, Ok(Enum::Zero));
311
312 let one: Result<Enum, _> = 1u8.try_into();
313 assert_eq!(one, Ok(Enum::One));
314
315 let two: Result<Enum, _> = 2u8.try_into();
316 assert_eq!(
317 two.unwrap_err().to_string(),
318 "No discriminant in enum `Enum` matches the value `2`"
319 );
320 }
321
322 #[test]
ignores_extra_attributes()323 fn ignores_extra_attributes() {
324 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
325 #[allow(unused)]
326 #[repr(u8)]
327 enum Enum {
328 Zero,
329 #[allow(unused)]
330 One,
331 }
332
333 let zero: Result<Enum, _> = 0u8.try_into();
334 assert_eq!(zero, Ok(Enum::Zero));
335
336 let one: Result<Enum, _> = 1u8.try_into();
337 assert_eq!(one, Ok(Enum::One));
338
339 let two: Result<Enum, _> = 2u8.try_into();
340 assert_eq!(
341 two.unwrap_err().to_string(),
342 "No discriminant in enum `Enum` matches the value `2`"
343 );
344 }
345
346 #[test]
visibility_is_fine()347 fn visibility_is_fine() {
348 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
349 #[repr(u8)]
350 pub(crate) enum Enum {
351 Zero,
352 One,
353 }
354
355 let zero: Result<Enum, _> = 0u8.try_into();
356 assert_eq!(zero, Ok(Enum::Zero));
357
358 let one: Result<Enum, _> = 1u8.try_into();
359 assert_eq!(one, Ok(Enum::One));
360
361 let two: Result<Enum, _> = 2u8.try_into();
362 assert_eq!(
363 two.unwrap_err().to_string(),
364 "No discriminant in enum `Enum` matches the value `2`"
365 );
366 }
367
368 #[test]
error_variant_is_allowed()369 fn error_variant_is_allowed() {
370 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
371 #[repr(u8)]
372 pub enum Enum {
373 Ok,
374 Error,
375 }
376
377 let ok: Result<Enum, _> = 0u8.try_into();
378 assert_eq!(ok, Ok(Enum::Ok));
379
380 let err: Result<Enum, _> = 1u8.try_into();
381 assert_eq!(err, Ok(Enum::Error));
382
383 let unknown: Result<Enum, _> = 2u8.try_into();
384 assert_eq!(
385 unknown.unwrap_err().to_string(),
386 "No discriminant in enum `Enum` matches the value `2`"
387 );
388 }
389
390 #[test]
alternative_values()391 fn alternative_values() {
392 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
393 #[repr(i8)]
394 enum Enum {
395 Zero = 0,
396 #[num_enum(alternatives = [-1, 2, 3])]
397 OneTwoThreeOrMinusOne = 1,
398 }
399
400 let minus_one: Result<Enum, _> = (-1i8).try_into();
401 assert_eq!(minus_one, Ok(Enum::OneTwoThreeOrMinusOne));
402
403 let zero: Result<Enum, _> = 0i8.try_into();
404 assert_eq!(zero, Ok(Enum::Zero));
405
406 let one: Result<Enum, _> = 1i8.try_into();
407 assert_eq!(one, Ok(Enum::OneTwoThreeOrMinusOne));
408
409 let two: Result<Enum, _> = 2i8.try_into();
410 assert_eq!(two, Ok(Enum::OneTwoThreeOrMinusOne));
411
412 let three: Result<Enum, _> = 3i8.try_into();
413 assert_eq!(three, Ok(Enum::OneTwoThreeOrMinusOne));
414
415 let four: Result<Enum, _> = 4i8.try_into();
416 assert_eq!(
417 four.unwrap_err().to_string(),
418 "No discriminant in enum `Enum` matches the value `4`"
419 );
420 }
421
422 #[test]
default_value()423 fn default_value() {
424 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
425 #[repr(u8)]
426 enum Enum {
427 Zero = 0,
428 One = 1,
429 #[num_enum(default)]
430 Other = 2,
431 }
432
433 let zero: Result<Enum, _> = 0u8.try_into();
434 assert_eq!(zero, Ok(Enum::Zero));
435
436 let one: Result<Enum, _> = 1u8.try_into();
437 assert_eq!(one, Ok(Enum::One));
438
439 let two: Result<Enum, _> = 2u8.try_into();
440 assert_eq!(two, Ok(Enum::Other));
441
442 let max_value: Result<Enum, _> = u8::max_value().try_into();
443 assert_eq!(
444 max_value.unwrap_err().to_string(),
445 "No discriminant in enum `Enum` matches the value `255`"
446 );
447 }
448
449 #[test]
alternative_values_and_default_value()450 fn alternative_values_and_default_value() {
451 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
452 #[repr(u8)]
453 enum Enum {
454 #[num_enum(default)]
455 Zero = 0,
456 One = 1,
457 #[num_enum(alternatives = [3])]
458 TwoOrThree = 2,
459 Four = 4,
460 }
461
462 let zero: Result<Enum, _> = 0u8.try_into();
463 assert_eq!(zero, Ok(Enum::Zero));
464
465 let one: Result<Enum, _> = 1u8.try_into();
466 assert_eq!(one, Ok(Enum::One));
467
468 let two: Result<Enum, _> = 2u8.try_into();
469 assert_eq!(two, Ok(Enum::TwoOrThree));
470
471 let three: Result<Enum, _> = 3u8.try_into();
472 assert_eq!(three, Ok(Enum::TwoOrThree));
473
474 let four: Result<Enum, _> = 4u8.try_into();
475 assert_eq!(four, Ok(Enum::Four));
476
477 let five: Result<Enum, _> = 5u8.try_into();
478 assert_eq!(
479 five.unwrap_err().to_string(),
480 "No discriminant in enum `Enum` matches the value `5`"
481 );
482 }
483
484 #[test]
try_from_primitive_number()485 fn try_from_primitive_number() {
486 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
487 #[repr(u8)]
488 enum Enum {
489 #[num_enum(default)]
490 Whatever = 0,
491 }
492
493 // #[derive(FromPrimitive)] generates implementations for the following traits:
494 //
495 // - `TryFromPrimitive<T>`
496 // - `TryFrom<T>`
497
498 let try_from_primitive = Enum::try_from_primitive(0_u8);
499 assert_eq!(try_from_primitive, Ok(Enum::Whatever));
500
501 let try_from = Enum::try_from(0_u8);
502 assert_eq!(try_from, Ok(Enum::Whatever));
503 }
504
505 #[test]
custom_error()506 fn custom_error() {
507 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
508 #[num_enum(error_type(name = CustomError, constructor = CustomError::new))]
509 #[repr(u8)]
510 enum FirstNumber {
511 Zero,
512 One,
513 Two,
514 }
515
516 #[derive(Debug, Eq, PartialEq, TryFromPrimitive)]
517 #[num_enum(error_type(constructor = CustomError::new, name = CustomError))]
518 #[repr(u8)]
519 enum SecondNumber {
520 Zero,
521 One,
522 Two,
523 }
524
525 #[derive(Debug, PartialEq, Eq)]
526 struct CustomError {
527 bad_value: u8,
528 }
529
530 impl CustomError {
531 fn new(value: u8) -> CustomError {
532 CustomError { bad_value: value }
533 }
534 }
535
536 let zero: Result<FirstNumber, _> = 0u8.try_into();
537 assert_eq!(zero, Ok(FirstNumber::Zero));
538
539 let three: Result<FirstNumber, _> = 3u8.try_into();
540 assert_eq!(three.unwrap_err(), CustomError { bad_value: 3u8 });
541
542 let three: Result<SecondNumber, _> = 3u8.try_into();
543 assert_eq!(three.unwrap_err(), CustomError { bad_value: 3u8 });
544 }
545
546 // #[derive(FromPrimitive)] generates implementations for the following traits:
547 //
548 // - `FromPrimitive<T>`
549 // - `From<T>`
550 // - `TryFromPrimitive<T>`
551 // - `TryFrom<T>`
552