@@ -119,6 +119,67 @@ struct Region {
119
119
end : u32 ,
120
120
}
121
121
122
+ impl Region {
123
+ /// Find the longest common prefix of the identifier names
124
+ /// for the fields in this region, if any.
125
+ fn common_prefix ( & self ) -> Option < String > {
126
+ let mut char_vecs = Vec :: new ( ) ;
127
+ let mut min_len = usize:: max_value ( ) ;
128
+
129
+ for f in & self . fields {
130
+ match f. field . ident {
131
+ None => return None ,
132
+ Some ( ref ident) => {
133
+ let chars : Vec < char > = ident. as_ref ( ) . chars ( ) . collect ( ) ;
134
+ min_len = min_len. min ( chars. len ( ) ) ;
135
+ char_vecs. push ( chars) ;
136
+ }
137
+ }
138
+ }
139
+
140
+ let mut result = String :: new ( ) ;
141
+
142
+ for i in 0 ..min_len {
143
+ let c = char_vecs[ 0 ] [ i] ;
144
+ for v in & char_vecs {
145
+ if v[ i] != c {
146
+ break ;
147
+ }
148
+ }
149
+
150
+ // This character position is the same across
151
+ // all variants, so emit it into the result
152
+ result. push ( c) ;
153
+ }
154
+
155
+ if result. is_empty ( ) {
156
+ None
157
+ } else {
158
+ Some ( result)
159
+ }
160
+ }
161
+
162
+ /// Return a description of this region
163
+ fn description ( & self ) -> String {
164
+ let mut result = String :: new ( ) ;
165
+ for f in & self . fields {
166
+ // In the Atmel SVDs the union variants all tend to
167
+ // have the same description. Rather than emitting
168
+ // the same text three times over, only join in the
169
+ // text from the other variants if it is different.
170
+ // This isn't a foolproof way of emitting the most
171
+ // reasonable short description, but it's good enough.
172
+ if f. description != result {
173
+ if result. len ( ) > 0 {
174
+ result. push ( ' ' ) ;
175
+ }
176
+ result. push_str ( & f. description ) ;
177
+ }
178
+ }
179
+ result
180
+ }
181
+ }
182
+
122
183
/// FieldRegions keeps track of overlapping field regions,
123
184
/// merging fields into appropriate regions as we process them.
124
185
/// This allows us to reason about when to create a union
@@ -213,6 +274,8 @@ fn register_or_cluster_block(
213
274
regions. add ( reg_block_field) ;
214
275
}
215
276
277
+ let block_is_union = regions. regions . len ( ) == 1 && regions. regions [ 0 ] . fields . len ( ) > 1 ;
278
+
216
279
// The end of the region from the prior iteration of the loop
217
280
let mut last_end = None ;
218
281
@@ -249,24 +312,33 @@ fn register_or_cluster_block(
249
312
Ident :: new ( "," ) . to_tokens ( & mut region_fields) ;
250
313
}
251
314
252
- if region. fields . len ( ) > 1 {
253
- // TODO: come up with nicer naming. Right now we're using the
254
- // region index as a unique-within-this-block identifier counter.
255
- let name = Ident :: new ( format ! ( "u{}" , i) ) ;
315
+ if region. fields . len ( ) > 1 && !block_is_union {
316
+ let ( type_name, name) = match region. common_prefix ( ) {
317
+ Some ( prefix) => {
318
+ ( Ident :: new ( format ! ( "{}_union" , prefix) ) ,
319
+ Ident :: new ( prefix) )
320
+ }
321
+ // If we can't find a common prefix for the name, fall back to the
322
+ // region index as a unique-within-this-block identifier counter.
323
+ None => {
324
+ let ident = Ident :: new ( format ! ( "u{}" , i) ) ;
325
+ ( ident. clone ( ) , ident)
326
+ }
327
+ } ;
256
328
257
- // TODO: if we only have a single region and that region is a
258
- // union, the overall RegisterBlock could be a union
329
+ let description = region. description ( ) ;
259
330
260
331
helper_types. append ( quote ! {
261
- /// Union container for a set of overlapping registers
332
+ # [ doc = #description ]
262
333
#[ repr( C ) ]
263
- pub union #name {
334
+ pub union #type_name {
264
335
#region_fields
265
336
}
266
337
} ) ;
267
338
268
339
fields. append ( quote ! {
269
- #name: #name
340
+ #[ doc = #description]
341
+ pub #name: #type_name
270
342
} ) ;
271
343
Ident :: new ( "," ) . to_tokens ( & mut fields) ;
272
344
@@ -280,10 +352,16 @@ fn register_or_cluster_block(
280
352
None => "RegisterBlock" . into ( ) ,
281
353
} ) ;
282
354
355
+ let block_type = if block_is_union {
356
+ Ident :: new ( "union" )
357
+ } else {
358
+ Ident :: new ( "struct" )
359
+ } ;
360
+
283
361
Ok ( quote ! {
284
362
/// Register block
285
363
#[ repr( C ) ]
286
- pub struct #name {
364
+ pub #block_type #name {
287
365
#fields
288
366
}
289
367
0 commit comments