@@ -153,7 +153,8 @@ impl Struct {
153153 // Generate additional Kubernetes code, this is split out to reduce the complexity in this
154154 // function.
155155 let status_struct = self . generate_kubernetes_status_struct ( kubernetes_arguments, is_nested) ;
156- let version_enum = self . generate_kubernetes_version_enum ( tokens, vis, is_nested) ;
156+ let version_enum =
157+ self . generate_kubernetes_version_enum ( kubernetes_arguments, tokens, vis, is_nested) ;
157158 let convert_method = self . generate_kubernetes_conversion ( versions) ;
158159
159160 let parse_object_error = quote ! { #versioned_path:: ParseObjectError } ;
@@ -173,7 +174,7 @@ impl Struct {
173174 #k8s_openapi_path:: apiextensions_apiserver:: pkg:: apis:: apiextensions:: v1:: CustomResourceDefinition ,
174175 #kube_core_path:: crd:: MergeError >
175176 {
176- #kube_core_path:: crd:: merge_crds( vec![ #( #crd_fns) , * ] , stored_apiversion. as_str ( ) )
177+ #kube_core_path:: crd:: merge_crds( vec![ #( #crd_fns) , * ] , stored_apiversion. as_version_str ( ) )
177178 }
178179
179180 #convert_method
@@ -234,6 +235,7 @@ impl Struct {
234235
235236 fn generate_kubernetes_version_enum (
236237 & self ,
238+ kubernetes_arguments : & KubernetesArguments ,
237239 tokens : & KubernetesTokens ,
238240 vis : & Visibility ,
239241 is_nested : bool ,
@@ -244,9 +246,16 @@ impl Struct {
244246 // module (in standalone mode).
245247 let automatically_derived = is_nested. not ( ) . then ( || quote ! { #[ automatically_derived] } ) ;
246248
249+ let versioned_path = & * kubernetes_arguments. crates . versioned ;
250+ let convert_object_error = quote ! { #versioned_path:: ConvertObjectError } ;
251+
247252 // Get the per-version items to be able to iterate over them via quote
248253 let variant_strings = & tokens. variant_strings ;
249254 let variant_idents = & tokens. variant_idents ;
255+ let api_versions = variant_strings
256+ . iter ( )
257+ . map ( |version| format ! ( "{group}/{version}" , group = & kubernetes_arguments. group) )
258+ . collect :: < Vec < _ > > ( ) ;
250259
251260 quote ! {
252261 #automatically_derived
@@ -257,17 +266,33 @@ impl Struct {
257266 #automatically_derived
258267 impl :: std:: fmt:: Display for #enum_ident {
259268 fn fmt( & self , f: & mut :: std:: fmt:: Formatter <' _>) -> :: std:: result:: Result <( ) , :: std:: fmt:: Error > {
260- f. write_str( self . as_str( ) )
269+ // The version (without the Kubernetes group) is probably more human-readable
270+ f. write_str( self . as_version_str( ) )
261271 }
262272 }
263273
264274 #automatically_derived
265275 impl #enum_ident {
266- pub fn as_str ( & self ) -> & str {
276+ pub fn as_version_str ( & self ) -> & str {
267277 match self {
268278 #( #variant_idents => #variant_strings) , *
269279 }
270280 }
281+
282+ pub fn as_api_version_str( & self ) -> & str {
283+ match self {
284+ #( #variant_idents => #api_versions) , *
285+ }
286+ }
287+
288+ pub fn try_from_api_version( api_version: & str ) -> Result <Self , #convert_object_error> {
289+ match api_version {
290+ #( #api_versions => Ok ( Self :: #variant_idents) ) , * ,
291+ _ => Err ( #convert_object_error:: DesiredApiVersionUnknown {
292+ unknown_desired_api_version: api_version. to_string( ) ,
293+ } ) ,
294+ }
295+ }
271296 }
272297 }
273298 }
@@ -331,6 +356,7 @@ impl Struct {
331356 let kubernetes_arguments = self . common . options . kubernetes_arguments . as_ref ( ) ?;
332357
333358 let struct_ident = & self . common . idents . kubernetes ;
359+ let version_enum_ident = & self . common . idents . kubernetes_version ;
334360
335361 let kube_client_path = & * kubernetes_arguments. crates . kube_client ;
336362 let serde_json_path = & * kubernetes_arguments. crates . serde_json ;
@@ -342,8 +368,7 @@ impl Struct {
342368 // Generate conversion paths and the match arms for these paths
343369 let conversion_match_arms =
344370 self . generate_kubernetes_conversion_match_arms ( versions, kubernetes_arguments) ;
345- let noop_match_arms =
346- self . generate_kubernetes_noop_match_arms ( versions, kubernetes_arguments) ;
371+ let noop_match_arms = self . generate_kubernetes_noop_match_arms ( versions) ;
347372
348373 // TODO (@Techassi): Make this a feature, drop the option from the macro arguments
349374 // Generate tracing attributes and events if tracing is enabled
@@ -393,11 +418,8 @@ impl Struct {
393418 }
394419 } ;
395420
396- // Extract the desired api version
397- let desired_api_version = request. desired_api_version. as_str( ) ;
398-
399421 // Convert all objects into the desired version
400- let response = match Self :: convert_objects( request. objects, desired_api_version) {
422+ let response = match Self :: convert_objects( request. objects, & request . desired_api_version) {
401423 :: std:: result:: Result :: Ok ( converted_objects) => {
402424 #successful_conversion_response_event
403425
@@ -444,6 +466,9 @@ impl Struct {
444466 )
445467 -> :: std:: result:: Result <:: std:: vec:: Vec <#serde_json_path:: Value >, #convert_object_error>
446468 {
469+ let desired_api_version = #version_enum_ident:: try_from_api_version( desired_api_version) ?;
470+ // let desired_api_version: #version_enum_ident = desired_api_version.try_into()?;
471+
447472 let mut converted_objects = :: std:: vec:: Vec :: with_capacity( objects. len( ) ) ;
448473
449474 for object in objects {
@@ -452,14 +477,11 @@ impl Struct {
452477 let current_object = Self :: from_json_value( object. clone( ) )
453478 . map_err( |source| #convert_object_error:: Parse { source } ) ?;
454479
455- match ( current_object, desired_api_version) {
480+ match ( current_object, & desired_api_version) {
456481 #( #conversion_match_arms, ) *
482+ // We explicitly list the remaining no-op cases, so the compiler ensures we
483+ // did not miss a conversion.
457484 #( #noop_match_arms, ) *
458- ( _, unknown_desired_api_version) => return :: std:: result:: Result :: Err (
459- #convert_object_error:: DesiredApiVersionUnknown {
460- unknown_desired_api_version: unknown_desired_api_version. to_string( )
461- }
462- )
463485 }
464486 }
465487
@@ -476,6 +498,7 @@ impl Struct {
476498 let group = & kubernetes_arguments. group ;
477499 let variant_data_ident = & self . common . idents . kubernetes_parameter ;
478500 let struct_ident = & self . common . idents . kubernetes ;
501+ let version_enum_ident = & self . common . idents . kubernetes_version ;
479502 let spec_ident = & self . common . idents . original ;
480503
481504 let versioned_path = & * kubernetes_arguments. crates . versioned ;
@@ -530,7 +553,7 @@ impl Struct {
530553 . then ( || quote ! { status: #variant_data_ident. status, } ) ;
531554
532555 quote ! {
533- ( Self :: #current_object_version_ident( #variant_data_ident) , #desired_object_api_version_string ) => {
556+ ( Self :: #current_object_version_ident( #variant_data_ident) , #version_enum_ident :: #desired_object_variant_ident ) => {
534557 #( #conversions) *
535558
536559 let desired_object = Self :: #desired_object_variant_ident( #desired_object_module_ident:: #struct_ident {
@@ -554,22 +577,19 @@ impl Struct {
554577 fn generate_kubernetes_noop_match_arms (
555578 & self ,
556579 versions : & [ VersionDefinition ] ,
557- kubernetes_arguments : & KubernetesArguments ,
558580 ) -> Vec < TokenStream > {
559- let group = & kubernetes_arguments . group ;
581+ let version_enum_ident = & self . common . idents . kubernetes_version ;
560582
561583 versions
562584 . iter ( )
563585 . map ( |version| {
564586 let version_ident = & version. idents . variant ;
565- let version_string = version. inner . to_string ( ) ;
566- let api_version_string = format ! ( "{group}/{version_string}" ) ;
567587
568588 quote ! {
569589 // This is the case if the desired version matches the current object api version.
570590 // NOTE (@Techassi): I'm curious if this will ever happen? In theory the K8s
571591 // apiserver should never send such a conversion review.
572- ( Self :: #version_ident( _) , #api_version_string ) => converted_objects. push( object)
592+ ( Self :: #version_ident( _) , #version_enum_ident :: #version_ident ) => converted_objects. push( object)
573593 }
574594 } )
575595 . collect ( )
0 commit comments