1#![allow(clippy::manual_unwrap_or_default)]
3
4use darling::{FromDeriveInput, FromMeta};
5use syn::{parse_quote, Data, DeriveInput, Path};
6
7#[derive(Debug, FromDeriveInput)]
9#[darling(attributes(resource))]
10struct InheritAttrs {
11 inherit: syn::Path,
12 #[darling(default)]
13 crates: Crates,
14}
15
16#[derive(Debug, FromMeta)]
17struct Crates {
18 #[darling(default = "Self::default_kube_core")]
19 kube_core: Path,
20 #[darling(default = "Self::default_k8s_openapi")]
21 k8s_openapi: Path,
22}
23
24impl Default for Crates {
27 fn default() -> Self {
28 Self::from_list(&[]).unwrap()
29 }
30}
31
32impl Crates {
33 fn default_kube_core() -> Path {
34 parse_quote! { ::kube::core } }
36
37 fn default_k8s_openapi() -> Path {
38 parse_quote! { ::k8s_openapi }
39 }
40}
41
42pub(crate) fn derive(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
43 let derive_input: DeriveInput = match syn::parse2(input) {
44 Err(err) => return err.to_compile_error(),
45 Ok(di) => di,
46 };
47 match derive_input.data {
49 Data::Struct(_) | Data::Enum(_) => {}
50 _ => {
51 return syn::Error::new_spanned(&derive_input.ident, r#"Unions can not #[derive(Resource)]"#)
52 .to_compile_error()
53 }
54 }
55 let kube_attrs = match InheritAttrs::from_derive_input(&derive_input) {
56 Err(err) => return err.write_errors(),
57 Ok(attrs) => attrs,
58 };
59
60 let InheritAttrs {
61 inherit: resource,
62 crates: Crates {
63 kube_core,
64 k8s_openapi,
65 },
66 ..
67 } = kube_attrs;
68
69 let rootident = derive_input.ident;
70
71 let inherit_resource = quote! {
72 impl #kube_core::Resource for #rootident {
73 type DynamicType = <#resource as #kube_core::Resource>::DynamicType;
74 type Scope = <#resource as #kube_core::Resource>::Scope;
75
76 fn group(_: &<#resource as #kube_core::Resource>::DynamicType) -> std::borrow::Cow<'_, str> {
77 #resource::group(&Default::default()).into_owned().into()
78 }
79
80 fn kind(_: &<#resource as #kube_core::Resource>::DynamicType) -> std::borrow::Cow<'_, str> {
81 #resource::kind(&Default::default()).into_owned().into()
82 }
83
84 fn version(_: &<#resource as #kube_core::Resource>::DynamicType) -> std::borrow::Cow<'_, str> {
85 #resource::version(&Default::default()).into_owned().into()
86 }
87
88 fn api_version(_: &<#resource as #kube_core::Resource>::DynamicType) -> std::borrow::Cow<'_, str> {
89 #resource::api_version(&Default::default()).into_owned().into()
90 }
91
92 fn plural(_: &<#resource as #kube_core::Resource>::DynamicType) -> std::borrow::Cow<'_, str> {
93 #resource::plural(&Default::default()).into_owned().into()
94 }
95
96 fn meta(&self) -> &#k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta {
97 &self.metadata
98 }
99
100 fn meta_mut(&mut self) -> &mut #k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta {
101 &mut self.metadata
102 }
103 }
104 };
105
106 quote! {
108 #inherit_resource
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_parse_inherit() {
118 let input = quote! {
119 #[derive(Resource)]
120 #[resource(inherit = "ConfigMap")]
121 struct Foo { metadata: ObjectMeta }
122 };
123
124 let input = syn::parse2(input).unwrap();
125 InheritAttrs::from_derive_input(&input).unwrap();
126 }
127}