Skip to content

Commit

Permalink
impl TryFrom<T::Type> for BitFlags<T>
Browse files Browse the repository at this point in the history
  • Loading branch information
arcnmx committed Aug 28, 2019
1 parent de54d59 commit 9eb16f3
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 4 deletions.
3 changes: 3 additions & 0 deletions enumflags/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ documentation = "https://docs.rs/enumflags2"
[dependencies]
enumflags2_derive = { version = "0.6.0", path = "../enumflags_derive" }
serde = { version = "^1.0.0", default-features = false, optional = true }

[features]
std = []
27 changes: 27 additions & 0 deletions enumflags/src/fallible.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use core::convert::TryFrom;
use super::{BitFlags, FromBitsError};
use super::_internal::RawBitFlags;

macro_rules! impl_try_from {
() => { };
($ty:ty, $($tt:tt)*) => {
impl_try_from! { $ty }
impl_try_from! { $($tt)* }
};
($ty:ty) => {
impl<T> TryFrom<$ty> for BitFlags<T>
where
T: RawBitFlags<Type=$ty>,
{
type Error = FromBitsError<T>;

fn try_from(bits: T::Type) -> Result<Self, Self::Error> {
Self::try_from_bits(bits)
}
}
};
}

impl_try_from! {
u8, u16, u32, u64, usize
}
2 changes: 1 addition & 1 deletion enumflags/src/formatting.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use core::fmt::{self, Debug, Binary};
use crate::{BitFlags, _internal::RawBitFlags};
use crate::{BitFlags, FromBitsError, _internal::RawBitFlags};

impl<T> fmt::Debug for BitFlags<T>
where
Expand Down
49 changes: 46 additions & 3 deletions enumflags/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@
//! ## Optional Feature Flags
//!
//! - [`serde`](https://serde.rs/) implements `Serialize` and `Deserialize` for `BitFlags<T>`.
//! - `std` implements `std::error::Error` for `FromBitsError`.
#![warn(missing_docs)]
#![cfg_attr(not(test), no_std)]
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]

#[cfg(test)]
#[cfg(all(test, not(feature = "std")))]
extern crate core;
use core::{cmp, ops};
use core::iter::FromIterator;
Expand Down Expand Up @@ -119,6 +120,9 @@ pub mod _internal {
// Internal debug formatting implementations
mod formatting;

// impl TryFrom<T::Type> for BitFlags<T>
mod fallible;

use _internal::RawBitFlags;

/// Represents a set of flags of some type `T`.
Expand Down Expand Up @@ -151,7 +155,7 @@ where

impl<T: RawBitFlags> From<T> for BitFlags<T> {
fn from(t: T) -> BitFlags<T> {
BitFlags { val: t.bits() }
Self::from_flag(t)
}
}

Expand Down Expand Up @@ -204,6 +208,22 @@ where
}
}

pub fn from_flag(t: T) -> Self {
BitFlags { val: t.bits() }
}

pub fn try_from_bits(bits: T::Type) -> Result<Self, FromBitsError<T>> {
let flags = Self::from_bits_truncate(bits);
if flags.bits() == bits {
Ok(flags)
} else {
Err(FromBitsError {
flags,
invalid: bits & !flags.bits(),
})
}
}

/// Truncates flags that are illegal
pub fn from_bits_truncate(bits: T::Type) -> Self {
unsafe { BitFlags::new(bits & T::all()) }
Expand Down Expand Up @@ -361,3 +381,26 @@ mod impl_serde {
}
}
}

#[derive(Debug, Copy, Clone)]
pub struct FromBitsError<T: RawBitFlags> {
flags: BitFlags<T>,
invalid: T::Type,
}

impl<T: RawBitFlags> FromBitsError<T> {
pub fn truncate(self) -> BitFlags<T> {
self.flags
}

pub fn invalid_bits(self) -> T::Type {
self.invalid
}
}

#[cfg(feature = "std")]
impl<T: RawBitFlags> std::error::Error for FromBitsError<T> {
fn description(&self) -> &str {
"invalid bit representation"
}
}

0 comments on commit 9eb16f3

Please sign in to comment.