Skip to content

Commit 42fb128

Browse files
committed
refactor: Unify field and variant attributes
1 parent 84a49c2 commit 42fb128

File tree

15 files changed

+668
-684
lines changed

15 files changed

+668
-684
lines changed

crates/stackable-versioned-macros/src/attrs/common/item.rs

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,83 @@
11
use darling::{util::SpannedValue, Error, FromMeta};
22
use k8s_version::Version;
33
use proc_macro2::Span;
4-
use syn::{Ident, Path};
4+
use syn::{spanned::Spanned, Ident, Path};
55

6-
use crate::consts::{DEPRECATED_FIELD_PREFIX, DEPRECATED_VARIANT_PREFIX};
6+
use crate::{
7+
attrs::common::ContainerAttributes,
8+
codegen::common::Attributes,
9+
consts::{DEPRECATED_FIELD_PREFIX, DEPRECATED_VARIANT_PREFIX},
10+
};
11+
12+
pub(crate) trait ValidateVersions<I>
13+
where
14+
I: Spanned,
15+
{
16+
/// Validates that each field action version is present in the declared
17+
/// container versions.
18+
fn validate_versions(
19+
&self,
20+
container_attrs: &ContainerAttributes,
21+
item: &I,
22+
) -> Result<(), darling::Error>;
23+
}
24+
25+
impl<I, T> ValidateVersions<I> for T
26+
where
27+
T: Attributes,
28+
I: Spanned,
29+
{
30+
fn validate_versions(
31+
&self,
32+
container_attrs: &ContainerAttributes,
33+
item: &I,
34+
) -> Result<(), darling::Error> {
35+
// NOTE (@Techassi): Can we maybe optimize this a little?
36+
let mut errors = Error::accumulator();
37+
38+
if let Some(added) = &self.common_attrs().added {
39+
if !container_attrs
40+
.versions
41+
.iter()
42+
.any(|v| v.name == *added.since)
43+
{
44+
errors.push(Error::custom(
45+
"variant action `added` uses version which was not declared via #[versioned(version)]")
46+
.with_span(item)
47+
);
48+
}
49+
}
50+
51+
for rename in &*self.common_attrs().renames {
52+
if !container_attrs
53+
.versions
54+
.iter()
55+
.any(|v| v.name == *rename.since)
56+
{
57+
errors.push(
58+
Error::custom("variant action `renamed` uses version which was not declared via #[versioned(version)]")
59+
.with_span(item)
60+
);
61+
}
62+
}
63+
64+
if let Some(deprecated) = &self.common_attrs().deprecated {
65+
if !container_attrs
66+
.versions
67+
.iter()
68+
.any(|v| v.name == *deprecated.since)
69+
{
70+
errors.push(Error::custom(
71+
"variant action `deprecated` uses version which was not declared via #[versioned(version)]")
72+
.with_span(item)
73+
);
74+
}
75+
}
76+
77+
errors.finish()?;
78+
Ok(())
79+
}
80+
}
781

882
#[derive(Debug, strum::Display)]
983
#[strum(serialize_all = "lowercase")]
Lines changed: 2 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use darling::{Error, FromField};
2-
use syn::{Field, Ident};
2+
use syn::Ident;
33

4-
use crate::attrs::common::{ContainerAttributes, ItemAttributes, ItemType};
4+
use crate::attrs::common::{ItemAttributes, ItemType};
55

