Skip to content

Commit 639086f

Browse files
committed
wip: Refactors
1 parent 6b92531 commit 639086f

File tree

8 files changed

+1296
-220
lines changed

8 files changed

+1296
-220
lines changed

crates/stackable-versioned-macros/src/codegen/container/enum.rs

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ use quote::quote;
66
use syn::{Generics, ItemEnum};
77

88
use crate::{
9-
attrs::container::NestedContainerAttributes,
9+
attrs::container::ContainerAttributes,
1010
codegen::{
11-
ItemStatus, StandaloneContainerAttributes, VersionDefinition,
11+
ItemStatus, VersionDefinition,
1212
changes::Neighbors,
13-
container::{CommonContainerData, Container, ContainerIdents, ContainerOptions, Direction},
13+
container::{
14+
CommonContainerData, Container, ContainerIdents, ContainerOptions, ContainerTokens,
15+
Direction, ExtendContainerTokens, ModuleGenerationContext, VersionContext,
16+
},
1417
item::VersionedVariant,
1518
},
1619
};
@@ -27,11 +30,13 @@ impl Container {
2730
}
2831

2932
let options = ContainerOptions {
30-
kubernetes_arguments: None,
31-
skip_from: attributes.options.skip.is_some_and(|s| s.from.is_present()),
33+
skip_from: attributes.skip.from.is_present(),
34+
skip_object_from: attributes.skip.object_from.is_present(),
35+
skip_merged_crd: attributes.skip.merged_crd.is_present(),
36+
skip_try_convert: attributes.skip.try_convert.is_present(),
3237
};
3338

34-
let idents = ContainerIdents::from(item_enum.ident, None);
39+
let idents = ContainerIdents::from(item_enum.ident);
3540

