diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aa1a2fd..b6c51ef4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ([#479](https://github.com/JelteF/derive_more/pull/479)) - Proxy-pass `#[allow]`/`#[expect]` attributes of the type in `Constructor` derive. ([#477](https://github.com/JelteF/derive_more/pull/477)) +- Support `Deref` and `DerefMut` derives for enums. + ([#485](https://github.com/JelteF/derive_more/pull/485)) ### Changed diff --git a/impl/doc/deref.md b/impl/doc/deref.md index c7dc1047..5a66c74f 100644 --- a/impl/doc/deref.md +++ b/impl/doc/deref.md @@ -1,6 +1,6 @@ # Using `#[derive(Deref)]` -Deriving `Deref` only works for a single field of a struct. +Deriving `Deref` only works for a single field of a struct, or a single field of each variant of an enum. It's possible to use it in two ways: 1. Dereferencing to the field, i.e. like if your type was a reference type. @@ -22,10 +22,23 @@ struct Num { num: i32, } +#[derive(Deref)] +enum Enum { + V1(i32), + V2 { num: i32 }, +} + #[derive(Deref)] #[deref(forward)] struct MyBoxedInt(Box); +#[derive(Deref)] +#[deref(forward)] +enum MyBoxedIntEnum { + V1(Box), + V2 { num: Box }, +} + // You can specify the field you want to derive `Deref` for. #[derive(Deref)] struct CoolVec { @@ -34,12 +47,25 @@ struct CoolVec { vec: Vec, } +#[derive(Deref)] +enum CoolVecEnum { + V1(Vec), + V2 { cool: bool, #[deref] vec: Vec }, +} + let num = Num{num: 123}; let boxed = MyBoxedInt(Box::new(123)); let cool_vec = CoolVec{cool: true, vec: vec![123]}; assert_eq!(123, *num); assert_eq!(123, *boxed); assert_eq!(vec![123], *cool_vec); + +let num_v2 = Enum::V2{num: 123}; +let boxed_v1 = MyBoxedIntEnum::V1(Box::new(123)); +let cool_vec_v2 = CoolVecEnum::V2{cool: true, vec: vec![123]}; +assert_eq!(123, *num_v2); +assert_eq!(123, *boxed_v1); +assert_eq!(vec![123], *cool_vec_v2); ``` @@ -104,4 +130,67 @@ impl derive_more::core::ops::Deref for MyBoxedInt { ## Enums -Deriving `Deref` is not supported for enums. +When deriving a non-forwarded `Deref` for an enum: + +```rust +# use derive_more::Deref; +# +#[derive(Deref)] +enum CoolVecEnum { + V1(Vec), + V2 { cool: bool, #[deref] vec: Vec }, +} +``` + +Code like this will be generated: + +```rust +# enum CoolVecEnum { +# V1(Vec), +# V2 { cool: bool, vec: Vec }, +# } +impl derive_more::with_trait::Deref for CoolVecEnum { + type Target = Vec; + #[inline] + fn deref(&self) -> &Self::Target { + match self { + CoolVecEnum::V1(__0) => __0, + CoolVecEnum::V2 { cool: _, vec: __0 } => __0, + } + } +} +``` + +When deriving a forwarded `Deref` for an enum: + +```rust +# use derive_more::Deref; +# +#[derive(Deref)] +#[deref(forward)] +enum MyBoxedIntEnum { + V1(Box), + V2 { num: Box }, +} +``` + +Code like this will be generated: + +```rust +# enum MyBoxedIntEnum { +# V1(Box), +# V2 { num: Box }, +# } +impl derive_more::with_trait::Deref for MyBoxedIntEnum { + type Target = as derive_more::with_trait::Deref>::Target; + #[inline] + fn deref(&self) -> &Self::Target { + match self { + MyBoxedIntEnum::V1(__0) => + as derive_more::with_trait::Deref>::deref(__0), + MyBoxedIntEnum::V2 { num: __0 } => + as derive_more::with_trait::Deref>::deref(__0), + } + } +} +``` diff --git a/impl/doc/deref_mut.md b/impl/doc/deref_mut.md index 319a79c8..ca52b191 100644 --- a/impl/doc/deref_mut.md +++ b/impl/doc/deref_mut.md @@ -1,6 +1,7 @@ # What `#[derive(DerefMut)]` generates -Deriving `Deref` only works for a single field of a struct. +Deriving `Deref` only works for a single field of a struct, or a single field of +each variant of an enum. Furthermore it requires that the type also implements `Deref`, so usually `Deref` should also be derived. The resulting implementation of `Deref` will allow you to mutably dereference @@ -26,11 +27,25 @@ struct Num { num: i32, } +#[derive(Deref, DerefMut)] +enum Enum { + V1(i32), + V2 { num: i32 }, +} + #[derive(Deref, DerefMut)] #[deref(forward)] #[deref_mut(forward)] struct MyBoxedInt(Box); +#[derive(Deref, DerefMut)] +#[deref(forward)] +#[deref_mut(forward)] +enum MyBoxedIntEnum { + V1(Box), + V2 { num: Box }, +} + // You can specify the field you want to derive DerefMut for #[derive(Deref, DerefMut)] struct CoolVec { @@ -40,6 +55,17 @@ struct CoolVec { vec: Vec, } +#[derive(Deref, DerefMut)] +enum CoolVecEnum { + V1(Vec), + V2 { + cool: bool, + #[deref] + #[deref_mut] + vec: Vec, + }, +} + let mut num = Num{num: 123}; let mut boxed = MyBoxedInt(Box::new(123)); let mut cool_vec = CoolVec{cool: true, vec: vec![123]}; @@ -56,7 +82,7 @@ assert_eq!(vec![123, 456], *cool_vec); ## Structs -When deriving a non-forwarded `Deref` for a struct: +When deriving a non-forwarded `DerefMut` for a struct: ```rust # use derive_more::{Deref, DerefMut}; @@ -129,4 +155,100 @@ impl derive_more::core::ops::DerefMut for MyBoxedInt { ## Enums -Deriving `DerefMut` is not supported for enums. +When deriving a non-forwarded `DerefMut` for an enum: + +```rust +# use derive_more::{Deref, DerefMut}; +# +#[derive(Deref, DerefMut)] +enum CoolVecEnum { + V1(Vec), + V2 { + cool: bool, + #[deref] + #[deref_mut] + vec: Vec, + }, +} +``` + +Code like this will be generated: + +```rust +# use ::core::ops::Deref; +# enum CoolVecEnum { +# V1(Vec), +# V2 { +# cool: bool, +# vec: Vec, +# }, +# } +# impl Deref for CoolVecEnum { +# type Target = Vec; +# #[inline] +# fn deref(&self) -> &Self::Target { +# match self { +# CoolVecEnum::V1(__0) => __0, +# CoolVecEnum::V2 { cool: _, vec: __0 } => __0, +# } +# } +# } +impl derive_more::with_trait::DerefMut for CoolVecEnum { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + match self { + CoolVecEnum::V1(__0) => __0, + CoolVecEnum::V2 { cool: _, vec: __0 } => __0, + } + } +} +``` + +When deriving a forwarded `DerefMut` for an enum: + +```rust +# use derive_more::{Deref, DerefMut}; +# +#[derive(Deref, DerefMut)] +#[deref(forward)] +#[deref_mut(forward)] +enum MyBoxedIntEnum { + V1(Box), + V2 { num: Box }, +} +``` + +Code like this will be generated: + +```rust +# use ::core::ops::Deref; +# enum MyBoxedIntEnum { +# V1(Box), +# V2 { num: Box }, +# } +# impl Deref for MyBoxedIntEnum { +# type Target = as derive_more::with_trait::Deref>::Target; +# #[inline] +# fn deref(&self) -> &Self::Target { +# match self { +# MyBoxedIntEnum::V1(__0) => +# as derive_more::with_trait::Deref>::deref(__0), +# MyBoxedIntEnum::V2 { num: __0 } => +# as derive_more::with_trait::Deref>::deref(__0), +# } +# } +# } +impl derive_more::with_trait::DerefMut for MyBoxedIntEnum { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + match self { + MyBoxedIntEnum::V1(__0) => { + as derive_more::with_trait::DerefMut>::deref_mut(__0) + } + MyBoxedIntEnum::V2 { num: __0 } => { + as derive_more::with_trait::DerefMut>::deref_mut(__0) + } + } + } +} +``` diff --git a/impl/src/deref.rs b/impl/src/deref.rs index eda19c94..cad120a5 100644 --- a/impl/src/deref.rs +++ b/impl/src/deref.rs @@ -1,10 +1,93 @@ -use crate::utils::{add_extra_where_clauses, SingleFieldData, State}; +use crate::utils::{ + add_extra_where_clauses, numbered_vars, panic_one_field, SingleFieldData, State, +}; use proc_macro2::TokenStream; use quote::quote; -use syn::{parse::Result, DeriveInput}; +use syn::{parse::Result, Data, DeriveInput}; /// Provides the hook to expand `#[derive(Deref)]` into an implementation of `Deref` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { + match input.data { + Data::Struct(_) => expand_struct(input, trait_name), + Data::Enum(_) => expand_enum(input, trait_name), + _ => panic!("only structs and enums can use `derive({trait_name})`"), + } +} + +fn expand_enum(input: &DeriveInput, trait_name: &'static str) -> Result { + let state = State::with_field_ignore_and_forward( + input, + trait_name, + trait_name.to_lowercase(), + )?; + + let trait_path = &state.trait_path; + let enum_name = &input.ident; + + let mut target = None; + let mut match_arms = vec![]; + let mut predicates = vec![]; + + for variant_state in state.enabled_variant_data().variant_states.into_iter() { + let data = variant_state.enabled_fields_data(); + if data.fields.len() != 1 { + panic_one_field(variant_state.trait_name, &variant_state.trait_attr); + }; + + let vars = numbered_vars(variant_state.fields.len(), ""); + let matcher = data.matcher(&data.field_indexes, &vars); + + let info = data.infos[0].clone(); + let field_type = data.field_types[0]; + + let (target_, var) = if info.forward { + let casted_trait = data.casted_traits[0].clone(); + predicates.push(quote! { #field_type: #trait_path }); + ( + quote! { #casted_trait::Target }, + quote! { #casted_trait::deref(__0) }, + ) + } else { + (quote! { #field_type }, quote! { __0 }) + }; + + if target.is_none() { + target = Some(target_); + } + + match_arms.push(quote! { + #matcher => #var + }); + } + + let target = target.unwrap(); + + let generics = if predicates.is_empty() { + &input.generics + } else { + &add_extra_where_clauses(&input.generics, quote! { where #(#predicates),* }) + }; + + let (imp_generics, type_generics, where_clause) = generics.split_for_impl(); + + Ok(quote! { + #[allow(deprecated)] // omit warnings on deprecated fields/variants + #[allow(unreachable_code)] // omit warnings for `!` and other unreachable types + #[automatically_derived] + impl #imp_generics #trait_path for #enum_name #type_generics #where_clause { + type Target = #target; + + #[inline] + fn deref(&self) -> &Self::Target { + match self { + #(#match_arms),* + } + } + } + }) +} + +fn expand_struct(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_field_ignore_and_forward( input, trait_name, diff --git a/impl/src/deref_mut.rs b/impl/src/deref_mut.rs index 5c9ffe92..0f991d49 100644 --- a/impl/src/deref_mut.rs +++ b/impl/src/deref_mut.rs @@ -1,10 +1,78 @@ -use crate::utils::{add_extra_where_clauses, SingleFieldData, State}; +use crate::utils::{ + add_extra_where_clauses, numbered_vars, panic_one_field, SingleFieldData, State, +}; use proc_macro2::TokenStream; use quote::quote; -use syn::{parse::Result, DeriveInput}; +use syn::{parse::Result, Data, DeriveInput}; /// Provides the hook to expand `#[derive(DerefMut)]` into an implementation of `DerefMut` pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { + match input.data { + Data::Struct(_) => expand_struct(input, trait_name), + Data::Enum(_) => expand_enum(input, trait_name), + _ => panic!("only structs and enums can use `derive({trait_name})`"), + } +} + +fn expand_enum(input: &DeriveInput, trait_name: &'static str) -> Result { + let state = + State::with_field_ignore_and_forward(input, trait_name, "deref_mut".into())?; + + let trait_path = &state.trait_path; + let enum_name = &input.ident; + + let mut match_arms = vec![]; + let mut predicates = vec![]; + + for variant_state in state.enabled_variant_data().variant_states.into_iter() { + let data = variant_state.enabled_fields_data(); + if data.fields.len() != 1 { + panic_one_field(variant_state.trait_name, &variant_state.trait_attr); + }; + + let vars = numbered_vars(variant_state.fields.len(), ""); + let matcher = data.matcher(&data.field_indexes, &vars); + + let info = data.infos[0].clone(); + let field_type = data.field_types[0]; + + let var = if info.forward { + let casted_trait = data.casted_traits[0].clone(); + predicates.push(quote! { #field_type: #trait_path }); + quote! { #casted_trait::deref_mut(__0) } + } else { + quote! { __0 } + }; + + match_arms.push(quote! { + #matcher => #var + }); + } + + let generics = if predicates.is_empty() { + &input.generics + } else { + &add_extra_where_clauses(&input.generics, quote! { where #(#predicates),* }) + }; + + let (imp_generics, type_generics, where_clause) = generics.split_for_impl(); + + Ok(quote! { + #[allow(deprecated)] // omit warnings on deprecated fields/variants + #[allow(unreachable_code)] // omit warnings for `!` and other unreachable types + #[automatically_derived] + impl #imp_generics #trait_path for #enum_name #type_generics #where_clause { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + match self { + #(#match_arms),* + } + } + } + }) +} + +fn expand_struct(input: &DeriveInput, trait_name: &'static str) -> Result { let state = State::with_field_ignore_and_forward(input, trait_name, "deref_mut".into())?; let SingleFieldData { diff --git a/impl/src/utils.rs b/impl/src/utils.rs index 0bf2db58..6689dcac 100644 --- a/impl/src/utils.rs +++ b/impl/src/utils.rs @@ -248,7 +248,7 @@ pub fn named_to_vec(fields: &FieldsNamed) -> Vec<&Field> { fields.named.iter().collect() } -fn panic_one_field(trait_name: &str, trait_attr: &str) -> ! { +pub(crate) fn panic_one_field(trait_name: &str, trait_attr: &str) -> ! { panic!( "derive({trait_name}) only works when forwarding to a single field. \ Try putting #[{trait_attr}] or #[{trait_attr}(ignore)] on the fields in the struct", @@ -533,6 +533,22 @@ impl<'input> State<'input> { .map(|attrs| get_meta_info(&trait_attr, attrs, &allowed_attr_params.field)) .collect(); let meta_infos = meta_infos?; + + let first_match = meta_infos + .iter() + .find_map(|info| info.enabled.map(|_| info)); + + let default_enabled = if trait_name == "Error" { + true + } else { + first_match.map_or(true, |info| !info.enabled.unwrap()) + }; + + let default_info = FullMetaInfo { + enabled: default_enabled, + ..default_info.clone() + }; + let full_meta_infos: Vec<_> = meta_infos .into_iter() .map(|info| info.into_full(default_info.clone())) diff --git a/tests/deref.rs b/tests/deref.rs index 85d9e958..13b60765 100644 --- a/tests/deref.rs +++ b/tests/deref.rs @@ -88,6 +88,134 @@ mod never { } } +#[derive(Deref)] +enum MyEnum<'a> { + Variant1(&'a [u8]), + Variant2(&'a [u8]), + Variant3(&'a [u8]), +} + +#[derive(Deref)] +enum Enum { + V1(i32), + V2 { num: i32 }, +} + +#[derive(Deref)] +#[deref(forward)] +enum MyBoxedIntEnum { + V1(Box), + V2 { num: Box }, +} + +#[derive(Deref)] +enum CoolVecEnum { + V1(Vec), + V2 { + cool: bool, + #[deref] + vec: Vec, + }, +} + +#[derive(Deref)] +#[deref(forward)] +enum NumRefEnum<'a> { + Variant1 { + num: &'a i32, + }, + Variant2(&'a i32), + Variant3 { + n: &'a i32, + #[deref(ignore)] + useless: bool, + }, +} + +#[derive(Deref)] +enum NumRefEnum2<'a> { + Variant1 { + #[deref] + num: &'a i32, + useless: bool, + }, + Variant2 { + num: &'a i32, + #[deref(ignore)] + useless: bool, + }, + Variant3(&'a i32), +} + +#[derive(Deref)] +enum NumRefEnum3 { + Variant1 { + #[deref(forward)] + num: Box, + useless: bool, + }, + Variant2 { + num: i32, + #[deref(ignore)] + useless: bool, + }, + Variant3(i32), +} + +#[derive(Deref)] +enum NumRefEnum4 { + Variant1(i32), + Variant2 { + #[deref(forward)] + num: Box, + useless: bool, + }, + Variant3 { + num: i32, + #[deref(ignore)] + useless: bool, + }, +} + +#[derive(Deref)] +enum GenericBoxEnum1 { + Variant1 { + #[deref(forward)] + b: Box, + }, + Variant2(bool, #[deref(forward)] Box), +} + +#[test] +fn deref_generic_forward_enum_inner() { + let boxed = GenericBoxEnum1::Variant2(true, Box::new(1i32)); + assert_eq!(*boxed, 1i32); +} + +#[derive(Deref)] +enum GenericBoxEnum2 { + Variant1 { + a: T, + #[deref(forward)] + b: Box, + }, + Variant2(bool, #[deref(forward)] Box), +} + +#[derive(Deref)] +#[deref(forward)] +enum GenericBoxEnum3 { + Variant1 { b: Box }, + Variant2(Box), + Variant3(#[deref(ignore)] bool, Box), +} + +#[test] +fn deref_generic_forward_enum_outer() { + let boxed = GenericBoxEnum3::Variant2(Box::new(1i32)); + assert_eq!(*boxed, 1i32); +} + mod deprecated { use super::*; diff --git a/tests/deref_mut.rs b/tests/deref_mut.rs index 349f816e..2d505720 100644 --- a/tests/deref_mut.rs +++ b/tests/deref_mut.rs @@ -137,6 +137,303 @@ fn deref_mut_generic_forward() { assert_eq!(*boxed, 3i32); } +#[derive(DerefMut)] +enum MyEnum<'a> { + Variant1(&'a [u8]), + Variant2(&'a [u8]), + Variant3(&'a [u8]), +} + +impl<'a> ::core::ops::Deref for MyEnum<'a> { + type Target = &'a [u8]; + + fn deref(&self) -> &Self::Target { + match self { + MyEnum::Variant1(inner) + | MyEnum::Variant2(inner) + | MyEnum::Variant3(inner) => inner, + } + } +} + +#[derive(DerefMut)] +enum Enum { + V1(i32), + V2 { num: i32 }, +} + +impl ::core::ops::Deref for Enum { + type Target = i32; + #[inline] + fn deref(&self) -> &Self::Target { + match self { + Enum::V1(num) | Enum::V2 { num } => num, + } + } +} + +#[derive(DerefMut)] +#[deref_mut(forward)] +enum MyBoxedIntEnum { + V1(Box), + V2 { num: Box }, +} + +impl ::core::ops::Deref for MyBoxedIntEnum { + type Target = as ::core::ops::Deref>::Target; + #[inline] + fn deref(&self) -> &Self::Target { + match self { + MyBoxedIntEnum::V1(num) | MyBoxedIntEnum::V2 { num } => { + as ::core::ops::Deref>::deref(num) + } + } + } +} + +#[derive(DerefMut)] +enum CoolVecEnum { + V1(Vec), + V2 { + cool: bool, + #[deref_mut] + vec: Vec, + }, +} + +impl ::core::ops::Deref for CoolVecEnum { + type Target = Vec; + #[inline] + fn deref(&self) -> &Self::Target { + match self { + CoolVecEnum::V1(vec) | CoolVecEnum::V2 { cool: _, vec } => vec, + } + } +} + +#[derive(DerefMut)] +#[deref_mut(forward)] +enum NumRefEnum<'a> { + Variant1 { + num: &'a i32, + }, + Variant2(&'a i32), + Variant3 { + n: &'a i32, + #[deref_mut(ignore)] + useless: bool, + }, +} + +impl<'a> ::core::ops::Deref for NumRefEnum<'a> { + type Target = <&'a i32 as ::core::ops::Deref>::Target; + #[inline] + fn deref(&self) -> &Self::Target { + match self { + NumRefEnum::Variant1 { num } + | NumRefEnum::Variant2(num) + | NumRefEnum::Variant3 { n: num, useless: _ } => { + <&'a i32 as ::core::ops::Deref>::deref(num) + } + } + } +} + +#[derive(DerefMut)] +enum NumRefEnum2<'a> { + Variant1 { + #[deref_mut] + num: &'a i32, + useless: bool, + }, + Variant2 { + num: &'a i32, + #[deref_mut(ignore)] + useless: bool, + }, + Variant3(&'a i32), +} + +impl<'a> ::core::ops::Deref for NumRefEnum2<'a> { + type Target = &'a i32; + #[inline] + fn deref(&self) -> &Self::Target { + match self { + NumRefEnum2::Variant1 { num, useless: _ } + | NumRefEnum2::Variant2 { num, useless: _ } + | NumRefEnum2::Variant3(num) => num, + } + } +} + +#[derive(DerefMut)] +enum NumRefEnum3 { + Variant1 { + #[deref_mut(forward)] + num: Box, + useless: bool, + }, + Variant2 { + num: i32, + #[deref_mut(ignore)] + useless: bool, + }, + Variant3(i32), +} + +impl ::core::ops::Deref for NumRefEnum3 { + type Target = as ::core::ops::Deref>::Target; + #[inline] + fn deref(&self) -> &Self::Target { + match self { + NumRefEnum3::Variant1 { num, useless: _ } => { + as ::core::ops::Deref>::deref(num) + } + NumRefEnum3::Variant2 { num, useless: _ } | NumRefEnum3::Variant3(num) => { + num + } + } + } +} + +#[derive(DerefMut)] +enum NumRefEnum4 { + Variant1(i32), + Variant2 { + #[deref_mut(forward)] + num: Box, + useless: bool, + }, + Variant3 { + num: i32, + #[deref_mut(ignore)] + useless: bool, + }, +} + +impl ::core::ops::Deref for NumRefEnum4 { + type Target = i32; + #[inline] + fn deref(&self) -> &Self::Target { + match self { + NumRefEnum4::Variant1(num) | NumRefEnum4::Variant3 { num, useless: _ } => { + num + } + NumRefEnum4::Variant2 { num, useless: _ } => { + as ::core::ops::Deref>::deref(num) + } + } + } +} + +#[derive(DerefMut)] +enum GenericVecEnum { + Variant1 { + #[deref_mut] + v: Vec, + useless: bool, + }, + Variant2(#[deref_mut(ignore)] bool, Vec), +} + +impl ::core::ops::Deref for GenericVecEnum { + type Target = Vec; + #[inline] + fn deref(&self) -> &Self::Target { + match self { + GenericVecEnum::Variant1 { v, useless: _ } + | GenericVecEnum::Variant2(_, v) => v, + } + } +} + +#[test] +fn deref_mut_generic_enum() { + let mut gv = GenericVecEnum::Variant2(true, vec![42i32]); + assert!(gv.get_mut(0).is_some()); +} + +#[derive(DerefMut)] +enum GenericBoxEnum1 { + Variant1 { + #[deref_mut(forward)] + b: Box, + useless: bool, + }, + Variant2(bool, #[deref_mut(forward)] Box), +} + +impl ::core::ops::Deref for GenericBoxEnum1 { + type Target = as ::core::ops::Deref>::Target; + #[inline] + fn deref(&self) -> &Self::Target { + match self { + GenericBoxEnum1::Variant1 { b, useless: _ } + | GenericBoxEnum1::Variant2(_, b) => { + as ::core::ops::Deref>::deref(b) + } + } + } +} + +#[test] +fn deref_mut_generic_forward_enum_inner() { + let mut boxed = GenericBoxEnum1::Variant2(true, Box::new(1i32)); + *boxed = 3; + assert_eq!(*boxed, 3i32); +} + +#[derive(DerefMut)] +enum GenericBoxEnum2 { + Variant1 { + a: T, + #[deref_mut(forward)] + b: Box, + }, + Variant2(bool, #[deref_mut(forward)] Box), +} + +impl ::core::ops::Deref for GenericBoxEnum2 { + type Target = as ::core::ops::Deref>::Target; + #[inline] + fn deref(&self) -> &Self::Target { + match self { + GenericBoxEnum2::Variant1 { a: _, b } | GenericBoxEnum2::Variant2(_, b) => { + as ::core::ops::Deref>::deref(b) + } + } + } +} + +#[derive(DerefMut)] +#[deref_mut(forward)] +enum GenericBoxEnum3 { + Variant1 { b: Box }, + Variant2(Box), + Variant3(#[deref_mut(ignore)] bool, Box), +} + +impl ::core::ops::Deref for GenericBoxEnum3 { + type Target = as ::core::ops::Deref>::Target; + #[inline] + fn deref(&self) -> &Self::Target { + match self { + GenericBoxEnum3::Variant1 { b } + | GenericBoxEnum3::Variant2(b) + | GenericBoxEnum3::Variant3(_, b) => { + as ::core::ops::Deref>::deref(b) + } + } + } +} + +#[test] +fn deref_mut_generic_forward_enum_outer() { + let mut boxed = GenericBoxEnum3::Variant2(Box::new(1i32)); + *boxed = 3; + assert_eq!(*boxed, 3i32); +} + #[cfg(nightly)] mod never { use super::*;