Skip to content

Commit 13cd4c1

Browse files
authored
fix(stackable-versioned): Correctly emit enum fields in From impls (#1086)
* fix(stackable-versioned): Correctly emit enum fields in From impls * chore(stackable-versioned): Add changelog entry * fix(stackable-versioned): Correctly emit empty named field variants * fix: Bump tracing-subscriber to 0.3.20 to fix RUSTSEC-2025-0055 See https://rustsec.org/advisories/RUSTSEC-2025-0055 * fix(stackable-versioned): Use correct quote repetition
1 parent 48f8aad commit 13cd4c1

File tree

6 files changed

+192
-100
lines changed

6 files changed

+192
-100
lines changed

Cargo.lock

Lines changed: 16 additions & 60 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/stackable-versioned-macros/src/codegen/item/variant.rs

Lines changed: 61 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use darling::{FromVariant, Result, util::IdentString};
44
use k8s_version::Version;
55
use proc_macro2::{Span, TokenStream};
66
use quote::{format_ident, quote};
7-
use syn::{Attribute, Fields, Type, TypeNever, Variant, token::Not};
7+
use syn::{
8+
Attribute, Fields, FieldsNamed, FieldsUnnamed, Ident, Type, TypeNever, Variant, token::Not,
9+
};
810

911
use crate::{
1012
attrs::item::VariantAttributes,
@@ -138,7 +140,8 @@ impl VersionedVariant {
138140
next_version: &VersionDefinition,
139141
enum_ident: &IdentString,
140142
) -> Option<TokenStream> {
141-
let variant_fields = self.fields_as_token_stream();
143+
let from_fields = self.generate_from_fields();
144+
let for_fields = self.generate_for_fields();
142145

143146
match &self.changes {
144147
Some(changes) => {
@@ -154,16 +157,15 @@ impl VersionedVariant {
154157
let next_variant_ident = next.get_ident();
155158
let old_variant_ident = old.get_ident();
156159

157-
let old = quote! {
158-
#old_version_ident::#enum_ident::#old_variant_ident #variant_fields
159-
};
160-
let next = quote! {
161-
#next_version_ident::#enum_ident::#next_variant_ident #variant_fields
162-
};
163-
164160
match direction {
165-
Direction::Upgrade => Some(quote! { #old => #next, }),
166-
Direction::Downgrade => Some(quote! { #next => #old, }),
161+
Direction::Upgrade => Some(quote! {
162+
#old_version_ident::#enum_ident::#old_variant_ident #from_fields
163+
=> #next_version_ident::#enum_ident::#next_variant_ident #for_fields,
164+
}),
165+
Direction::Downgrade => Some(quote! {
166+
#next_version_ident::#enum_ident::#next_variant_ident #from_fields
167+
=> #old_version_ident::#enum_ident::#old_variant_ident #from_fields,
168+
}),
167169
}
168170
}
169171
}
@@ -173,48 +175,67 @@ impl VersionedVariant {
173175
let old_version_ident = &version.idents.module;
174176
let variant_ident = &*self.ident;
175177

176-
let old = quote! {
177-
#old_version_ident::#enum_ident::#variant_ident #variant_fields
178-
};
179-
let next = quote! {
180-
#next_version_ident::#enum_ident::#variant_ident #variant_fields
181-
};
182-
183178
match direction {
184-
Direction::Upgrade => Some(quote! { #old => #next, }),
185-
Direction::Downgrade => Some(quote! { #next => #old, }),
179+
Direction::Upgrade => Some(quote! {
180+
#old_version_ident::#enum_ident::#variant_ident #from_fields
181+
=> #next_version_ident::#enum_ident::#variant_ident #for_fields,
182+
}),
183+
Direction::Downgrade => Some(quote! {
184+
#next_version_ident::#enum_ident::#variant_ident #from_fields
185+
=> #old_version_ident::#enum_ident::#variant_ident #for_fields,
186+
}),
186187
}
187188
}
188189
}
189190
}
190191

191-
fn fields_as_token_stream(&self) -> Option<TokenStream> {
192+
fn generate_for_fields(&self) -> Option<TokenStream> {
192193
match &self.fields {
193194
Fields::Named(fields_named) => {
194-
let fields: Vec<_> = fields_named
195-
.named
196-
.iter()
197-
.map(|field| {
198-
field
199-
.ident
200-
.as_ref()
201-
.expect("named fields always have an ident")
202-
})
203-
.collect();
195+
let fields = Self::named_field_idents(fields_named);
196+
Some(quote! { { #(#fields: #fields.into(),)* } })
197+
}
198+
Fields::Unnamed(fields_unnamed) => {
199+
let fields = Self::unnamed_field_ident(fields_unnamed);
200+
Some(quote! { ( #(#fields.into())* ) })
201+
}
202+
Fields::Unit => None,
203+
}
204+
}
204205

205-
Some(quote! { { #(#fields),* } })
206+
fn generate_from_fields(&self) -> Option<TokenStream> {
207+
match &self.fields {
208+
Fields::Named(fields_named) => {
209+
let fields = Self::named_field_idents(fields_named);
210+
Some(quote! { { #(#fields,)* } })
206211
}
207212
Fields::Unnamed(fields_unnamed) => {
208-
let fields: Vec<_> = fields_unnamed
209-
.unnamed
210-
.iter()
211-
.enumerate()
212-
.map(|(index, _)| format_ident!("__sv_{index}"))
213-
.collect();
214-
215-
Some(quote! { ( #(#fields),* ) })
213+
let fields = Self::unnamed_field_ident(fields_unnamed);
214+
Some(quote! { ( #(#fields)* ) })
216215
}
217216
Fields::Unit => None,
218217
}
219218
}
219+
220+
fn named_field_idents(fields_named: &FieldsNamed) -> Vec<&Ident> {
221+
fields_named
222+
.named
223+
.iter()
224+
.map(|field| {
225+
field
226+
.ident
227+
.as_ref()
228+
.expect("named fields always have an ident")
229+
})
230+
.collect()
231+
}
232+
233+
fn unnamed_field_ident(fields_unnamed: &FieldsUnnamed) -> Vec<Ident> {
234+
fields_unnamed
235+
.unnamed
236+
.iter()
237+
.enumerate()
238+
.map(|(index, _)| format_ident!("__sv_{index}"))
239+
.collect()
240+
}
220241
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use stackable_versioned::versioned;
2+
// ---
3+
#[versioned(version(name = "v1alpha1"), version(name = "v1alpha2"))]
4+
// ---
5+
pub mod versioned {
6+
enum Foo {
7+
A { aa: usize, aaa: u64 },
8+
B { bb: bool },
9+
}
10+
11+
enum Bar {
12+
A(A),
13+
B {},
14+
}
15+
16+
struct A {}
17+
}
18+
// ---
19+
fn main() {}

0 commit comments

Comments
 (0)