-
-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathcommon.rs
More file actions
127 lines (107 loc) · 3.36 KB
/
Copy pathcommon.rs
File metadata and controls
127 lines (107 loc) · 3.36 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
use std::ops::Deref;
use darling::{
Error, FromMeta, Result,
util::{Flag, Override as FlagOrOverride, SpannedValue},
};
use itertools::Itertools;
use k8s_version::Version;
pub trait CommonOptions {
fn allow_unsorted(&self) -> Flag;
}
#[derive(Debug, FromMeta)]
#[darling(and_then = CommonRootArguments::validate)]
pub struct CommonRootArguments<T>
where
T: CommonOptions + Default,
{
#[darling(default)]
pub options: T,
#[darling(multiple, rename = "version")]
pub versions: SpannedValue<Vec<VersionArguments>>,
}
impl<T> CommonRootArguments<T>
where
T: CommonOptions + Default,
{
fn validate(mut self) -> Result<Self> {
let mut errors = Error::accumulator();
if self.versions.is_empty() {
errors.push(
Error::custom("at least one or more `version`s must be defined")
.with_span(&self.versions.span()),
);
}
let is_sorted = self.versions.iter().is_sorted_by_key(|v| v.name);
// It needs to be sorted, even though the definition could be unsorted
// (if allow_unsorted is set).
self.versions.sort_by(|lhs, rhs| lhs.name.cmp(&rhs.name));
if !self.options.allow_unsorted().is_present() && !is_sorted {
let versions = self.versions.iter().map(|v| v.name).join(", ");
errors.push(Error::custom(format!(
"versions must be defined in ascending order: {versions}",
)));
}
let duplicate_versions: Vec<_> = self
.versions
.iter()
.duplicates_by(|v| v.name)
.map(|v| v.name)
.collect();
if !duplicate_versions.is_empty() {
let versions = duplicate_versions.iter().join(", ");
errors.push(Error::custom(format!(
"contains duplicate versions: {versions}",
)));
}
errors.finish_with(self)
}
}
/// This struct contains supported version arguments.
///
/// Supported arguments are:
///
/// - `name` of the version, like `v1alpha1`.
/// - `deprecated` flag to mark that version as deprecated.
/// - `skip` option to skip generating various pieces of code.
/// - `doc` option to add version-specific documentation.
#[derive(Clone, Debug, FromMeta)]
pub struct VersionArguments {
pub deprecated: Option<FlagOrOverride<String>>,
pub skip: Option<SkipArguments>,
pub doc: Option<String>,
pub name: Version,
}
/// This struct contains supported common skip arguments.
///
/// Supported arguments are:
///
/// - `from` flag, which skips generating [`From`] implementations when provided.
#[derive(Clone, Debug, Default, FromMeta)]
pub struct SkipArguments {
/// Whether the [`From`] implementation generation should be skipped for all versions of this
/// container.
pub from: Flag,
}
/// Wraps a value to indicate whether it is original or has been overridden.
#[derive(Clone, Debug)]
pub enum Override<T> {
Default(T),
Explicit(T),
}
impl<T> FromMeta for Override<T>
where
T: FromMeta,
{
fn from_meta(item: &syn::Meta) -> Result<Self> {
FromMeta::from_meta(item).map(Override::Explicit)
}
}
impl<T> Deref for Override<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match &self {
Override::Default(inner) => inner,
Override::Explicit(inner) => inner,
}
}
}