1 | use super::BitFlag; |
2 | use super::BitFlags; |
3 | use core::convert::TryFrom; |
4 | use core::fmt; |
5 | |
6 | // Coherence doesn't let us use a generic type here. Work around by implementing |
7 | // for each integer type manually. |
8 | for_each_uint! { $ty $hide_docs => |
9 | impl<T> TryFrom<$ty> for BitFlags<T> |
10 | where |
11 | T: BitFlag<Numeric=$ty>, |
12 | { |
13 | type Error = FromBitsError<T>; |
14 | |
15 | fn try_from(bits: T::Numeric) -> Result<Self, Self::Error> { |
16 | Self::from_bits(bits) |
17 | } |
18 | } |
19 | } |
20 | |
21 | /// The error struct used by [`BitFlags::from_bits`] |
22 | /// and the [`TryFrom`] implementation for invalid values. |
23 | /// |
24 | /// Note that the implementation of [`std::error::Error`] |
25 | /// for this type is gated on the `std` feature flag. |
26 | /// |
27 | /// ``` |
28 | /// # use std::convert::TryInto; |
29 | /// # use enumflags2::{bitflags, BitFlags}; |
30 | /// #[bitflags] |
31 | /// #[derive(Clone, Copy, Debug)] |
32 | /// #[repr(u8)] |
33 | /// enum MyFlags { |
34 | /// A = 0b0001, |
35 | /// B = 0b0010, |
36 | /// C = 0b0100, |
37 | /// D = 0b1000, |
38 | /// } |
39 | /// |
40 | /// let result: Result<BitFlags<MyFlags>, _> = 0b10101u8.try_into(); |
41 | /// assert!(result.is_err()); |
42 | /// let error = result.unwrap_err(); |
43 | /// assert_eq!(error.truncate(), MyFlags::C | MyFlags::A); |
44 | /// assert_eq!(error.invalid_bits(), 0b10000); |
45 | /// ``` |
46 | #[derive (Debug, Copy, Clone)] |
47 | pub struct FromBitsError<T: BitFlag> { |
48 | pub(crate) flags: BitFlags<T>, |
49 | pub(crate) invalid: T::Numeric, |
50 | } |
51 | |
52 | impl<T: BitFlag> FromBitsError<T> { |
53 | /// Return the truncated result of the conversion. |
54 | pub fn truncate(self) -> BitFlags<T> { |
55 | self.flags |
56 | } |
57 | |
58 | /// Return the bits that didn't correspond to any flags. |
59 | pub fn invalid_bits(self) -> T::Numeric { |
60 | self.invalid |
61 | } |
62 | } |
63 | |
64 | impl<T: BitFlag + fmt::Debug> fmt::Display for FromBitsError<T> { |
65 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
66 | write!( |
67 | fmt, |
68 | "Invalid bits for {:?}: {:#b}" , |
69 | self.flags, self.invalid |
70 | ) |
71 | } |
72 | } |
73 | |
74 | #[cfg (feature = "std" )] |
75 | impl<T: BitFlag + fmt::Debug> std::error::Error for FromBitsError<T> { |
76 | fn description(&self) -> &str { |
77 | "invalid bitflags representation" |
78 | } |
79 | } |
80 | |