Skip to content

Commit

Permalink
[WIP] TryFromBuild derive support for enums
Browse files Browse the repository at this point in the history
TODO:
- Clean up repr computation
- Support enums with fields
- If we don't support enums with fields, enforce that
- Should enum variants be considered "used" in the sense of dead code?
  It's possible to never construct an enum variant from Rust's
  perspective even though it is constructed via TryFromBytes.
- Confirm that we reject uninhabited enums. Currently Rust doesn't let
  you put a repr on these enums, so we would reject them for lack of a
  repr, but we should probably have a more reliable check than that.
  • Loading branch information
joshlf committed Sep 12, 2023
1 parent 4004cbe commit 5fbe8b4
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 81 deletions.
32 changes: 32 additions & 0 deletions src/derive_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,5 +145,37 @@ mod tests {
assert_eq!(try_transmute!([1u8, 1]), Some(Foo(1, true)));
assert_eq!(try_transmute!([2u8, 2]), None::<Foo>);
assert_eq!(try_transmute!([128u8, 1]), None::<Foo>);

#[derive(TryFromBytes, Eq, PartialEq, Debug)]
#[zerocopy(validator = "validate")]
#[repr(u8)]
enum Baz {
A, // 0
B = 5, // 5
C, // 6
D = 1 + 1, // 2
E, // 3
F, // 4
}

impl Baz {
fn validate(&self) -> bool {
use Baz::*;
matches!(self, A | B | C | D | E)
}
}

impl_known_layout!(Baz);

assert_eq!(try_transmute!(0u8), Some(Baz::A));
assert_eq!(try_transmute!(1u8), None::<Baz>);
assert_eq!(try_transmute!(2u8), Some(Baz::D));
assert_eq!(try_transmute!(3u8), Some(Baz::E));

assert_eq!(try_transmute!(4u8), None::<Baz>);

assert_eq!(try_transmute!(5u8), Some(Baz::B));
assert_eq!(try_transmute!(6u8), Some(Baz::C));
assert_eq!(try_transmute!(7u8), None::<Baz>);
}
}
8 changes: 7 additions & 1 deletion zerocopy-derive/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::{Data, DataEnum, DataStruct, DataUnion, Field, Index, Type};
use syn::{Data, DataEnum, DataStruct, DataUnion, Field, Fields, Index, Type};

pub trait DataExt {
/// Extract the names and types of all fields. For enums, extract the names
Expand Down Expand Up @@ -46,6 +46,12 @@ impl DataExt for DataUnion {
}
}

impl DataExt for Fields {
fn fields(&self) -> Vec<(TokenStream, &Type)> {
map_fields(self)
}
}

fn map_fields<'a>(
fields: impl 'a + IntoIterator<Item = &'a Field>,
) -> Vec<(TokenStream, &'a Type)> {
Expand Down
Loading

0 comments on commit 5fbe8b4

Please sign in to comment.