Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplified the parsing for primitive enum variants, removed integer type autodetection #88

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packed_struct/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "packed_struct"
description = "Binary-level structure packing and unpacking generator"
repository = "https://github.com/hashmismatch/packed_struct.rs"
homepage = "http://www.hashmismatch.net/libraries/packed-struct/"
version = "0.10.1"
version = "0.11.0"
rust-version = "1.51"
authors = ["Rudi Benkovic <[email protected]>"]
license = "MIT OR Apache-2.0"
Expand All @@ -13,7 +13,7 @@ readme = "../README.md"
edition = "2018"

[dependencies]
packed_struct_codegen = { path = "../packed_struct_codegen/", version = "0.10.1" }
packed_struct_codegen = { path = "../packed_struct_codegen/", version = "0.11.0" }
serde = { version = "1.0", optional = true, default-features = false }
serde_derive = { version = "1.0", optional = true }
bitvec = { version = "0.22.3", default-features = false }
Expand Down
3 changes: 1 addition & 2 deletions packed_struct/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@
//! ```rust
//! use packed_struct::prelude::*;
//!
//! #[derive(PrimitiveEnum, Clone, Copy, PartialEq, Debug)]
//! #[derive(PrimitiveEnum_u8, Clone, Copy, PartialEq, Debug)]
//! pub enum ImplicitType {
//! VariantMin = 0,
//! VariantMax = 255
Expand Down Expand Up @@ -377,7 +377,6 @@ pub use self::packing::*;
/// The derivation macros for packing and enums.
pub mod derive {
pub use packed_struct_codegen::PackedStruct;
pub use packed_struct_codegen::PrimitiveEnum;
pub use packed_struct_codegen::{PrimitiveEnum_u8, PrimitiveEnum_u16, PrimitiveEnum_u32, PrimitiveEnum_u64};
pub use packed_struct_codegen::{PrimitiveEnum_i8, PrimitiveEnum_i16, PrimitiveEnum_i32, PrimitiveEnum_i64};
}
Expand Down
2 changes: 1 addition & 1 deletion packed_struct_codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "packed_struct_codegen"
description = "This crate implements the code generation for the packed_struct library."
repository = "https://github.com/hashmismatch/packed_struct.rs"
version = "0.10.1"
version = "0.11.0"
license = "MIT OR Apache-2.0"
authors = ["Rudi Benkovic <[email protected]>"]
edition = "2018"
Expand Down
25 changes: 9 additions & 16 deletions packed_struct_codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,55 +36,48 @@ pub fn derive_packable_bytes(tokens: TokenStream) -> TokenStream {
.into()
}

/// A derive macro that generates packing and unpacking code for simple enum variants.
/// It helps with converting your enums into integer types and back, with many other helper
/// traits.
#[proc_macro_derive(PrimitiveEnum)]
pub fn derive_primitive_detect(input: TokenStream) -> TokenStream {
derive_primitive(input, None)
}

#[proc_macro_derive(PrimitiveEnum_u8)]
pub fn derive_primitive_u8(input: TokenStream) -> TokenStream {
derive_primitive(input, Some(syn::parse_str::<syn::Type>("u8").unwrap()))
derive_primitive(input, syn::parse_str::<syn::Type>("u8").unwrap())
}

#[proc_macro_derive(PrimitiveEnum_u16)]
pub fn derive_primitive_u16(input: TokenStream) -> TokenStream {
derive_primitive(input, Some(syn::parse_str::<syn::Type>("u16").unwrap()))
derive_primitive(input, syn::parse_str::<syn::Type>("u16").unwrap())
}

#[proc_macro_derive(PrimitiveEnum_u32)]
pub fn derive_primitive_u32(input: TokenStream) -> TokenStream {
derive_primitive(input, Some(syn::parse_str::<syn::Type>("u32").unwrap()))
derive_primitive(input, syn::parse_str::<syn::Type>("u32").unwrap())
}

