Skip to content

Commit e2abc28

Browse files
Merge #617
617: feat: add argument feature_group r=burrbull a=duskmoon314 Add new feature `feature_group` - When off, do nothing else - When on - generate cfg attribute for every `groupName` - generate `features.toml` containing all `groupName` close #614 Co-authored-by: Campbell He <[email protected]>
2 parents 9681ec6 + 69306b6 commit e2abc28

File tree

6 files changed

+121
-20
lines changed

6 files changed

+121
-20
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
- Add new feature `feature_group` which will generate cfg attribute for
11+
every group name when it is on
12+
1013
## [v0.24.1] - 2022-07-04
1114

1215
- Make field writer always generic around bit offset (fix bug #620)

src/generate/device.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::svd::{array::names, Device, Peripheral};
2-
use crate::util::U32Ext;
2+
use crate::util::{ToSanitizedSnakeCase, U32Ext};
33
use proc_macro2::{Ident, Span, TokenStream};
44
use quote::{quote, ToTokens};
55

@@ -204,7 +204,12 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
204204
}
205205

206206
debug!("Rendering interrupts");
207-
out.extend(interrupt::render(config.target, &d.peripherals, device_x)?);
207+
out.extend(interrupt::render(
208+
config.target,
209+
&d.peripherals,
210+
device_x,
211+
config,
212+
)?);
208213

