Skip to content

Commit 9eb16f3

Browse files
committed
impl TryFrom<T::Type> for BitFlags<T>
1 parent de54d59 commit 9eb16f3

File tree

4 files changed

+77
-4
lines changed

4 files changed

+77
-4
lines changed

enumflags/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ documentation = "https://docs.rs/enumflags2"
1212
[dependencies]
1313
enumflags2_derive = { version = "0.6.0", path = "../enumflags_derive" }
1414
serde = { version = "^1.0.0", default-features = false, optional = true }
15+
16+
[features]
17+
std = []

enumflags/src/fallible.rs

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use core::convert::TryFrom;
2+
use super::{BitFlags, FromBitsError};
3+
use super::_internal::RawBitFlags;
4+
5+
macro_rules! impl_try_from {
6+
() => { };
7+
($ty:ty, $($tt:tt)*) => {
8+
impl_try_from! { $ty }
9+
impl_try_from! { $($tt)* }
10+
};
11+
($ty:ty) => {
12+
impl<T> TryFrom<$ty> for BitFlags<T>
13+
where
14+
T: RawBitFlags<Type=$ty>,
15+
{
16+
type Error = FromBitsError<T>;
17+
18+
fn try_from(bits: T::Type) -> Result<Self, Self::Error> {
19+
Self::try_from_bits(bits)
20+
}
21+
}
22+
};
23+
}
24+
25+
impl_try_from! {
26+
u8, u16, u32, u64, usize
27+
}

enumflags/src/formatting.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use core::fmt::{self, Debug, Binary};
2-
use crate::{BitFlags, _internal::RawBitFlags};
2+
use crate::{BitFlags, FromBitsError, _internal::RawBitFlags};
33

44
impl<T> fmt::Debug for BitFlags<T>
55
where

enumflags/src/lib.rs

+46-3
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@
4444
//! ## Optional Feature Flags
4545
//!
4646
//! - [`serde`](https://serde.rs/) implements `Serialize` and `Deserialize` for `BitFlags<T>`.
47+
//! - `std` implements `std::error::Error` for `FromBitsError`.
4748
#![warn(missing_docs)]
48-
#![cfg_attr(not(test), no_std)]
49+
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
4950

50-
#[cfg(test)]
51+
#[cfg(all(test, not(feature = "std")))]
5152
extern crate core;
5253
use core::{cmp, ops};
5354
use core::iter::FromIterator;
@@ -119,6 +120,9 @@ pub mod _internal {
119120
// Internal debug formatting implementations
120121
mod formatting;
121122

123+
// impl TryFrom<T::Type> for BitFlags<T>
124+
mod fallible;
125+
122126
use _internal::RawBitFlags;
123127

124128
/// Represents a set of flags of some type `T`.
@@ -151,7 +155,7 @@ where
151155

152156
impl<T: RawBitFlags> From<T> for BitFlags<T> {
153157
fn from(t: T) -> BitFlags<T> {
154-
BitFlags { val: t.bits() }
158+
Self::from_flag(t)
155159
}
156160
}
157161

@@ -204,6 +208,22 @@ where
204208
}
205209
}
206210

211+
pub fn from_flag(t: T) -> Self {
212+
BitFlags { val: t.bits() }
213+
}
214+
215+
pub fn try_from_bits(bits: T::Type) -> Result<Self, FromBitsError<T>> {
216+
let flags = Self::from_bits_truncate(bits);
217+
if flags.bits() == bits {
218+
Ok(flags)
219+
} else {
220+
Err(FromBitsError {
221+
flags,
222+
invalid: bits & !flags.bits(),
223+
})
224+
}
225+
}
226+
207227
/// Truncates flags that are illegal
208228
pub fn from_bits_truncate(bits: T::Type) -> Self {
209229
unsafe { BitFlags::new(bits & T::all()) }
@@ -361,3 +381,26 @@ mod impl_serde {
361381
}
362382
}
363383
}
384+
385+
#[derive(Debug, Copy, Clone)]
386+
pub struct FromBitsError<T: RawBitFlags> {
387+
flags: BitFlags<T>,
388+
invalid: T::Type,
389+
}
390+
391+
impl<T: RawBitFlags> FromBitsError<T> {
392+
pub fn truncate(self) -> BitFlags<T> {
393+
self.flags
394+
}
395+
396+
pub fn invalid_bits(self) -> T::Type {
397+
self.invalid
398+
}
399+
}
400+
401+
#[cfg(feature = "std")]
402+
impl<T: RawBitFlags> std::error::Error for FromBitsError<T> {
403+
fn description(&self) -> &str {
404+
"invalid bit representation"
405+
}
406+
}

0 commit comments

Comments
 (0)