-
-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathcontainer.rs
119 lines (103 loc) · 4.17 KB
/
container.rs
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
use std::{cmp::Ordering, collections::HashSet, ops::Deref};
use darling::{
util::{Flag, SpannedValue},
Error, FromMeta, Result,
};
use k8s_version::Version;
/// This struct contains supported container attributes.
///
/// Currently supported atttributes are:
///
/// - `version`, which can occur one or more times. See [`VersionAttributes`].
/// - `options`, which allow further customization of the generated code. See [`ContainerOptions`].
#[derive(Debug, FromMeta)]
#[darling(and_then = ContainerAttributes::validate)]
pub(crate) struct ContainerAttributes {
#[darling(multiple, rename = "version")]
pub(crate) versions: SpannedValue<Vec<VersionAttributes>>,
#[darling(default)]
pub(crate) options: ContainerOptions,
}
impl ContainerAttributes {
fn validate(mut self) -> Result<Self> {
// Most of the validation for individual version strings is done by the
// k8s-version crate. That's why the code below only checks that at
// least one version is defined, they are defined in order (to ensure
// code consistency) and that all declared versions are unique.
// If there are no versions defined, the derive macro errors out. There
// should be at least one version if the derive macro is used.
if self.versions.is_empty() {
return Err(Error::custom(
"attribute `#[versioned()]` must contain at least one `version`",
)
.with_span(&self.versions.span()));
}
// NOTE (@Techassi): Do we even want to allow to opt-out of this?
// Ensure that versions are defined in sorted (ascending) order to keep
// code consistent.
if !self.options.allow_unsorted.is_present() {
let original = self.versions.deref().clone();
self.versions
.sort_by(|lhs, rhs| lhs.name.partial_cmp(&rhs.name).unwrap_or(Ordering::Equal));
for (index, version) in original.iter().enumerate() {
if version.name == self.versions.get(index).unwrap().name {
continue;
}
return Err(Error::custom(format!(
"versions in `#[versioned()]` must be defined in ascending order (version `{name}` is misplaced)",
name = version.name
)));
}
}
// TODO (@Techassi): Add validation for skip(from) for last version,
// which will skip nothing, because nothing is generated in the first
// place.
// Ensure every version is unique and isn't declared multiple times. This
// is inspired by the itertools all_unique function.
let mut unique = HashSet::new();
for version in &*self.versions {
if !unique.insert(version.name) {
return Err(Error::custom(format!(
"attribute `#[versioned()]` contains duplicate version `name`: {name}",
name = version.name
))
.with_span(&self.versions.span()));
}
}
Ok(self)
}
}
/// This struct contains supported version options.
///
/// Supported options are:
///
/// - `name` of the version, like `v1alpha1`.
/// - `deprecated` flag to mark that version as deprecated.
/// - `skip` option to skip generating various pieces of code.
#[derive(Clone, Debug, FromMeta)]
pub(crate) struct VersionAttributes {
pub(crate) deprecated: Flag,
pub(crate) name: Version,
pub(crate) skip: Option<SkipOptions>,
}
/// This struct contains supported container options.
///
/// Supported options are:
///
/// - `allow_unsorted`, which allows declaring versions in unsorted order,
/// instead of enforcing ascending order.
/// - `skip` option to skip generating various pieces of code.
#[derive(Clone, Debug, Default, FromMeta)]
pub(crate) struct ContainerOptions {
pub(crate) allow_unsorted: Flag,
pub(crate) skip: Option<SkipOptions>,
}
/// This struct contains supported skip options.
///
/// Supported options are:
///
/// - `from` flag, which skips generating [`From`] implementations when provided.
#[derive(Clone, Debug, Default, FromMeta)]
pub(crate) struct SkipOptions {
pub(crate) from: Flag,
}