Skip to content

Commit e31074d

Browse files
bors[bot]burrbull
andauthored
Merge #647
647: features for each peripheral r=therealprof,emilgardis a=burrbull Co-authored-by: Andrey Zgarbul <[email protected]>
2 parents 4c6d6e8 + 3de2114 commit e31074d

File tree

6 files changed

+164
-56
lines changed

6 files changed

+164
-56
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
- Add `feature_peripheral` option which generates cfg features for each peripheral
1011
- Use register aliases in `RegisterBlock` (both structure and mod)
1112
- Create aliases for derived registers & clusters
1213
- Move cluster struct inside mod

src/generate/device.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -248,18 +248,21 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
248248
// in the `Peripherals` struct
249249
continue;
250250
}
251-
let feature_attribute = if config.feature_group && p.group_name.is_some() {
251+
let mut feature_attribute = TokenStream::new();
252+
if config.feature_group && p.group_name.is_some() {
252253
let feature_name = p.group_name.as_ref().unwrap().to_sanitized_snake_case();
253-
quote!(#[cfg(feature = #feature_name)])
254-
} else {
255-
quote!()
254+
feature_attribute.extend(quote! { #[cfg(feature = #feature_name)] })
256255
};
257256

258257
match p {
259258
Peripheral::Single(_p) => {
260259
let p_name = util::name_of(p, config.ignore_groups);
260+
let p_snake = p_name.to_sanitized_snake_case();
261261
let p = p_name.to_sanitized_constant_case();
262262
let id = Ident::new(&p, Span::call_site());
263+
if config.feature_peripheral {
264+
feature_attribute.extend(quote! { #[cfg(feature = #p_snake)] })
265+
};
263266
fields.extend(quote! {
264267
#[doc = #p]
265268
#feature_attribute
@@ -272,6 +275,17 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
272275
let p = p_names.iter().map(|p| p.to_sanitized_constant_case());
273276
let ids_f = p.clone().map(|p| Ident::new(&p, Span::call_site()));
274277
let ids_e = ids_f.clone();
278+
let feature_attribute = p_names
279+
.iter()
280+
.map(|p_name| {
281+
let p_snake = p_name.to_sanitized_snake_case();
282+
let mut feature_attribute = feature_attribute.clone();
283+
if config.feature_peripheral {
284+
feature_attribute.extend(quote! { #[cfg(feature = #p_snake)] })
285+
};
286+
feature_attribute
287+
})
288+
.collect::<Vec<_>>();
275289
fields.extend(quote! {
276290
#(
277291
#[doc = #p]

src/generate/interrupt.rs

+30-18
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::fmt::Write;
33

44
use crate::svd::Peripheral;
55
use cast::u64;
6-
use proc_macro2::{Ident, Span, TokenStream};
6+
use proc_macro2::{Span, TokenStream};
77
use quote::quote;
88

99
use crate::util::{self, ToSanitizedCase};
@@ -19,8 +19,19 @@ pub fn render(
1919
) -> Result<TokenStream> {
2020
let interrupts = peripherals
2121
.iter()
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)))
22+
.flat_map(|p| {
23+
p.interrupt.iter().map(move |i| {
24+
(i, p.group_name.clone(), {
25+
match p {
26+
Peripheral::Single(info) => info.name.clone(),
27+
Peripheral::Array(info, dim_element) => {
28+
svd_rs::array::names(info, dim_element).next().unwrap()
29+
}
30+
}
31+
})
32+
})
33+
})
34+
.map(|i| (i.0.value, (i.0, i.1, i.2)))
2435
.collect::<HashMap<_, _>>();
2536

2637
let mut interrupts = interrupts.into_iter().map(|(_, v)| v).collect::<Vec<_>>();
@@ -43,10 +54,7 @@ pub fn render(
4354
}
4455
pos += 1;
4556

46-
let name_constant_case = Ident::new(
47-
&interrupt.0.name.to_sanitized_constant_case(),
48-
Span::call_site(),
49-
);
57+
let name_constant_case = interrupt.0.name.to_constant_case_ident(Span::call_site());
5058
let description = format!(
5159
"{} - {}",
5260
interrupt.0.value,
@@ -63,17 +71,21 @@ pub fn render(
6371
let value = util::unsuffixed(u64(interrupt.0.value));
6472

6573
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-
};
74+
let mut feature_attribute = TokenStream::new();
75+
let mut not_feature_attribute = TokenStream::new();
76+
if config.feature_group && interrupt.1.is_some() {
77+
let feature_name = interrupt.1.as_ref().unwrap().to_sanitized_snake_case();
78+
feature_attribute_flag = true;
79+
feature_attribute.extend(quote! { #[cfg(feature = #feature_name)] });
80+
not_feature_attribute.extend(quote! { feature = #feature_name, });
81+
}
82+
if config.feature_peripheral {
83+
let feature_name = interrupt.2.to_sanitized_snake_case();
84+
feature_attribute_flag = true;
85+
feature_attribute.extend(quote! { #[cfg(feature = #feature_name)] });
86+
not_feature_attribute.extend(quote! { feature = #feature_name, });
87+
}
88+
let not_feature_attribute = quote! { #[cfg(not(all(#not_feature_attribute)))] };
7789

7890
variants.extend(quote! {
7991
#[doc = #description]

src/generate/peripheral.rs

+50-23
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,10 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result
4040
(false, name_snake_case.clone(), BlockPath::new(&p.name))
4141
};
4242

43-
let feature_attribute = if config.feature_group && p.group_name.is_some() {
43+
let mut feature_attribute = TokenStream::new();
44+
if config.feature_group && p.group_name.is_some() {
4445
let feature_name = p.group_name.as_ref().unwrap().to_sanitized_snake_case();
45-
quote! (#[cfg(feature = #feature_name)])
46-
} else {
47-
quote! {}
46+
feature_attribute.extend(quote! { #[cfg(feature = #feature_name)] });
4847
};
4948

5049
match &p {
@@ -54,18 +53,28 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result
5453
let names_constant_case = names_str.clone().map(|n| Ident::new(&n, span));
5554
let addresses =
5655
(0..=dim.dim).map(|i| util::hex(p.base_address + (i * dim.dim_increment) as u64));
57-
56+
let snake_names = names
57+
.iter()
58+
.map(|p_name| p_name.to_sanitized_snake_case())
59+
.collect::<Vec<_>>();
60+
let feature_attribute_n = snake_names.iter().map(|p_snake| {
61+
let mut feature_attribute = feature_attribute.clone();
62+
if config.feature_peripheral {
63+
feature_attribute.extend(quote! { #[cfg(feature = #p_snake)] })
64+
};
65+
feature_attribute
66+
});
5867
// Insert the peripherals structure
5968
out.extend(quote! {
6069
#(
6170
#[doc = #description]
62-
#feature_attribute
71+
#feature_attribute_n
6372
pub struct #names_constant_case { _marker: PhantomData<*const ()> }
6473

65-
#feature_attribute
74+
#feature_attribute_n
6675
unsafe impl Send for #names_constant_case {}
6776

68-
#feature_attribute
77+
#feature_attribute_n
6978
impl #names_constant_case {
7079
///Pointer to the register block
7180
pub const PTR: *const #base::RegisterBlock = #addresses as *const _;
@@ -77,7 +86,7 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result
7786
}
7887
}
7988

80-
#feature_attribute
89+
#feature_attribute_n
8190
impl Deref for #names_constant_case {
8291
type Target = #base::RegisterBlock;
8392

@@ -87,16 +96,34 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result
8796
}
8897
}
8998

90-
#feature_attribute
99+
#feature_attribute_n
91100
impl core::fmt::Debug for #names_constant_case {
92101
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
93102
f.debug_struct(#names_str).finish()
94103
}
95104
}
96105
)*
97106
});
107+
108+
let feature_any_attribute = quote! {#[cfg(any(#(feature = #snake_names),*))]};
109+
110+
// Derived peripherals may not require re-implementation, and will instead
111+
// use a single definition of the non-derived version.
112+
if derive_regs {
113+
// re-export the base module to allow deriveFrom this one
114+
out.extend(quote! {
115+
#[doc = #description]
116+
#feature_any_attribute
117+
pub use #base as #name_snake_case;
118+
});
119+
return Ok(out);
120+
}
98121
}
99-
_ => {
122+
Peripheral::Single(_) => {
123+
let p_snake = name.to_sanitized_snake_case();
124+
if config.feature_peripheral {
125+
feature_attribute.extend(quote! { #[cfg(feature = #p_snake)] })
126+
};
100127
// Insert the peripheral structure
101128
out.extend(quote! {
102129
#[doc = #description]
@@ -135,19 +162,19 @@ pub fn render(p_original: &Peripheral, index: &Index, config: &Config) -> Result
135162
}
136163
}
137164
});
138-
}
139-
}
140165

141-
// Derived peripherals may not require re-implementation, and will instead
142-
// use a single definition of the non-derived version.
143-
if derive_regs {
144-
// re-export the base module to allow deriveFrom this one
145-
out.extend(quote! {
146-
#[doc = #description]
147-
#feature_attribute
148-
pub use #base as #name_snake_case;
149-
});
150-
return Ok(out);
166+
// Derived peripherals may not require re-implementation, and will instead
167+
// use a single definition of the non-derived version.
168+
if derive_regs {
169+
// re-export the base module to allow deriveFrom this one
170+
out.extend(quote! {
171+
#[doc = #description]
172+
#feature_attribute
173+
pub use #base as #name_snake_case;
174+
});
175+
return Ok(out);
176+
}
177+
}
151178
}
152179

153180
let description = util::escape_brackets(

src/main.rs

+39-7
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, group_names, Config, SourceType, Target},
15+
util::{self, build_rs, Config, SourceType, Target},
1616
};
1717

1818
fn run() -> Result<()> {
@@ -80,6 +80,11 @@ fn run() -> Result<()> {
8080
.long("feature_group")
8181
.help("Use group_name of peripherals as feature"),
8282
)
83+
.arg(
84+
Arg::with_name("feature_peripheral")
85+
.long("feature_peripheral")
86+
.help("Use independent cfg feature flags for each peripheral"),
87+
)
8388
.arg(
8489
Arg::with_name("make_mod")
8590
.long("make_mod")
@@ -176,6 +181,8 @@ fn run() -> Result<()> {
176181
cfg.bool_flag("derive_more", Filter::Arg) || cfg.bool_flag("derive_more", Filter::Conf);
177182
let feature_group =
178183
cfg.bool_flag("feature_group", Filter::Arg) || cfg.bool_flag("feature_group", Filter::Conf);
184+
let feature_peripheral = cfg.bool_flag("feature_peripheral", Filter::Arg)
185+
|| cfg.bool_flag("feature_peripheral", Filter::Conf);
179186

180187
let mut source_type = cfg
181188
.grab()
@@ -201,6 +208,7 @@ fn run() -> Result<()> {
201208
pascal_enum_values,
202209
derive_more,
203210
feature_group,
211+
feature_peripheral,
204212
output_dir: path.clone(),
205213
source_type,
206214
};
@@ -229,18 +237,42 @@ fn run() -> Result<()> {
229237
writeln!(File::create(path.join("build.rs"))?, "{}", build_rs())?;
230238
}
231239

232-
if feature_group {
233-
let group_names: Vec<String> = group_names(&device)
234-
.iter()
235-
.map(|s| format!("{s} = []\n"))
236-
.collect();
240+
if feature_group || feature_peripheral {
241+
let mut features = Vec::new();
242+
if feature_group {
243+
features.extend(
244+
util::group_names(&device)
245+
.iter()
246+
.map(|s| format!("{s} = []\n")),
247+
);
248+
let add_groups: Vec<_> = util::group_names(&device)
249+
.iter()
250+
.map(|s| format!("\"{s}\""))
251+
.collect();
252+
features.push(format!("all-groups = [{}]\n", add_groups.join(",")))
253+
}
254+
if feature_peripheral {
255+
features.extend(
256+
util::peripheral_names(&device)
257+
.iter()
258+
.map(|s| format!("{s} = []\n")),
259+
);
260+
let add_peripherals: Vec<_> = util::peripheral_names(&device)
261+
.iter()
262+
.map(|s| format!("\"{s}\""))
263+
.collect();
264+
features.push(format!(
265+
"all-peripherals = [{}]\n",
266+
add_peripherals.join(",")
267+
))
268+
}
237269
write!(
238270
File::create(path.join("features.toml"))?,
239271
"# Below are the FEATURES generated by svd2rust base on groupName in SVD file.\n\
240272
# Please copy them to Cargo.toml.\n\
241273
[features]\n\
242274
{}",
243-
group_names.join("")
275+
features.join("")
244276
)?;
245277
}
246278

src/util.rs

+26-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use quote::quote;
77
use std::collections::HashSet;
88
use std::path::{Path, PathBuf};
99
use svd_parser::expand::BlockPath;
10-
use svd_rs::{MaybeArray, PeripheralInfo};
10+
use svd_rs::{MaybeArray, Peripheral, PeripheralInfo};
1111

1212
use syn::{
1313
punctuated::Punctuated, token::Colon2, AngleBracketedGenericArguments, GenericArgument, Lit,
@@ -35,6 +35,7 @@ pub struct Config {
3535
pub pascal_enum_values: bool,
3636
pub derive_more: bool,
3737
pub feature_group: bool,
38+
pub feature_peripheral: bool,
3839
pub output_dir: PathBuf,
3940
pub source_type: SourceType,
4041
}
@@ -53,6 +54,7 @@ impl Default for Config {
5354
pascal_enum_values: false,
5455
derive_more: false,
5556
feature_group: false,
57+
feature_peripheral: false,
5658
output_dir: PathBuf::from("."),
5759
source_type: SourceType::default(),
5860
}
@@ -536,10 +538,30 @@ impl FullName for PeripheralInfo {
536538
}
537539
}
538540

539-
pub fn group_names(d: &Device) -> HashSet<Cow<str>> {
540-
d.peripherals
541+
pub fn group_names(d: &Device) -> Vec<Cow<str>> {
542+
let set: HashSet<_> = d
543+
.peripherals
541544
.iter()
542545
.filter_map(|p| p.group_name.as_ref())
543546
.map(|name| name.to_sanitized_snake_case())
544-
.collect()
547+
.collect();
548+
let mut v: Vec<_> = set.into_iter().collect();
549+
v.sort();
550+
v
551+
}
552+
553+
pub fn peripheral_names(d: &Device) -> Vec<String> {
554+
let mut v = Vec::new();
555+
for p in &d.peripherals {
556+
match p {
557+
Peripheral::Single(info) => {
558+
v.push(replace_suffix(&info.name.to_sanitized_snake_case(), ""))
559+
}
560+
Peripheral::Array(info, dim) => v.extend(
561+
svd_rs::array::names(info, dim).map(|n| n.to_sanitized_snake_case().into()),
562+
),
563+
}
564+
}
565+
v.sort();
566+
v
545567
}

0 commit comments

Comments
 (0)