Skip to content

Commit 1d821e7

Browse files
committed
Add basic From impl generation
1 parent f379b3e commit 1d821e7

File tree

6 files changed

+76
-30
lines changed

6 files changed

+76
-30
lines changed

crates/stackable-versioned/src/attrs/container.rs

+1
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,5 @@ pub(crate) struct VersionAttributes {
103103
#[derive(Clone, Debug, Default, FromMeta)]
104104
pub(crate) struct ContainerOptions {
105105
pub(crate) allow_unsorted: Flag,
106+
pub(crate) skip_from: Flag,
106107
}

crates/stackable-versioned/src/attrs/field.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use darling::{util::SpannedValue, Error, FromField, FromMeta};
22
use k8s_version::Version;
3-
use syn::{Field, Ident};
3+
use syn::{Field, Ident, Path};
44

55
use crate::{attrs::container::ContainerAttributes, consts::DEPRECATED_PREFIX};
66

@@ -40,6 +40,7 @@ pub(crate) struct FieldAttributes {
4040
#[derive(Clone, Debug, FromMeta)]
4141
pub(crate) struct AddedAttributes {
4242
pub(crate) since: SpannedValue<Version>,
43+
pub(crate) default: Option<SpannedValue<Path>>,
4344
}
4445

4546
#[derive(Clone, Debug, FromMeta)]

crates/stackable-versioned/src/gen/field.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ pub(crate) struct VersionedField {
2424
inner: Field,
2525
}
2626

27-
impl ToTokensExt for VersionedField {
28-
fn to_tokens_for_version(&self, container_version: &ContainerVersion) -> Option<TokenStream> {
27+
impl ToTokensExt<&ContainerVersion> for VersionedField {
28+
fn to_tokens(&self, container_version: &ContainerVersion) -> Option<TokenStream> {
2929
match &self.chain {
3030
Some(chain) => {
3131
// Check if the provided container version is present in the map

crates/stackable-versioned/src/gen/mod.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use syn::{spanned::Spanned, Data, DeriveInput, Error, Result};
77

88
use crate::{
99
attrs::container::ContainerAttributes,
10-
gen::{venum::VersionedEnum, version::ContainerVersion, vstruct::VersionedStruct},
10+
gen::{venum::VersionedEnum, vstruct::VersionedStruct},
1111
};
1212

1313
pub(crate) mod field;
@@ -33,9 +33,9 @@ pub(crate) fn expand(input: DeriveInput) -> Result<TokenStream> {
3333

3434
// Validate container shape and generate code
3535
let expanded = match input.data {
36-
Data::Struct(data) => {
37-
VersionedStruct::new(input.ident, data, attributes)?.to_token_stream()
38-
}
36+
Data::Struct(data) => VersionedStruct::new(input.ident, data, attributes)?
37+
.to_tokens(true)
38+
.expect("internal error: must produce tokens for versioned struct"),
3939
Data::Enum(data) => VersionedEnum::new(input.ident, data, attributes)?.to_token_stream(),
4040
Data::Union(_) => {
4141
return Err(Error::new(
@@ -48,8 +48,11 @@ pub(crate) fn expand(input: DeriveInput) -> Result<TokenStream> {
4848
Ok(expanded)
4949
}
5050

51-
pub(crate) trait ToTokensExt {
52-
fn to_tokens_for_version(&self, version: &ContainerVersion) -> Option<TokenStream>;
51+
pub(crate) trait ToTokensExt<T>
52+
where
53+
T: Copy,
54+
{
55+
fn to_tokens(&self, state: T) -> Option<TokenStream>;
5356
}
5457

5558
pub(crate) trait Neighbors<K, V>

crates/stackable-versioned/src/gen/version.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use k8s_version::Version;
22

3-
#[derive(Debug)]
3+
#[derive(Debug, Clone)]
44
pub(crate) struct ContainerVersion {
55
pub(crate) deprecated: bool,
66
pub(crate) inner: Version,

crates/stackable-versioned/src/gen/vstruct.rs

+61-20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use darling::FromField;
22
use proc_macro2::TokenStream;
3-
use quote::{format_ident, quote, ToTokens};
3+
use quote::{format_ident, quote};
44
use syn::{DataStruct, Ident, Result};
55

66
use crate::{
@@ -26,41 +26,82 @@ pub(crate) struct VersionedStruct {
2626
pub(crate) fields: Vec<VersionedField>,
2727
}
2828

29-
impl ToTokens for VersionedStruct {
30-
fn to_tokens(&self, _tokens: &mut TokenStream) {
31-
let mut versions = self.versions.iter().peekable();
29+
impl ToTokensExt<bool> for VersionedStruct {
30+
fn to_tokens(&self, generate_modules: bool) -> Option<TokenStream> {
31+
// TODO (@Techassi): This unwrap should be fine, should we expect here?
32+
let mut versions = self.versions.clone();
33+
versions.pop().unwrap();
34+
let mut versions = versions.iter().peekable();
3235

36+
let mut tokens = TokenStream::new();
37+
38+
// TODO (@Techassi): Move this into own functions
3339
while let Some(version) = versions.next() {
34-
let mut fields = TokenStream::new();
40+
let mut field_tokens = TokenStream::new();
3541

3642
for field in &self.fields {
37-
fields.extend(field.to_tokens_for_version(version));
43+
field_tokens.extend(field.to_tokens(version));
3844
}
3945

40-
// TODO (@Techassi): Make the generation of the module optional to
41-
// enable the attribute macro to be applied to a module which
42-
// generates versioned versions of all contained containers.
43-
44-
let deprecated_attr = version.deprecated.then_some(quote! {#[deprecated]});
4546
let module_name = format_ident!("{version}", version = version.inner.to_string());
47+
let deprecated_attr = version.deprecated.then_some(quote! {#[deprecated]});
4648
let struct_name = &self.ident;
4749

48-
// Only generate a module when there is at least one more version.
49-
// This skips generating a module for the latest version, because
50-
// the base struct always represents the latest version.
51-
if versions.peek().is_some() {
52-
_tokens.extend(quote! {
50+
let struct_tokens = quote! {
51+
pub struct #struct_name {
52+
#field_tokens
53+
}
54+
};
55+
56+
// Only generate modules when asked to do so by the caller. This
57+
// enables us the support attribute macros to generate code for
58+
// multiple versioned containers in a single file (no module name
59+
// collition).
60+
if generate_modules {
61+
// Only generate a module when there is at least one more
62+
// version. This skips generating a module for the latest
63+
// version, because the base struct always represents the
64+
// latest version.
65+
tokens.extend(quote! {
5366
#[automatically_derived]
5467
#deprecated_attr
5568
pub mod #module_name {
56-
57-
pub struct #struct_name {
58-
#fields
59-
}
69+
#struct_tokens
6070
}
6171
});
72+
73+
if let Some(next) = versions.peek() {
74+
// Generate From<THIS> for NEXT impls
75+
let next_module = format_ident!("{}", next.inner.to_string());
76+
77+
let from_impl_tokens = quote! {
78+
#[automatically_derived]
79+
impl From<#module_name::#struct_name> for #next_module::#struct_name {
80+
fn from(from: #module_name::#struct_name) -> Self {
81+
todo!();
82+
}
83+
}
84+
};
85+
86+
tokens.extend(from_impl_tokens);
87+
} else {
88+
let from_impl_tokens = quote! {
89+
#[automatically_derived]
90+
impl From<#module_name::#struct_name> for #struct_name {
91+
fn from(from: #module_name::#struct_name) -> Self {
92+
todo!();
93+
}
94+
}
95+
};
96+
97+
tokens.extend(from_impl_tokens);
98+
}
99+
} else {
100+
tokens.extend(struct_tokens)
62101
}
63102
}
103+
104+
Some(tokens)
64105
}
65106
}
66107

0 commit comments

Comments
 (0)