From b6a46d5e819dc75cd05012fec76b5399901b18d2 Mon Sep 17 00:00:00 2001 From: wcampbell Date: Tue, 30 Apr 2024 09:18:09 -0400 Subject: [PATCH] Fix error for invalid deku_id generation on generic enum (#411) Add/Fixup lifetime for generated code for enum ext id finding. Lifetime __deku needs to be added to the deku_id_type, and the impl. --- deku-derive/src/macros/deku_read.rs | 9 +++++++-- deku-derive/src/macros/mod.rs | 5 +++++ src/lib.rs | 2 +- tests/test_compile/cases/no_deku_id_generic_enum.rs | 13 +++++++++++++ .../cases/no_deku_id_generic_enum.stderr | 12 ++++++++++++ 5 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 tests/test_compile/cases/no_deku_id_generic_enum.rs create mode 100644 tests/test_compile/cases/no_deku_id_generic_enum.stderr diff --git a/deku-derive/src/macros/deku_read.rs b/deku-derive/src/macros/deku_read.rs index 600ff6cb..37199b86 100644 --- a/deku-derive/src/macros/deku_read.rs +++ b/deku-derive/src/macros/deku_read.rs @@ -409,8 +409,12 @@ fn emit_enum(input: &DekuData) -> Result { // Implement `DekuEnumExt` if let Some(deku_id_type) = deku_id_type { - tokens.extend(quote! { - impl #imp DekuEnumExt<#lifetime, (#deku_id_type)> for #ident #wher { + if !imp.to_token_stream().is_empty() { + // Generics (#imp) are not supported, as our __deku + // would need to be appended to #imp + } else { + tokens.extend(quote! { + impl<'__deku> #imp ::#crate_::DekuEnumExt<#lifetime, (#deku_id_type)> for #ident #wher { #[inline] fn deku_id(&self) -> core::result::Result<(#deku_id_type), DekuError> { match self { @@ -420,6 +424,7 @@ fn emit_enum(input: &DekuData) -> Result { } } }); + } } // println!("{}", tokens.to_string()); diff --git a/deku-derive/src/macros/mod.rs b/deku-derive/src/macros/mod.rs index 256137cf..f5fbf401 100644 --- a/deku-derive/src/macros/mod.rs +++ b/deku-derive/src/macros/mod.rs @@ -4,6 +4,7 @@ use syn::parse::Parser; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::token::Comma; +use syn::Lifetime; use crate::Num; @@ -211,6 +212,10 @@ fn gen_type_from_ctx_id( if let syn::FnArg::Typed(pat_type) = arg { if let syn::Pat::Ident(ident) = &*pat_type.pat { if id == ident.ident { + let mut pat_type = pat_type.clone(); + if let syn::Type::Reference(r) = pat_type.ty.as_mut() { + r.lifetime = Some(Lifetime::new("'__deku", Span::call_site())); + } let ty = &pat_type.ty; t = Some(quote! {#ty}); } diff --git a/src/lib.rs b/src/lib.rs index a9acfdc0..7e14233f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -521,7 +521,7 @@ pub trait DekuUpdate { } /// "Extended Enum" trait: obtain additional enum information -pub trait DekuEnumExt<'a, T> { +pub trait DekuEnumExt<'__deku, T> { /// Obtain `id` of a given enum variant fn deku_id(&self) -> Result; } diff --git a/tests/test_compile/cases/no_deku_id_generic_enum.rs b/tests/test_compile/cases/no_deku_id_generic_enum.rs new file mode 100644 index 00000000..4bcde370 --- /dev/null +++ b/tests/test_compile/cases/no_deku_id_generic_enum.rs @@ -0,0 +1,13 @@ +use deku::prelude::*; + +#[derive(DekuRead)] +#[deku(id_type = "u8")] +pub enum Body DekuReader<'a>> { + #[deku(id = "0x0001")] + First(T), +} + +fn main() { + let n = Body::::First(1); + n.deku_id(); +} diff --git a/tests/test_compile/cases/no_deku_id_generic_enum.stderr b/tests/test_compile/cases/no_deku_id_generic_enum.stderr new file mode 100644 index 00000000..778e7b96 --- /dev/null +++ b/tests/test_compile/cases/no_deku_id_generic_enum.stderr @@ -0,0 +1,12 @@ +error[E0599]: no method named `deku_id` found for enum `Body` in the current scope + --> tests/test_compile/cases/no_deku_id_generic_enum.rs:12:7 + | +5 | pub enum Body DekuReader<'a>> { + | ---------------------------------------- method `deku_id` not found for this enum +... +12 | n.deku_id(); + | ^^^^^^^ method not found in `Body` + | + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `deku_id`, perhaps you need to implement it: + candidate #1: `deku::DekuEnumExt`