@@ -9,7 +9,7 @@ use syn::{Field, Ident};
9
9
use crate :: {
10
10
attrs:: field:: FieldAttributes ,
11
11
consts:: DEPRECATED_PREFIX ,
12
- gen:: { version:: ContainerVersion , ToTokensExt } ,
12
+ gen:: { neighbors :: Neighbors , version:: ContainerVersion , ToTokensExt } ,
13
13
} ;
14
14
15
15
/// A versioned field, which contains contains common [`Field`] data and a chain
@@ -36,96 +36,29 @@ impl ToTokensExt for VersionedField {
36
36
// The code generation then depends on the relation to other
37
37
// versions (with actions).
38
38
39
- // TODO (@Techassi): Make this more robust by also including
40
- // the container versions in the action chain. I'm not happy
41
- // with the follwoing code at all. It serves as a good first
42
- // implementation to get something out of the door.
43
- match chain. get ( & container_version. inner ) {
44
- Some ( action) => match action {
45
- FieldStatus :: Added ( field_ident) => {
46
- let field_type = & self . inner . ty ;
47
-
48
- Some ( quote ! {
49
- pub #field_ident: #field_type,
50
- } )
51
- }
52
- FieldStatus :: Renamed { from : _, to } => {
53
- let field_type = & self . inner . ty ;
54
-
55
- Some ( quote ! {
56
- pub #to: #field_type,
57
- } )
58
- }
59
- FieldStatus :: Deprecated ( field_ident) => {
60
- let field_type = & self . inner . ty ;
61
-
62
- Some ( quote ! {
63
- #[ deprecated]
64
- pub #field_ident: #field_type,
65
- } )
66
- }
67
- } ,
68
- None => {
69
- // Generate field if the container version is not
70
- // included in the action chain. First we check the
71
- // earliest field action version.
72
- if let Some ( ( version, action) ) = chain. first_key_value ( ) {
73
- if container_version. inner < * version {
74
- match action {
75
- FieldStatus :: Added ( _) => return None ,
76
- FieldStatus :: Renamed { from, to : _ } => {
77
- let field_type = & self . inner . ty ;
78
-
79
- return Some ( quote ! {
80
- pub #from: #field_type,
81
- } ) ;
82
- }
83
- FieldStatus :: Deprecated ( field_ident) => {
84
- let field_type = & self . inner . ty ;
85
-
86
- return Some ( quote ! {
87
- pub #field_ident: #field_type,
88
- } ) ;
89
- }
90
- }
91
- }
92
- }
93
-
94
- // Check the container version against the latest
95
- // field action version.
96
- if let Some ( ( version, action) ) = chain. last_key_value ( ) {
97
- if container_version. inner > * version {
98
- match action {
99
- FieldStatus :: Added ( field_ident) => {
100
- let field_type = & self . inner . ty ;
101
-
102
- return Some ( quote ! {
103
- pub #field_ident: #field_type,
104
- } ) ;
105
- }
106
- FieldStatus :: Renamed { from : _, to } => {
107
- let field_type = & self . inner . ty ;
108
-
109
- return Some ( quote ! {
110
- pub #to: #field_type,
111
- } ) ;
112
- }
113
- FieldStatus :: Deprecated ( field_ident) => {
114
- let field_type = & self . inner . ty ;
115
-
116
- return Some ( quote ! {
117
- #[ deprecated]
118
- pub #field_ident: #field_type,
119
- } ) ;
120
- }
121
- }
122
- }
123
- }
124
-
125
- // TODO (@Techassi): Handle versions which are in between
126
- // versions defined in field actions.
127
- None
128
- }
39
+ let field_type = & self . inner . ty ;
40
+
41
+ match chain
42
+ . get ( & container_version. inner )
43
+ . expect ( "internal error: chain must contain container version" )
44
+ {
45
+ FieldStatus :: Added ( field_ident) => Some ( quote ! {
46
+ pub #field_ident: #field_type,
47
+ } ) ,
48
+ FieldStatus :: Renamed { _from : _, to } => Some ( quote ! {
49
+ pub #to: #field_type,
50
+ } ) ,
51
+ FieldStatus :: Deprecated {
52
+ ident : field_ident,
53
+ note,
54
+ } => Some ( quote ! {
55
+ #[ deprecated = #note]
56
+ pub #field_ident: #field_type,
57
+ } ) ,
58
+ FieldStatus :: NotPresent => None ,
59
+ FieldStatus :: NoChange ( field_ident) => Some ( quote ! {
60
+ pub #field_ident: #field_type,
61
+ } ) ,
129
62
}
130
63
}
131
64
None => {
@@ -144,11 +77,16 @@ impl ToTokensExt for VersionedField {
144
77
}
145
78
146
79
impl VersionedField {
80
+ /// Create a new versioned field by creating a status chain for each version
81
+ /// defined in an action in the field attribute.
82
+ ///
83
+ /// This chain will get extended by the versions defined on the container by
84
+ /// calling the [`VersionedField::insert_container_versions`] function.
147
85
pub ( crate ) fn new ( field : Field , attrs : FieldAttributes ) -> Result < Self , Error > {
148
- // Constructing the change chain requires going through the actions from
86
+ // Constructing the action chain requires going through the actions from
149
87
// the end, because the base struct always represents the latest (most
150
88
// up-to-date) version of that struct. That's why the following code
151
- // needs to go through the changes in reverse order, as otherwise it is
89
+ // needs to go through the actions in reverse order, as otherwise it is
152
90
// impossible to extract the field ident for each version.
153
91
154
92
// Deprecating a field is always the last state a field can end up in. For
@@ -160,7 +98,13 @@ impl VersionedField {
160
98
let mut actions = BTreeMap :: new ( ) ;
161
99
162
100
let ident = field. ident . as_ref ( ) . unwrap ( ) ;
163
- actions. insert ( * deprecated. since , FieldStatus :: Deprecated ( ident. clone ( ) ) ) ;
101
+ actions. insert (
102
+ * deprecated. since ,
103
+ FieldStatus :: Deprecated {
104
+ ident : ident. clone ( ) ,
105
+ note : deprecated. note . to_string ( ) ,
106
+ } ,
107
+ ) ;
164
108
165
109
// When the field is deprecated, any rename which occured beforehand
166
110
// requires access to the field ident to infer the field ident for
@@ -175,7 +119,7 @@ impl VersionedField {
175
119
actions. insert (
176
120
* rename. since ,
177
121
FieldStatus :: Renamed {
178
- from : from. clone ( ) ,
122
+ _from : from. clone ( ) ,
179
123
to : ident,
180
124
} ,
181
125
) ;
@@ -201,7 +145,7 @@ impl VersionedField {
201
145
actions. insert (
202
146
* rename. since ,
203
147
FieldStatus :: Renamed {
204
- from : from. clone ( ) ,
148
+ _from : from. clone ( ) ,
205
149
to : ident,
206
150
} ,
207
151
) ;
@@ -241,11 +185,58 @@ impl VersionedField {
241
185
} )
242
186
}
243
187
}
188
+
189
+ /// Inserts container versions not yet present in the status chain.
190
+ ///
191
+ /// When intially creating a new [`VersionedField`], the code doesn't have
192
+ /// access to the versions defined on the container. This function inserts
193
+ /// all non-present container versions and decides which status and ident
194
+ /// is the right fit based on the status neighbors.
195
+ ///
196
+ /// This continous chain ensures that when generating code (tokens), each
197
+ /// field can lookup the status for a requested version.
198
+ pub ( crate ) fn insert_container_versions ( & mut self , versions : & Vec < ContainerVersion > ) {
199
+ if let Some ( chain) = & mut self . chain {
200
+ for version in versions {
201
+ if chain. contains_key ( & version. inner ) {
202
+ continue ;
203
+ }
204
+
205
+ match chain. get_neighbors ( & version. inner ) {
206
+ ( None , Some ( _) ) => chain. insert ( version. inner , FieldStatus :: NotPresent ) ,
207
+ ( Some ( status) , None ) => {
208
+ let ident = match status {
209
+ FieldStatus :: Added ( ident) => ident,
210
+ FieldStatus :: Renamed { _from : _, to } => to,
211
+ FieldStatus :: Deprecated { ident, note : _ } => ident,
212
+ FieldStatus :: NoChange ( ident) => ident,
213
+ FieldStatus :: NotPresent => unreachable ! ( ) ,
214
+ } ;
215
+
216
+ chain. insert ( version. inner , FieldStatus :: NoChange ( ident. clone ( ) ) )
217
+ }
218
+ ( Some ( status) , Some ( _) ) => {
219
+ let ident = match status {
220
+ FieldStatus :: Added ( ident) => ident,
221
+ FieldStatus :: Renamed { _from : _, to } => to,
222
+ FieldStatus :: NoChange ( ident) => ident,
223
+ _ => unreachable ! ( ) ,
224
+ } ;
225
+
226
+ chain. insert ( version. inner , FieldStatus :: NoChange ( ident. clone ( ) ) )
227
+ }
228
+ _ => unreachable ! ( ) ,
229
+ } ;
230
+ }
231
+ }
232
+ }
244
233
}
245
234
246
235
#[ derive( Debug ) ]
247
236
pub ( crate ) enum FieldStatus {
248
237
Added ( Ident ) ,
249
- Renamed { from : Ident , to : Ident } ,
250
- Deprecated ( Ident ) ,
238
+ Renamed { _from : Ident , to : Ident } ,
239
+ Deprecated { ident : Ident , note : String } ,
240
+ NoChange ( Ident ) ,
241
+ NotPresent ,
251
242
}
0 commit comments