209214
for p in &d.peripherals {
210215
if config.target == Target::CortexM && core_peripherals.contains(&&*p.name.to_uppercase()) {
@@ -246,6 +251,12 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
246251
// in the `Peripherals` struct
247252
continue;
248253
}
254+
let feature_attribute = if config.feature_group && p.group_name.is_some() {
255+
let feature_name = p.group_name.as_ref().unwrap().to_sanitized_snake_case();
256+
quote!(#[cfg(feature = #feature_name)])
257+
} else {
258+
quote!()
259+
};
249260

250261
match p {
251262
Peripheral::Single(_p) => {
@@ -254,9 +265,10 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
254265
let id = Ident::new(&p, Span::call_site());
255266
fields.extend(quote! {
256267
#[doc = #p]
268+
#feature_attribute
257269
pub #id: #id,
258270
});
259-
exprs.extend(quote!(#id: #id { _marker: PhantomData },));
271+
exprs.extend(quote!(#feature_attribute #id: #id { _marker: PhantomData },));
260272
}
261273
Peripheral::Array(_p, dim_element) => {
262274
let p_names: Vec<Cow<str>> = names(p, dim_element).map(|n| n.into()).collect();
@@ -266,10 +278,13 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
266278
fields.extend(quote! {
267279
#(
268280
#[doc = #p]
281+
#feature_attribute
269282
pub #ids_f: #ids_f,
270283
)*
271284
});
272-
exprs.extend(quote!(#(#ids_e: #ids_e { _marker: PhantomData },)*));
285+
exprs.extend(
286+
quote!(#(#feature_attribute #ids_e: #ids_e { _marker: PhantomData },)*),
287+
);
273288
}
274289
}
275290
}

src/generate/interrupt.rs

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,67 +6,98 @@ use cast::u64;
66
use proc_macro2::{Ident, Span, TokenStream};
77
use quote::quote;
88

9-
use crate::util::{self, ToSanitizedUpperCase};
10-
use crate::Target;
9+
use crate::util::{self, ToSanitizedSnakeCase, ToSanitizedUpperCase};
10+
use crate::{Config, Target};
1111
use anyhow::Result;
1212

1313
/// Generates code for `src/interrupt.rs`
1414
pub fn render(
1515
target: Target,
1616
peripherals: &[Peripheral],
1717
device_x: &mut String,
18+
config: &Config,
1819
) -> Result<TokenStream> {
1920
let interrupts = peripherals
2021
.iter()
21-
.flat_map(|p| p.interrupt.iter())
22-
.map(|i| (i.value, i))
22+
.flat_map(|p| p.interrupt.iter().map(move |i| (i, p.group_name.clone())))
23+
.map(|i| (i.0.value, (i.0, i.1)))
2324
.collect::<HashMap<_, _>>();
2425

2526
let mut interrupts = interrupts.into_iter().map(|(_, v)| v).collect::<Vec<_>>();
26-
interrupts.sort_by_key(|i| i.value);
27+
interrupts.sort_by_key(|i| i.0.value);
2728

2829
let mut root = TokenStream::new();
2930
let mut from_arms = TokenStream::new();
3031
let mut elements = TokenStream::new();
3132
let mut names = vec![];
33+
let mut names_cfg_attr = vec![];
3234
let mut variants = TokenStream::new();
3335

3436
// Current position in the vector table
3537
let mut pos = 0;
3638
let mut mod_items = TokenStream::new();
3739
for interrupt in &interrupts {
38-
while pos < interrupt.value {
40+
while pos < interrupt.0.value {
3941
elements.extend(quote!(Vector { _reserved: 0 },));
4042
pos += 1;
4143
}
4244
pos += 1;
4345

44-
let name_uc = Ident::new(&interrupt.name.to_sanitized_upper_case(), Span::call_site());
46+
let name_uc = Ident::new(
47+
&interrupt.0.name.to_sanitized_upper_case(),
48+
Span::call_site(),
49+
);
4550
let description = format!(
4651
"{} - {}",
47-
interrupt.value,
52+
interrupt.0.value,
4853
interrupt
54+
.0
4955
.description
5056
.as_ref()
5157
.map(|s| util::respace(s))
5258
.as_ref()
5359
.map(|s| util::escape_brackets(s))
54-
.unwrap_or_else(|| interrupt.name.clone())
60+
.unwrap_or_else(|| interrupt.0.name.clone())
5561
);
5662

57-
let value = util::unsuffixed(u64(interrupt.value));
63+
let value = util::unsuffixed(u64(interrupt.0.value));
64+
65+
let mut feature_attribute_flag = false;
66+
let (feature_attribute, not_feature_attribute) =
67+
if config.feature_group && interrupt.1.is_some() {
68+
let feature_name = interrupt.1.as_ref().unwrap().to_sanitized_snake_case();
69+
feature_attribute_flag = true;
70+
(
71+
quote!(#[cfg(feature = #feature_name)]),
72+
quote!(#[cfg(not(feature = #feature_name))]),
73+
)
74+
} else {
75+
(quote!(), quote!())
76+
};
5877

5978
variants.extend(quote! {
6079
#[doc = #description]
80+
#feature_attribute
6181
#name_uc = #value,
6282
});
6383

6484
from_arms.extend(quote! {
85+
#feature_attribute
6586
#value => Ok(Interrupt::#name_uc),
6687
});
6788

68-
elements.extend(quote!(Vector { _handler: #name_uc },));
89+
if feature_attribute_flag {
90+
elements.extend(quote! {
91+
#not_feature_attribute
92+
Vector { _reserved: 0 },
93+
#feature_attribute
94+
Vector { _handler: #name_uc },
95+
});
96+
} else {
97+
elements.extend(quote!(Vector { _handler: #name_uc },));
98+
}
6999
names.push(name_uc);
100+
names_cfg_attr.push(feature_attribute);
70101
}
71102

72103
let n = util::unsuffixed(u64(pos));
@@ -79,7 +110,7 @@ pub fn render(
79110
root.extend(quote! {
80111
#[cfg(feature = "rt")]
81112
extern "C" {
82-
#(fn #names();)*
113+
#(#names_cfg_attr fn #names();)*
83114
}
84115

85116
#[doc(hidden)]
@@ -105,7 +136,7 @@ pub fn render(
105136
root.extend(quote! {
106137
#[cfg(feature = "rt")]
107138
extern "msp430-interrupt" {
108-
#(fn #names();)*
139+
#(#names_cfg_attr fn #names();)*
109140
}
110141

111142
#[doc(hidden)]
@@ -133,7 +164,7 @@ pub fn render(
133164
root.extend(quote! {
134165
#[cfg(feature = "rt")]
135166
extern "C" {
136-
#(fn #names();)*
167+
#(#names_cfg_attr fn #names();)*
137168
}
138169

139170
#[doc(hidden)]
@@ -158,7 +189,7 @@ pub fn render(
158189
root.extend(quote! {
159190
#[cfg(feature = "rt")]
160191
extern "C" {
161-
#(fn #names();)*
192+
#(#names_cfg_attr fn #names();)*
162193
}
163194

164195
#[doc(hidden)]

src/generate/peripheral.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ pub fn render(
5656
(false, name_sc.clone())
5757
};
5858

59+
let feature_attribute = if config.feature_group && p.group_name.is_some() {
60+
let feature_name = p.group_name.as_ref().unwrap().to_sanitized_snake_case();
61+
quote! (#[cfg(feature = #feature_name)])
62+
} else {
63+
quote! {}
64+
};
65+
5966
match p_original {
6067
Peripheral::Array(p, dim) => {
6168
let names: Vec<Cow<str>> = names(p, dim).map(|n| n.into()).collect();
@@ -68,10 +75,13 @@ pub fn render(
6875
out.extend(quote! {
6976
#(
7077
#[doc = #description]
78+
#feature_attribute
7179
pub struct #names_pc { _marker: PhantomData<*const ()> }
7280

81+
#feature_attribute
7382
unsafe impl Send for #names_pc {}
7483

84+
#feature_attribute
7585
impl #names_pc {
7686
///Pointer to the register block
7787
pub const PTR: *const #base::RegisterBlock = #addresses as *const _;
@@ -83,6 +93,7 @@ pub fn render(
8393
}
8494
}
8595

96+
#feature_attribute
8697
impl Deref for #names_pc {
8798
type Target = #base::RegisterBlock;
8899

@@ -92,6 +103,7 @@ pub fn render(
92103
}
93104
}
94105

106+
#feature_attribute
95107
impl core::fmt::Debug for #names_pc {
96108
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
97109
f.debug_struct(#names_str).finish()
@@ -104,10 +116,13 @@ pub fn render(
104116
// Insert the peripheral structure
105117
out.extend(quote! {
106118
#[doc = #description]
119+
#feature_attribute
107120
pub struct #name_pc { _marker: PhantomData<*const ()> }
108121

122+
#feature_attribute
109123
unsafe impl Send for #name_pc {}
110124

125+
#feature_attribute
111126
impl #name_pc {
112127
///Pointer to the register block
113128
pub const PTR: *const #base::RegisterBlock = #address as *const _;
@@ -119,6 +134,7 @@ pub fn render(
119134
}
120135
}
121136

137+
#feature_attribute
122138
impl Deref for #name_pc {
123139
type Target = #base::RegisterBlock;
124140

@@ -128,6 +144,7 @@ pub fn render(
128144
}
129145
}
130146

147+
#feature_attribute
131148
impl core::fmt::Debug for #name_pc {
132149
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
133150
f.debug_struct(#name_str).finish()
@@ -143,6 +160,7 @@ pub fn render(
143160
// re-export the base module to allow deriveFrom this one
144161
out.extend(quote! {
145162
#[doc = #description]
163+
#feature_attribute
146164
pub use #base as #name_sc;
147165
});
148166
return Ok(out);
@@ -216,6 +234,7 @@ pub fn render(
216234

217235
out.extend(quote! {
218236
#[doc = #description]
237+
#feature_attribute
219238
pub mod #name_sc #open
220239
});
221240

src/main.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use clap::{App, Arg};
1212

1313
use svd2rust::{
1414
generate, load_from,
15-
util::{build_rs, Config, SourceType, Target},
15+
util::{build_rs, group_names, Config, SourceType, Target},
1616
};
1717

1818
fn run() -> Result<()> {
@@ -75,6 +75,11 @@ fn run() -> Result<()> {
7575
.short("g")
7676
.help("Push generic mod in separate file"),
7777
)
78+
.arg(
79+
Arg::with_name("feature_group")
80+
.long("feature_group")
81+
.help("Use group_name of peripherals as feature"),
82+
)
7883
.arg(
7984
Arg::with_name("make_mod")
8085
.long("make_mod")
@@ -169,6 +174,8 @@ fn run() -> Result<()> {
169174
|| cfg.bool_flag("pascal_enum_values", Filter::Conf);
170175
let derive_more =
171176
cfg.bool_flag("derive_more", Filter::Arg) || cfg.bool_flag("derive_more", Filter::Conf);
177+
let feature_group =
178+
cfg.bool_flag("feature_group", Filter::Arg) || cfg.bool_flag("feature_group", Filter::Conf);
172179

173180
let mut source_type = cfg
174181
.grab()
@@ -193,6 +200,7 @@ fn run() -> Result<()> {
193200
strict,
194201
pascal_enum_values,
195202
derive_more,
203+
feature_group,
196204
output_dir: path.clone(),
197205
source_type,
198206
};
@@ -221,6 +229,21 @@ fn run() -> Result<()> {
221229
writeln!(File::create(path.join("build.rs"))?, "{}", build_rs())?;
222230
}
223231

232+
if feature_group {
233+
let group_names: Vec<String> = group_names(&device)
234+
.iter()
235+
.map(|s| format!("{} = []\n", s))
236+
.collect();
237+
write!(
238+
File::create(path.join("features.toml"))?,
239+
"# Below are the FEATURES generated by svd2rust base on groupName in SVD file.\n\
240+
# Please copy them to Cargo.toml.\n\
241+
[features]\n\
242+
{}",
243+
group_names.join("")
244+
)?;
245+
}
246+
224247
Ok(())
225248
}
226249

src/util.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub struct Config {
3030
pub strict: bool,
3131
pub pascal_enum_values: bool,
3232
pub derive_more: bool,
33+
pub feature_group: bool,
3334
pub output_dir: PathBuf,
3435
pub source_type: SourceType,
3536
}
@@ -47,6 +48,7 @@ impl Default for Config {
4748
strict: false,
4849
pascal_enum_values: false,
4950
derive_more: false,
51+
feature_group: false,
5052
output_dir: PathBuf::from("."),
5153
source_type: SourceType::default(),
5254
}
@@ -482,3 +484,11 @@ impl FullName for PeripheralInfo {
482484
self.name.as_str().into()
483485
}
484486
}
487+
488+
pub fn group_names(d: &Device) -> HashSet<Cow<str>> {
489+
d.peripherals
490+
.iter()
491+
.filter_map(|p| p.group_name.as_ref())
492+
.map(|name| name.to_sanitized_snake_case())
493+
.collect()
494+
}

0 commit comments

Comments
 (0)