-
-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathmod.rs
More file actions
235 lines (205 loc) · 7.04 KB
/
mod.rs
File metadata and controls
235 lines (205 loc) · 7.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
use std::collections::HashMap;
use darling::util::IdentString;
use k8s_version::Version;
use proc_macro2::{Span, TokenStream, TokenTree};
use quote::format_ident;
use syn::{Attribute, Ident};
use crate::{
attrs::container::StructCrdArguments,
codegen::{
VersionDefinition,
container::{r#enum::Enum, r#struct::Struct},
module::ModuleGenerationContext,
},
utils::ContainerIdentExt,
};
mod r#enum;
mod r#struct;
/// Contains common container data shared between structs and enums.
#[derive(Debug)]
pub struct CommonContainerData {
/// Original attributes placed on the container, like `#[derive()]` or `#[cfg()]`.
pub original_attributes: Vec<Attribute>,
/// Different options which influence code generation.
pub options: ContainerOptions,
/// A collection of container idents used for different purposes.
pub idents: ContainerIdents,
}
/// Supported types of containers, structs and enums.
///
/// Abstracting away with kind of container is generated makes it possible to create a list of
/// containers when the macro is used on modules. This enum provides functions to generate code
/// which then internally call the appropriate function based on the variant.
#[allow(clippy::large_enum_variant)]
pub enum Container {
Struct(Struct),
Enum(Enum),
}
#[derive(Debug, Default)]
pub struct ContainerTokens<'a> {
pub versioned: HashMap<&'a Version, VersionedContainerTokens>,
pub outer: TokenStream,
}
#[derive(Debug, Default)]
/// A collection of generated tokens for a container per version.
pub struct VersionedContainerTokens {
/// The inner tokens are placed inside the version module. These tokens mostly only include the
/// container definition with attributes, doc comments, etc.
pub inner: TokenStream,
/// These tokens are placed between version modules. These could technically be grouped together
/// with the outer tokens, but it makes sense to keep them separate to achieve a more structured
/// code generation. These tokens mostly only include `From` impls to convert between two versions
pub between: TokenStream,
}
pub trait ExtendContainerTokens<'a, T> {
fn extend_inner<I: IntoIterator<Item = T>>(
&mut self,
version: &'a Version,
streams: I,
) -> &mut Self;
fn extend_between<I: IntoIterator<Item = T>>(
&mut self,
version: &'a Version,
streams: I,
) -> &mut Self;
fn extend_outer<I: IntoIterator<Item = T>>(&mut self, streams: I) -> &mut Self;
}
impl<'a> ExtendContainerTokens<'a, TokenStream> for ContainerTokens<'a> {
fn extend_inner<I: IntoIterator<Item = TokenStream>>(
&mut self,
version: &'a Version,
streams: I,
) -> &mut Self {
self.versioned
.entry(version)
.or_default()
.inner
.extend(streams);
self
}
fn extend_between<I: IntoIterator<Item = TokenStream>>(
&mut self,
version: &'a Version,
streams: I,
) -> &mut Self {
self.versioned
.entry(version)
.or_default()
.between
.extend(streams);
self
}
fn extend_outer<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) -> &mut Self {
self.outer.extend(streams);
self
}
}
impl<'a> ExtendContainerTokens<'a, TokenTree> for ContainerTokens<'a> {
fn extend_inner<I: IntoIterator<Item = TokenTree>>(
&mut self,
version: &'a Version,
streams: I,
) -> &mut Self {
self.versioned
.entry(version)
.or_default()
.inner
.extend(streams);
self
}
fn extend_between<I: IntoIterator<Item = TokenTree>>(
&mut self,
version: &'a Version,
streams: I,
) -> &mut Self {
self.versioned
.entry(version)
.or_default()
.between
.extend(streams);
self
}
fn extend_outer<I: IntoIterator<Item = TokenTree>>(&mut self, streams: I) -> &mut Self {
self.outer.extend(streams);
self
}
}
impl Container {
// TODO (@Techassi): Only have a single function here. It should return and store all generated
// tokens. It should also have access to a single GenerationContext, which provides all external
// parameters which influence code generation.
pub fn generate_tokens<'a>(
&'a self,
versions: &'a [VersionDefinition],
ctx: ModuleGenerationContext<'a>,
) -> ContainerTokens<'a> {
match self {
Container::Struct(s) => s.generate_tokens(versions, ctx),
Container::Enum(e) => e.generate_tokens(versions, ctx),
}
}
/// Returns the original ident of the container.
pub fn get_original_ident(&self) -> &Ident {
match &self {
Container::Struct(s) => s.common.idents.original.as_ident(),
Container::Enum(e) => e.common.idents.original.as_ident(),
}
}
}
/// A collection of container idents used for different purposes.
#[derive(Debug)]
pub struct ContainerIdents {
/// The original ident, or name, of the versioned container.
pub original: IdentString,
/// The ident used as a parameter.
pub parameter: IdentString,
}
#[derive(Debug)]
pub struct KubernetesIdents {
/// This ident removes the 'Spec' suffix present in the definition container.
/// This ident is only used in the context of Kubernetes specific code.
pub kind: IdentString,
/// This ident uses the base Kubernetes ident to construct an appropriate ident
/// for auto-generated status structs. This ident is only used in the context of
/// Kubernetes specific code.
pub status: IdentString,
/// This ident uses the base Kubernetes ident to construct an appropriate ident
/// for auto-generated version enums. This enum is used to select the stored
/// api version when merging CRDs. This ident is only used in the context of
/// Kubernetes specific code.
pub version: IdentString,
// TODO (@Techassi): Add comment
pub parameter: IdentString,
}
impl From<Ident> for ContainerIdents {
fn from(ident: Ident) -> Self {
Self {
parameter: ident.as_parameter_ident(),
original: ident.into(),
}
}
}
impl KubernetesIdents {
pub fn from(ident: &IdentString, arguments: &StructCrdArguments) -> Self {
let kind = match &arguments.kind {
Some(kind) => IdentString::from(Ident::new(kind, Span::call_site())),
None => ident.as_cleaned_kubernetes_ident(),
};
let status = IdentString::from(format_ident!("{kind}StatusWithChangedValues"));
let version = IdentString::from(format_ident!("{kind}Version"));
let parameter = kind.as_parameter_ident();
Self {
parameter,
version,
status,
kind,
}
}
}
#[derive(Debug)]
pub struct ContainerOptions {
pub skip_from: bool,
pub skip_object_from: bool,
pub skip_merged_crd: bool,
pub skip_try_convert: bool,
}