#[proc_macro_derive(PrimitiveEnum_u64)]
pub fn derive_primitive_u64(input: TokenStream) -> TokenStream {
derive_primitive(input, Some(syn::parse_str::<syn::Type>("u64").unwrap()))
derive_primitive(input, syn::parse_str::<syn::Type>("u64").unwrap())
}

#[proc_macro_derive(PrimitiveEnum_i8)]
pub fn derive_primitive_i8(input: TokenStream) -> TokenStream {
derive_primitive(input, Some(syn::parse_str::<syn::Type>("i8").unwrap()))
derive_primitive(input, syn::parse_str::<syn::Type>("i8").unwrap())
}

#[proc_macro_derive(PrimitiveEnum_i16)]
pub fn derive_primitive_i16(input: TokenStream) -> TokenStream {
derive_primitive(input, Some(syn::parse_str::<syn::Type>("i16").unwrap()))
derive_primitive(input, syn::parse_str::<syn::Type>("i16").unwrap())
}

#[proc_macro_derive(PrimitiveEnum_i32)]
pub fn derive_primitive_i32(input: TokenStream) -> TokenStream {
derive_primitive(input, Some(syn::parse_str::<syn::Type>("i32").unwrap()))
derive_primitive(input, syn::parse_str::<syn::Type>("i32").unwrap())
}

#[proc_macro_derive(PrimitiveEnum_i64)]
pub fn derive_primitive_i64(input: TokenStream) -> TokenStream {
derive_primitive(input, Some(syn::parse_str::<syn::Type>("i64").unwrap()))
derive_primitive(input, syn::parse_str::<syn::Type>("i64").unwrap())
}

fn derive_primitive(input: TokenStream, ty: Option<syn::Type>) -> TokenStream {
fn derive_primitive(input: TokenStream, ty: syn::Type) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);