66
/// This struct describes all available field attributes, as well as the field
77
/// name to display better diagnostics.
@@ -57,57 +57,4 @@ impl FieldAttributes {
5757

5858
Ok(self)
5959
}
60-
61-
/// Validates that each field action version is present in the declared
62-
/// container versions.
63-
pub(crate) fn validate_versions(
64-
&self,
65-
container_attrs: &ContainerAttributes,
66-
field: &Field,
67-
) -> Result<(), Error> {
68-
// NOTE (@Techassi): Can we maybe optimize this a little?
69-
let mut errors = Error::accumulator();
70-
71-
if let Some(added) = &self.common.added {
72-
if !container_attrs
73-
.versions
74-
.iter()
75-
.any(|v| v.name == *added.since)
76-
{
77-
errors.push(Error::custom(
78-
"field action `added` uses version which was not declared via #[versioned(version)]")
79-
.with_span(&field.ident)
80-
);
81-
}
82-
}
83-
84-
for rename in &self.common.renames {
85-
if !container_attrs
86-
.versions
87-
.iter()
88-
.any(|v| v.name == *rename.since)
89-
{
90-
errors.push(
91-
Error::custom("field action `renamed` uses version which was not declared via #[versioned(version)]")
92-
.with_span(&field.ident)
93-
);
94-
}
95-
}
96-
97-
if let Some(deprecated) = &self.common.deprecated {
98-
if !container_attrs
99-
.versions
100-
.iter()
101-
.any(|v| v.name == *deprecated.since)
102-
{
103-
errors.push(Error::custom(
104-
"field action `deprecated` uses version which was not declared via #[versioned(version)]")
105-
.with_span(&field.ident)
106-
);
107-
}
108-
}
109-
110-
errors.finish()?;
111-
Ok(())
112-
}
11360
}
Lines changed: 2 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use convert_case::{Case, Casing};
22
use darling::{Error, FromVariant};
3-
use syn::{Ident, Variant};
3+
use syn::Ident;
44

5-
use crate::attrs::common::{ContainerAttributes, ItemAttributes, ItemType};
5+
use crate::attrs::common::{ItemAttributes, ItemType};
66

77
#[derive(Debug, FromVariant)]
88
#[darling(
@@ -53,57 +53,4 @@ impl VariantAttributes {
5353
errors.finish()?;
5454
Ok(self)
5555
}
56-
57-
pub(crate) fn validate_versions(
58-
&self,
59-
container_attrs: &ContainerAttributes,
60-
variant: &Variant,
61-
) -> Result<(), Error> {
62-
// NOTE (@Techassi): Can we maybe optimize this a little?
63-
// TODO (@Techassi): Unify this with the field impl, e.g. by introducing
64-
// a T: Spanned bound for the second function parameter.
65-
let mut errors = Error::accumulator();
66-
67-
if let Some(added) = &self.common.added {
68-
if !container_attrs
69-
.versions
70-
.iter()
71-
.any(|v| v.name == *added.since)
72-
{
73-
errors.push(Error::custom(
74-
"variant action `added` uses version which was not declared via #[versioned(version)]")
75-
.with_span(&variant.ident)
76-
);
77-
}
78-
}
79-
80-
for rename in &*self.common.renames {
81-
if !container_attrs
82-
.versions
83-
.iter()
84-
.any(|v| v.name == *rename.since)
85-
{
86-
errors.push(
87-
Error::custom("variant action `renamed` uses version which was not declared via #[versioned(version)]")
88-
.with_span(&variant.ident)
89-
);
90-
}
91-
}
92-
93-
if let Some(deprecated) = &self.common.deprecated {
94-
if !container_attrs
95-
.versions
96-
.iter()
97-
.any(|v| v.name == *deprecated.since)
98-
{
99-
errors.push(Error::custom(
100-
"variant action `deprecated` uses version which was not declared via #[versioned(version)]")
101-
.with_span(&variant.ident)
102-
);
103-
}
104-
}
105-
106-
errors.finish()?;
107-
Ok(())
108-
}
10956
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use std::ops::Deref;
2+
3+
use proc_macro2::TokenStream;
4+
use syn::Ident;
5+
6+
use crate::{attrs::common::ContainerAttributes, codegen::common::ContainerVersion};
7+
8+
pub(crate) trait Container<D, I>
9+
where
10+
Self: Sized + Deref<Target = VersionedContainer<I>>,
11+
{
12+
fn new(ident: Ident, data: D, attributes: ContainerAttributes) -> syn::Result<Self>;
13+
14+
/// This generates the complete code for a single versioned container.
15+
///
16+
/// Internally, it will create a module for each declared version which
17+
/// contains the container with the appropriate items (fields or variants)
18+
/// Additionally, it generates `From` implementations, which enable
19+
/// conversion from an older to a newer version.
20+
fn generate_tokens(&self) -> TokenStream;
21+
}
22+
23+
#[derive(Debug)]
24+
pub(crate) struct VersionedContainer<I> {
25+
pub(crate) versions: Vec<ContainerVersion>,
26+
pub(crate) items: Vec<I>,
27+
pub(crate) ident: Ident,
28+
29+
pub(crate) from_ident: Ident,
30+
pub(crate) skip_from: bool,
31+
}

0 commit comments

Comments
 (0)