@@ -45,7 +45,7 @@ impl Container {
4545 // Ensure that the struct name includes the 'Spec' suffix.
4646 if kubernetes_data. is_some ( ) && !idents. original . as_str ( ) . ends_with ( "Spec" ) {
4747 return Err ( Error :: custom (
48- "struct name needs to include the `Spec` suffix if Kubernetes features are enabled via `#[versioned(k8s ())]`"
48+ "struct name needs to include the `Spec` suffix if CRD features are enabled via `#[versioned(crd ())]`"
4949 ) . with_span ( & idents. original . span ( ) ) ) ;
5050 }
5151
@@ -207,7 +207,7 @@ impl Struct {
207207 fn generate_kube_attribute (
208208 & self ,
209209 ver_ctx : VersionContext < ' _ > ,
210- gen_ctx : ModuleGenerationContext < ' _ > ,
210+ mod_gen_ctx : ModuleGenerationContext < ' _ > ,
211211 spec_gen_ctx : & SpecGenerationContext < ' _ > ,
212212 ) -> Option < TokenStream > {
213213 // Required arguments
@@ -234,27 +234,37 @@ impl Struct {
234234 . as_ref ( )
235235 . map ( |p| quote ! { , plural = #p } ) ;
236236
237- let crates = gen_ctx . crates ;
237+ let crates = mod_gen_ctx . crates ;
238238
239239 let namespaced = spec_gen_ctx
240240 . kubernetes_arguments
241241 . namespaced
242242 . is_present ( )
243243 . then_some ( quote ! { , namespaced } ) ;
244244
245+ // NOTE (@Techassi): What an abomination
245246 let status = match (
246- gen_ctx
247+ mod_gen_ctx
247248 . kubernetes_options
248249 . experimental_conversion_tracking
249250 . is_present ( ) ,
250251 & spec_gen_ctx. kubernetes_arguments . status ,
251252 ) {
252- ( true , _) => {
253- let status_ident = & spec_gen_ctx. kubernetes_idents . status ;
254- Some ( quote ! { , status = #status_ident } )
253+ ( true , status_path) => {
254+ if ( mod_gen_ctx. skip . merged_crd . is_present ( ) || self . common . options . skip_merged_crd )
255+ && ( mod_gen_ctx. skip . try_convert . is_present ( )
256+ || self . common . options . skip_try_convert )
257+ {
258+ status_path
259+ . as_ref ( )
260+ . map ( |status_path| quote ! { , status = #status_path } )
261+ } else {
262+ let status_ident = & spec_gen_ctx. kubernetes_idents . status ;
263+ Some ( quote ! { , status = #status_ident } )
264+ }
255265 }
256- ( _ , Some ( status_ident ) ) => Some ( quote ! { , status = #status_ident } ) ,
257- ( _ , _ ) => None ,
266+ ( false , Some ( status_path ) ) => Some ( quote ! { , status = #status_path } ) ,
267+ _ => None ,
258268 } ;
259269
260270 let shortnames: TokenStream = spec_gen_ctx
@@ -306,14 +316,7 @@ impl Struct {
306316 ) -> TokenStream {
307317 let enum_ident = & spec_gen_ctx. kubernetes_idents . kind ;
308318
309- // Only generate merged_crd associated function if not opted out
310- let merged_crd_fn =
311- if !mod_gen_ctx. skip . merged_crd . is_present ( ) && !self . common . options . skip_merged_crd {
312- Some ( self . generate_merged_crd_fn ( mod_gen_ctx, spec_gen_ctx) )
313- } else {
314- None
315- } ;
316-
319+ let merged_crd_fn = self . generate_merged_crd_fn ( mod_gen_ctx, spec_gen_ctx) ;
317320 let try_convert_fn = self . generate_try_convert_fn ( versions, mod_gen_ctx, spec_gen_ctx) ;
318321 let from_json_value_fn = self . generate_from_json_value_fn ( mod_gen_ctx, spec_gen_ctx) ;
319322 let into_json_value_fn = self . generate_into_json_value_fn ( mod_gen_ctx, spec_gen_ctx) ;
@@ -421,22 +424,84 @@ impl Struct {
421424 return None ;
422425 }
423426
424- if !mod_gen_ctx
425- . kubernetes_options
426- . experimental_conversion_tracking
427- . is_present ( )
428- {
429- return None ;
430- }
431-
432427 let next_version = ver_ctx. next_version ;
433428 let version = ver_ctx. version ;
434429
435430 next_version. map ( |next_version| {
436- self . generate_tracking_from_impl ( direction, version, next_version, mod_gen_ctx)
431+ if mod_gen_ctx
432+ . kubernetes_options
433+ . experimental_conversion_tracking
434+ . is_present ( )
435+ {
436+ self . generate_tracking_from_impl ( direction, version, next_version, mod_gen_ctx)
437+ } else {
438+ self . generate_plain_from_impl ( direction, version, next_version, mod_gen_ctx)
439+ }
437440 } )
438441 }
439442
443+ fn generate_plain_from_impl (
444+ & self ,
445+ direction : Direction ,
446+ version : & VersionDefinition ,
447+ next_version : & VersionDefinition ,
448+ mod_gen_ctx : ModuleGenerationContext < ' _ > ,
449+ ) -> TokenStream {
450+ // TODO (@Techassi): A bunch this stuff is duplicated in self.generate_tracking_from_impl.
451+ // Ideally we remove that duplication.
452+ let from_struct_ident = & self . common . idents . parameter ;
453+ let struct_ident = & self . common . idents . original ;
454+
455+ // Include allow(deprecated) only when this or the next version is
456+ // deprecated. Also include it, when a field in this or the next
457+ // version is deprecated.
458+ let allow_attribute = ( version. deprecated . is_some ( )
459+ || next_version. deprecated . is_some ( )
460+ || self . is_any_field_deprecated ( version)
461+ || self . is_any_field_deprecated ( next_version) )
462+ . then ( || quote ! { #[ allow( deprecated) ] } ) ;
463+
464+ // Only add the #[automatically_derived] attribute only if this impl is used
465+ // outside of a module (in standalone mode).
466+ let automatically_derived = mod_gen_ctx. automatically_derived_attr ( ) ;
467+
468+ let fields = |direction : Direction | -> TokenStream {
469+ self . fields
470+ . iter ( )
471+ . filter_map ( |f| {
472+ f. generate_for_from_impl ( direction, version, next_version, from_struct_ident)
473+ } )
474+ . collect ( )
475+ } ;
476+
477+ let ( fields, for_module_ident, from_module_ident) = match direction {
478+ direction @ Direction :: Upgrade => {
479+ let from_module_ident = & version. idents . module ;
480+ let for_module_ident = & next_version. idents . module ;
481+
482+ ( fields ( direction) , for_module_ident, from_module_ident)
483+ }
484+ direction @ Direction :: Downgrade => {
485+ let from_module_ident = & next_version. idents . module ;
486+ let for_module_ident = & version. idents . module ;
487+
488+ ( fields ( direction) , for_module_ident, from_module_ident)
489+ }
490+ } ;
491+
492+ quote ! {
493+ #automatically_derived
494+ #allow_attribute
495+ impl :: core:: convert:: From <#from_module_ident:: #struct_ident> for #for_module_ident:: #struct_ident {
496+ fn from( #from_struct_ident: #from_module_ident:: #struct_ident) -> Self {
497+ Self {
498+ #fields
499+ }
500+ }
501+ }
502+ }
503+ }
504+
440505 /// Returns whether any field is deprecated in the provided `version`.
441506 fn is_any_field_deprecated ( & self , version : & VersionDefinition ) -> bool {
442507 // First, iterate over all fields. The `any` function will return true
0 commit comments