primitive_enum::derive(&input, ty)
Expand Down
2 changes: 1 addition & 1 deletion packed_struct_codegen/src/pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub struct FieldMidPositioning {
pub enum FieldKind {
Regular {
ident: syn::Ident,
field: FieldRegular
field: Box<FieldRegular>
},
Array {
ident: syn::Ident,
Expand Down
4 changes: 2 additions & 2 deletions packed_struct_codegen/src/pack_codegen_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub fn struct_runtime_formatter(parsed: &PackStruct) -> syn::Result<proc_macro2:
},
FieldKind::Array { ref ident, ref elements, .. } => {
for (i, field) in elements.iter().enumerate() {
let name_str = format!("{}[{}]", ident.to_string(), i);
let name_str = format!("{}[{}]", ident, i);
let bits: syn::ExprRange = syn::parse_str(&format!("{}..{}", field.bit_range.start, field.bit_range.end))?;

debug_fields.push(quote! {
Expand Down Expand Up @@ -136,7 +136,7 @@ pub fn type_docs(parsed: &PackStruct) -> proc_macro2::TokenStream {
},
FieldKind::Array { ref ident, ref elements, .. } => {
for (i, field) in elements.iter().enumerate() {
emit_field_docs(&field.bit_range, format!("{}[{}]", ident.to_string(), i), &field.ty);
emit_field_docs(&field.bit_range, format!("{}[{}]", ident, i), &field.ty);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions packed_struct_codegen/src/pack_parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ fn parse_field(field: &syn::Field, mp: &FieldMidPositioning, bit_range: &Range<u
syn::Type::Path(_) => {
return Ok(
FieldKind::Regular {
field: parse_reg_field(field, &field.ty, bit_range, default_endianness)?,
field: Box::new(parse_reg_field(field, &field.ty, bit_range, default_endianness)?),
ident: field.ident.clone().ok_or_else(|| syn::Error::new(field.span(), "Missing ident!"))?
}
);
Expand Down Expand Up @@ -468,7 +468,7 @@ pub fn parse_struct(ast: &syn::DeriveInput) -> syn::Result<PackStruct> {
},
FieldKind::Array { ref ident, ref elements, .. } => {
for (i, field) in elements.iter().enumerate() {
find_overlaps(format!("{}[{}]", ident.to_string(), i), &field.bit_range)?;
find_overlaps(format!("{}[{}]", ident, i), &field.bit_range)?;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion packed_struct_codegen/src/pack_parse_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ pub fn parse_position_val(v: &str, multiplier: usize) -> Result<BitsPositionPars
let n = parse_num(&v)?;
return Ok(BitsPositionParsed::Start(n * multiplier));
} else if v.ends_with(':') {
let v = v.replace(":", "");
let v = v.replace(':', "");
let n = parse_num(&v)?;
return Ok(BitsPositionParsed::Start(n * multiplier));
} else if v.contains(':') || v.contains("..=") {
Expand Down
142 changes: 9 additions & 133 deletions packed_struct_codegen/src/primitive_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,19 @@ use syn::spanned::Spanned;
use crate::utils::*;
use crate::common::collections_prefix;

pub fn derive(ast: &syn::DeriveInput, mut prim_type: Option<syn::Type>) -> syn::Result<proc_macro2::TokenStream> {
pub fn derive(ast: &syn::DeriveInput, prim_type: syn::Type) -> syn::Result<proc_macro2::TokenStream> {

let stdlib_prefix = collections_prefix();

let name = &ast.ident;
let v = get_unitary_enum(ast)?;

let from_primitive_match: Vec<_> = v.iter().map(|x| {
let d = x.get_discriminant();
let n = &x.variant.ident;
quote! {
#d => Some(#name::#n)
if val == #name::#n as #prim_type {
return Some(#name::#n);
}
}
}).collect();

Expand Down Expand Up @@ -49,65 +50,8 @@ pub fn derive(ast: &syn::DeriveInput, mut prim_type: Option<syn::Type>) -> syn::
}).collect();
let all_variants_len = all_variants.len();

if prim_type.is_none() {
let min_ty: Vec<String> = v.iter().map(|d| {
if !d.suffix.is_empty() {
d.suffix.clone()
} else if d.negative {
let n = d.discriminant as i64;
if n < <i32>::min_value() as i64 {
"i64".into()
} else {
let n = -n;
if n < <i16>::min_value() as i64 {
"i32".into()
} else if n < <i8>::min_value() as i64 {
"i16".into()
} else {
"i8".into()
}
}
} else {
let n = d.discriminant as u64;
if n > <u32>::max_value() as u64 {
"u64".into()
} else if n > <u16>::max_value() as u64 {
"u32".into()
} else if n > <u8>::max_value() as u64 {
"u16".into()
} else {
"u8".into()
}
}
}).collect();

// first mention, higher priority
let priority = [
"i64",
"i32",
"i16",
"i8",
"u64",
"u32",
"u16",
"u8"
];

let mut ty = "u8".to_string();
for t in min_ty {
if priority.iter().position(|&x| x == t).unwrap() < priority.iter().position(|&x| x == ty).unwrap() {
ty = t;
}
}

prim_type = Some(syn::parse_str(&ty).expect("int ty parsing failed"));
}

let prim_type = prim_type.expect("Unable to detect the primitive type for this enum.");

let all_variants_const_ident = syn::Ident::new(&format!("{}_ALL", to_snake_case(&name.to_string())).to_uppercase(), Span::call_site());


let mut str_format = {
let to_display_str = to_display_str.clone();
let all_variants_const_ident = all_variants_const_ident.clone();
Expand Down Expand Up @@ -158,10 +102,9 @@ pub fn derive(ast: &syn::DeriveInput, mut prim_type: Option<syn::Type>) -> syn::

#[inline]
fn from_primitive(val: #prim_type) -> Option<Self> {
match val {
#(#from_primitive_match),* ,
_ => None
}
#(#from_primitive_match)*

None
}

#[inline]
Expand Down Expand Up @@ -192,31 +135,9 @@ pub fn derive(ast: &syn::DeriveInput, mut prim_type: Option<syn::Type>) -> syn::
}

struct Variant {
variant: syn::Variant,
discriminant: u64,
negative: bool,
suffix: String
variant: syn::Variant
}

impl Variant {
fn get_discriminant(&self) -> proc_macro2::TokenStream {
let s = format!("{}{}",
self.discriminant,
self.suffix
);
let v: syn::LitInt = syn::parse_str(&s).expect("Error mid-parsing for disc value");

if self.negative {
quote! {
- #v
}
} else {
quote! { #v }
}
}
}


fn get_unitary_enum(input: &syn::DeriveInput) -> syn::Result<Vec<Variant>> {
let data_enum = if let syn::Data::Enum(data_enum) = &input.data {
data_enum
Expand All @@ -226,9 +147,6 @@ fn get_unitary_enum(input: &syn::DeriveInput) -> syn::Result<Vec<Variant>> {

let mut r = Vec::new();

let mut d: Option<u64> = None;
let mut neg = false;

for variant in &data_enum.variants {

match variant.fields {
Expand All @@ -238,51 +156,9 @@ fn get_unitary_enum(input: &syn::DeriveInput) -> syn::Result<Vec<Variant>> {
syn::Fields::Unit => {}
}

let (discriminant, negative, suffix) = match &variant.discriminant {
Some((_, syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(ref lit_int), .. }))) => {
(lit_int.base10_parse()?, false, lit_int.suffix().into())
},
Some((_,
syn::Expr::Unary(syn::ExprUnary {
op: syn::UnOp::Neg(_),
expr,
..
})
)) => {

match **expr {
syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(ref lit_int), .. }) => {
(lit_int.base10_parse()?, true, lit_int.suffix().into())
},
_ => return Err(syn::Error::new(expr.span(), "Unsupported enum const expr (negated)"))
}
}
Some(_) => {
return Err(syn::Error::new(variant.span(), "Unsupported enum const expr"));
},
None => {
match d {
None => (0, false, "".into()),
Some(d) => {
if neg {
(d-1, d-1 != 0, "".into())
} else {
(d+1, false, "".into())
}
}
}
}
};

r.push(Variant {
variant: variant.clone(),
discriminant,
negative,
suffix
variant: variant.clone()
});

d = Some(discriminant);
neg = negative;
}

Ok(r)
Expand Down
2 changes: 1 addition & 1 deletion packed_struct_examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ publish = false
edition = "2018"

[dependencies]
packed_struct = { path = "../packed_struct/", version = "0.10", features = ["byte_types_64"] }
packed_struct = { path = "../packed_struct/", version = "0.11", features = ["byte_types_64"] }
2 changes: 1 addition & 1 deletion packed_struct_examples/src/example1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub struct ControlRegister {
pub sensor_value: i16
}

#[derive(PrimitiveEnum, Debug, Copy, Clone, PartialEq)]
#[derive(PrimitiveEnum_u8, Debug, Copy, Clone, PartialEq)]
pub enum PowerMode {
/// The sensor is turned off
Off = 0,
Expand Down
2 changes: 1 addition & 1 deletion packed_struct_nostd_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ version = "0.1.0"
authors = ["Rudi Benkovic <[email protected]>"]

[dependencies]
packed_struct = { path = "../packed_struct/", version = "0.10", default-features = false }
packed_struct = { path = "../packed_struct/", version = "0.11", default-features = false }
2 changes: 1 addition & 1 deletion packed_struct_nostd_tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub struct ControlRegister {
pub sensor_value: i16
}

#[derive(PrimitiveEnum, Debug, Copy, Clone, PartialEq)]
#[derive(PrimitiveEnum_u8, Debug, Copy, Clone, PartialEq)]
pub enum PowerMode {
/// The sensor is turned off
Off = 0,
Expand Down
Loading