| 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 | |