Skip to content

Commit 6edd842

Browse files
committed
Use TokenStreams directly instead of Vec<TokenStream>
Also buffer the output to a String (and postprocess slightly to lessen issues caused by having a single line with hundreds thousands of bytes) giving a 10x speedup. Signed-off-by: Daniel Egger <daniel@eggers-club.de>
1 parent 39934be commit 6edd842

File tree

6 files changed

+48
-47
lines changed

6 files changed

+48
-47
lines changed

src/generate/device.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ pub fn render(
1717
nightly: bool,
1818
generic_mod: bool,
1919
device_x: &mut String,
20-
) -> Result<Vec<TokenStream>> {
21-
let mut out = vec![];
20+
) -> Result<TokenStream> {
21+
let mut out = TokenStream::new();
2222

2323
let doc = format!(
2424
"Peripheral access API for {0} microcontrollers \
@@ -30,20 +30,20 @@ pub fn render(
3030
);
3131

3232
if target == Target::Msp430 {
33-
out.push(quote! {
33+
out.extend(quote! {
3434
#![feature(abi_msp430_interrupt)]
3535
});
3636
}
3737

3838
if target != Target::None && target != Target::CortexM && target != Target::RISCV {
39-
out.push(quote! {
39+
out.extend(quote! {
4040
#![cfg_attr(feature = "rt", feature(global_asm))]
4141
#![cfg_attr(feature = "rt", feature(use_extern_macros))]
4242
#![cfg_attr(feature = "rt", feature(used))]
4343
});
4444
}
4545

46-
out.push(quote! {
46+
out.extend(quote! {
4747
#![doc = #doc]
4848
// Deny a subset of warnings
4949
#![deny(const_err)]
@@ -73,14 +73,14 @@ pub fn render(
7373

7474
match target {
7575
Target::CortexM => {
76-
out.push(quote! {
76+
out.extend(quote! {
7777
extern crate cortex_m;
7878
#[cfg(feature = "rt")]
7979
extern crate cortex_m_rt;
8080
});
8181
}
8282
Target::Msp430 => {
83-
out.push(quote! {
83+
out.extend(quote! {
8484
extern crate msp430;
8585
#[cfg(feature = "rt")]
8686
extern crate msp430_rt;
@@ -89,7 +89,7 @@ pub fn render(
8989
});
9090
}
9191
Target::RISCV => {
92-
out.push(quote! {
92+
out.extend(quote! {
9393
extern crate riscv;
9494
#[cfg(feature = "rt")]
9595
extern crate riscv_rt;
@@ -98,7 +98,7 @@ pub fn render(
9898
Target::None => {}
9999
}
100100

101-
out.push(quote! {
101+
out.extend(quote! {
102102
extern crate bare_metal;
103103
extern crate vcell;
104104

@@ -112,7 +112,7 @@ pub fn render(
112112
if let Some(cpu) = d.cpu.as_ref() {
113113
let bits = util::unsuffixed(u64::from(cpu.nvic_priority_bits));
114114

115-
out.push(quote! {
115+
out.extend(quote! {
116116
///Number available in the NVIC for configuring priority
117117
pub const NVIC_PRIO_BITS: u8 = #bits;
118118
});
@@ -136,7 +136,7 @@ pub fn render(
136136
let mut fields = vec![];
137137
let mut exprs = vec![];
138138
if target == Target::CortexM {
139-
out.push(quote! {
139+
out.extend(quote! {
140140
pub use cortex_m::peripheral::Peripherals as CorePeripherals;
141141
#[cfg(feature = "rt")]
142142
pub use cortex_m_rt::interrupt;
@@ -145,13 +145,13 @@ pub fn render(
145145
});
146146

147147
if fpu_present {
148-
out.push(quote! {
148+
out.extend(quote! {
149149
pub use cortex_m::peripheral::{
150150
CBP, CPUID, DCB, DWT, FPB, FPU, ITM, MPU, NVIC, SCB, SYST, TPIU,
151151
};
152152
});
153153
} else {
154-
out.push(quote! {
154+
out.extend(quote! {
155155
pub use cortex_m::peripheral::{
156156
CBP, CPUID, DCB, DWT, FPB, ITM, MPU, NVIC, SCB, SYST, TPIU,
157157
};
@@ -165,7 +165,7 @@ pub fn render(
165165
} else {
166166
let tokens = syn::parse_file(generic_file).unwrap().into_token_stream();
167167

168-
out.push(quote! {
168+
out.extend(quote! {
169169
#[allow(unused_imports)]
170170
use generic::*;
171171
///Common register and bit access and modify traits
@@ -227,7 +227,7 @@ pub fn render(
227227
}
228228
});
229229

230-
out.push(quote! {
230+
out.extend(quote! {
231231
// NOTE `no_mangle` is used here to prevent linking different minor versions of the device
232232
// crate as that would let you `take` the device peripherals more than once (one per minor
233233
// version)

src/generate/interrupt.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub fn render(
1414
target: Target,
1515
peripherals: &[Peripheral],
1616
device_x: &mut String,
17-
) -> Result<Vec<TokenStream>> {
17+
) -> Result<TokenStream> {
1818
let interrupts = peripherals
1919
.iter()
2020
.flat_map(|p| p.interrupt.iter())
@@ -24,7 +24,7 @@ pub fn render(
2424
let mut interrupts = interrupts.into_iter().map(|(_, v)| v).collect::<Vec<_>>();
2525
interrupts.sort_by_key(|i| i.value);
2626

27-
let mut root = vec![];
27+
let mut root = TokenStream::new();
2828
let mut arms = vec![];
2929
let mut from_arms = vec![];
3030
let mut elements = vec![];
@@ -80,7 +80,7 @@ pub fn render(
8080
writeln!(device_x, "PROVIDE({} = DefaultHandler);", name).unwrap();
8181
}
8282

83-
root.push(quote! {
83+
root.extend(quote! {
8484
#[cfg(feature = "rt")]
8585
extern "C" {
8686
#(fn #names();)*
@@ -169,7 +169,7 @@ pub fn render(
169169
};
170170

171171
if target == Target::CortexM {
172-
root.push(interrupt_enum);
172+
root.extend(interrupt_enum);
173173
} else {
174174
mod_items.push(quote! {
175175
#interrupt_enum
@@ -283,14 +283,14 @@ pub fn render(
283283
}
284284

285285
if !interrupts.is_empty() && target != Target::CortexM {
286-
root.push(quote! {
286+
root.extend(quote! {
287287
#[doc(hidden)]
288288
pub mod interrupt {
289289
#(#mod_items)*
290290
}
291291
});
292292

293-
root.push(quote! {
293+
root.extend(quote! {
294294
pub use self::interrupt::Interrupt;
295295
});
296296
}

src/generate/peripheral.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ pub fn render(
2020
all_peripherals: &[Peripheral],
2121
defaults: &RegisterProperties,
2222
nightly: bool,
23-
) -> Result<Vec<TokenStream>> {
24-
let mut out = vec![];
23+
) -> Result<TokenStream> {
24+
let mut out = TokenStream::new();
2525

2626
let p_derivedfrom = p_original.derived_from.as_ref().and_then(|s| {
2727
all_peripherals.iter().find(|x| x.name == *s)
@@ -50,7 +50,7 @@ pub fn render(
5050
};
5151

5252
// Insert the peripheral structure
53-
out.push(quote! {
53+
out.extend(quote! {
5454
#[doc = #description]
5555
pub struct #name_pc { _marker: PhantomData<*const ()> }
5656

@@ -137,19 +137,18 @@ pub fn render(
137137
// No `struct RegisterBlock` can be generated
138138
if registers.is_empty() && clusters.is_empty() {
139139
// Drop the definition of the peripheral
140-
out.pop();
141-
return Ok(out);
140+
return Ok(TokenStream::new());
142141
}
143142

144143
let defaults = p.default_register_properties.derive_from(defaults);
145144

146145
// Push any register or cluster blocks into the output
147-
let mut mod_items = vec![];
148-
mod_items.push(register_or_cluster_block(ercs, &defaults, None, nightly)?);
146+
let mut mod_items = TokenStream::new();
147+
mod_items.extend(register_or_cluster_block(ercs, &defaults, None, nightly)?);
149148

150149
// Push all cluster related information into the peripheral module
151150
for c in &clusters {
152-
mod_items.push(cluster_block(c, &defaults, p, all_peripherals, nightly)?);
151+
mod_items.extend(cluster_block(c, &defaults, p, all_peripherals, nightly)?);
153152
}
154153

155154
// Push all regsiter realted information into the peripheral module
@@ -169,18 +168,18 @@ pub fn render(
169168
let open = Punct::new('{', Spacing::Alone);
170169
let close = Punct::new('}', Spacing::Alone);
171170

172-
out.push(quote! {
171+
out.extend(quote! {
173172
#[doc = #description]
174173
pub mod #name_sc #open
175174
});
176175

177176
for item in mod_items {
178-
out.push(quote! {
177+
out.extend(quote! {
179178
#item
180179
});
181180
}
182181

183-
out.push(quote! {
182+
out.extend(quote! {
184183
#close
185184
});
186185

@@ -710,7 +709,7 @@ fn cluster_block(
710709
all_peripherals: &[Peripheral],
711710
nightly: bool,
712711
) -> Result<TokenStream> {
713-
let mut mod_items: Vec<TokenStream> = vec![];
712+
let mut mod_items = TokenStream::new();
714713

715714
// name_sc needs to take into account array type.
716715
let description = util::escape_brackets(util::respace(&c.description).as_ref());
@@ -743,7 +742,7 @@ fn cluster_block(
743742
// Generate the sub-cluster blocks.
744743
let clusters = util::only_clusters(&c.children);
745744
for c in &clusters {
746-
mod_items.push(cluster_block(c, &defaults, p, all_peripherals, nightly)?);
745+
mod_items.extend(cluster_block(c, &defaults, p, all_peripherals, nightly)?);
747746
}
748747

749748
Ok(quote! {
@@ -752,7 +751,7 @@ fn cluster_block(
752751
///Register block
753752
#[doc = #description]
754753
pub mod #name_sc {
755-
#(#mod_items)*
754+
#mod_items
756755
}
757756
})
758757
}

src/generate/register.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub fn render(
1515
peripheral: &Peripheral,
1616
all_peripherals: &[Peripheral],
1717
defs: &RegisterProperties,
18-
) -> Result<Vec<TokenStream>> {
18+
) -> Result<TokenStream> {
1919
let access = util::access_of(register);
2020
let name = util::name_of(register);
2121
let span = Span::call_site();
@@ -150,15 +150,15 @@ pub fn render(
150150
});
151151
}
152152

153-
let mut out = vec![];
153+
let mut out = TokenStream::new();
154154
let methods = methods.iter().map(|s| format!("[`{0}`](crate::generic::Reg::{0})", s)).collect::<Vec<_>>();
155155
let mut doc = format!("{}\n\nThis register you can {}. See [API](https://docs.rs/svd2rust/#read--modify--write-api).",
156156
&description, methods.join(", "));
157157

158158
if name_sc != "cfg" {
159159
doc += format!("\n\nFor information about available fields see [{0}]({0}) module", &name_sc).as_str();
160160
}
161-
out.push(quote! {
161+
out.extend(quote! {
162162
#[doc = #doc]
163163
pub type #name_pc = crate::Reg<#rty, #_name_pc>;
164164

@@ -169,31 +169,31 @@ pub fn render(
169169

170170
if can_read {
171171
let doc = format!("`read()` method returns [{0}::R]({0}::R) reader structure", &name_sc);
172-
out.push(quote! {
172+
out.extend(quote! {
173173
#[doc = #doc]
174174
impl crate::Readable for #name_pc {}
175175
});
176176
}
177177
if can_write {
178178
let doc = format!("`write(|w| ..)` method takes [{0}::W]({0}::W) writer structure", &name_sc);
179-
out.push(quote! {
179+
out.extend(quote! {
180180
#[doc = #doc]
181181
impl crate::Writable for #name_pc {}
182182
});
183183
}
184184

185-
out.push(quote! {
185+
out.extend(quote! {
186186
#[doc = #description]
187187
pub mod #name_sc #open
188188
});
189189

190190
for item in mod_items {
191-
out.push(quote! {
191+
out.extend(quote! {
192192
#item
193193
});
194194
}
195195

196-
out.push(quote! {
196+
out.extend(quote! {
197197
#close
198198
});
199199

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ pub fn generate(xml: &str, target: Target, nightly: bool) -> Result<Generation>
482482
&mut lib_rs,
483483
"{}",
484484
quote! {
485-
#(#items)*
485+
#items
486486
}
487487
)
488488
.or(Err(SvdError::Fmt))?;

src/main.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod util;
1515
use std::fs::File;
1616
use std::io::Write;
1717
use std::process;
18+
use std::fmt::Write as _;
1819

1920
use clap::{App, Arg};
2021

@@ -102,9 +103,10 @@ fn run() -> Result<()> {
102103
let items = generate::device::render(&device, target, nightly, generic_mod, &mut device_x)?;
103104
let mut file = File::create("lib.rs").expect("Couldn't create lib.rs file");
104105

105-
for item in items {
106-
writeln!(file, "{}", item).expect("Could not write item to lib.rs");
107-
}
106+
let mut data = String::new();
107+
write!(data, "{}", items).expect("Could not output code");
108+
let data = data.replace("] ", "]\n");
109+
file.write_all(data.as_ref()).expect("Could not write code to lib.rs");
108110

109111
if target == Target::CortexM {
110112
writeln!(File::create("device.x").unwrap(), "{}", device_x).unwrap();

0 commit comments

Comments
 (0)