3641
let common = CommonContainerData {
3742
original_attributes: item_enum.attrs,
@@ -62,18 +67,43 @@ pub struct Enum {
6267

6368
// Common token generation
6469
impl Enum {
70+
pub fn generate_tokens<'a>(
71+
&'a self,
72+
versions: &'a [VersionDefinition],
73+
gen_ctx: ModuleGenerationContext<'a>,
74+
) -> ContainerTokens<'a> {
75+
let mut versions = versions.iter().peekable();
76+
let mut container_tokens = ContainerTokens::default();
77+
78+
while let Some(version) = versions.next() {
79+
let next_version = versions.peek().copied();
80+
let ver_ctx = VersionContext::new(version, next_version);
81+
82+
let enum_definition = self.generate_definition(ver_ctx);
83+
let upgrade_from = self.generate_from_impl(Direction::Upgrade, ver_ctx, gen_ctx);
84+
let downgrade_from = self.generate_from_impl(Direction::Downgrade, ver_ctx, gen_ctx);
85+
86+
container_tokens
87+
.extend_inner(&version.inner, enum_definition)
88+
.extend_between(&version.inner, upgrade_from)
89+
.extend_between(&version.inner, downgrade_from);
90+
}
91+
92+
container_tokens
93+
}
94+
6595
/// Generates code for the enum definition.
66-
pub fn generate_definition(&self, version: &VersionDefinition) -> TokenStream {
96+
pub fn generate_definition(&self, ver_ctx: VersionContext<'_>) -> TokenStream {
6797
let where_clause = self.generics.where_clause.as_ref();
6898
let type_generics = &self.generics;
6999

70100
let original_attributes = &self.common.original_attributes;
71101
let ident = &self.common.idents.original;
72-
let version_docs = &version.docs;
102+
let version_docs = &ver_ctx.version.docs;
73103

74104
let mut variants = TokenStream::new();
75105
for variant in &self.variants {
76-
variants.extend(variant.generate_for_container(version));
106+
variants.extend(variant.generate_for_container(ver_ctx.version));
77107
}
78108

79109
quote! {
@@ -89,15 +119,16 @@ impl Enum {
89119
pub fn generate_from_impl(
90120
&self,
91121
direction: Direction,
92-
version: &VersionDefinition,
93-
next_version: Option<&VersionDefinition>,
94-
add_attributes: bool,
122+
ver_ctx: VersionContext<'_>,
123+
gen_ctx: ModuleGenerationContext<'_>,
95124
) -> Option<TokenStream> {
96-
if version.skip_from || self.common.options.skip_from {
125+
if ver_ctx.version.skip_from || self.common.options.skip_from {
97126
return None;
98127
}
99128

100-
next_version.map(|next_version| {
129+
let version = ver_ctx.version;
130+
131+
ver_ctx.next_version.map(|next_version| {
101132
// TODO (@Techassi): Support generic types which have been removed in newer versions,
102133
// but need to exist for older versions How do we represent that? Because the
103134
// defined struct always represents the latest version. I guess we could generally
@@ -118,7 +149,7 @@ impl Enum {
118149

119150
// Only add the #[automatically_derived] attribute only if this impl is used
120151
// outside of a module (in standalone mode).
121-
let automatically_derived = add_attributes
152+
let automatically_derived = gen_ctx.add_attributes
122153
.not()
123154
.then(|| quote! {#[automatically_derived]});
124155

crates/stackable-versioned-macros/src/codegen/container/mod.rs

Lines changed: 148 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1-
use darling::{Result, util::IdentString};
2-
use proc_macro2::{Span, TokenStream};
3-
use quote::{format_ident, quote};
4-
use syn::{Attribute, Ident, ItemEnum, ItemStruct, Visibility};
1+
use std::collections::HashMap;
2+
3+
use darling::util::IdentString;
4+
use k8s_version::Version;
5+
use proc_macro2::{Span, TokenStream, TokenTree};
6+
use quote::format_ident;
7+
use syn::{Attribute, Ident, Visibility};
58

69
use crate::{
7-
attrs::container::{StandaloneContainerAttributes, k8s::KubernetesArguments},
10+
attrs::{
11+
container::StructCrdArguments,
12+
module::{CrateArguments, KubernetesConfigOptions, ModuleSkipArguments},
13+
},
814
codegen::{
9-
KubernetesTokens, VersionDefinition,
15+
VersionDefinition,
1016
container::{r#enum::Enum, r#struct::Struct},
1117
},
1218
utils::ContainerIdentExt,
@@ -37,57 +43,117 @@ pub enum Container {
3743
Enum(Enum),
3844
}
3945

40-
impl Container {
41-
/// Generates the container definition for the specified `version`.
42-
pub fn generate_definition(&self, version: &VersionDefinition) -> TokenStream {
43-
match self {
44-
Container::Struct(s) => s.generate_definition(version),
45-
Container::Enum(e) => e.generate_definition(version),
46-
}
46+
#[derive(Debug, Default)]
47+
pub struct ContainerTokens<'a> {
48+
pub versioned: HashMap<&'a Version, VersionedContainerTokens>,
49+
pub outer: TokenStream,
50+
}
51+
52+
#[derive(Debug, Default)]
53+
/// A collection of generated tokens for a container per version.
54+
pub struct VersionedContainerTokens {
55+
/// The inner tokens are placed inside the version module. These tokens mostly only include the
56+
/// container definition with attributes, doc comments, etc.
57+
pub inner: TokenStream,
58+
59+
/// These tokens are placed between version modules. These could technically be grouped together
60+
/// with the outer tokens, but it makes sense to keep them separate to achieve a more structured
61+
/// code generation. These tokens mostly only include `From` impls to convert between two versions
62+
pub between: TokenStream,
63+
}
64+
65+
pub trait ExtendContainerTokens<'a, T> {
66+
fn extend_inner<I: IntoIterator<Item = T>>(
67+
&mut self,
68+
version: &'a Version,
69+
streams: I,
70+
) -> &mut Self;
71+
fn extend_between<I: IntoIterator<Item = T>>(
72+
&mut self,
73+
version: &'a Version,
74+
streams: I,
75+
) -> &mut Self;
76+
fn extend_outer<I: IntoIterator<Item = T>>(&mut self, streams: I) -> &mut Self;
77+
}
78+
79+
impl<'a> ExtendContainerTokens<'a, TokenStream> for ContainerTokens<'a> {
80+
fn extend_inner<I: IntoIterator<Item = TokenStream>>(
81+
&mut self,
82+
version: &'a Version,
83+
streams: I,
84+
) -> &mut Self {
85+
self.versioned
86+
.entry(version)
87+
.or_default()
88+
.inner
89+
.extend(streams);
90+
self
4791
}
4892

49-
pub fn generate_from_impl(
50-
&self,
51-
direction: Direction,
52-
version: &VersionDefinition,
53-
next_version: Option<&VersionDefinition>,
54-
add_attributes: bool,
55-
) -> Option<TokenStream> {
56-
match self {
57-
Container::Struct(s) => {
58-
// TODO (@Techassi): Decide here (based on K8s args) what we want to generate
59-
s.generate_from_impl(direction, version, next_version, add_attributes)
60-
}
61-
Container::Enum(e) => {
62-
e.generate_from_impl(direction, version, next_version, add_attributes)
63-
}
64-
}
93+
fn extend_between<I: IntoIterator<Item = TokenStream>>(
94+
&mut self,
95+
version: &'a Version,
96+
streams: I,
97+
) -> &mut Self {
98+
self.versioned
99+
.entry(version)
100+
.or_default()
101+
.between
102+
.extend(streams);
103+
self
65104
}
66105

67-
/// Generates Kubernetes specific code for the container.
68-
///
69-
/// This includes CRD merging, CRD conversion, and the conversion tracking status struct.
70-
pub fn generate_kubernetes_code(
71-
&self,
72-
versions: &[VersionDefinition],
73-
tokens: &KubernetesTokens,
74-
vis: &Visibility,
75-
is_nested: bool,
76-
) -> Option<TokenStream> {
77-
match self {
78-
Container::Struct(s) => s.generate_kubernetes_code(versions, tokens, vis, is_nested),
79-
Container::Enum(_) => None,
80-
}
106+
fn extend_outer<I: IntoIterator<Item = TokenStream>>(&mut self, streams: I) -> &mut Self {
107+
self.outer.extend(streams);
108+
self
109+
}
110+
}
111+
112+
impl<'a> ExtendContainerTokens<'a, TokenTree> for ContainerTokens<'a> {
113+
fn extend_inner<I: IntoIterator<Item = TokenTree>>(
114+
&mut self,
115+
version: &'a Version,
116+
streams: I,
117+
) -> &mut Self {
118+
self.versioned
119+
.entry(version)
120+
.or_default()
121+
.inner
122+
.extend(streams);
123+
self
124+
}
125+
126+
fn extend_between<I: IntoIterator<Item = TokenTree>>(
127+
&mut self,
128+
version: &'a Version,
129+
streams: I,
130+
) -> &mut Self {
131+
self.versioned
132+
.entry(version)
133+
.or_default()
134+
.between
135+
.extend(streams);
136+
self
81137
}
82138

83-
/// Generates KUbernetes specific code for individual versions.
84-
pub fn generate_kubernetes_version_items(
85-
&self,
86-
version: &VersionDefinition,
87-
) -> Option<(TokenStream, IdentString, TokenStream, String)> {
139+
fn extend_outer<I: IntoIterator<Item = TokenTree>>(&mut self, streams: I) -> &mut Self {
140+
self.outer.extend(streams);
141+
self
142+
}
143+
}
144+
145+
impl Container {
146+
// TODO (@Techassi): Only have a single function here. It should return and store all generated
147+
// tokens. It should also have access to a single GenerationContext, which provides all external
148+
// parameters which influence code generation.
149+
pub fn generate_tokens<'a>(
150+
&'a self,
151+
versions: &'a [VersionDefinition],
152+
ctx: ModuleGenerationContext<'a>,
153+
) -> ContainerTokens<'a> {
88154
match self {
89-
Container::Struct(s) => s.generate_kubernetes_version_items(version),
90-
Container::Enum(_) => None,
155+
Container::Struct(s) => s.generate_tokens(versions, ctx),
156+
Container::Enum(e) => e.generate_tokens(versions, ctx),
91157
}
92158
}
93159

@@ -162,12 +228,43 @@ impl KubernetesIdents {
162228

163229
#[derive(Debug)]
164230
pub struct ContainerOptions {
165-
pub kubernetes_arguments: Option<KubernetesArguments>,
166231
pub skip_from: bool,
232+
pub skip_object_from: bool,
233+
pub skip_merged_crd: bool,
234+
pub skip_try_convert: bool,
167235
}
168236

237+
/// Describes the direction of [`From`] implementations.
169238
#[derive(Copy, Clone, Debug)]
170239
pub enum Direction {
171240
Upgrade,
172241
Downgrade,
173242
}
243+
244+
#[derive(Clone, Copy, Debug)]
245+
pub struct ModuleGenerationContext<'a> {
246+
pub kubernetes_options: &'a KubernetesConfigOptions,
247+
pub skip: &'a ModuleSkipArguments,
248+
pub crates: &'a CrateArguments,
249+
pub vis: &'a Visibility,
250+
251+
pub add_attributes: bool,
252+
}
253+
254+
#[derive(Clone, Copy, Debug)]
255+
pub struct VersionContext<'a> {
256+
pub version: &'a VersionDefinition,
257+
pub next_version: Option<&'a VersionDefinition>,
258+
}
259+
260+
impl<'a> VersionContext<'a> {
261+
pub fn new(
262+
version: &'a VersionDefinition,
263+
next_version: Option<&'a VersionDefinition>,
264+
) -> Self {
265+
Self {
266+
version,
267+
next_version,
268+
}
269+
}
270+
}

0 commit comments

Comments
 (0)